This is generate-makefile.m in view mode; [Download] [Up]
/*
* generate-makefile
*
* COPYRIGHT: Hutchison Avenue Software, 1994 [514/499-2067, info@hasc.ca]
*
* USAGE:
*
* cc -o generate-makefile generate-makefile.m -all_load -lMiscKit -lNeXT_s
*
* generate-makefile Class.m OtherClass.m OtherOtherClass.m ...
*
* CREDITS:
*
* Author: Darcy Brockbank <samurai@hasc.ca>
* Date: Thursday, Jul 6, 1995
* Version: 1.4
*/
static const char * version = "generate-makefile (v1.2)";
/*
* ADDITIONAL CREDITS:
*
* This program makes use of the most excellent MiscKit. If you don't
* have the MiscKit, you can't compile this program. Luckily for you,
* the MiscKit is available for free... contact Don Yactman at
* Don_Yacktman@byu.edu for information on the MiscKit.
*
* Modification History:
*
* Version 1.0, Dec 4, 1994. samurai@hasc.ca.
* Version 1.1, Dec 8, 1994. samurai@hasc.ca.
* - added ICONSECTIONS to generated makefile
* - changed spacing
* - added PSWFILES
* Version 1.2, Dec 15, 1994. samurai@hasc.ca.
* - checks to see if a class is in there before adding it.
* Version 1.3, July 6, 1995. yackd@xmission.com.
* - changed calls to MiscString compatability methods to
* calls to the *real* method that should be called.
*
* Description:
*
* Adds the given Classes to the PB.project in the current directory, and
* generates a new makefile. This program is pretty stripped down in
* functionality. I can forsee someone adding a few switches to the program,
* adding functionality, and this program becoming a nice addition for people
* using emacs and other configurable editors...
*
* Calling this program with no arguments simply transforms the PB.project
* file in the current directory into a Makefile. So, if you have to make
* custom changes to the PB.project, you can do so then call this
* program.
*
* Please feel free to add functionality to this, and keep me up to date on
* new versions! This is only a quick and dirty hack...
*
* DISCLAIMER
*
* This software is provided as-is, with no warrantee, or guarantee of fitness
* for any particular purpose. You use this software at your own risk, and the
* Author(s) may not be held liable for damages resulting from use of this
* software.
*
* COPYING INFORMATION AND GRANTED RIGHTS
*
* You may freely copy and modify this software as long as you do not modify
* any part of this notice, with the following two exceptions:
*
* (1) If you modify this code, you must add your name and email address
* to the modifiction history, together with an explanation of your
* modification.
* (2) If your modification changes any functionality already present, you
* may modify the description to reflect your changes.
*
*/
#import <misckit/MiscString.h>
#import <misckit/MiscParseTableFile.h>
#import <misckit/MiscDictionary.h>
#import <misckit/MiscList.h>
#import <errno.h>
id read_project(const char *filename)
{
id string = [[MiscString alloc] initString:filename];
id dictionary = MiscParseTableFile(string);
if (!dictionary) {
fprintf(stderr,"Problem opening \"%s\", (%s)\n",
filename,strerror(errno));
exit(1);
}
[string free];
return dictionary;
}
id list_from_array(int count, const char * const *names)
{
int i;
id list = [[List alloc] init];
for (i=0;i<count;i++){
id string = [[MiscString alloc] initString:names[i]];
[list addObject:string];
}
return list;
}
void add_if_absent(id list, id object)
{
int i, count = [list count];
for(i=0;i<count;i++){
if ([[list objectAt:i] isEqual:object]){
return;
}
}
[list addObject:object];
}
void append_uniquely(id list, id files)
{
int i, count = [files count];
for(i=0;i<count;i++){
add_if_absent(list,[files objectAt:i]);
}
}
void add_to_mfiles(id mfiles, id dictionary)
{
id name = [[MiscString alloc] initString:"FILESTABLE"];
id section = [dictionary valueForKey:name];
[name setStringValue:"M_FILES"];
section = [section valueForKey:name];
append_uniquely(section,mfiles);
[mfiles empty];
}
void add_to_classes(id mfiles, id dictionary)
{
id name = [[MiscString alloc] initString:"FILESTABLE"];
id section = [dictionary valueForKey:name];
[name setStringValue:"CLASSES"];
section = [section valueForKey:name];
append_uniquely(section,mfiles);
[mfiles empty];
}
void backup(const char *name)
{
struct stat sb;
id backup = [[MiscString alloc] initString:name];
[backup cat:"~"];
if (stat(name,&sb)==0){
/* we have something to back up */
if (stat([backup stringValue],&sb)){
/* error finding old backup */
if (errno != ENOENT) {
/* backup was there, but something happened */
fprintf(stderr,"Error stat'ing old backup"
" \"%s\", (%s)\n",
[backup stringValue],strerror(errno));
exit(1);
}
} else {
/* backup was there, so remove it */
if (unlink([backup stringValue])){
fprintf(stderr,"Error unlinking old backup"
" \"%s\", (%s)\n",
[backup stringValue],strerror(errno));
exit(1);
}
}
/* make the backup */
if (link(name,[backup stringValue])){
fprintf(stderr,"Error creating backup \"%s\", (%s)\n",
[backup stringValue],strerror(errno));
exit(1);
} else if (unlink(name)){ /* remove the existing file */
fprintf(stderr,"Error deleting old file \"%s\", (%s)\n",
name,strerror(errno));
exit(1);
}
}
}
void write_project(const char *name, id dictionary)
{
id string = [[MiscString alloc] initString:name];
backup(name);
MiscWriteTableFile(string,dictionary);
[string free];
}
void write_makefile(const char *name, id dictionary);
/*
* main
*/
void main(int argc, char *argv[])
{
id dictionary = read_project("PB.project");
if (argc>1){
id mfiles = list_from_array(argc-1,argv+1);
add_to_classes(mfiles,dictionary);
write_project("PB.project",dictionary);
}
write_makefile("Makefile",dictionary);
}
/*
* This next chunk handles 80 character wide formatting stuff for the rules.
* You call format_setup() then call format_next() every time you want to
* write a string, and it takes care of making sure the correct number of
* spaces is being added, and that you don't go over the top.
*/
#define PREFIX " "
#define PREFIX_LEN (strlen(PREFIX))
#define MAX_LEN 80
static int _formatLen;
void format_setup(FILE *file, int startlen)
{
_formatLen = startlen;
}
void format_next(FILE *file, id string)
{
_formatLen += ([string length]) +1 ;
if (_formatLen>=MAX_LEN-2){
fprintf(file,"\\\n%s",PREFIX);
_formatLen = PREFIX_LEN + ([string length]) +1;
}
fprintf(file,"%s ",[string stringValue]);
}
/*
* All the semi-complicated stuff follows here (it's all for generating the
* makefile. I'd normally not put it after main(), but everything before
* main() is very simple...
*/
void write_key(FILE *file, const char *rule, const char *tag, id dict)
{
id find = [[MiscString alloc] initString:tag];
id val = [dict valueForKey:find];
if (val) fprintf(file,"%s = %s\n",rule,[val stringValue]);
[find free];
}
void write_blank(FILE *file)
{
fprintf(file,"\n");
}
void write_comment_header(FILE *file)
{
fprintf(file,
"#\n"
"# Generated by \"%s\"\n"
"#\n"
"# Copyright (C) 1994, Hutchison Avenue Software.\n"
"#\n"
"# \"%s\" is distributable and modifiable, see the source\n"
"# for limitations and restrictions.\n"
"#\n"
"# Contact Darcy Brockbank <samurai@hasc.ca> if you have any problems.\n"
"#\n",version,version);
}
void write_list_formatted(FILE *file, id list)
{
int i,count = [list count];
for(i=0;i<count;i++){
id string = [list objectAt:i];
format_next(file,string);
}
fprintf(file,"\n");
}
void write_dictionary_formatted(FILE *file, id dict)
{
id key,val;
NXHashState state = [dict initState];
while([dict nextState:&state key:(void **)&key value:(void **)&val]){
format_next(file,key);
}
fprintf(file,"\n");
}
void write_dictionary(FILE *file, const char *rule, const char *tag, id dict)
{
id find = [[MiscString alloc] initString:tag];
id subdict = [dict valueForKey:find];
if (subdict) {
fprintf(file,"%s = ",rule);
format_setup(file,strlen(rule)+3);
write_dictionary_formatted(file,subdict);
}
[find free];
}
void write_list(FILE *file, const char *rule, const char *tag, id dict)
{
id find = [[MiscString alloc] initString:tag];
id list = [dict valueForKey:find];
if (list) {
fprintf(file,"%s = ",rule);
format_setup(file,strlen(rule)+3);
write_list_formatted(file,list);
}
[find free];
}
void write_global_resources(FILE *file, const char *rule, id dict)
{
id find = [[MiscString alloc] initString:"FILESTABLE"];
id filestable = [dict valueForKey:find];
id local, list;
const char * resources[] = {"IMAGES", "OTHER_RESOURCES",
"INTERFACES", 0};
int i,j,count;
fprintf(file,"%s = ",rule);
format_setup(file,strlen(rule)+3);
[find setStringValue:"LOCALIZABLE_FILES"];
local = [dict valueForKey:find];
for(i=0;resources[i];i++){
[find setStringValue:resources[i]];
list = [filestable valueForKey:find];
for(j=0,count=[list count];j<count;j++){
id current = [list objectAt:j];
if (![local isKey:current]){
format_next(file,current);
}
}
}
fprintf(file,"\n");
[find free];
}
void write_libs(FILE *file, const char *rule, const char *tag, id dict)
{
id find = [[MiscString alloc] initString:tag];
id libs = [dict valueForKey:find];
int i,count;
fprintf(file,"%s = ",rule);
format_setup(file,strlen(rule)+3);
for(i=0,count=[libs count];i<count;i++){
id current = [libs objectAt:i];
[current insert:"-l"];
format_next(file,current);
}
fprintf(file,"\n");
[find free];
}
void write_iconsections(FILE *file, const char *rule, id dict)
{
id find = [[MiscString alloc] initString:"DOCICONFILES"];
id docicons = [dict valueForKey:find];
id appicon;
int i,count;
fprintf(file,"%s = ",rule);
format_setup(file,strlen(rule)+3);
[find setStringValue:"APPICON"];
appicon = [dict valueForKey:find];
if (!appicon) {
appicon = [[MiscString alloc]
initString:"/usr/lib/NextStep/Workspace.app/application.tiff"];
}
[appicon insert:"-sectcreate __ICON app "];
format_next(file,appicon);
for(i=0,count=[docicons count];i<count;i++){
id current = [docicons objectAt:i];
id extension = [current fileBasename];
[current insert:" "];
[current insert:[extension stringValue]];
[current insert:"-sectcreate __ICON "];
format_next(file,current);
[extension free];
}
fprintf(file,"\n");
[find free];
}
void write_make_info(FILE *file, id dict)
{
const char * types[] = {"Application", "Bundle", "Palette", "Tool",0};
const char * files[] = {"app.make", "bundle.make", "palette.make",
"tool.make",0};
int i;
id find = [[MiscString alloc] initString:"PROJECTTYPE"];
id string;
/* driverkit should do this differently */
fprintf(file,
"%s = %s\n",
"MAKEFILEDIR",
"/NextDeveloper/Makefiles/app");
string = [dict valueForKey:find];
for(i=0;types[i];i++){
if ([string cmp:types[i]]==0){
break;
}
}
if (types[i]){
fprintf(file,"%s = %s\n","MAKEFILE",files[i]);
} else {
fprintf(stderr,"Error... can't find a makefile type\n");
fprintf(stderr,"You should restore the Makefile from the backup.\n");
exit(1);
}
[find free];
}
void write_string(FILE *file, const char *string)
{
fprintf(file,"%s\n",string);
}
void write_rule(FILE *file, const char *rule, const char *val)
{
fprintf(file,"%s = %s\n",rule,val);
}
void write_makefile(const char *name, id dict)
{
FILE * file;
id find = [[MiscString alloc] initString:"FILESTABLE"];
id filestable = [dict valueForKey:find];
[find free];
backup(name);
file = fopen(name,"w");
if (!file) {
fprintf(stderr,"Can't open \"%s\" for writing, (%s)\n",
name,strerror(errno));
exit(1);
}
write_comment_header(file);
write_blank(file);
write_key(file,"NAME","PROJECTNAME",dict);
write_blank(file);
write_key(file,"PROJECTVERSION","PROJECTVERSION",dict);
write_key(file,"LANGUAGE","LANGUAGE",dict);
write_key(file,"APPICON","APPICON",dict);
write_blank(file);
write_list(file,"DOCICONS","DOCICONFILES",dict);
write_blank(file);
write_dictionary(file,"LOCAL_RESOURCES","LOCALIZABLE_FILES",dict);
write_blank(file);
write_global_resources(file,"GLOBAL_RESOURCES",dict);
write_blank(file);
write_list(file,"CLASSES","CLASSES",filestable);
write_blank(file);
write_list(file,"HFILES","H_FILES",filestable);
write_blank(file);
write_list(file,"MFILES","M_FILES",filestable);
write_blank(file);
write_list(file,"CFILES","C_FILES",filestable);
write_blank(file);
write_list(file,"SUBPROJECTS","SUBPROJECTS",filestable);
write_blank(file);
write_list(file,"BUNDLES","BUNDLES",filestable);
write_blank(file);
write_list(file,"PSWFILES","PSW_FILES",filestable);
write_blank(file);
write_list(file,"OTHERSRCS","OTHER_SOURCES",filestable);
write_blank(file);
write_blank(file);
write_make_info(file,dict);
write_key(file,"INSTALLDIR","INSTALLDIR",dict);
write_rule(file,"SOURCEMODE","444");
write_blank(file);
write_iconsections(file,"ICONSECTIONS",dict);
write_blank(file);
write_libs(file,"LIBS","OTHER_LIBS",filestable);
write_rule(file,"DEBUG_LIBS","$(LIBS)");
write_rule(file,"PROF_LIBS","$(LIBS)");
write_blank(file);
write_string(file,"-include Makefile.preamble");
write_string(file,"include $(MAKEFILEDIR)/$(MAKEFILE)");
write_string(file,"-include Makefile.postamble");
write_string(file,"-include Makefile.dependencies");
}
These are the contents of the former NiCE NeXT User Group NeXTSTEP/OpenStep software archive, currently hosted by Netfuture.ch.