home *** CD-ROM | disk | FTP | other *** search
/ Fresh Fish 10 / Fresh_Fish_10_2352.bin / useful / util / edit / mg / src.lzh / tools / makemake.c < prev    next >
C/C++ Source or Header  |  1990-05-23  |  11KB  |  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