home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 5 / FreshFish_July-August1994.bin / bbs / util / mg-3b.lha / mg-3b / src.LZH / tools / makemake.c < prev    next >
Encoding:
C/C++ Source or Header  |  1990-05-23  |  10.8 KB  |  427 lines

  1. /*
  2.  * MakeMake - a program to construct a makefile from C source code
  3.  *
  4.  *   Usage: makemake [ -dir ... ] file.c ...
  5.  *
  6.  * MakeMake reads the C source files and outputs on standard out a file
  7.  *    of the form:
  8.  * target.o: target.c header file list
  9.  * where the header file list is the transitive closure of all
  10.  * files #included in filex.c (i.e. if filex.c #includes "header.h", and
  11.  * "header.h" #includes "subheader.h", both "header.h" and "subheader.h"
  12.  * appear in the list of header files). MakeMake only examines header
  13.  * files delimited by double quotes ("). It looks for those file in the
  14.  * current directory, and in all directories given as arguments. Include
  15.  * directories are indicated by prepending a "-" to their name. That name
  16.  * is then prepended to the include file name from scanned files, so you'll
  17.  * want to use something like "-/h/ -rexx:".  System header files enclosed
  18.  * in angle brackets ("<" and ">") are not examined.
  19.  *
  20.  * Written and placed in the public domain by Tim McGrath 4/2/87
  21.  *
  22.  * modified by Mike Meyer to be usefull in with the BSD-oid makefile
  23.  * construction technic, which replaces the end of an existing makefile
  24.  * with a dependency list. The result is still in the public domain.
  25.  *
  26.  * While I was at it, I deleted the multiple statements per line (so the
  27.  * source-level debugger would be more usefull), and all the tacky, tacky
  28.  * passing around of pointers to int to get a return value. Also fixed
  29.  * the bugs of not printing the first elelement in the array of file
  30.  * names, and other oddities. I also fixed the memory allocator to
  31.  * be less proficient at exercising malloc, and to believe in real
  32.  * limits. The "heap" struct comes from that. My final change was adding
  33.  * -dir to indicate include files. Strange, strange code, this was.
  34.  *
  35.  * Modified again by Lynn Kerby to be useful with the MANX compiler and
  36.  * to use a slightly different convention for command line arguments. 
  37.  * to turn on generation of the compilation rule and a more common make
  38.  * file dependency format, use the -M option (upper or lower works fine).
  39.  * Directories must be prefixed with a -i (again, upper or lower case) to
  40.  * be more compatible with C compiler syntax.  Also changed it to allow
  41.  * for NON-ANSI compilers with conditional prototypes
  42.  */
  43. #ifdef    LATTICE
  44. #define _ANSI_C
  45. #endif
  46.  
  47. #include <stdio.h>
  48. #ifdef _ANSI_C
  49. #include <stdlib.h>
  50. #endif
  51. #include <string.h>
  52.  
  53. #ifdef _ANSI_C
  54. #define PROTO(x) x
  55. void main(int, char **) ;
  56. #else
  57. #define PROTO(x) ()
  58. #define NO_PROTOS
  59. #endif
  60.  
  61. #define LINEMAX     80
  62.  
  63. struct heap {
  64.     char **h_names;
  65.     int h_used;
  66.     int h_incr;
  67. };
  68. int heap_init PROTO((struct heap * h, int size));
  69. int heap_add PROTO((struct heap * h, int where, char *name));
  70.  
  71. #define heap_names(h)    ((h) . h_names)
  72.  
  73. void free_space PROTO((char **dp, int dc));
  74. char *file_exten PROTO((char *pgm_name, char extension, char *bufout));
  75. char *base_name PROTO((char *name, char *bufout));
  76. char *path_name PROTO((char *name, char *bufout));
  77. void depend_file PROTO((int ct, char **flist, char *pgm_name));
  78. void start_line PROTO((char *with_name, char *buf));
  79. int get_dependents PROTO((char *name, struct heap * files,
  80.               struct heap * incs, int cinc));
  81. int scan_file PROTO((struct heap * h, int list_to_use, FILE * fp,
  82.              struct heap * incs, int cinc));
  83. FILE *incopen PROTO((char *file, struct heap * incs, int count, char *bufout));
  84.  
  85. static char RCSid[] = "$Header: makemake.c,v 1.5 90/04/27 15:40:40 lfk Exp $";
  86. int    manx_output = 0;
  87.  
  88. void
  89. main(argc, argv)
  90. char **argv;
  91. int argc;
  92. {
  93.     int i, dependent_count, include_count = 0;
  94.     struct heap dependents, includes;
  95.  
  96.     if (!heap_init(&dependents, 10) || !heap_init(&includes, 10)) {
  97.     fprintf(stderr, "No memory\n");
  98.     exit(20);
  99.     }
  100.     for (i = 1; i < argc; i++)
  101.     if (argv[i][0] == '-') {
  102.         switch(argv[i][1]) {
  103.           case 'i':
  104.           case 'I':
  105.         heap_add(&includes, include_count, &argv[i][2]);
  106.         include_count++;
  107.         break;
  108.           case 'm':
  109.           case 'M':
  110.         manx_output++;
  111.         break;
  112.           default:
  113.         fprintf(stderr,"unknown argument %s\n",argv[i]);
  114.         }
  115.     } else {
  116.         dependent_count = get_dependents(argv[i], &dependents, &includes,
  117.                          include_count);
  118.         if (dependent_count > 0)
  119.         depend_file(dependent_count, heap_names(dependents), argv[i]);
  120.         free_space(heap_names(dependents), dependent_count);
  121.     }
  122.     exit(0);
  123. }
  124.  
  125. void
  126. free_space(dp, dc)
  127. /*
  128.  * Purpose: free up list of file names
  129.  * Inputs:  dp - points to list of pointers to strings
  130.  *        dc - number of pointers in the list
  131.  */
  132. char **dp;
  133. int dc;
  134. {
  135.     while (dc > 0) {
  136.     free(*dp++);
  137.     dc--;
  138.     }
  139. }
  140.  
  141. char *
  142. file_exten(pgm_name, extension, bufout)
  143. /*
  144.  * Purpose: append new extension onto file name
  145.  * Inputs:  pgm_name - pointer to name of file
  146.  *        xtension - pointer to new file name extension (2 chars only)
  147.  * Outputs: bufout - points to area for new file name
  148.  * Returns: bufout
  149.  */
  150. char *pgm_name, extension, *bufout;
  151. {
  152.     int i = 0;
  153.  
  154.     while (*pgm_name) {
  155.     bufout[i++] = *pgm_name;
  156.     if (*pgm_name++ == '.' && extension) {
  157.         bufout[i++] = extension;
  158.         bufout[i] = '\0';
  159.         return (bufout);
  160.     }
  161.     }
  162.     if (extension) {
  163.     bufout[i++] = '.';
  164.     bufout[i++] = extension;
  165.     }
  166.     bufout[i] = '\0';
  167.     return (bufout);
  168. }
  169.  
  170. char *
  171. base_name(name, bufout)
  172. /*
  173.  * Purpose: strip any extensions and path off of a file name.
  174.  * Inputs:  name - pointer to file name
  175.  * Outputs: bufout - area for new file name
  176.  * Returns: bufout
  177.  */
  178. char *name, *bufout;
  179. {
  180.     char *p;
  181.  
  182.     p = strrchr(name, '/');
  183.     if (p == NULL)
  184.     p = strrchr(name, ':');
  185.     if (p == NULL)
  186.     p = name;
  187.     else
  188.     p += 1;
  189.     strcpy(bufout, p);
  190.     p = strrchr(bufout, '.');
  191.     if (p != NULL)
  192.     *p = '\0';
  193.     return bufout;
  194. }
  195.  
  196. char *
  197. path_name(name, bufout)
  198. /*
  199.  * Purpose: strip the filename off the path 
  200.  * Inputs:  name - pointer to file name
  201.  * Outputs: bufout - containing the filename portion of the path
  202.  * Returns: bufout
  203.  */
  204. char *name, *bufout;
  205. {
  206.     char *p;
  207.  
  208.     strcpy(bufout, name);
  209.     p = strrchr(bufout, '/');
  210.     if (p == NULL)
  211.     p = strrchr(bufout, ':');
  212.     if (p == NULL)
  213.     p = bufout;
  214.     else
  215.     p += 1;
  216.     *p = '\0';
  217.     return bufout;
  218. }
  219.  
  220. void
  221. depend_file(ct, flist, pgm_name)
  222. /*
  223.  * Purpose: print file name and list of dependents
  224.  * Inputs:  ct - number of dependents in the list
  225.  *        flist - pointer to a list of pointers to dependent names
  226.  *        pgm_name - name of file whose dependents are being printed
  227.  */
  228. char **flist, *pgm_name;
  229. int ct;
  230. {
  231.     int i;
  232.     char buf[LINEMAX], add_name[LINEMAX], pname[LINEMAX];
  233.     
  234.     start_line(file_exten(base_name(pgm_name, add_name), 'o', pname), buf);
  235.     for (i = 0; i < ct; i++) {
  236.     file_exten(flist[i], 0, add_name);
  237.     if (manx_output) {
  238.         if (strlen(buf) + strlen(add_name) + 1 >= LINEMAX - 3) {
  239.         strcat(buf," \\");
  240.         puts(buf);
  241.         strcpy(buf, "       ");
  242.         }
  243.     } else {
  244.         if (strlen(buf) + strlen(add_name) + 1 >= LINEMAX - 1) {
  245.         puts(buf);
  246.         start_line(pname, buf);
  247.         }
  248.     }
  249.     strcat(strcat(buf," "),add_name);
  250.     }
  251.     puts(buf);
  252.     if (manx_output) {
  253.     sprintf(buf,"\t$(CC) $(CFLAGS) -o $@ %s$*.c\n",
  254.         path_name(pgm_name,add_name));
  255.     puts(buf);
  256.     }
  257. }
  258.  
  259. void
  260. start_line(with_name, buf)
  261. /*
  262.  * Purpose: give each line a standard indentation
  263.  * Inputs:  with_name - name of root file on each line
  264.  *        buf - place to put indented line
  265.  */
  266. char *with_name, *buf;
  267. {
  268.     strcpy(buf, with_name);
  269.     strcat(buf, ":");
  270. }
  271.  
  272. int
  273. get_dependents(name, files, incs, cinc)
  274. /*
  275.  * Purpose: get heap of dependent files for input file
  276.  * Inputs:  name - file name to scan for dependents.
  277.  *        incs - heap of include directories to look at
  278.  *        cinc - cout of above.
  279.  * Outputs: files - heap of dependent file names.
  280.  * Returns: number of files in files.
  281.  */
  282. char *name;
  283. struct heap *files, *incs;
  284. int cinc;
  285. {
  286.     FILE *fp;
  287.     int result;
  288.  
  289.     if ((fp = fopen(name, "r")) == NULL) {
  290.     fprintf(stderr, "Couldn't open file %s\n", name);
  291.     return 0;
  292.     }
  293.     heap_add(files, 0, name);
  294.     result = scan_file(files, 1, fp, incs, cinc);
  295.     fclose(fp);
  296.     return result;
  297. }
  298.  
  299. int
  300. scan_file(file_name_heap, next_to_use, fp, inc, cinc)
  301. /*
  302.  * Purpose: search a C source file file #includes, and search the #includes
  303.  *        for nested #includes
  304.  * Inputs:  fn - name of file to scan
  305.  *        next_to_use - last used filename position in file_name_list
  306.  * Outputs: file_name_list - list of included files
  307.  * Returns: new value for last_list_used.
  308.  */
  309. struct heap *file_name_heap, *inc;
  310. FILE *fp;
  311. int next_to_use, cinc;
  312. {
  313.     FILE *ifp;
  314.     char buf[1024], ifn[LINEMAX];
  315.     int j, k;
  316.  
  317.  
  318.     while (fgets(buf, 1024, fp)) {
  319.     if (strncmp(buf, "#include", 8) == 0) {
  320.         j = 8;
  321.         while (buf[j] == ' ' || buf[j] == '\t')
  322.         j++;
  323.         if (buf[j++] != '"')
  324.         continue;
  325.         k = 0;
  326.         while (buf[j]) {
  327.         if (buf[j] == '"' || buf[j] == '\n')
  328.             break;
  329.         else
  330.             ifn[k++] = buf[j++];
  331.         }
  332.         ifn[k] = '\0';
  333.  
  334.         ifp = incopen(ifn, inc, cinc, buf);
  335.         if (!ifp)
  336.         fprintf(stdout, "Couldn't open include file %s\n", ifn);
  337.         else if (heap_add(file_name_heap, next_to_use, buf))
  338.         next_to_use = scan_file(file_name_heap, next_to_use + 1, ifp,
  339.                     inc, cinc);
  340.         fclose(ifp);
  341.     }
  342.     }
  343.     return next_to_use;
  344. }
  345.  
  346. FILE *
  347. incopen(file, incs, count, bufout)
  348. /*
  349.  * Purpose: Open an include file, figuring out where it is along the way.
  350.  * Inputs:  file - name of the file
  351.  *        incs - heap of include files to check
  352.  *        count - number of include files in the heap
  353.  * Outputs: bufout - name of the file we actually opened.
  354.  * Returns: open file, or NULL if we didn't open the file
  355.  */
  356. char *file, *bufout;
  357. struct heap *incs;
  358. int count;
  359. {
  360.     FILE *out;
  361.     char *pp;
  362.     register int i = 0;
  363.  
  364.     strcpy(bufout, file);
  365.     out = fopen(bufout, "r");
  366.  
  367.     while (out == NULL && i < count) {
  368.     pp=heap_names(*incs)[i++];
  369.     if (*(pp + strlen(pp) - 1) != '/' && *(pp + strlen(pp) - 1) != ':')
  370.         sprintf(bufout, "%s/%s", pp, file);
  371.     else
  372.         sprintf(bufout, "%s%s", pp, file);
  373.     out = fopen(bufout, "r");
  374.     }
  375.     return out;
  376. }
  377.  
  378. heap_init(h, size)
  379. /*
  380.  * Purpose: Initalize a heap of file names.
  381.  * Inputs:  h - the heap
  382.  *        size - the initial size and growth increment.
  383.  *
  384.  * Outputs: h, correctly initialized.
  385.  * Returns: TRUE if all went well, FALSE otherwise.
  386.  */
  387. struct heap *h;
  388. int size;
  389. {
  390.     if ((h->h_names = (char **)malloc(size * sizeof(char *))) == NULL)
  391.     return 0;
  392.     h->h_incr = h->h_used = size;
  393.     return 1;
  394. }
  395.  
  396. heap_add(h, where, fn)
  397. /*
  398.  * Purpose: Add a file name to the heap if it's not there already
  399.  * Inputs:  h - the heap of names
  400.  *        where - where to add the name
  401.  *        fn - name of file
  402.  * Returns: 1 if file name added, 0 otherwise
  403.  */
  404. struct heap *h;
  405. int where;
  406. char *fn;
  407. {
  408.     int i;
  409.     char *p;
  410.  
  411.     for (i = 0; i < where; i++)
  412.     if (!strcmp(h->h_names[i], fn))
  413.         return (0);
  414.     if (where >= h->h_used)
  415.     h->h_names = (char **) realloc(h->h_names,
  416.                  (h->h_used += h->h_incr) * sizeof(char *));
  417.     p = strdup(fn);
  418.     if (p == NULL || h->h_names == NULL) {
  419.     fprintf(stderr, "Out of memory");
  420.     exit(20);
  421.     }
  422.     h->h_names[where] = p;
  423.     return (1);
  424. }
  425. /*EOF MARKER*/
  426.  
  427.