home *** CD-ROM | disk | FTP | other *** search
/ Nebula 2 / Nebula Two.iso / SourceCode / MiscKit1.7.1 / MiscKit / Examples / generate-makefile / generate-makefile.m next >
Encoding:
Text File  |  1995-07-06  |  13.0 KB  |  488 lines

  1. /*
  2.  * generate-makefile
  3.  *
  4.  * COPYRIGHT: Hutchison Avenue Software, 1994 [514/499-2067, info@hasc.ca]
  5.  *
  6.  * USAGE:
  7.  *
  8.  * cc -o generate-makefile generate-makefile.m -all_load -lMiscKit -lNeXT_s
  9.  *
  10.  * generate-makefile Class.m OtherClass.m OtherOtherClass.m ...
  11.  *
  12.  * CREDITS:
  13.  *
  14.  *    Author: Darcy Brockbank <samurai@hasc.ca>
  15.  *    Date: Thursday, Jul 6, 1995
  16.  *    Version: 1.4
  17.  */
  18.  
  19. static const char * version = "generate-makefile (v1.2)";
  20.  
  21. /*
  22.  * ADDITIONAL CREDITS:
  23.  *
  24.  * This program makes use of the most excellent MiscKit. If you don't
  25.  * have the MiscKit, you can't compile this program. Luckily for you,
  26.  * the MiscKit is available for free... contact Don Yactman at
  27.  * Don_Yacktman@byu.edu for information on the MiscKit.
  28.  *
  29.  * Modification History:
  30.  *
  31.  * Version 1.0, Dec 4, 1994. samurai@hasc.ca.
  32.  * Version 1.1, Dec 8, 1994. samurai@hasc.ca.
  33.  *    - added ICONSECTIONS to generated makefile
  34.  *    - changed spacing
  35.  *    - added PSWFILES
  36.  * Version 1.2, Dec 15, 1994. samurai@hasc.ca.
  37.  *    - checks to see if a class is in there before adding it.
  38.  * Version 1.3, July 6, 1995. yackd@xmission.com.
  39.  *    - changed calls to MiscString compatability methods to
  40.  *    calls to the *real* method that should be called.
  41.  *
  42.  * Description:
  43.  *
  44.  * Adds the given Classes to the PB.project in the current directory, and
  45.  * generates a new makefile. This program is pretty stripped down in
  46.  * functionality. I can forsee someone adding a few switches to the program,
  47.  * adding functionality, and this program becoming a nice addition for people
  48.  * using emacs and other configurable editors...
  49.  *
  50.  * Calling this program with no arguments simply transforms the PB.project
  51.  * file in the current directory into a Makefile. So, if you have to make
  52.  * custom changes to the PB.project, you can do so then call this
  53.  * program.
  54.  *
  55.  * Please feel free to add functionality to this, and keep me up to date on
  56.  * new versions! This is only a quick and dirty hack...
  57.  *
  58.  * DISCLAIMER
  59.  *
  60.  * This software is provided as-is, with no warrantee, or guarantee of fitness
  61.  * for any particular purpose. You use this software at your own risk, and the
  62.  * Author(s) may not be held liable for damages resulting from use of this
  63.  * software.
  64.  *
  65.  * COPYING INFORMATION AND GRANTED RIGHTS
  66.  *
  67.  * You may freely copy and modify this software as long as you do not modify
  68.  * any part of this notice, with the following two exceptions:
  69.  *
  70.  * (1) If you modify this code, you must add your name and email address
  71.  *     to the modifiction history, together with an explanation of your
  72.  *     modification.     
  73.  * (2) If your modification changes any functionality already present, you
  74.  *     may modify the description to reflect your changes.
  75.  *     
  76.  */
  77.  
  78. #import <misckit/MiscString.h>
  79. #import <misckit/MiscParseTableFile.h>
  80. #import <misckit/MiscDictionary.h>
  81. #import <misckit/MiscList.h>
  82. #import <errno.h>
  83.  
  84. id read_project(const char *filename)
  85. {
  86.     id string = [[MiscString alloc] initString:filename];
  87.     id dictionary = MiscParseTableFile(string);
  88.     if (!dictionary) {
  89.         fprintf(stderr,"Problem opening \"%s\", (%s)\n",
  90.             filename,strerror(errno));
  91.         exit(1);
  92.     }
  93.     [string free];
  94.     return dictionary;
  95. }
  96.  
  97. id list_from_array(int count, const char * const *names)
  98. {
  99.     int i;
  100.     id list = [[List alloc] init];
  101.     for (i=0;i<count;i++){
  102.         id string = [[MiscString alloc] initString:names[i]];
  103.         [list addObject:string];
  104.     }
  105.     return list;
  106. }
  107.  
  108. void add_if_absent(id list, id object)
  109. {
  110.     int i, count = [list count];
  111.     for(i=0;i<count;i++){
  112.         if ([[list objectAt:i] isEqual:object]){
  113.             return;
  114.         }
  115.     }
  116.     [list addObject:object];
  117. }
  118.  
  119. void append_uniquely(id list, id files)
  120. {
  121.     int i, count = [files count];
  122.     for(i=0;i<count;i++){
  123.         add_if_absent(list,[files objectAt:i]);
  124.     }
  125. }
  126.  
  127. void add_to_mfiles(id mfiles, id dictionary)
  128. {
  129.     id name = [[MiscString alloc] initString:"FILESTABLE"];
  130.     id section = [dictionary valueForKey:name];
  131.     [name setStringValue:"M_FILES"];
  132.     section = [section valueForKey:name];
  133.     append_uniquely(section,mfiles);
  134.     [mfiles empty];
  135. }
  136.  
  137. void add_to_classes(id mfiles, id dictionary)
  138. {
  139.     id name = [[MiscString alloc] initString:"FILESTABLE"];
  140.     id section = [dictionary valueForKey:name];
  141.     [name setStringValue:"CLASSES"];
  142.     section = [section valueForKey:name];
  143.     append_uniquely(section,mfiles);
  144.     [mfiles empty];
  145. }
  146.  
  147. void backup(const char *name)
  148. {
  149.     struct stat sb;
  150.     id backup = [[MiscString alloc] initString:name];
  151.     [backup cat:"~"];
  152.     if (stat(name,&sb)==0){
  153.         /* we have something to back up */
  154.         if (stat([backup stringValue],&sb)){
  155.             /* error finding old backup */
  156.             if (errno != ENOENT) {
  157.                 /* backup was there, but something happened */
  158.                 fprintf(stderr,"Error stat'ing old backup"
  159.                     " \"%s\", (%s)\n",
  160.                     [backup stringValue],strerror(errno));
  161.                 exit(1);
  162.             }
  163.         } else {
  164.             /* backup was there, so remove it */
  165.             if (unlink([backup stringValue])){
  166.                 fprintf(stderr,"Error unlinking old backup"
  167.                     " \"%s\", (%s)\n",
  168.                     [backup stringValue],strerror(errno));
  169.                 exit(1);
  170.             }
  171.         }
  172.         /* make the backup */
  173.         if (link(name,[backup stringValue])){
  174.             fprintf(stderr,"Error creating backup \"%s\", (%s)\n",
  175.                     [backup stringValue],strerror(errno));
  176.             exit(1);
  177.         } else if (unlink(name)){ /* remove the existing file */
  178.             fprintf(stderr,"Error deleting old file \"%s\", (%s)\n",
  179.                     name,strerror(errno));
  180.             exit(1);
  181.         }
  182.         
  183.     }
  184. }
  185.  
  186. void write_project(const char *name, id dictionary)
  187. {
  188.     id string = [[MiscString alloc] initString:name];
  189.     backup(name);
  190.     MiscWriteTableFile(string,dictionary);
  191.     [string free];
  192. }
  193.  
  194. void write_makefile(const char *name, id dictionary);
  195.  
  196. /*
  197.  * main
  198.  */
  199. void main(int argc, char *argv[])
  200. {
  201.     id dictionary = read_project("PB.project");
  202.     if (argc>1){
  203.         id mfiles = list_from_array(argc-1,argv+1);
  204.         add_to_classes(mfiles,dictionary);
  205.         write_project("PB.project",dictionary);
  206.     }
  207.     write_makefile("Makefile",dictionary);
  208. }
  209.  
  210. /*
  211.  * This next chunk handles 80 character wide formatting stuff for the rules.
  212.  * You call format_setup() then call format_next() every time you want to
  213.  * write a string, and it takes care of making sure the correct number of
  214.  * spaces is being added, and that you don't go over the top.
  215.  */
  216. #define PREFIX "    "
  217. #define PREFIX_LEN (strlen(PREFIX))
  218. #define MAX_LEN 80
  219.  
  220. static int _formatLen;
  221.  
  222. void format_setup(FILE *file, int startlen)
  223. {
  224.     _formatLen = startlen;
  225. }
  226. void format_next(FILE *file, id string)
  227. {
  228.     _formatLen += ([string length]) +1 ;
  229.     if (_formatLen>=MAX_LEN-2){
  230.         fprintf(file,"\\\n%s",PREFIX);
  231.         _formatLen = PREFIX_LEN + ([string length]) +1;
  232.     }
  233.     fprintf(file,"%s ",[string stringValue]);
  234. }
  235.  
  236. /*
  237.  * All the semi-complicated stuff follows here (it's all for generating the
  238.  * makefile. I'd normally not put it after main(), but everything before
  239.  * main() is very simple... 
  240.  */
  241.  
  242. void write_key(FILE *file, const char *rule, const char *tag, id dict)
  243. {
  244.     id find = [[MiscString alloc] initString:tag];
  245.     id val = [dict valueForKey:find];
  246.     if (val) fprintf(file,"%s = %s\n",rule,[val stringValue]);
  247.     [find free];
  248. }
  249.  
  250. void write_blank(FILE *file)
  251. {
  252.     fprintf(file,"\n");
  253. }
  254.  
  255. void write_comment_header(FILE *file)
  256. {
  257.     fprintf(file,
  258.         "#\n"
  259.         "# Generated by \"%s\"\n"
  260.         "#\n"
  261.         "# Copyright (C) 1994, Hutchison Avenue Software.\n"
  262.         "#\n"
  263.         "# \"%s\" is distributable and modifiable, see the source\n"
  264.         "# for limitations and restrictions.\n"
  265.         "#\n"
  266.         "# Contact Darcy Brockbank <samurai@hasc.ca> if you have any problems.\n"
  267.         "#\n",version,version);
  268. }
  269.  
  270. void write_list_formatted(FILE *file, id list)
  271. {
  272.     int i,count = [list count];
  273.     for(i=0;i<count;i++){
  274.         id string = [list objectAt:i];
  275.         format_next(file,string);
  276.     }
  277.     fprintf(file,"\n");
  278. }
  279.  
  280. void write_dictionary_formatted(FILE *file, id dict)
  281. {
  282.     id key,val;
  283.     NXHashState state = [dict initState];
  284.     while([dict nextState:&state key:(void **)&key value:(void **)&val]){
  285.         format_next(file,key);
  286.     }
  287.     fprintf(file,"\n");
  288. }
  289.  
  290. void write_dictionary(FILE *file, const char *rule, const char *tag, id dict)
  291. {
  292.     id find = [[MiscString alloc] initString:tag];
  293.     id subdict = [dict valueForKey:find];
  294.     if (subdict) {
  295.         fprintf(file,"%s = ",rule);
  296.         format_setup(file,strlen(rule)+3);
  297.         write_dictionary_formatted(file,subdict);
  298.     }
  299.     [find free];
  300. }
  301.  
  302. void write_list(FILE *file, const char *rule, const char *tag, id dict)
  303. {
  304.     id find = [[MiscString alloc] initString:tag];
  305.     id list = [dict valueForKey:find];
  306.     if (list) {
  307.         fprintf(file,"%s = ",rule);
  308.         format_setup(file,strlen(rule)+3);
  309.         write_list_formatted(file,list);
  310.     }
  311.     [find free];
  312. }
  313.  
  314. void write_global_resources(FILE *file, const char *rule, id dict)
  315. {
  316.     id find = [[MiscString alloc] initString:"FILESTABLE"];
  317.     id filestable = [dict valueForKey:find];
  318.     id local, list;
  319.     const char * resources[] = {"IMAGES", "OTHER_RESOURCES",
  320.                     "INTERFACES", 0};
  321.     int i,j,count;
  322.  
  323.     fprintf(file,"%s = ",rule);
  324.     format_setup(file,strlen(rule)+3);
  325.     [find setStringValue:"LOCALIZABLE_FILES"];
  326.     local = [dict valueForKey:find];
  327.     for(i=0;resources[i];i++){
  328.         [find setStringValue:resources[i]];
  329.         list = [filestable valueForKey:find];
  330.         for(j=0,count=[list count];j<count;j++){
  331.             id current = [list objectAt:j];
  332.             if (![local isKey:current]){
  333.                 format_next(file,current);
  334.             }
  335.         }
  336.     }
  337.     fprintf(file,"\n");
  338.     [find free];
  339. }
  340.  
  341. void write_libs(FILE *file, const char *rule, const char *tag, id dict)
  342. {
  343.     id find = [[MiscString alloc] initString:tag];
  344.     id libs = [dict valueForKey:find];
  345.     int i,count;
  346.     fprintf(file,"%s = ",rule);
  347.     format_setup(file,strlen(rule)+3);
  348.     for(i=0,count=[libs count];i<count;i++){
  349.         id current = [libs objectAt:i];
  350.         [current insert:"-l"];
  351.         format_next(file,current);
  352.     }
  353.     fprintf(file,"\n");
  354.     [find free];
  355. }
  356.  
  357. void write_iconsections(FILE *file, const char *rule, id dict)
  358. {
  359.     id find = [[MiscString alloc] initString:"DOCICONFILES"];
  360.     id docicons = [dict valueForKey:find];
  361.     id appicon;
  362.     int i,count;
  363.     
  364.     fprintf(file,"%s = ",rule);
  365.     format_setup(file,strlen(rule)+3);
  366.     [find setStringValue:"APPICON"];
  367.     appicon = [dict valueForKey:find];
  368.     if (!appicon) {
  369.         appicon = [[MiscString alloc]
  370.             initString:"/usr/lib/NextStep/Workspace.app/application.tiff"];
  371.     }
  372.     [appicon insert:"-sectcreate __ICON app "];
  373.     format_next(file,appicon);
  374.     for(i=0,count=[docicons count];i<count;i++){
  375.         id current = [docicons objectAt:i];
  376.         id extension = [current fileBasename];
  377.         [current insert:" "];
  378.         [current insert:[extension stringValue]];
  379.         [current insert:"-sectcreate __ICON "];
  380.         format_next(file,current);
  381.         [extension free];
  382.     }
  383.     fprintf(file,"\n");
  384.     [find free];
  385. }
  386.  
  387. void write_make_info(FILE *file, id dict)
  388. {
  389.     const char * types[] = {"Application", "Bundle", "Palette", "Tool",0};
  390.     const char * files[] = {"app.make", "bundle.make", "palette.make",
  391.                 "tool.make",0};
  392.     int i;
  393.     id find = [[MiscString alloc] initString:"PROJECTTYPE"];
  394.     id string;
  395.     
  396.     /* driverkit should do this differently */
  397.     fprintf(file,
  398.         "%s = %s\n",
  399.         "MAKEFILEDIR",
  400.         "/NextDeveloper/Makefiles/app");
  401.     string = [dict valueForKey:find];
  402.     for(i=0;types[i];i++){
  403.         if ([string cmp:types[i]]==0){
  404.             break;
  405.         }
  406.     }
  407.     if (types[i]){
  408.         fprintf(file,"%s = %s\n","MAKEFILE",files[i]);
  409.     } else {
  410.         fprintf(stderr,"Error... can't find a makefile type\n");
  411.         fprintf(stderr,"You should restore the Makefile from the backup.\n");
  412.         exit(1);
  413.     }
  414.     [find free];
  415. }
  416.  
  417. void write_string(FILE *file, const char *string)
  418. {
  419.     fprintf(file,"%s\n",string);
  420. }
  421.  
  422. void write_rule(FILE *file, const char *rule, const char *val)
  423. {
  424.     fprintf(file,"%s = %s\n",rule,val);
  425. }
  426.     
  427. void write_makefile(const char *name, id dict)
  428. {
  429.     FILE * file;
  430.     id find = [[MiscString alloc] initString:"FILESTABLE"];
  431.     id filestable = [dict valueForKey:find];
  432.  
  433.     [find free];
  434.     backup(name);
  435.     file = fopen(name,"w");
  436.     if (!file) {
  437.         fprintf(stderr,"Can't open \"%s\" for writing, (%s)\n",
  438.             name,strerror(errno));
  439.         exit(1);
  440.     }
  441.     write_comment_header(file);
  442.     write_blank(file);
  443.     write_key(file,"NAME","PROJECTNAME",dict);
  444.     write_blank(file);
  445.     write_key(file,"PROJECTVERSION","PROJECTVERSION",dict);
  446.     write_key(file,"LANGUAGE","LANGUAGE",dict);
  447.     write_key(file,"APPICON","APPICON",dict);
  448.     write_blank(file);
  449.     write_list(file,"DOCICONS","DOCICONFILES",dict);
  450.     write_blank(file);
  451.     write_dictionary(file,"LOCAL_RESOURCES","LOCALIZABLE_FILES",dict);
  452.     write_blank(file);
  453.     write_global_resources(file,"GLOBAL_RESOURCES",dict);
  454.     write_blank(file);
  455.     write_list(file,"CLASSES","CLASSES",filestable);
  456.     write_blank(file);
  457.     write_list(file,"HFILES","H_FILES",filestable);
  458.     write_blank(file);
  459.     write_list(file,"MFILES","M_FILES",filestable);
  460.     write_blank(file);
  461.     write_list(file,"CFILES","C_FILES",filestable);
  462.     write_blank(file);
  463.     write_list(file,"SUBPROJECTS","SUBPROJECTS",filestable);
  464.     write_blank(file);
  465.     write_list(file,"BUNDLES","BUNDLES",filestable);
  466.     write_blank(file);
  467.     write_list(file,"PSWFILES","PSW_FILES",filestable);
  468.     write_blank(file);
  469.     write_list(file,"OTHERSRCS","OTHER_SOURCES",filestable);
  470.     write_blank(file);
  471.     write_blank(file);
  472.     write_make_info(file,dict);
  473.     write_key(file,"INSTALLDIR","INSTALLDIR",dict);
  474.     write_rule(file,"SOURCEMODE","444");
  475.     write_blank(file);
  476.     write_iconsections(file,"ICONSECTIONS",dict);
  477.     write_blank(file);
  478.     write_libs(file,"LIBS","OTHER_LIBS",filestable);
  479.     write_rule(file,"DEBUG_LIBS","$(LIBS)");
  480.     write_rule(file,"PROF_LIBS","$(LIBS)");
  481.     write_blank(file);
  482.     write_string(file,"-include Makefile.preamble");
  483.     write_string(file,"include $(MAKEFILEDIR)/$(MAKEFILE)");
  484.     write_string(file,"-include Makefile.postamble");
  485.     write_string(file,"-include Makefile.dependencies");
  486. }
  487.  
  488.