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