home *** CD-ROM | disk | FTP | other *** search
/ ftp.update.uu.se / ftp.update.uu.se.2014.03.zip / ftp.update.uu.se / pub / rainbow / msdos / misc / make.lzh / MAKE.C < prev    next >
Text File  |  1986-01-19  |  18KB  |  774 lines

  1. /*
  2.  * \usr\c\make.c
  3.  *
  4.  *    An imitation of the Unix MAKE facility
  5.  *
  6.  *    Copyright (C) 1984 by Larry Campbell, 73 Concord St., Maynard, Mass.
  7.  *
  8.  *    This software may be freely copied and disseminated for
  9.  *    noncommercial purposes, if and only if this entire copyright
  10.  *    statement and notice is included intact.  This software, and
  11.  *    the information contained herein, may not be used for commercial
  12.  *    purposes without my prior written permission.
  13.  *
  14.  *    This program runs a new shell (COMMAND.COM) for each command
  15.  *    specified in the makefile.  This, I recommend that you put
  16.  *    a copy of the shell in ramdisk (if you have one).  Assuming
  17.  *    your ramdisk is called, say, drive F:, you would:
  18.  *    
  19.  *        COPY A:\COMMAND.COM F:
  20.  *        SET COMSPEC=F:\COMMAND.COM
  21.  *
  22.  */
  23.  
  24. /*
  25.  * Revision history
  26.  *
  27.  *  1.11    Make default makefilename be MAKEFILE.
  28.  *  1.10    Add -n (trace) switch.
  29.  *  1.09    Allow multiple targets before colon.
  30.  *  1.08    Cleanup and speedup of makefile parsing.
  31.  *  1.07    Add continuation lines (hyphen as last char of line)
  32.  *  1.06    Don't need to make dummy FCBs, zero seems to work OK.
  33.  *  1.05    Fix bug finding COMSPEC when it's not first env variable
  34.  *  1.04    Wordier usage text, including copyright notice.
  35.  *        Remove printf's (except when DEBUG on) to shrink EXE
  36.  *  1.03    Don't uppercase shell command and fix datetime bug
  37.  *  1.02    Random cleanup
  38.  *  1.01    The beginning
  39.  */
  40. #define VERSION "MAKE version 1.11  Copyright (C) 1984 by Larry Campbell, Maynard Mass."
  41.  
  42. #include <stdio.h>
  43.  
  44. #define ABORT(s) { puts (s); exit (); }
  45. #define DOS_ERROR(n) { fputs (dos_error (n), stderr); exit (); }
  46. #define DOS(n) { srv.ax = n << 8;\
  47.          status = sysint (0x21, &srv, &rrv);\
  48.          if (status & 1) DOS_ERROR (rrv.ax); };
  49.  
  50. #define PREREQ_MAGIC 123
  51. #define FILE_MAGIC 543
  52. #define SHELL_MAGIC 678
  53. #define TARG_MAGIC 987
  54.  
  55. #define MAXTARGETS 12
  56.  
  57. extern char
  58.     *dos_error ();
  59.  
  60. unsigned long
  61.     getdatetime ();
  62.  
  63. struct target_node
  64.     *lookup_target ();
  65.  
  66. struct prereq_node
  67.     *new_prereq_node ();
  68.  
  69. struct file_node
  70.     *new_file_node ();
  71.  
  72. struct regval {int ax, bx, cx, dx, si, di, ds, es;};
  73. struct segval {int scs, sss, sds, ses;};
  74.  
  75. struct regval srv, rrv;
  76. struct segval seg;
  77.  
  78. struct
  79.     {
  80.     char reserved[21];
  81.     char attr;
  82.     unsigned time;
  83.     unsigned date;
  84.     unsigned size_l;
  85.     unsigned size_h;
  86.     char pname[13];
  87.     } find_buf;
  88.  
  89. /*
  90.  * MAKE parses the make file and constructs a somewhat tangled
  91.  * directed graph describing dependencies.  There is a list of
  92.  * target_node structures, each of which points to a list of
  93.  * prereq_node structures.  These both point to file_node structures,
  94.  * which contain information about files such as date-time of write
  95.  * and the filename.  To keep things simple, MAKE insures that only
  96.  * one file_node exists for any given file.
  97.  */
  98.  
  99. struct file_node
  100.     {
  101.     int magic;
  102.     char *fname;
  103.     unsigned long fdatetime;
  104.     struct file_node *chain;
  105.     };
  106.  
  107. typedef struct file_node *fileptr;
  108.  
  109. struct target_node
  110.     {
  111.     int magic;
  112.     struct target_node *next;
  113.     fileptr file;
  114.     struct prereq_node *prereq_list;
  115.     struct shell_node *shell_list;
  116.     };
  117.  
  118. struct prereq_node
  119.     {
  120.     int magic;
  121.     struct prereq_node *next;
  122.     fileptr file;
  123.     };
  124.  
  125. struct shell_node
  126.     {
  127.     int magic;
  128.     struct shell_node *next;
  129.     char *command;
  130.     };
  131.  
  132. static struct target_node
  133.     *target_list;
  134.  
  135. static struct file_node
  136.     *file_node_list;
  137.  
  138. static char
  139.     *makefilename,
  140.     comspec[132];
  141.  
  142. static int
  143.     status,
  144.     trace_flag;
  145.  
  146. usage ()
  147. {
  148. puts (VERSION);
  149. puts ("This program may be copied freely for noncommercial purposes.  It may");
  150. puts ("not be copied for commercial use without my prior written permission.\n");
  151. puts ("This  program is an imitation of the MAKE program supplied with Unix.");
  152. puts ("It works exactly like Unix MAKE (and VAX/VMS MMS) except that it  has");
  153. puts ("no default rules and no macro facility.\n");
  154. puts ("Usage:  make [-f makefile] [options] file ...");
  155. puts ("Options:");
  156. puts ("        -f filename  specify makefile, default is MAKEFILE");
  157. puts ("        -n           trace and print, but don't execute commands");
  158. exit ();
  159. }
  160.  
  161. main (argc, argv)
  162. int argc;
  163. char **argv;
  164. {
  165. int
  166.     argi,
  167.     targi;
  168.  
  169. char
  170.     *targname[MAXTARGETS];
  171.  
  172. if (argc < 2)
  173.     usage ();
  174. makefilename = "MAKEFILE";
  175. trace_flag = 0;
  176. target_list = 0;
  177. file_node_list = 0;
  178. targi = 0;
  179. random_inits ();            /* init random stuff */
  180. puts (VERSION);
  181. for (argi = 1; argi < argc; argi++)
  182.     {
  183.     if (argv[argi][0] == '-')        /* switch */
  184.     switch (argv[argi][1])        /* switch character */
  185.         {
  186.         case 'f':
  187.                 if (argi < (argc - 1))
  188.                     makefilename = argv[++argi];
  189.                 else
  190.                     usage ();
  191.         break;
  192.         case 'n':
  193.         trace_flag = 1;
  194.         break;
  195.         default:
  196.         usage ();
  197.         }
  198.     else
  199.     {                /* target name */
  200.     if (targi + 1 == MAXTARGETS)
  201.         ABORT ("too many target files");
  202.     targname[targi] = malloc (strlen (argv[argi]) + 1);
  203.     if (targname[targi] == NULL)
  204.         ABORT ("no memory");
  205.     strcpy (targname[targi], argv[argi]);
  206.     targi++;
  207.     };
  208.     };
  209. parse (makefilename);
  210. for (argi = 0; argi < targi; argi++)
  211.     make (targname[argi]);
  212. puts ("MAKE complete.");
  213. }
  214.  
  215. /*
  216.  * Init random stuff.  This routine frees all memory we're not using,
  217.  * and finds out where the shell lives.
  218.  */
  219.  
  220. random_inits ()
  221. {
  222. unsigned int
  223.     segsize,
  224.     envseg;
  225.  
  226. segread (&seg);                /* read segment registers */
  227. srv.es = seg.scs;
  228. segsize = peek (0x2, seg.scs);        /* get top of memory address */
  229. segsize = segsize - seg.sss;        /* compute size of data segment */
  230. if (segsize > 0x1000) segsize = 0x1000;    /* max CI-C86 version 1.33 uses */
  231. srv.bx = (seg.sss + segsize) - seg.scs;    /* free memory we'll never use */
  232. DOS (0x4A);
  233. envseg = peek (0x2C, seg.scs);        /* get environment segment */
  234. if (! env_fetch ("COMSPEC", envseg, comspec))
  235.     ABORT ("Can't find COMSPEC environment string");
  236. }
  237.  
  238. parse (makefilename)
  239. char *makefilename;
  240. {
  241. FILE
  242.     *fd;
  243.  
  244. #define LINESIZE 400        /* max length of input line */
  245. #define MAXCOMMON 8        /* max no. of targets with common prereqs */
  246. #define WORDSIZE 80
  247.  
  248. int
  249.     targi,
  250.     i,
  251.     line_length;
  252.  
  253. char
  254.     c,
  255.     *sp,
  256.     *dp,
  257.     input[LINESIZE],
  258.     cont_line[LINESIZE],
  259.     word[WORDSIZE];
  260.  
  261. struct target_node
  262.     *targ[MAXTARGETS];
  263.  
  264. fd = fopen (makefilename, "r");
  265. if (fd == NULL) ABORT ("can't open makefile");
  266. targi = 0;
  267. while (fgets (input, LINESIZE, fd) != 0)
  268.     {
  269.     line_length = strlen (input);
  270.     if (input[line_length - 1] == '\n')        /* stomp on trailing newline */
  271.     input[--line_length] = 0;
  272.     while (input[line_length - 1] == '-')    /* continuation line coming? */
  273.     {
  274.     input[--line_length] = 0;        /* stomp on trailing hyphen */
  275.     fgets (cont_line, LINESIZE, fd);    /* read next line */
  276.     line_length += strlen (cont_line);    /* and append to input */
  277.     strcat (input, cont_line);
  278.     if (input[line_length - 1] == '\n')    /* stomp on trailing newline */
  279.         input[--line_length] = 0;
  280.     };
  281. #ifdef DEBUG
  282.     printf ("Makefile Input: \"%s\"\n", input);
  283. #endif
  284.     sp = input;
  285.     c = *sp;
  286.     if (c == '!' || c == '#') continue;    /* ignore comment lines */
  287.     if (isspace (c))            /* target or shell line? */
  288.         {                /* leading whitespace - shell */
  289.     while (isspace (*sp)) sp++;    /* skip leading whitespace */
  290.     if (targi == 0) ABORT ("Target line must come before shell lines");
  291.     for (i = 0; i < targi; i++)
  292.         link_new_shell_line (targ[i], sp);
  293.     continue;
  294.     };
  295.     targi = 0;
  296.     dp = word;                /* where to put target name */
  297.     while (c = *sp++)
  298.     if (c == ':' || isspace (c))    /* space or colon ends target name */
  299.             {
  300.         char colonflag;
  301.         *dp = 0;            /* ASCIZ */
  302.         colonflag = (c == ':');    /* "colon present" flag */
  303.         while ((c = *sp) && isspace (c)) sp++;    /* skip whitespace */
  304.         if (c == ':')        /* if whitespace followed by colon */
  305.         {
  306.         colonflag = 1;        /* remember colon present */
  307.         sp++;            /* skip colon and */
  308.         while ((c = *sp) && isspace (c)) sp++;    /* trailing spaces */
  309.         };
  310.         targ[targi++] = new_target (word);
  311.         if (colonflag)
  312.         break;
  313.         if (targi > MAXTARGETS) ABORT ("too many targets in one line");
  314.         dp = word;
  315.             }
  316.     else
  317.             *dp++ = c;            /* accumulate target name */
  318.     if (targi == 0)
  319.         {
  320.         fputs ("No target found in this line:\n \"");
  321.         fputs (input, stdout);
  322.         puts ("\"");
  323.         ABORT ("bad makefile");
  324.         };
  325.     while ((c = *sp) && isspace (c)) sp++;
  326.     dp = word;                /* where to accumulate prereq names */
  327.     while (1)                /* pick off prerequisite names */
  328.     {
  329.     c = *sp++;
  330.         if (c == 0 || isspace (c))    /* space terminates a name */
  331.             {
  332.         if (dp == word) break;    /* if nothing found, line has ended */
  333.         *dp = 0;
  334.         for (i = 0; i < targi; i++)
  335.         link_new_prereq (targ[i], word);
  336.         while ((c = *sp) && isspace (c)) sp++;
  337.         dp = word;            /* reset destination pointer */
  338.             }
  339.         else
  340.             *dp++ = c;
  341.     };/* end while */
  342.     };/* end while */
  343. fclose (fd);
  344. }
  345.  
  346. /*
  347.  * new_target
  348.  *
  349.  *    We think we have a new target;  this routine scans the
  350.  *    target list and if we've already seen this name returns
  351.  *    the node we already built.  Otherwise, a new node is
  352.  *    allocated and linked.
  353.  */
  354.  
  355. new_target (name)
  356. char *name;
  357. {
  358. struct target_node
  359.     *targ,
  360.     *last_targ;
  361.  
  362. #ifdef DEBUG
  363. printf ("new_target (\"%s\")\n", name);
  364. #endif
  365.  
  366. targ = target_list;
  367. while (targ != 0)
  368.     {
  369.     if (targ->magic != TARG_MAGIC) ABORT ("bad target_list");
  370.     if (strcmp (targ->file->fname, name) == 0)
  371.     return (targ);
  372.     last_targ = targ;
  373.     targ = targ->next;
  374.     };
  375. targ = malloc (sizeof (struct target_node));
  376. if (targ == NULL) ABORT ("no memory");
  377. targ->magic = TARG_MAGIC;
  378. targ->file = new_file_node (name);
  379. targ->next = 0;
  380. targ->shell_list = 0;
  381. targ->prereq_list = 0;
  382. if (target_list == 0)
  383.     target_list = targ;
  384. else
  385.     last_targ->next = targ;
  386. return (targ);
  387. }
  388.  
  389. /*
  390.  * link_new_shell_line
  391.  *
  392.  *    Add a shell command to the list of commands needed to update
  393.  *    a target file
  394.  */
  395.  
  396. link_new_shell_line (targ, line)
  397. struct target_node *targ;
  398. char *line;
  399. {
  400. struct shell_node
  401.     *next,
  402.     *snode,
  403.     *new;
  404.  
  405. #ifdef DEBUG
  406. printf ("link_new_shell_line (%x, \"%s\")\n", targ, line);
  407. #endif
  408.  
  409. new = malloc (sizeof (struct shell_node));
  410. if (new == NULL) ABORT ("no memory");
  411. new->next = 0;
  412. new->magic = SHELL_MAGIC;
  413. new->command = malloc (strlen (line) + 1);
  414. if (new->command == NULL) ABORT ("no memory");
  415. strcpy (new->command, line);
  416. if (snode = targ->shell_list)
  417.     {
  418.     if (snode->magic != SHELL_MAGIC) ABORT ("bad shell chain");
  419.     while (next = snode->next) snode = next;
  420.     snode->next = new;
  421.     }
  422. else
  423.     targ->shell_list = new;
  424. }
  425.  
  426. /*
  427.  * link_new_prereq (targ, name)
  428.  *
  429.  *    Link a new prerequisite file onto prereq list for a target.
  430.  *    We first scan the list to make sure this isn't a duplicate
  431.  *    (if duplicate, we just ignore it).
  432.  */
  433.  
  434. link_new_prereq (targ, name)
  435. struct target_node *targ;
  436. char *name;
  437. {
  438. struct prereq_node
  439.     *prereq,
  440.     *last;
  441.  
  442. fileptr
  443.     fnode;
  444.  
  445. #ifdef DEBUG
  446. printf ("link_new_prereq (%x, \"%s\")\n", targ, name);
  447. #endif
  448.  
  449. prereq = targ->prereq_list;
  450. if (prereq == 0)
  451.     {
  452.     targ->prereq_list = new_prereq_node (new_file_node (name));
  453. #ifdef DEBUG
  454.     printf (" 1st prereq linked is at %x\n", targ->prereq_list);
  455. #endif
  456.     return;
  457.     };
  458. while (prereq)
  459.     {
  460.     if (prereq->magic != PREREQ_MAGIC) ABORT ("bad prerequisite chain");
  461.     if (strcmp (name, prereq->file->fname) == 0)
  462.     return;
  463.     last = prereq;
  464.     prereq = prereq->next;
  465.     };
  466. last->next = new_prereq_node (new_file_node (name));
  467. }
  468.  
  469. /*
  470.  * new_prereq_node
  471.  *
  472.  *    Allocate and return a new prerequisite node
  473.  */
  474.  
  475. struct prereq_node *new_prereq_node (fnode)
  476. struct file_node *fnode;
  477. {
  478. struct prereq_node
  479.     *new;
  480.  
  481. #ifdef DEBUG
  482. printf ("new_prereq_node (struct file_node *%x)\n", fnode);
  483. #endif
  484.  
  485. new = malloc (sizeof (struct prereq_node));
  486. if (new == NULL) ABORT ("no memory");
  487. new->next = 0;
  488. new->magic = PREREQ_MAGIC;
  489. new->file = fnode;
  490. return (new);
  491. }
  492.  
  493. /*
  494.  * new_file_node
  495.  *
  496.  *    Return file_node pointer for a file;  returns pointer to
  497.  *    existing file_node if this file already seen, else allocates
  498.  *    and inits a new node
  499.  */
  500.  
  501. struct file_node *new_file_node (name)
  502. char *name;
  503. {
  504. struct file_node
  505.     *last,
  506.     *newnode,
  507.     *fnode;
  508.  
  509. #ifdef DEBUG
  510. printf ("new_file_node (\"%s\")\n", name);
  511. #endif
  512.  
  513. fnode = file_node_list;
  514. last = 0;
  515. while (fnode)
  516.     {
  517.     if (fnode->magic != FILE_MAGIC) ABORT ("bad file_node_list chain");
  518.     if (strcmp (name, fnode->fname) == 0)
  519.     {
  520. #ifdef DEBUG
  521.     printf ("new_file_node returning existing node at %x\n", fnode);
  522. #endif
  523.     return (fnode);
  524.     };
  525.     last = fnode;
  526.     fnode = fnode->chain;
  527.     };
  528. newnode = malloc (sizeof (struct file_node));
  529. if (newnode == NULL) ABORT ("no memory");
  530. init_fnode (newnode, name);
  531. if (last == 0)
  532.     file_node_list = newnode;
  533. else
  534.     last->chain = newnode;
  535. return (newnode);
  536. }
  537.  
  538. /*
  539.  * init_fnode
  540.  *
  541.  *    Init a file_node with name and date/time of a file
  542.  */
  543.  
  544. init_fnode (fnode, name)
  545. char *name;
  546. struct file_node *fnode;
  547. {
  548.  
  549. #ifdef DEBUG
  550. printf ("init_fnode (%x, \"%s\")\n", fnode, name);
  551. #endif
  552.  
  553. fnode->fname = malloc (strlen (name) + 1);
  554. if (fnode->fname == NULL) ABORT ("no memory");
  555. strcpy (fnode->fname, name);
  556. fnode->fdatetime = getdatetime (name);
  557. fnode->chain = 0;
  558. fnode->magic = FILE_MAGIC;
  559. }
  560.  
  561. /*
  562.  * getdatetime
  563.  *
  564.  *    Return date-time of a file squished into a long so compares
  565.  *    are easy
  566.  */
  567.  
  568. unsigned long getdatetime (name)
  569. char *name;
  570. {
  571. unsigned long
  572.     datetime;
  573.  
  574. int
  575.     dma_off,
  576.     dma_seg;
  577.  
  578. srv.ax = 0x2F00;        /* get current DMA address */
  579. sysint (0x21, &srv, &rrv);    /*  .. */
  580. dma_off = rrv.bx;        /* and save for later restoration */
  581. dma_seg = rrv.es;
  582.  
  583. srv.ds = seg.sds;
  584. srv.dx = &find_buf;        /* set DMA to GNJFN block */
  585. srv.ax = 0x1A00;
  586. sysint (0x21, &srv, &rrv);
  587.  
  588. srv.ds = seg.sds;
  589. srv.dx = name;            /* pathname */
  590. srv.cx = 0;            /* attributes */
  591. srv.ax = 0x4E00;        /* GTJFN */
  592. status = sysint (0x21, &srv, &rrv);
  593. if (status & 1)
  594.     {
  595. #ifdef DEBUG
  596.     printf ("MAKE: warning -- can't find file \"%s\", continuing...\n", name);
  597. #endif
  598.     return (0L);
  599.     };
  600.  
  601. srv.ds = dma_seg;        /* restore DMA address */
  602. srv.dx = dma_off;
  603. srv.ax = 0x1A00;
  604. sysint (0x21, &srv, &rrv);
  605.  
  606. #ifdef DEBUG
  607. printf ("filespec = \"%s\", date = %u, time = %u, sizel = %d\n",
  608.     &find_buf.pname, find_buf.date, find_buf.time, find_buf.size_l);
  609. #endif
  610.  
  611. datetime = (unsigned long) find_buf.date;
  612. datetime = datetime << 16;
  613. datetime = datetime + ((unsigned long) find_buf.time);
  614. return (datetime);
  615. }
  616.  
  617. /*
  618.  * make (name)
  619.  *
  620.  *    This routine actually does the work.  It scans the list of
  621.  *    targets parsed from the makefile, and checks the target's
  622.  *    prerequisites date/time values against the target's.  If
  623.  *    the prerequisite is itself a target (present in target_list),
  624.  *    we call make recursively to check it.  Then, if any of our
  625.  *    prerequisites are newer than we are, we execute all our shell
  626.  *    commands.
  627.  */
  628.  
  629. make (targname)
  630. char *targname;
  631. {
  632. struct target_node
  633.     *targ;
  634.  
  635. struct prereq_node
  636.     *prereq;
  637.  
  638. unsigned long
  639.     newest_prereq;
  640.  
  641. #ifdef DEBUG
  642. printf ("Making %s\n", targname);
  643. #endif
  644.  
  645. newest_prereq = 0;
  646. if ((targ = lookup_target (targname)) == 0)
  647.     {
  648.     puts ("Target not found");
  649.     ABORT ("make failed");
  650.     };
  651. if (prereq = targ->prereq_list)        /* check each prerequisite file */
  652.     while (prereq)
  653.     {
  654.     if (lookup_target (prereq->file->fname))    /* if prereq known, */
  655.         make (prereq->file->fname);            /* recursively make */
  656.     if (prereq->file->fdatetime > newest_prereq)    /* now check age */
  657.         newest_prereq = prereq->file->fdatetime;
  658.     prereq = prereq->next;
  659.     };
  660.  
  661. #ifdef DEBUG
  662. printf ("Target \"%s\" datetime is %ld, newest prereq is %ld\n",
  663.     targ->file->fname, targ->file->fdatetime, newest_prereq);
  664. #endif
  665.  
  666. if (targ->file->fdatetime < newest_prereq)
  667.     build (targ);
  668. }
  669.  
  670. /*
  671.  * build
  672.  *
  673.  *    Invoke shell commands to build a target file
  674.  */
  675.  
  676. build (targ)
  677. struct target_node *targ;
  678. {
  679. struct shell_node
  680.     *snode;
  681.  
  682. char
  683.     *cmd;
  684.  
  685. #ifdef DEBUG
  686. printf ("MAKE: Building \"%s\"\n", targ->file->fname);
  687. #endif
  688.  
  689. snode = targ->shell_list;
  690. if (snode == 0) ABORT ("No shell commands specified");
  691. while (snode)
  692.     {
  693.     if (snode->magic != SHELL_MAGIC) ABORT ("bad shell node");
  694.     cmd = snode->command;
  695.     fputs ("MAKE: ", stdout);
  696.     fputs (cmd, stdout);
  697.     if (trace_flag)
  698.     puts ("");        /* EXEC does newline, so must be faked */
  699.     else            /* here if just tracing */
  700.     system (cmd);
  701.     snode = snode->next;
  702.     };
  703. targ->file->fdatetime = getdatetime (targ->file->fname);
  704. }
  705.  
  706. /*
  707.  * system
  708.  *
  709.  *    Execute a shell command
  710.  */
  711.  
  712. static struct        /* execute program parameter block */
  713.     {
  714.     int environment;
  715.     int cmdoff;
  716.     int cmdseg;
  717.     int fcb5off;
  718.     int fcb5seg;
  719.     int fcb6off;
  720.     int fcb6seg;
  721.     } params;
  722.  
  723. static char
  724.     *sp,
  725.     c,
  726.     cmdstring[132];
  727.  
  728. system (cmd)
  729. char *cmd;
  730. {
  731. int
  732.     i;
  733.  
  734. sp = "/C";        /* magic switch for shell to say "here's a command" */
  735. i = 1;
  736. while (c = *sp++)
  737.     cmdstring[i++] = c;
  738. sp = cmd;        /* append user's shell command */
  739. while (c = *sp++)
  740.     cmdstring[i++] = c;
  741. cmdstring[i++] = 0x0D;
  742. cmdstring[i] = 0;
  743. cmdstring[0] = i - 2;
  744. params.environment = peek (0x2c, seg.scs);    /* inherit our environment */
  745. params.cmdseg = seg.sss;
  746. params.cmdoff = cmdstring;
  747. params.fcb5seg = params.fcb6seg = 0;
  748. params.fcb5off = params.fcb6off = 0;
  749.  
  750. status = exec (seg.sds, comspec, ¶ms);
  751. if (status)
  752.     {
  753.     fputs ("\nMAKE error: ", stdout);
  754.     puts (dos_error (status));
  755.     ABORT ("EXEC failed");
  756.     };
  757. }
  758.  
  759. struct target_node *lookup_target (name)
  760. char *name;
  761. {
  762. struct target_node
  763.     *targ;
  764.  
  765. targ = target_list;
  766. while (targ)
  767.     {
  768.     if (strcmp (name, targ->file->fname) == 0)
  769.     return (targ);
  770.     targ = targ->next;
  771.     };
  772. return (0);
  773. }
  774.