home *** CD-ROM | disk | FTP | other *** search
- /*
- * 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");
- }
-
-