home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume6 / msdos_mk / make.c < prev    next >
Encoding:
C/C++ Source or Header  |  1986-11-30  |  6.1 KB  |  316 lines

  1. #include <stdio.h>
  2. #include <ctype.h>
  3. #include "make.h"
  4.  
  5. /*
  6.  *    MAKE - Maintain seperate source files
  7.  *
  8.  *    SYNOPSIS
  9.  *        MK [-f file] [-a] [-n] [-d] [name] ...
  10.  *           f: use 'file' instead of default makefile
  11.  *           a: assume all modules are obsolete (recompile everything)
  12.  *           n: don't recompile, just list steps to recompile
  13.  *           d: debugging (print tree, file info)
  14.  *           name: module name to recompile
  15.  *
  16.  *        'secret' options (not to be used by humans):
  17.  *           -ofile    'file' is the script file to write to
  18.  *
  19.  *    AUTHOR
  20.  *        Landon M. Dyer, Atari Inc.
  21.  *
  22.  */
  23.  
  24. #define SCRIPTFILE "make$$$$.bat"    /* (default) script-listing file */
  25. #define    INIT    "~INIT"            /* initialization macro */
  26. #define    DEINIT    "~DEINIT"        /* de-init macro */
  27. #define    BEFORE    "~BEFORE"        /* the per-root 'startup' method */
  28. #define    AFTER    "~AFTER"        /* the per-root 'wrapup' method */
  29.  
  30.  
  31. char *mfiles[] = {            /* default makefiles */
  32.     "makefile",
  33.  
  34. #ifdef VAXVMS
  35.     "[-]makefile",
  36.     "sys$login:makefile",
  37. #endif
  38.  
  39. #ifdef MSDOS
  40.     "..\makefile",
  41. #endif
  42.     ""
  43. };
  44.  
  45.  
  46. MACRO *mroot = NULL;        /* root of macro-list */
  47. FILENODE *froot = NULL;        /* root of filenode-list */
  48. FILENODE *firstf = NULL;    /* the very first filenode */
  49. FILE *mkfp = NULL;        /* script file */
  50. char *modnames[MAXMODS];    /* module-names mentioned in commandline */
  51. int modcount = 0;        /* #of module-names */
  52. int debug = 0;            /* nonzero: turn on debugging */
  53. int obsolete = 0;        /* nonzero: every file should be recompiled */
  54. int noscript = 0;        /* nonzero: print methods on standard output */
  55. char *scriptf = SCRIPTFILE;    /* default script file */
  56. DATE bigbang;            /* a date, the very earliest possible */
  57. DATE endoftime;            /* a date, the very last possible */
  58.  
  59.  
  60. main(argc, argv)
  61. int argc;
  62. char **argv;
  63. {
  64.     int arg, i;
  65.     char *mfile = NULL;
  66.     DATE adate();
  67.  
  68.     bigbang = adate(0, 0);        /* init root dates */
  69.     endoftime = adate(~0, ~0);
  70.  
  71.     for(arg = 1; arg < argc; ++arg)
  72.         if(*argv[arg] == '-') switch(tolower(argv[arg][1]))
  73.         {
  74.            case 'f':
  75.             if(++arg >= argc)
  76.             {
  77.                 fprintf(stderr, "-f needs filename argument.\n")
  78. ;
  79.                 return;
  80.             }
  81.             mfile = argv[arg];
  82.             break;
  83.  
  84.            case 'a':
  85.             obsolete = 1;
  86.             break;
  87.  
  88.            case 'n':
  89.             noscript = 1;
  90.             break;
  91.  
  92.            case 'd':
  93.             debug = 1;
  94.             break;
  95.  
  96.            case 'o':
  97.                scriptf = argv[arg] + 2;
  98.             break;
  99.  
  100.            default:
  101.             fprintf(stderr, "Unknown switch: %c\n", argv[arg][1]);
  102.             break;
  103.         } else if(modcount < MAXMODS)
  104.             modnames[modcount++] = argv[arg];
  105.         else
  106.         {
  107.             fprintf(stderr, "Too many module names.\n");
  108.             return;
  109.         }
  110.  
  111.     if(mfile != NULL)
  112.     {
  113.         if(fmake(mfile) == -1)
  114.             fprintf(stderr, "Cannot open makefile '%s'.\n", mfile);
  115.     } else {
  116.         for(i = 0; *mfiles[i]; ++i)
  117.             if(fmake(mfiles[i]) != -1) break;
  118.         if(!*mfiles[i])
  119.             fprintf(stderr, "Cannot open makefile.\n");
  120.     }
  121.  
  122.     if(debug) prtree();
  123. }
  124.  
  125.  
  126. /*
  127.  * Construct dependency tree from the makefile 'fn'.
  128.  * Figure out what has to be recompiled, and write a script file to do that.
  129.  */
  130. fmake(fn)
  131. char *fn;
  132. {
  133.     FILE *fp;
  134.  
  135.     if((fp = fopen(fn, "r")) == NULL) return -1;
  136.  
  137.     fparse(fp);
  138.     determ();
  139.  
  140.     fclose(fp);
  141.     return 0;
  142. }
  143.  
  144.  
  145. /*
  146.  * Parse the input file, defining macros and building the dependency tree.
  147.  */
  148. fparse(fp)
  149. FILE *fp;
  150. {
  151.     char ibuf[STRSIZ], ebuf[STRSIZ];
  152.     char *strp, *tok1, *tok2, *s;
  153.     FILENODE *lastf = NULL;
  154.     FILENODE *sf;
  155.  
  156.     for(;;)
  157.     {
  158.         if(fgets(ibuf, STRSIZ, fp) == NULL) break;
  159.         mexpand(ibuf, ebuf, STRSIZ, MACCHAR);
  160.         escape(ebuf, COMCHAR);
  161.  
  162.             /* clobber last newline in string */
  163.         s = ebuf + strlen(ebuf) - 1;
  164.         if(s >= ebuf && *s == '\n') *s = '\0';
  165.  
  166.         if(*ebuf == '\t')
  167.         {
  168.             addmeth(lastf, ebuf+1);
  169.             continue;
  170.         }
  171.  
  172.         strp = ebuf;
  173.         if((tok1 = token(&strp)) == NULL) continue;
  174.         if((tok2 = token(&strp)) != NULL)
  175.             if(!strcmp(tok2, DEFMAC))
  176.             {
  177.                 if(*strp) defmac(tok1, strp);
  178.                 else if(undefmac(tok1) < 0)
  179.                     fprintf(stderr,
  180.                       "Can't undefine macro '%s'\n", tok1);
  181.                 continue;
  182.             }
  183.             else if(!strcmp(tok2, DEPEND))
  184.             {
  185.                 addmeth(lastf, gmacro(AFTER));
  186.  
  187.                 lastf = filenode(tok1);
  188.                 if(firstf == NULL) firstf = lastf;
  189.                 lastf->fmake = NULL;
  190.  
  191.                 addmeth(lastf, gmacro(BEFORE));
  192.  
  193.                 lastf->fflag |= ROOTP;
  194.                 while((tok1 = token(&strp)) != NULL)
  195.                     addfile(lastf, tok1);
  196.                 continue;
  197.             }
  198.             else addfile(lastf, tok2);
  199.  
  200.         do {
  201.             addfile(lastf, tok1);
  202.         } while((tok1 = token(&strp)) != NULL);
  203.     }
  204.  
  205.     addmeth(lastf, gmacro(AFTER));
  206. }
  207.  
  208.  
  209. /*
  210.  * Determine sequence of recompiles from the creation dates.
  211.  * If there is anything to recompile, then create a script file full of commands
  212. .
  213.  */
  214. determ()
  215. {
  216.     FILENODE *f;
  217.     int i;
  218.     char *m;
  219.  
  220.     if(firstf == NULL)            /* empty tree */
  221.     {
  222.         printf("No changes.\n");
  223.         return;
  224.     }
  225.  
  226.     if(modcount == 0) examine(firstf, endoftime);
  227.     else for(i = 0; i < modcount; ++i)
  228.     {
  229.         if((f = gfile(modnames[i])) == NULL)
  230.         {
  231.             fprintf(stderr, "Can't find root '%s'.\n", modnames[i]);
  232.             continue;
  233.         }
  234.  
  235.         if(f->fflag & ROOTP == 0)
  236.         {
  237.             fprintf(stderr, "'%s' is not a root!\n", f->fname);
  238.             continue;
  239.         }
  240.         examine(f, endoftime);
  241.     }
  242.  
  243.     if(mkfp != NULL)
  244.     {
  245.         if((m = gmacro(DEINIT)) != NULL)
  246.         {
  247.             fputs(m, mkfp);
  248.             fputc('\n', mkfp);
  249.         }
  250.         fclose(mkfp);
  251.     } else printf("No changes.\n");
  252. }
  253.  
  254.  
  255. /*
  256.  * Examine filenode 'fnd' and see if it has to be recompiled.
  257.  * 'date' is the last-touched date of the node's father
  258.  * (or 'endoftime' if its a root file.)
  259.  * Root files with NO dependencies are assumed not to be up to date.
  260.  */
  261. examine(fnd, date)
  262. FILENODE *fnd;
  263. DATE date;
  264. {
  265.     int rebuildp = 0;
  266.     NODE *n;
  267.  
  268.     getdate(fnd);
  269.     if(fnd->fnode == NULL && fnd->fflag & ROOTP)
  270.         rebuildp = 1;
  271.     else for(n = fnd->fnode; n != NULL; n = n->nnext)
  272.         if(examine(n->nfile, fnd->fdate)) rebuildp = 1;
  273.  
  274.     if(rebuildp) recomp(fnd);
  275.     if(obsolete || laterdt(fnd->fdate, date) >= 0)
  276.         rebuildp = 1;
  277.     return rebuildp;
  278. }
  279.  
  280.  
  281. /*
  282.  * Make sure a filenode gets recompiled.
  283.  */
  284. recomp(f)
  285. FILENODE *f;
  286. {
  287.     FILENODE *sf;
  288.     char *m;
  289.  
  290.     if(mkfp == NULL)
  291.     {
  292.         if(noscript) mkfp = stdout;
  293.         else if((mkfp = fopen(scriptf, "w")) == NULL)
  294.             fprintf(stderr, "Cannot create: '%s'\n", scriptf);
  295.  
  296.     if((m = gmacro(INIT)) != NULL)
  297.         {
  298.             fputs(m, mkfp);
  299.             fputc('\n', mkfp);
  300.         }
  301.     }
  302.  
  303.     if(f->fflag & REBUILT) return;
  304.     if(f->fmake != NULL) fputs(f->fmake, mkfp);
  305.     f->fflag |= REBUILT;
  306. }
  307.  
  308.  
  309. /*
  310.  * Complain about being out of memory, and then die.
  311.  */
  312. allerr() {
  313.     fprintf(stderr, "Can't alloc -- no space left (I give up!)\n");
  314.     exit(1);
  315. }
  316.