home *** CD-ROM | disk | FTP | other *** search
/ Power-Programmierung / CD2.mdf / c / tools / make / nmake / make.c < prev    next >
Text File  |  1987-07-21  |  23KB  |  767 lines

  1. /* file make.c */
  2. /* received from km@cadre.arpa, originally a usenet posting.
  3.    heavily modified to appear more like UNIX make, working only from the
  4.    manual page ( macros, embedded macros, rules, default rules,
  5.    multiple targets per line, and special handling of cc for multiple passes
  6.    gregg@nlm-vax.arpa
  7. */
  8.  
  9. #include <stdio.h>
  10. #include "make.h"
  11. #include "rules.h"
  12.  
  13. #if MSC
  14. #include <ctype.h>
  15. #endif
  16.  
  17. #if LC
  18. int _stack = SIZ_STK;
  19. #endif
  20.  
  21. char *whoami = "Make";
  22.  
  23. struct macrec   *maclist = NULL;
  24. struct defnrec  *defnlist = NULL;
  25. struct llist    *dolist = NULL;
  26. struct rulerec  *rulelist = NULL;
  27.  
  28. long make(),getmodified();
  29. char *mov_in(),*get_mem(),*extrac_comp(),*new_c_rule;
  30.  
  31. int execute = TRUE;
  32. int stopOnErr = TRUE;
  33. int madesomething = FALSE;
  34. int knowhow = FALSE;
  35. int no_file = TRUE;
  36. int linecont = LINE_DEFAULT;
  37. char *DRIVE = DRIVE_DEFAULT;
  38. int tree_and_quit = FALSE;
  39. int firstcc = TRUE;
  40. int tmake = FALSE;
  41. int update_time_latest = TRUE;
  42.  
  43. main(argc,argv)
  44. int argc;
  45. char *argv[];
  46. {
  47.  
  48.     init(argc,argv);
  49.     if (tree_and_quit){ prtree();exit(0);}
  50.         
  51.  
  52.     /* now fall down the dolist and do them all */
  53.  
  54.     while (dolist != NULL) {
  55.         madesomething = FALSE;
  56.         make(dolist->name);
  57.         if (!madesomething) {
  58.             if (knowhow) {
  59.                 fprintf(stderr,"Make: '%s' is up to date.",dolist->name);
  60.             } else {
  61.                 error("Don't know how to make '%s'.",dolist->name);
  62.             }
  63.         }
  64.         dolist = dolist->next;
  65.     }
  66.     exit( 0 );
  67. }
  68.  
  69.  
  70. init(argc,argv)
  71. int argc;
  72. char *argv[];
  73. {
  74. int     i,k;
  75. char    *filearg;
  76. struct llist *ptr,*ptr2,*ptr3;
  77. int usedefault = TRUE;
  78.  
  79.     for (k=i=0;i < NDRULES ;i++){
  80.         /* couldn't init the linked list  with the compiler */
  81.         dflt_rules[i].dep = def_list[k++];
  82.         dflt_rules[i].targ = def_list[k++];
  83.         ptr = NULL;
  84.         while ( def_list[k] != NULL ) {
  85.             ptr2 = MkListMem();
  86.             ptr2->name = def_list[k++];
  87.             ptr2->next = NULL;
  88.             if ( ptr == NULL ) ptr = ptr2;
  89.             else {
  90.                 ptr3 = ptr;
  91.                 while ( ptr3->next != NULL ) ptr3 = ptr3->next;
  92.                 ptr3->next = ptr2;
  93.             }
  94.         }
  95.         dflt_rules[i].rule = ptr;
  96.         dflt_rules[i].nextrule = (i+1 < NDRULES ) ? &dflt_rules[i+1] : NULL;
  97.         k++;
  98.     }
  99.  
  100.  
  101.     for (i=1; i < argc; i++) {
  102.         if (argv[i][0] == '-') {    /* option */
  103.             switch (argv[i][1]) {
  104.  
  105.                 case 'f': case 'F': /* arg following is a makefile */
  106.                     if (++i < argc) {
  107.                         filearg = argv[i];
  108.                         usedefault = FALSE;
  109.                     }
  110.                     else 
  111.                         panic("'-f' requires filename");
  112.                     break;
  113.  
  114.                 case 'c': case 'C':  /* line continuation char */
  115.                    if ( argv[i][2] != NUL ) 
  116.                       linecont = argv[i][2];
  117.                    else {
  118.                             if ( ++i < argc || notnull(argv[i][1]) )
  119.                                 linecont = argv[i][0];
  120.                        else
  121.                            error("'-c' requires single character");
  122.                    }
  123.                    break;
  124.  
  125.                 case 'i': case 'I': /* ignore errors on execution */
  126.                     stopOnErr = FALSE;
  127.                     break;
  128.  
  129.                 case 'x':case 'X':  /* print a tree and quit */
  130.                     tree_and_quit = TRUE;
  131.                     break;
  132.                     
  133.                 case 't':case 'T':  /* trace selected subroutines */
  134.                     tmake = TRUE;
  135.                     break;
  136.                 
  137.                 case 'w':case 'W':   /* if made something, update time to 
  138.                                         the latest of the targets */
  139.                     update_time_latest = FALSE;
  140.                     break;
  141.  
  142.                 case 'n': case 'N': /* don't execute commands - just print */
  143.                     execute = FALSE;
  144.                     break;
  145.                     
  146.                 case 'd': case 'D': /* change the drive to look for FULL NAMES */
  147.                     if ( argv[i][2] != NUL ) 
  148.                          DRIVE[0] = toupper(argv[i][2]);
  149.                    else {
  150.                        if ( ++i < argc || notnull(argv[i][1]) )
  151.                            DRIVE[0] = toupper(argv[i][0]);
  152.                        else
  153.                            error("'-d' requires single character");
  154.                    }
  155.                    break;
  156.  
  157.                 default:
  158.                     error("unknown option '%s'.",argv[i]);
  159.             }
  160.         }
  161.         else {
  162.             /* it must be something to make */
  163.              add_do(argv[i]);
  164.              no_file = FALSE;
  165.         }
  166.     }
  167.     /* 
  168.        collect the flags, then read the makefile, otherwise a construct like
  169.        make -f make2 aardvark
  170.        will make both aardvark and the first target in make2
  171.     */   
  172.     if (usedefault)
  173.          readmakefile(DEFAULT);
  174.     else readmakefile(filearg);
  175.     
  176.     adjust();   /* this is where we adjust the rules and macros... */
  177. }/* init */
  178.  
  179. adjust()
  180. {
  181. struct rulerec *rptr;
  182. struct macrec  *mptr;
  183.     
  184.     /* in the case that a .c.obj rule is defined, and a cc macro is not...  */
  185.     rptr = rulelist;
  186.     if (rptr != NULL){
  187.         while ( TRUE ) {
  188.             if (
  189.                  ( (strcmp(rptr->dep,"c") == 0 ) ||
  190.                    (strcmp(rptr->dep,"C") == 0 )
  191.                  )
  192.                  &&
  193.                  ( (strcmp(rptr->targ,"obj") == 0) ||
  194.                    (strcmp(rptr->targ,"OBJ") == 0)
  195.                  )
  196.                ) break;
  197.  
  198.             else if (rptr->nextrule == NULL) {
  199.                  rptr = NULL;
  200.                  break;
  201.             }
  202.             else rptr = rptr->nextrule;
  203.         }
  204.  
  205.         if (rptr != NULL){
  206.             /* rptr points to a .c.obj rule */
  207.             mptr = maclist;
  208.             if (mptr != NULL){
  209.                 while ( TRUE ) {
  210.                     if ((strcmp(mptr->name,"CC") == 0 )) break;
  211.  
  212.                     else if (mptr->nextmac == NULL)  break;
  213.  
  214.                     else mptr = mptr->nextmac;
  215.                 }
  216.  
  217.                 if ( strcmp(mptr->name,"CC") != 0 ) {
  218.                     /* there is .c.obj and no CC macro */
  219.                     mptr->nextmac = (struct macrec *)get_mem(sizeof (struct macrec));
  220.                     mptr->nextmac->name = mov_in("CC");
  221.                     /* here we make the possibly unwarrented assumption that
  222.                        the compiler is the first string in the first part of
  223.                        the rule
  224.                     */
  225.                     mptr->nextmac->mexpand = extrac_comp(rptr->rule->name);
  226.                     mptr->nextmac->nextmac = NULL;
  227.                     rptr->rule->name = new_c_rule;
  228.                 }
  229.             }
  230.         }
  231.     }
  232. }/* adjust */
  233.  
  234.  
  235. long make(s)    /* returns the modified date/time */
  236. char *s;
  237. {
  238. struct defnrec   *defnp,*tryrules(),*dummy;
  239. struct llist    *depp,*depp2;
  240. struct llist    *howp;
  241. long             latest,timeof,now();
  242.  
  243.     /* look for the definition */
  244.     if ( tmake ) fprintf(stderr,"make\(%s\)\n",s);
  245.     defnp = defnlist;
  246.  
  247.     while (defnp != NULL) {
  248.         if (strcmp(defnp->name,s) == 0)
  249.             break;
  250.         defnp = defnp->nextdefn;
  251.     }
  252.     
  253.     /* 
  254.        there might be some adjusting of the lists for implied compilations.
  255.        these additions are not done in readmakefile;
  256.        they might not be required for these targets.
  257.     */
  258.  
  259.     if (defnp == NULL ){
  260.         defnp = tryrules(s);
  261.         if (defnp == NULL){   /* tryrules returns a pointer to a defnrec */
  262.             /* tryrules fails, and there is no definition */        
  263.             knowhow = FALSE;
  264.             latest = getmodified(s,DEFINED);
  265.             if (latest==0) {
  266.                 /* doesn't exist but don't know how to make */
  267.                 panic("Can't make '%s'.",s);
  268.             }
  269.             else {
  270.                 /* exists - assume it's up to date since we don't know */
  271.                 if ( tmake ) fprintf(stderr,"make\(%s\) returns, assumed up to date\n",s);
  272.                 return(latest);
  273.             }
  274.         }
  275.     }
  276.     
  277.     else{    /* there is a definition line */
  278.         if (defnp->uptodate) {
  279.             if ( tmake ) fprintf(stderr,"make\(%s\) is up to date\n",s);
  280.             return(defnp->modified);
  281.         }
  282.         dummy = tryrules(s); 
  283.         if (dummy != NULL && defnp->howto == NULL){  /* any explicit howto overrides an implicit one */
  284.             /*add depend*/
  285.             if (defnp->dependson == NULL)
  286.                 defnp->dependson = dummy->dependson;
  287.             else{
  288.                 depp2 = defnp->dependson;
  289.                 while (depp2->next != NULL)
  290.                     depp2 = depp2->next;
  291.                 depp2->next = dummy->dependson;
  292.             }
  293.             /* add howto line */
  294.             defnp->howto = dummy->howto;
  295.         }
  296.     }
  297.     /* finished adjusting the lists */
  298.  
  299.     /* check that everything that the current target depends on is uptodate */
  300.     latest = 0;
  301.     depp = defnp->dependson;
  302.     while (depp != NULL) {
  303.  
  304.         timeof = make(depp->name);
  305.         latest = max(timeof,latest); /* written this way to avoid side effects */
  306.         depp = depp->next;
  307.     }
  308.  
  309.     knowhow = TRUE; /* has dependencies therefore we know how */
  310.  
  311.     /* if necessary, execute all of the commands to make it */
  312.     /* if (out of date) || (depends on nothing)             */
  313.     if (latest > defnp->modified || defnp->dependson==NULL) {
  314.         /* make those suckers */
  315.         howp = defnp->howto;
  316.         if (howp == NULL) error("%s is out of date, but there is no command line",s);
  317.         while (howp != NULL) {
  318.  
  319.            /* the execute flag controls whether execution takes place */
  320.             if (exec_how(howp->name) != 0)
  321.                 error("error from %s",extrac_comp(howp->name));
  322.             howp = howp->next;
  323.         }
  324.         /* we just made something. Set the time of modification to now. The
  325.            old way was to set the time to the latest of the depends, with
  326.            a reason like "If we don't actually have a file, it works OK"
  327.            switch -w reverts to latest, not system time. Using now works better
  328.            when the sources may be in another directory.
  329.         */
  330.         defnp->modified =  ( update_time_latest == TRUE ) ? now() : latest;
  331.         defnp->uptodate = TRUE;
  332.         if (defnp->howto != NULL)   /* we had instructions */
  333.             madesomething = TRUE;
  334.     }
  335.     if ( tmake ) fprintf(stderr,"make\(%s\) returns, having made something\n",s);
  336.     return(defnp->modified);
  337.  
  338. }
  339.  
  340.  
  341. add_do(s)  /*this adds to the list of targets to make*/
  342. char *s;
  343. {
  344.     struct llist *ptr1, *ptr2;
  345.  
  346.     ptr1 = MkListMem();
  347.  
  348.     ptr1->name = mov_in(s);  /*mov_in returns pointer to newly allocated copy of name*/
  349.     ptr1->next = NULL;
  350.  
  351.     /* now go down the dolist */
  352.     if (dolist == NULL)
  353.         dolist = ptr1;
  354.     else {
  355.         ptr2 = dolist;
  356.         while (ptr2->next != NULL)
  357.             ptr2 = ptr2->next;
  358.         ptr2->next = ptr1;
  359.     }
  360.  
  361. }
  362.  
  363. expand(src,dest,target,flag)    /* expand any macros found*/
  364. char *src,*dest,*target;
  365. int  flag;
  366. {
  367. char  thismac[INMAX],*ismac(),*ismac_c(),cht[2];
  368. char  thismac2[INMAX],*macptr;
  369. int   i,pos,back;
  370.  
  371.    back = pos = 0;
  372.    while( notnull(src[pos]) ) {
  373.  
  374.        if (src[pos] != '$') dest[back++] = src[pos++];
  375.  
  376.        else {
  377.        pos++;
  378.        /*found '$'. What kind of macro is this? */
  379.            switch(src[pos]){
  380.                 case '(':   /*regular macro*/
  381.                 case '{':   /*regular macro*/
  382.                    /* do macro stuff */
  383.            pos = x_scan(src,pos,thismac); /* get macro */
  384.            if ( maclist == NULL && flag == REPT_ERR)
  385.               error("can't expand macro \"%s\" \(no macros defined\)",thismac);
  386.            else if ( (macptr=ismac(thismac)) == NULL) {
  387.                expand(thismac,thismac2,target,flag);
  388.                if ((macptr=ismac(thismac2))==NULL && flag==REPT_ERR)
  389.                    error("Can't expand macro \"%s\"",thismac2);
  390.                else 
  391.                /* thismac2 has expanded macro */
  392.                back = mv_expand(macptr,dest,back,target,flag);
  393.            }
  394.            else
  395.                /* did find expansion the first time */
  396.             back = mv_expand(macptr,dest,back,target,flag);
  397.  
  398.            break;
  399.  
  400.                 case '*':    /*target without extension*/
  401.                 case '@':    /*whole target*/
  402.                    if (flag == NO_TARG){
  403.                sprintf(cht,"%c",src[pos]);
  404.                        error("'$%s' not in a command or dependency line",cht);
  405.            }
  406.            else {
  407.                for (i=0; notnull(target[i]) ; i++) {
  408.                    if ( target[i] == '.' && src[pos] == '*') break;
  409.                            dest[back++] = target[i];
  410.                }
  411.            }
  412.  
  413.            break;
  414.  
  415.                 default:
  416.            if ( (macptr = ismac_c(src[pos])) != NULL )
  417.                back = mv_expand(macptr,dest,back,target,flag);
  418.  
  419.            else {
  420.                /*not an approved macro, ignore*/
  421.                dest[back++] = '$';
  422.                dest[back++] = src[pos];
  423.            }
  424.  
  425.            break;
  426.        }
  427.        pos++;
  428.        }
  429.    }
  430.    dest[back] = NUL;
  431. }
  432.  
  433. /* is this a character macro? */
  434. char *ismac_c(cc)
  435. char cc;
  436. {
  437. char *str = "A"; /* A is placeholder */
  438.     str[0] = cc;
  439.     return(ismac(str));
  440. }
  441.  
  442. /* is this string a macro? */
  443. char *ismac(test)
  444. char *test;
  445. {
  446. struct macrec *ptr;
  447. char rettemp[INMAX];
  448.  
  449.     ptr = maclist;
  450.     if ( ptr == NULL ) return( NULL );
  451.     strcpy(rettemp,test);
  452.     uppercase(rettemp);
  453.     while( TRUE ) {
  454.     if (strcmp(ptr->name,rettemp) == 0) 
  455.         return( ptr->mexpand );
  456.     else if ( ptr->nextmac == NULL )
  457.        return( NULL );
  458.     else
  459.        ptr = ptr->nextmac;
  460.     }
  461. }
  462. x_scan(src,pos,dest)
  463. char *src,*dest;
  464. int pos;
  465. {
  466. char bterm,eterm;
  467. int cnt;
  468.  
  469.     /* load dest with macro, allowing for nesting */
  470.     if ( src[pos] == '('  ) eterm = ')';
  471.     else if ( src[pos] == '{'  ) eterm = '}';
  472.     else panic("very bad things happening in x_scan");
  473.  
  474.     bterm = src[pos++];
  475.     cnt = 1;
  476.  
  477.     while ( notnull(src[pos]) ) {
  478.     if ( src[pos] == bterm ) cnt++;
  479.     else if ( src[pos] == eterm ) {
  480.         cnt--;
  481.         if ( cnt == 0 ) {
  482.         *dest = NUL;
  483.         return( pos );
  484.         }
  485.     }
  486.     *dest++ = src[pos++];
  487.     }
  488.     panic("No closing brace/paren for %s",src);
  489.     /* NOTREACHED */
  490. }
  491.     
  492. /* expand and move to dest */
  493. mv_expand(from,to,back,target,flag)
  494. char *from,*to,*target;
  495. int back,flag;
  496. {
  497. int i;
  498. char temp[INMAX];
  499.  
  500.     expand( from,temp,target,flag );
  501.     for ( i=0; notnull(temp[i]) ; i++)
  502.         to[back++] = temp[i];
  503.     return( back );
  504. }
  505.  
  506.  
  507. /*
  508. attempts to apply a rule.  If an applicable rule is found, returns a 
  509. pointer to a (new) struct which can be added to the defnlist
  510. An applicable rule is one in which target ext matches, and a source file
  511. exists
  512. */
  513.  
  514. char          ext[INMAXSH];       /*place to store the extension*/
  515.  
  516. struct defnrec *tryrules(string)  /*check for user defined rules*/
  517. char *string;
  518. {
  519.  
  520.  
  521. struct rulerec *rulep;
  522. struct defnrec *trydef(),*construct();
  523. int            found,i;
  524. char           s[INMAXSH];
  525.  
  526.         strcpy(s,string);
  527.         if ( tmake ) fprintf(stderr,"tryrules\(%s\)  ",string);
  528.         for (i=0;notnull(s[i]) && s[i] != '.';i++) ; /*skip to beginning of ext */
  529.         if (isnull(s[i])) {
  530.             /*target has no extension*/
  531.             if ( tmake ) fprintf(stderr,"failed\n");
  532.             return(NULL);
  533.         }
  534.         s[i++] = NUL;     /*truncate the object and advance to the extension*/
  535.         strcpy(ext,s + i );
  536.             
  537.         if (rulelist == NULL)
  538.             return(trydef(s,ext));  /*try default rules*/
  539.         else{
  540.             rulep = rulelist;
  541.             while ( TRUE ){
  542.                 if ((strcmp(ext,rulep->targ) == 0) && exists(s,rulep->dep)) {
  543.                     found = TRUE;break;
  544.                 }
  545.                 else if (rulep->nextrule != NULL){
  546.                     rulep = rulep->nextrule;
  547.                 }
  548.                 else{
  549.                     found = FALSE;break;
  550.                 }
  551.             }
  552.         }
  553.         if ( !found ) return(trydef(s,ext));
  554.         /*found a user defined rule*/
  555.         if ( tmake ) fprintf(stderr,"found user rule\n");
  556.         return(construct(s,rulep,REPT_ERR)); /* make a new defnrec with this rule*/
  557. }
  558. struct defnrec *trydef(s,t)  /*try the default rules*/
  559. char *s,*t;
  560. {
  561.  
  562. struct rulerec *rulep;
  563. struct defnrec *construct();
  564. int            found;
  565.  
  566.         if (dflt_rules == NULL)
  567.             return(NULL);
  568.         else{
  569.             rulep = dflt_rules;
  570.             while ( TRUE ){
  571.                 if ((strcmp(t,rulep->targ) == 0) && exists(s,rulep->dep)) {
  572.                     found = TRUE;
  573.                     break;
  574.                 }
  575.                 else if (rulep->nextrule != NULL)
  576.                     rulep = rulep->nextrule;
  577.                 else{
  578.                     found = FALSE;break;
  579.                 }
  580.             }
  581.         }
  582.         if (!found) {
  583.             if ( tmake ) fprintf(stderr,"fails\n");
  584.             return(NULL);
  585.         }
  586.         /*found a default rule*/
  587.         if ( tmake ) fprintf(stderr,"found a default rule\n");
  588.         return(construct(s,rulep,IGN_ERR)); /* make a new defnrec with this rule, ignoring macros not defined*/
  589. }
  590.  
  591.  
  592. struct defnrec *construct(object,rulep,flag)   /*construct definition from rule and return pointer to new memory containing it*/
  593. char           *object;
  594. struct rulerec *rulep;
  595. int            flag;
  596. {
  597.  
  598. char           buf[INMAXSH];
  599. struct defnrec *retval;
  600. struct llist *mkllist(),*mkexphow();
  601.  
  602.             retval = (struct defnrec *)get_mem((unsigned) sizeof(struct defnrec));
  603.             strcpy(buf,object);     /*object is the stem of the object*/
  604.             strcat(buf,".");
  605.             strcat(buf,rulep->targ);
  606.             retval->name = mov_in(buf);
  607.             strcpy(buf,object);
  608.             strcat(buf,".");
  609.             strcat(buf,rulep->dep);
  610.             retval->dependson = mkllist(buf);
  611.             retval->uptodate = FALSE;
  612.             retval->modified = getmodified(retval->name,DEPENDANT);
  613.             retval->nextdefn = NULL;
  614.             retval->howto = mkexphow(rulep->rule,retval->name,flag);
  615.             return(retval);                 /*whew*/
  616.  
  617. }
  618.  
  619.  
  620. /* does the file exist? */
  621. exists(name,suffix)
  622. char *name,*suffix;
  623. {
  624. char t[INMAXSH];
  625.  
  626.     strcpy(t,name);
  627.     strcat(t,".");
  628.     strcat(t,suffix);
  629.     return (getmodified(t,DEFINED) != 0L ? TRUE : FALSE );
  630. }
  631.  
  632. /*debugging*/
  633. /* print the dependencies and command lines... */
  634. prtree()
  635. {
  636. struct defnrec *dummy;
  637. struct macrec  *mdum;
  638. struct llist   *dum2,*dum3,*rdum2;
  639. struct rulerec *rdum;
  640. int    cnt;
  641.     dummy = defnlist;
  642.     while (dummy != NULL){
  643.         fprintf(stderr,"name '%s'  modified:%ld\n\n",dummy->name,dummy->modified);
  644.         dum2 = dummy->dependson;
  645.         fprintf(stderr,"   depends-on:");cnt =0;
  646.         while (dum2 != NULL){
  647.             fprintf(stderr,"'%s'   ",dum2->name);cnt++;
  648.             if (cnt == 5){
  649.                 cnt = 0;
  650.                 fprintf(stderr,"\n              ");
  651.             }
  652.             dum2 = dum2->next;
  653.         }
  654.         printf("\n");
  655.         dum3 = dummy->howto;
  656.         while (dum3 != NULL){
  657.             fprintf(stderr,"   command: %s\n",dum3->name);
  658.             dum3 = dum3->next;
  659.         }
  660.         dummy = dummy->nextdefn;
  661.         fprintf(stderr,"\n");
  662.     }
  663.     fprintf(stderr,"        *RULES*\n\n");
  664.     fprintf(stderr,"src=     dest=     rule=\n");
  665.     rdum = rulelist;
  666.     while ( rdum != NULL ) {
  667.         fprintf(stderr,"%4s     %4s      %s\n",rdum->dep,rdum->targ,rdum->rule->name);
  668.         rdum2 = rdum->rule->next;
  669.         while ( rdum2 != NULL ) {
  670.             fprintf(stderr,"                %s\n",rdum2->name);
  671.             rdum2 = rdum2->next;
  672.         }
  673.         rdum = rdum->nextrule;
  674.     }
  675.     /* default rules */
  676.     for ( cnt = 0 ; cnt < NDRULES ; cnt++ ) {
  677.         rdum = rulelist;
  678.         while ( rdum != NULL ) {
  679.             if ( (strcmp(rdum->dep,dflt_rules[cnt].dep) == 0) &&
  680.                  (strcmp(rdum->targ,dflt_rules[cnt].targ) == 0) ) break;
  681.             rdum = rdum->nextrule;
  682.         }
  683.         if ( rdum == NULL ) {
  684.             fprintf(stderr,"%4s     %4s      %s\n",dflt_rules[cnt].dep,dflt_rules[cnt].targ,dflt_rules[cnt].rule->name);
  685.             rdum2 = dflt_rules[cnt].rule->next;
  686.             while ( rdum2 != NULL ) {
  687.                 fprintf(stderr,"                   %s\n",rdum2->name);
  688.                 rdum2 = rdum2->next;
  689.             }
  690.         }
  691.     }
  692.     mdum = maclist;
  693.     if ( mdum == NULL ) 
  694.        fprintf(stderr,"\n        *NO MACROS*\n");
  695.     else {
  696.         fprintf(stderr,"\n        *MACROS*\n\n");
  697.         fprintf(stderr," macro          expansion\n");
  698.         while ( mdum != NULL ) {
  699.              fprintf(stderr," %7s       %s\n",mdum->name,mdum->mexpand);
  700.              mdum = mdum->nextmac;
  701.         }
  702.     }
  703. } /*debug*/
  704.  
  705. /* VARARGS */
  706. error(s1,s2)
  707. char *s1,*s2;
  708. {
  709.     fprintf(stderr,"%s: ",whoami);
  710.     fprintf(stderr,s1,s2);
  711.     fprintf(stderr,"\n");
  712.     if (stopOnErr) exit(-1);
  713.     else return;
  714. }
  715.  
  716. error2(s1,s2,s3)
  717. char *s1,*s2,*s3;
  718. {
  719.     fprintf(stderr,"%s: ",whoami);
  720.     fprintf(stderr,s1,s2,s3);
  721.     fprintf(stderr,"\n");
  722.     if (stopOnErr) exit(-1);
  723.     else return;
  724. }
  725. /* VARARGS */
  726. panic(s1,s2)
  727. char *s1,*s2;
  728. {
  729.     fprintf(stderr,"%s: ",whoami);
  730.     fprintf(stderr,s1,s2);
  731.     fprintf(stderr,"\n");
  732.     exit(-1);
  733. }
  734.  
  735. char *extrac_comp(r)
  736. char *r;
  737. {
  738.     /* extract the compiler from a rule */
  739.     int i,k,x,end,mark;
  740.     char *retval,temp[INMAXSH];
  741.     
  742.     i = k = 0;
  743.     while ( isspace(r[i]) ) i++;/*skip WS*/
  744.     
  745.     while ( !isspace(r[i]) && notnull(r[i]) ) temp[k++] = r[i++];
  746.     temp[k] = NUL;  
  747.     mark = i;
  748.  
  749.     if  ( notnull(r[i]) ) {
  750.         while ( notnull(r[i]) && r[i] != BKSLSH ) i++;/* skip to backslash */
  751.         if ( notnull(r[i]) && r[++i] == ';')  strcat(temp,r+i-2);
  752.     }
  753.     retval = mov_in(temp);
  754.     
  755.     /* if the rule is  <compiler><WS><whatever><numpasses> , fill
  756.        new_c_rule with "cc <whatever>"
  757.     */
  758.     strcpy(temp,"cc ");
  759.     if ( isnull(r[i]) ) end = i;
  760.     else  end = i-1;
  761.     for ( x = mark ; x < end ; x++ ) temp[3+x-mark] = r[x];
  762.     temp[3+x-mark] = NUL;
  763.     new_c_rule = mov_in(temp);
  764.  
  765.     return(retval);
  766. }
  767.