home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume8 / make.gy / part01 / make.c < prev    next >
Encoding:
C/C++ Source or Header  |  1989-11-02  |  17.3 KB  |  820 lines

  1. /*
  2.  * make.c    An imitation of the Unix MAKE facility
  3.  *
  4.  * 88-10-01 v1.0    created by greg yachuk, placed in the public domain
  5.  * 88-10-06 v1.1    changed prerequisite list handling
  6.  * 88-11-11 v1.2    fixed some bugs and added environment variables
  7.  * 89-07-12 v1.3    stop appending shell commands, and flush output
  8.  * 89-08-01 v1.4 AB    lots of new options and code
  9.  * 89-10-30 v1.5 greggy    -f -S -q options, took some changes from v1.4
  10.  *
  11.  */
  12.  
  13. #include <stdio.h>
  14. #include <errno.h>
  15. #include <fcntl.h>
  16. #include <string.h>
  17. #include <sys/types.h>
  18. #include <sys/stat.h>
  19. #ifdef    MSDOS
  20. #include <stdlib.h>
  21. #endif
  22.  
  23. #include "make.h"
  24. #include "tstring.h"
  25. #include "decl.h"
  26.  
  27.  
  28. targptr target_list = NULL;    /* list of target nodes */
  29. fileptr file_list = NULL;    /* list of file nodes */
  30. symptr  symbol_list = NULL;    /* list of symbol nodes */
  31. shellptr shell_list = NULL;    /* list of shell nodes */
  32.  
  33. int     make_level = 0;        /* for counting new_make()'s */
  34.  
  35. targptr first_targ = NULL;    /* first target, in case nothing explicit */
  36. targptr suffix_targ = NULL;    /* .SUFFIXES target pointer */
  37.  
  38. char  **tlist = NULL;        /* command line targets */
  39. char  **flist = NULL;        /* command line make files */
  40. char  **mlist = NULL;        /* command line macros */
  41.  
  42. int     tmax = 0;        /* max size of tlist */
  43. int     fmax = 0;        /* max size of flist */
  44. int     mmax = 0;        /* max size of mlist */
  45.  
  46. optnode opts;            /* all the options */
  47. int     readdef = 1;        /* -r option */
  48. int     dispcount = 0;        /* used for -D option */
  49.  
  50. long    now;            /* time at startup */
  51. char   *makeflags;        /* value to update the MAKEFLAGS macro with */
  52.  
  53.  
  54. main(argc, argv)
  55. int     argc;
  56. char  **argv;
  57. {
  58.     REGISTER int i;
  59.     REGISTER targptr targp;
  60.     REGISTER int mk;
  61.     symptr  symp;
  62.     char   *envp;
  63.     char  **envv;
  64.  
  65.     /* initialize the various global lists */
  66.  
  67.     opts.depend = 0;
  68.     dispcount = 0;
  69.  
  70.     target_list = NULL;
  71.     file_list = NULL;
  72.     shell_list = NULL;
  73.     /* don't set symbol_list to NULL, or recursive makes won't work */
  74.  
  75.     /* allocate space for command line targets, files and macros */
  76.  
  77.     tlist = grow_list(NULL, &tmax);
  78.     flist = grow_list(NULL, &fmax);
  79.     mlist = grow_list(NULL, &mmax);
  80.  
  81.     /* process MAKEFLAGS environment variable, first */
  82.  
  83.     symp = get_symbol("MAKEFLAGS", 0);
  84.     if (symp->svalue != NULL)
  85.     {
  86.         /* chop up the MAKEFLAGS and feed them to to make_args() */
  87.  
  88.         envp = tstrcpy(symp->svalue);
  89.         envv = tokenize(envp);
  90.         for (i = 0; envv[i] != NULL; i++);
  91.         make_args(i, envv);
  92.  
  93.         /* free the vector of pointers, and the string itself, */
  94.         /* since you cannot have macros, targets or makefiles  */
  95.         /* in the MAKEFLAGS macro.                             */
  96.  
  97.         tfree(envv);
  98.         tfree(envp);
  99.         tfree(makeflags);    /* ignore this, since we just read it */
  100.     }
  101.  
  102.     make_args(--argc, ++argv);    /* process command line options */
  103.  
  104.     add_macro(makeflags, 0);/* update the MAKEFLAGS macro */
  105.     tfree(makeflags);
  106.  
  107.     /* add command line macros, so they DON'T get overridden */
  108.  
  109.     for (i = 0; mlist[i] != NULL; i++)
  110.         add_macro(mlist[i], 1);
  111.  
  112.     tfree(mlist);        /* all done with macros */
  113.  
  114.     if (opts.query)        /* -q never executes anything */
  115.         opts.noexec = 1;
  116.  
  117.     if (opts.noexec)
  118.         opts.touch = 0;    /* -n never touches */
  119.  
  120.     if (dispcount > 1)    /* display `default.mk' on -DD */
  121.         opts.display = 1;
  122.  
  123.     first_targ = NULL;    /* used in parse() */
  124.  
  125.     if (readdef)        /* read in `default.mk' */
  126.         parse(fopenp(MAKEINI, "r"));
  127.  
  128.     if (dispcount > 0)    /* display makefile's on -D */
  129.         opts.display = 1;
  130.  
  131.     first_targ = NULL;    /* get first target in `makefile' */
  132.  
  133.     /* parse the makefiles given on command line */
  134.     for (i = 0; flist[i] != NULL; i++)
  135.     {
  136.         parse(equal(flist[i], "-") ? fdopen(dup(fileno(stdin)), "r")
  137.               : fopen(flist[i], "r"));
  138.     }
  139.  
  140.     /* no makefiles specified, so use "makefile" or "Makefile" */
  141.     if (i == 0)
  142.     {
  143.         if (parse(fopen("makefile", "r")) == 0)
  144.         {
  145. #ifndef    MSDOS
  146.             parse(fopen("Makefile", "r"));
  147. #endif
  148.         }
  149.     }
  150.  
  151.     tfree(flist);        /* all done with makefile's */
  152.  
  153.     /* find the current value of the $(MAKE) macro */
  154.     symp = get_symbol("MAKE", 0);
  155.     opts.make = (symp->svalue == NULL) ? "make" : symp->svalue;
  156.  
  157.     if ((targp = get_target(".INIT")) != NULL)
  158.         build(targp->tshell);    /* process the .INIT rule */
  159.  
  160.     mk = 0;
  161.  
  162.     for (i = 0; tlist[i] != NULL; i++)
  163.     {
  164.         /* process command line arguments */
  165.         mk |= (make(tlist[i], 1) > 0) ? 1 : 0;
  166.     }
  167.  
  168.     tfree(tlist);        /* all done with targets */
  169.  
  170.     /* if no targets specified, make the first one */
  171.     if (i == 0 && first_targ)
  172.         mk |= (make(first_targ->tfile->fname, 1) > 0) ? 1 : 0;
  173.  
  174.     if ((targp = get_target(".DONE")) != NULL)
  175.         build(targp->tshell);    /* process the .DONE rule */
  176.  
  177.     return (mk & opts.query);    /* not exit(); see new_make() */
  178. }
  179.  
  180.  
  181. /*
  182.  * make_args    - process the command line arguments
  183.  */
  184. make_args(argc, argv)
  185. int     argc;
  186. char  **argv;
  187. {
  188.     REGISTER int tlen;
  189.     REGISTER int flen;
  190.     REGISTER int mlen;
  191.     REGISTER int no_k = 0;    /* override the -k option */
  192.     char   *tmf;
  193.     int     addflag;
  194.  
  195.     now = time(NULL);    /* get current date & time */
  196.  
  197.     makeflags = tstrcpy("MAKEFLAGS+=");
  198.  
  199.     tlen = flen = mlen = 0;
  200.  
  201.     for (; argc != 0; ++argv, --argc)
  202.     {
  203.         if (**argv != '-')
  204.         {
  205.             /* doesn't start with '-'; must be macro or target */
  206.  
  207.             if (strchr(*argv, '='))
  208.             {    /* store as a macro */
  209.                 if (mlen == mmax)
  210.                     mlist = grow_list(mlist, &mmax);
  211.                 mlist[mlen++] = *argv;
  212.             }
  213.             else
  214.             {    /* store as a target */
  215.                 if (tlen == tmax)
  216.                     tlist = grow_list(tlist, &tmax);
  217.                 tlist[tlen++] = *argv;
  218.             }
  219.             continue;
  220.         }
  221.  
  222.         /* must be an option */
  223.  
  224.         tmf = tstrcat(makeflags, *argv);
  225.  
  226.         while (*argv && *++*argv)
  227.         {
  228.             addflag = 1;    /* add to MAKEFLAGS */
  229.             switch (**argv)
  230.             {
  231.             case 'd':    /* show dependencies */
  232.                 addflag = 0;    /* don't add to MAKEFLAGS */
  233.                 opts.depend++;
  234.                 break;
  235.  
  236.             case 'D':    /* display makefiles */
  237.                 dispcount++;
  238.                 break;
  239.  
  240.             case 'e':    /* don't override environment */
  241.                 opts.envirn = 1;
  242.                 break;
  243.  
  244.             case 'f':    /* new makefile name */
  245.                 addflag = 0;    /* don't add to MAKEFLAGS */
  246.                 if (argc < 2)
  247.                     usage();
  248.                 if (flen == fmax)
  249.                     flist = grow_list(flist, &fmax);
  250.                 ++argv, --argc;
  251.                 flist[flen++] = *argv;
  252.  
  253.                 *argv = NULL;
  254.                 break;
  255.  
  256.             case 'i':    /* ignore errors */
  257.                 opts.ignore = 1;
  258.                 break;
  259.  
  260.             case 'k':    /* give up on current target on error */
  261.                 opts.keepon = 1;
  262.                 break;
  263.  
  264.             case 'n':    /* don't execute commands */
  265.                 opts.noexec = 1;
  266.                 break;
  267.  
  268.             case 'q':    /* question mode */
  269.                 opts.query = 1;
  270.                 break;
  271.  
  272.             case 'r':    /* don't read default.mk */
  273.                 readdef = 0;
  274.                 break;
  275.  
  276.             case 's':    /* don't echo commands */
  277.                 opts.silent = 1;
  278.                 break;
  279.  
  280.             case 'S':    /* Undo -k option */
  281.                 no_k = 1;
  282.                 break;
  283.  
  284.             case 't':    /* touch files, don't build */
  285.                 opts.touch = 1;
  286.                 break;
  287.  
  288.             default:
  289.                 usage();    /* never returns */
  290.             }
  291.         }
  292.  
  293.         if (addflag)
  294.         {
  295.             tfree(makeflags);
  296.             makeflags = tstrcat(tmf, " ");
  297.         }
  298.  
  299.         tfree(tmf);
  300.     }
  301.  
  302.     /* terminate all lists with a NULL pointer */
  303.  
  304.     tlist[tlen] = NULL;
  305.     flist[flen] = NULL;
  306.     mlist[mlen] = NULL;
  307.  
  308.     /* check for -S over-riding -k option */
  309.     if (no_k)
  310.         opts.keepon = 0;
  311.  
  312.     /* let the caller update the makeflags macro */
  313. }
  314.  
  315.  
  316. /*
  317.  * grow_list    - expand the list of pointers by a factor of two
  318.  */
  319. char  **
  320. grow_list(list, len)
  321. char  **list;
  322. int    *len;
  323. {
  324.     REGISTER int l;
  325.  
  326.     /* if list is NULL, start off with a default list */
  327.  
  328.     if (list == NULL)
  329.         list = (char **) talloc(((l = 1) + 1) * sizeof(char *));
  330.     else
  331.     {
  332.         l = *len;    /* get current length */
  333.  
  334.         list = (char **) trealloc((char *) list,
  335.                       ((l <<= 1) + 1) * sizeof(char *));
  336.     }
  337.  
  338.     if (list == NULL)
  339.         terror(1, "too many options");
  340.  
  341.     /* if we are initially allocating it, set first pointer to NULL */
  342.  
  343.     if (l == 1)
  344.         *list = NULL;
  345.  
  346.     *len = l;        /* update current length */
  347.     return (list);
  348. }
  349.  
  350.  
  351. /*
  352.  * fopenp    - open file in current directory or along PATH
  353.  */
  354. FILE   *
  355. fopenp(fname, type)
  356. char   *fname;
  357. char   *type;
  358. {
  359.     REGISTER int len;
  360.     REGISTER char *fpath;
  361.     FILE   *fd;
  362.     char   *path;
  363.     char   *tp;
  364.  
  365.     /* try to open file relative to current directory */
  366.     if ((fd = fopen(fname, type)) != NULL)
  367.         return (fd);
  368. #ifndef    MSDOS
  369.     /* didn't work, try home directory */
  370.     if ((path = getenv("HOME")) != NULL)
  371.     {
  372.         fpath = talloc(strlen(path) + strlen(fname) + 2);
  373.  
  374.         strcpy(fpath, path);
  375.         len = strlen(fpath) - 1;
  376.  
  377.         /* make sure there is a separator between path and filename */
  378.  
  379.         if (!strchr(FILE_SEPARATOR, fpath[len]))
  380.             fpath[++len] = '/';
  381.  
  382.         strcpy(&fpath[len + 1], fname);    /* attach the filename */
  383.         fd = fopen(fpath, type);
  384.         tfree(fpath);
  385.  
  386.         if (fd != NULL)
  387.             return (fd);
  388.     }
  389. #endif
  390.     /* didn't work, search along path */
  391.  
  392.     if ((path = getenv("PATH")) == NULL)
  393.         return (NULL);
  394.  
  395.     path = tstrcpy(path);    /* allocate string and copy */
  396.     fpath = talloc(strlen(path) + strlen(fname) + 2);
  397.  
  398.     /* look for tokens separated by semi-colons (;) or colons (:) */
  399.  
  400.     tp = token(path, PATH_SEPARATOR, NULL);
  401.     while (tp != NULL)
  402.     {
  403.         strcpy(fpath, tp);
  404.         len = strlen(fpath) - 1;
  405.  
  406.         /* make sure there is a separator between path and filename */
  407.  
  408.         if (!strchr(FILE_SEPARATOR, fpath[len]))
  409.             fpath[++len] = '/';
  410.  
  411.         strcpy(&fpath[len + 1], fname);    /* attach the filename */
  412.         if ((fd = fopen(fpath, type)) != NULL)
  413.             break;
  414.  
  415.         tp = token(NULL, PATH_SEPARATOR, NULL);
  416.     }
  417.  
  418.     tfree(path);
  419.     tfree(fpath);
  420.  
  421.     return (fd);
  422. }
  423.  
  424.  
  425. /*
  426.  * make        - guts of the make command
  427.  *        - make all pre-requisites, and if necessary, build target
  428.  *
  429.  *    returns    -1 target was already up to date w.r.t. pre-requisites
  430.  *         0 target has not been built
  431.  *         1 target is now built (and up to date)
  432.  */
  433. make(targname, worry)
  434. char   *targname;
  435. int     worry;            /* if set, it is an error to NOT build this */
  436. {
  437.     REGISTER targptr targp;
  438.     REGISTER fileptr *preqp;
  439.     REGISTER int mk;
  440.     fileptr filep;
  441.     long    targtime;
  442.     long    preqtime;
  443.  
  444.     mk = 0;
  445.  
  446.     /* if recorded time of file is not default, we've already built it */
  447.     filep = get_file(targname);
  448.     if (filep && filep->ftime != MAXNEGTIME)
  449.         return (1);
  450.  
  451.     targp = get_target(targname);    /* find the target node */
  452.     if (targp == NULL)
  453.         return (default_rule(targname, NULL, worry, 0));
  454.  
  455.     /* keep actual time of current target */
  456.     targtime = file_time(targname, 0);
  457.  
  458.     /* must build non-existant files, even with no pre-requisites */
  459.     preqtime = MAXNEGTIME + 1;
  460.  
  461.     /* make all pre-requisites */
  462.     preqp = targp->tpreq;
  463.     while (preqp && *preqp)
  464.     {
  465.         mk |= make((*preqp)->fname, worry);
  466.  
  467.         /* keep track of newest pre-requisite */
  468.         if (preqtime < (*preqp)->ftime)
  469.             preqtime = (*preqp)->ftime;
  470.  
  471.         /* display as necessary */
  472.         if (opts.depend > 1 ||
  473.             (opts.depend && (*preqp)->ftime > targtime))
  474.         {
  475.             display_prereq(targname, targtime, (*preqp)->fname,
  476.                        (*preqp)->ftime);
  477.         }
  478.  
  479.         ++preqp;
  480.     }
  481.  
  482.     if (targp->tshell == NULL)    /* try default rules anyway */
  483.     {
  484.         if (default_rule(targname, targp, 0, preqtime > targtime))
  485.             return (1);
  486.         return (mk);
  487.     }
  488.     else if (preqtime > targtime)
  489.     {
  490.         if (opts.touch)    /* won't be set when `noexec' */
  491.             touch_file(targname);
  492.         else
  493.         {
  494.             add_metas("", "", targname);
  495.             if (build(targp->tshell))
  496.                 return (0);
  497.         }
  498.  
  499.         targp->tfile->ftime = (opts.noexec) ? now
  500.             : file_time(targname, 1);
  501.         return (1);
  502.     }
  503.  
  504.     targp->tfile->ftime = targtime;
  505.  
  506.     return (mk);
  507. }
  508.  
  509.  
  510. /*
  511.  * default_rule    - try the .SUFFIXES when we don't have an explicit target
  512.  *        - if `worry' is set, it is an ERROR to NOT build this target
  513.  *        - `mustbuild' is set if make() has out-of-date prereq's
  514.  *           but no explicit shell rules
  515.  */
  516. default_rule(targname, targetp, worry, mustbuild)
  517. char   *targname;
  518. targptr targetp;
  519. int     worry;
  520. int     mustbuild;
  521. {
  522.     REGISTER targptr targp;
  523.     REGISTER fileptr *preqp;
  524.     fileptr filep;
  525.     char   *ext;
  526.     char   *basename;
  527.     char   *preqname;
  528.     long    targtime;
  529.     long    preqtime;
  530.     int     built;
  531.     char    suffrule[80];
  532.  
  533.     ext = strrchr(targname, '.');    /* find the extension */
  534.     if (ext == NULL)
  535.         ext = targname + strlen(targname);
  536.  
  537.     basename = tstrncpy(targname, ext - targname);    /* find the base name */
  538.  
  539.     targtime = file_time(targname, 0);
  540.  
  541.     /* suffix_targ is used to (slightly) speed up this function */
  542.     preqp = suffix_targ ? suffix_targ->tpreq : NULL;
  543.     built = 0;
  544.  
  545.     while (preqp && *preqp && !built)
  546.     {
  547.         /* look for a default rule from SUFFIX to `ext' */
  548.         strcat(strcpy(suffrule, (*preqp)->fname), ext);
  549.         targp = get_target(suffrule);    /* e.g. `.c.o' */
  550.  
  551.         if (targp != NULL)
  552.         {
  553.             /* found a rule; see if file exists */
  554.             preqname = get_preqname(targetp, (*preqp)->fname,
  555.                         basename);
  556.             preqtime = file_time(preqname, 0);
  557.  
  558.             /*
  559.              * don't bother recursive makes unless necessary e.g.
  560.              * we have .c.o and .l.c, but also .l.o! we want to
  561.              * use .l.o if a .c file does not exist
  562.              */
  563.             if (preqtime != MAXNEGTIME || mustbuild)
  564.                 built = make(preqname, 0);
  565.  
  566.             /* check if pre-req file exists and is newer */
  567.             preqtime = file_time(preqname, 0);
  568.             if (preqtime > targtime || (mustbuild && built))
  569.             {
  570.                 if (opts.depend)
  571.                 {
  572.                     display_prereq(targname, targtime,
  573.                                preqname, preqtime);
  574.                 }
  575.  
  576.                 if (opts.touch)    /* won't be set when `noexec' */
  577.                     touch_file(targname);
  578.                 else
  579.                 {
  580.                     add_metas(basename, preqname, targname);
  581.                     if (build(targp->tshell))
  582.                         return (0);
  583.                 }
  584.                 built = 1;
  585.             }
  586.             else if (opts.depend > 1 && preqtime != MAXNEGTIME)
  587.             {
  588.                 display_prereq(targname, targtime,
  589.                            preqname, preqtime);
  590.             }
  591.  
  592.             tfree(preqname);
  593.         }
  594.  
  595.         ++preqp;    /* try next .SUFFIXES rule */
  596.     }
  597.  
  598.     if (!built)
  599.     {
  600.         /* didn't find anything; try the default rule */
  601.         targp = get_target(".DEFAULT");
  602.         if (targp != NULL)
  603.         {
  604.             add_metas(basename, "", targname);
  605.             if (build(targp->tshell))
  606.                 return (0);
  607.             built = 1;
  608.         }
  609.         else if (targtime == MAXNEGTIME && worry)
  610.             terror(1, tstrcat("Don't know how to make ", targname));
  611.     }
  612.  
  613.     tfree(basename);
  614.  
  615.     /* record the current file time */
  616.     if ((filep = get_file(targname)) != NULL)
  617.     {
  618.         filep->ftime = (built == 1 && opts.noexec) ? now
  619.             : file_time(targname, 1);
  620.     }
  621.  
  622.     return (built ? built : ((targtime == MAXNEGTIME) ? 0 : 1));
  623. }
  624.  
  625.  
  626. /*
  627.  * get_preqname - find prerequisite name from target and prerequisite suffix
  628.  */
  629. char   *
  630. get_preqname(targp, suffix, basename)
  631. targptr targp;
  632. char   *suffix;
  633. char   *basename;
  634. {
  635.     fileptr *preqp;
  636.     char   *preqf;
  637.     char   *basef;
  638.     int     i;
  639.  
  640.     if (targp != NULL)
  641.     {
  642.         /* strip the directory name from the basename */
  643.         basef = tsplit(basename, FILE_SEPARATOR, NULL);
  644.  
  645.         /* look through prerequisite list for file with right name */
  646.         for (preqp = targp->tpreq; preqp && *preqp; ++preqp)
  647.         {
  648.             /* split the pre-requisite into dir and filenames */
  649.             preqf = tsplit((*preqp)->fname, FILE_SEPARATOR, NULL);
  650.  
  651.             /* see if the filename part matches the target */
  652.             for (i = 0; preqf[i] != '\0'; i++)
  653.             {
  654.                 if (preqf[i] != basef[i])
  655.                     break;
  656.             }
  657.  
  658.             /* if we differed only on the suffix, we're okay */
  659.             if (strcmp(preqf + i, suffix) == 0)
  660.                 return (tstrcpy((*preqp)->fname));
  661.         }
  662. #ifdef    ALL_PREQS
  663.         /* didn't find a matching basename + suffix in the preq-list. */
  664.         /* look through prerequisite list for file with right suffix. */
  665.         for (preqp = targp->tpreq; preqp && *preqp; ++preqp)
  666.         {
  667.             preqf = strrchr((*preqp)->fname, '.');
  668.             if (preqf == NULL)
  669.                 continue;
  670.  
  671.             /* take the first file which has right suffix */
  672.             if (strcmp(suffix, preqf) == 0)
  673.                 return (tstrcpy((*preqp)->fname));
  674.         }
  675. #endif                /* ALL_PREQS */
  676.     }
  677.  
  678.     /* didn't find one, so try forming one using basename + suffix */
  679.  
  680.     return (tstrcat(basename, suffix));
  681. }
  682.  
  683.  
  684. /*
  685.  * add_metas    - add symbols for $*, $< and $@
  686.  */
  687. add_metas(basename, preqname, targname)
  688. char   *basename;
  689. char   *preqname;
  690. char   *targname;
  691. {
  692.     /* $* is the basename */
  693.     add_symbol("*", basename, 0);
  694.     split_meta("*", basename);
  695.  
  696.     add_symbol("<", preqname, 0);
  697.     split_meta("<", preqname);
  698.  
  699.     add_symbol("@", targname, 0);
  700.     split_meta("@", targname);
  701. }
  702.  
  703.  
  704. /*
  705.  * split_meta -    split a metasymbol into Directory and File parts
  706.  */
  707. split_meta(sym, name)
  708. char   *sym;
  709. char   *name;
  710. {
  711.     char   *dname;
  712.     char   *dsym;
  713.     char   *fsym;
  714.  
  715.     /* construct the macro names (e.g. $(*D), $(@F)) */
  716.     dsym = tstrcat(sym, "D");
  717.     fsym = tstrcat(sym, "F");
  718.  
  719.     add_symbol(fsym, tsplit(name, FILE_SEPARATOR, &dname), 0);
  720.  
  721.     if (dname == NULL)
  722.         add_symbol(dsym, ".", 0);
  723.     else
  724.     {
  725.         add_symbol(dsym, dname, 0);
  726.         tfree(dname);
  727.     }
  728.  
  729.     tfree(dsym);
  730.     tfree(fsym);
  731. }
  732.  
  733.  
  734. /*
  735.  * touch_file    - set the MODIFICATION time of the file to NOW
  736.  */
  737. touch_file(targname)
  738. char   *targname;
  739. {
  740.     REGISTER int handle;
  741.  
  742. #ifndef    MSDOS
  743.     time_t  timep[2];
  744.  
  745.     time(&timep[0]);
  746.     timep[1] = timep[0];
  747.     handle = utime(targname, timep);
  748. #else
  749.     handle = utime(targname, NULL);
  750. #endif
  751.     fputs("touch ", stdout);
  752.     puts(targname);
  753.  
  754.     if (handle == 0)
  755.         return;
  756.  
  757.     /* create the file, if it did not exist */
  758.     if (errno == ENOENT)
  759.     {
  760.         handle = open(targname, O_CREAT | O_TRUNC, S_IWRITE);
  761.         if (handle != -1)
  762.         {
  763.             close(handle);
  764.             return;
  765.         }
  766.     }
  767.  
  768.     perror("touch");
  769.     exit(1);
  770. }
  771.  
  772. display_prereq(targname, targtime, preqname, preqtime)
  773. char   *targname;
  774. long    targtime;
  775. char   *preqname;
  776. long    preqtime;
  777. {
  778. #ifdef    MSDOS
  779.     char    chtime[10];
  780.  
  781.     fputs(targname, stdout);
  782.     fputs(" (", stdout);
  783.     fputs(ltoa(targtime, chtime, 16), stdout);
  784.     fputs((targtime <= preqtime) ? ") older than " : ") newer than ", stdout);
  785.     fputs(preqname, stdout);
  786.     fputs(" (", stdout);
  787.     fputs(ltoa(preqtime, chtime, 16), stdout);
  788.     puts(")");
  789. #else
  790.     printf("%s (%08lx) %s than %s (%08lx)\n",
  791.            targname, targtime,
  792.            (targtime < preqtime) ? "older" : "newer",
  793.            preqname, preqtime);
  794. #endif
  795. }
  796.  
  797.  
  798. long
  799. file_time(fname, built)
  800. char   *fname;
  801. int     built;
  802. {
  803.     struct stat sbuf;
  804.  
  805.     /*
  806.      * if the file is supposedly built, but still does not exists, just
  807.      * fake it by returning the current time.
  808.      */
  809.     if (stat(fname, &sbuf) != 0)
  810.         return (built ? now : MAXNEGTIME);
  811.     return (sbuf.st_mtime);
  812. }
  813.  
  814.  
  815. usage()
  816. {
  817.     puts("make [-f filename] [-dDiknqrsSt] [target ...] [macro=value ...]");
  818.     exit(1);
  819. }
  820.