home *** CD-ROM | disk | FTP | other *** search
- /* file make.c */
- /* received from km@cadre.arpa, originally a usenet posting.
- heavily modified to appear more like UNIX make, working only from the
- manual page ( macros, embedded macros, rules, default rules,
- multiple targets per line, and special handling of cc for multiple passes
- gregg@nlm-vax.arpa
- */
-
- #include <stdio.h>
- #include "make.h"
- #include "rules.h"
-
- #if MSC
- #include <ctype.h>
- #endif
-
- #if LC
- int _stack = SIZ_STK;
- #endif
-
- char *whoami = "Make";
-
- struct macrec *maclist = NULL;
- struct defnrec *defnlist = NULL;
- struct llist *dolist = NULL;
- struct rulerec *rulelist = NULL;
-
- long make(),getmodified();
- char *mov_in(),*get_mem(),*extrac_comp(),*new_c_rule;
-
- int execute = TRUE;
- int stopOnErr = TRUE;
- int madesomething = FALSE;
- int knowhow = FALSE;
- int no_file = TRUE;
- int linecont = LINE_DEFAULT;
- char *DRIVE = DRIVE_DEFAULT;
- int tree_and_quit = FALSE;
- int firstcc = TRUE;
- int tmake = FALSE;
- int update_time_latest = TRUE;
-
- main(argc,argv)
- int argc;
- char *argv[];
- {
-
- init(argc,argv);
- if (tree_and_quit){ prtree();exit(0);}
-
-
- /* now fall down the dolist and do them all */
-
- while (dolist != NULL) {
- madesomething = FALSE;
- make(dolist->name);
- if (!madesomething) {
- if (knowhow) {
- fprintf(stderr,"Make: '%s' is up to date.",dolist->name);
- } else {
- error("Don't know how to make '%s'.",dolist->name);
- }
- }
- dolist = dolist->next;
- }
- exit( 0 );
- }
-
-
- init(argc,argv)
- int argc;
- char *argv[];
- {
- int i,k;
- char *filearg;
- struct llist *ptr,*ptr2,*ptr3;
- int usedefault = TRUE;
-
- for (k=i=0;i < NDRULES ;i++){
- /* couldn't init the linked list with the compiler */
- dflt_rules[i].dep = def_list[k++];
- dflt_rules[i].targ = def_list[k++];
- ptr = NULL;
- while ( def_list[k] != NULL ) {
- ptr2 = MkListMem();
- ptr2->name = def_list[k++];
- ptr2->next = NULL;
- if ( ptr == NULL ) ptr = ptr2;
- else {
- ptr3 = ptr;
- while ( ptr3->next != NULL ) ptr3 = ptr3->next;
- ptr3->next = ptr2;
- }
- }
- dflt_rules[i].rule = ptr;
- dflt_rules[i].nextrule = (i+1 < NDRULES ) ? &dflt_rules[i+1] : NULL;
- k++;
- }
-
-
- for (i=1; i < argc; i++) {
- if (argv[i][0] == '-') { /* option */
- switch (argv[i][1]) {
-
- case 'f': case 'F': /* arg following is a makefile */
- if (++i < argc) {
- filearg = argv[i];
- usedefault = FALSE;
- }
- else
- panic("'-f' requires filename");
- break;
-
- case 'c': case 'C': /* line continuation char */
- if ( argv[i][2] != NUL )
- linecont = argv[i][2];
- else {
- if ( ++i < argc || notnull(argv[i][1]) )
- linecont = argv[i][0];
- else
- error("'-c' requires single character");
- }
- break;
-
- case 'i': case 'I': /* ignore errors on execution */
- stopOnErr = FALSE;
- break;
-
- case 'x':case 'X': /* print a tree and quit */
- tree_and_quit = TRUE;
- break;
-
- case 't':case 'T': /* trace selected subroutines */
- tmake = TRUE;
- break;
-
- case 'w':case 'W': /* if made something, update time to
- the latest of the targets */
- update_time_latest = FALSE;
- break;
-
- case 'n': case 'N': /* don't execute commands - just print */
- execute = FALSE;
- break;
-
- case 'd': case 'D': /* change the drive to look for FULL NAMES */
- if ( argv[i][2] != NUL )
- DRIVE[0] = toupper(argv[i][2]);
- else {
- if ( ++i < argc || notnull(argv[i][1]) )
- DRIVE[0] = toupper(argv[i][0]);
- else
- error("'-d' requires single character");
- }
- break;
-
- default:
- error("unknown option '%s'.",argv[i]);
- }
- }
- else {
- /* it must be something to make */
- add_do(argv[i]);
- no_file = FALSE;
- }
- }
- /*
- collect the flags, then read the makefile, otherwise a construct like
- make -f make2 aardvark
- will make both aardvark and the first target in make2
- */
- if (usedefault)
- readmakefile(DEFAULT);
- else readmakefile(filearg);
-
- adjust(); /* this is where we adjust the rules and macros... */
- }/* init */
-
- adjust()
- {
- struct rulerec *rptr;
- struct macrec *mptr;
-
- /* in the case that a .c.obj rule is defined, and a cc macro is not... */
- rptr = rulelist;
- if (rptr != NULL){
- while ( TRUE ) {
- if (
- ( (strcmp(rptr->dep,"c") == 0 ) ||
- (strcmp(rptr->dep,"C") == 0 )
- )
- &&
- ( (strcmp(rptr->targ,"obj") == 0) ||
- (strcmp(rptr->targ,"OBJ") == 0)
- )
- ) break;
-
- else if (rptr->nextrule == NULL) {
- rptr = NULL;
- break;
- }
- else rptr = rptr->nextrule;
- }
-
- if (rptr != NULL){
- /* rptr points to a .c.obj rule */
- mptr = maclist;
- if (mptr != NULL){
- while ( TRUE ) {
- if ((strcmp(mptr->name,"CC") == 0 )) break;
-
- else if (mptr->nextmac == NULL) break;
-
- else mptr = mptr->nextmac;
- }
-
- if ( strcmp(mptr->name,"CC") != 0 ) {
- /* there is .c.obj and no CC macro */
- mptr->nextmac = (struct macrec *)get_mem(sizeof (struct macrec));
- mptr->nextmac->name = mov_in("CC");
- /* here we make the possibly unwarrented assumption that
- the compiler is the first string in the first part of
- the rule
- */
- mptr->nextmac->mexpand = extrac_comp(rptr->rule->name);
- mptr->nextmac->nextmac = NULL;
- rptr->rule->name = new_c_rule;
- }
- }
- }
- }
- }/* adjust */
-
-
- long make(s) /* returns the modified date/time */
- char *s;
- {
- struct defnrec *defnp,*tryrules(),*dummy;
- struct llist *depp,*depp2;
- struct llist *howp;
- long latest,timeof,now();
-
- /* look for the definition */
- if ( tmake ) fprintf(stderr,"make\(%s\)\n",s);
- defnp = defnlist;
-
- while (defnp != NULL) {
- if (strcmp(defnp->name,s) == 0)
- break;
- defnp = defnp->nextdefn;
- }
-
- /*
- there might be some adjusting of the lists for implied compilations.
- these additions are not done in readmakefile;
- they might not be required for these targets.
- */
-
- if (defnp == NULL ){
- defnp = tryrules(s);
- if (defnp == NULL){ /* tryrules returns a pointer to a defnrec */
- /* tryrules fails, and there is no definition */
- knowhow = FALSE;
- latest = getmodified(s,DEFINED);
- if (latest==0) {
- /* doesn't exist but don't know how to make */
- panic("Can't make '%s'.",s);
- }
- else {
- /* exists - assume it's up to date since we don't know */
- if ( tmake ) fprintf(stderr,"make\(%s\) returns, assumed up to date\n",s);
- return(latest);
- }
- }
- }
-
- else{ /* there is a definition line */
- if (defnp->uptodate) {
- if ( tmake ) fprintf(stderr,"make\(%s\) is up to date\n",s);
- return(defnp->modified);
- }
- dummy = tryrules(s);
- if (dummy != NULL && defnp->howto == NULL){ /* any explicit howto overrides an implicit one */
- /*add depend*/
- if (defnp->dependson == NULL)
- defnp->dependson = dummy->dependson;
- else{
- depp2 = defnp->dependson;
- while (depp2->next != NULL)
- depp2 = depp2->next;
- depp2->next = dummy->dependson;
- }
- /* add howto line */
- defnp->howto = dummy->howto;
- }
- }
- /* finished adjusting the lists */
-
- /* check that everything that the current target depends on is uptodate */
- latest = 0;
- depp = defnp->dependson;
- while (depp != NULL) {
-
- timeof = make(depp->name);
- latest = max(timeof,latest); /* written this way to avoid side effects */
- depp = depp->next;
- }
-
- knowhow = TRUE; /* has dependencies therefore we know how */
-
- /* if necessary, execute all of the commands to make it */
- /* if (out of date) || (depends on nothing) */
- if (latest > defnp->modified || defnp->dependson==NULL) {
- /* make those suckers */
- howp = defnp->howto;
- if (howp == NULL) error("%s is out of date, but there is no command line",s);
- while (howp != NULL) {
-
- /* the execute flag controls whether execution takes place */
- if (exec_how(howp->name) != 0)
- error("error from %s",extrac_comp(howp->name));
- howp = howp->next;
- }
- /* we just made something. Set the time of modification to now. The
- old way was to set the time to the latest of the depends, with
- a reason like "If we don't actually have a file, it works OK"
- switch -w reverts to latest, not system time. Using now works better
- when the sources may be in another directory.
- */
- defnp->modified = ( update_time_latest == TRUE ) ? now() : latest;
- defnp->uptodate = TRUE;
- if (defnp->howto != NULL) /* we had instructions */
- madesomething = TRUE;
- }
- if ( tmake ) fprintf(stderr,"make\(%s\) returns, having made something\n",s);
- return(defnp->modified);
-
- }
-
-
- add_do(s) /*this adds to the list of targets to make*/
- char *s;
- {
- struct llist *ptr1, *ptr2;
-
- ptr1 = MkListMem();
-
- ptr1->name = mov_in(s); /*mov_in returns pointer to newly allocated copy of name*/
- ptr1->next = NULL;
-
- /* now go down the dolist */
- if (dolist == NULL)
- dolist = ptr1;
- else {
- ptr2 = dolist;
- while (ptr2->next != NULL)
- ptr2 = ptr2->next;
- ptr2->next = ptr1;
- }
-
- }
-
- expand(src,dest,target,flag) /* expand any macros found*/
- char *src,*dest,*target;
- int flag;
- {
- char thismac[INMAX],*ismac(),*ismac_c(),cht[2];
- char thismac2[INMAX],*macptr;
- int i,pos,back;
-
- back = pos = 0;
- while( notnull(src[pos]) ) {
-
- if (src[pos] != '$') dest[back++] = src[pos++];
-
- else {
- pos++;
- /*found '$'. What kind of macro is this? */
- switch(src[pos]){
- case '(': /*regular macro*/
- case '{': /*regular macro*/
- /* do macro stuff */
- pos = x_scan(src,pos,thismac); /* get macro */
- if ( maclist == NULL && flag == REPT_ERR)
- error("can't expand macro \"%s\" \(no macros defined\)",thismac);
- else if ( (macptr=ismac(thismac)) == NULL) {
- expand(thismac,thismac2,target,flag);
- if ((macptr=ismac(thismac2))==NULL && flag==REPT_ERR)
- error("Can't expand macro \"%s\"",thismac2);
- else
- /* thismac2 has expanded macro */
- back = mv_expand(macptr,dest,back,target,flag);
- }
- else
- /* did find expansion the first time */
- back = mv_expand(macptr,dest,back,target,flag);
-
- break;
-
- case '*': /*target without extension*/
- case '@': /*whole target*/
- if (flag == NO_TARG){
- sprintf(cht,"%c",src[pos]);
- error("'$%s' not in a command or dependency line",cht);
- }
- else {
- for (i=0; notnull(target[i]) ; i++) {
- if ( target[i] == '.' && src[pos] == '*') break;
- dest[back++] = target[i];
- }
- }
-
- break;
-
- default:
- if ( (macptr = ismac_c(src[pos])) != NULL )
- back = mv_expand(macptr,dest,back,target,flag);
-
- else {
- /*not an approved macro, ignore*/
- dest[back++] = '$';
- dest[back++] = src[pos];
- }
-
- break;
- }
- pos++;
- }
- }
- dest[back] = NUL;
- }
-
- /* is this a character macro? */
- char *ismac_c(cc)
- char cc;
- {
- char *str = "A"; /* A is placeholder */
- str[0] = cc;
- return(ismac(str));
- }
-
- /* is this string a macro? */
- char *ismac(test)
- char *test;
- {
- struct macrec *ptr;
- char rettemp[INMAX];
-
- ptr = maclist;
- if ( ptr == NULL ) return( NULL );
- strcpy(rettemp,test);
- uppercase(rettemp);
- while( TRUE ) {
- if (strcmp(ptr->name,rettemp) == 0)
- return( ptr->mexpand );
- else if ( ptr->nextmac == NULL )
- return( NULL );
- else
- ptr = ptr->nextmac;
- }
- }
- x_scan(src,pos,dest)
- char *src,*dest;
- int pos;
- {
- char bterm,eterm;
- int cnt;
-
- /* load dest with macro, allowing for nesting */
- if ( src[pos] == '(' ) eterm = ')';
- else if ( src[pos] == '{' ) eterm = '}';
- else panic("very bad things happening in x_scan");
-
- bterm = src[pos++];
- cnt = 1;
-
- while ( notnull(src[pos]) ) {
- if ( src[pos] == bterm ) cnt++;
- else if ( src[pos] == eterm ) {
- cnt--;
- if ( cnt == 0 ) {
- *dest = NUL;
- return( pos );
- }
- }
- *dest++ = src[pos++];
- }
- panic("No closing brace/paren for %s",src);
- /* NOTREACHED */
- }
-
- /* expand and move to dest */
- mv_expand(from,to,back,target,flag)
- char *from,*to,*target;
- int back,flag;
- {
- int i;
- char temp[INMAX];
-
- expand( from,temp,target,flag );
- for ( i=0; notnull(temp[i]) ; i++)
- to[back++] = temp[i];
- return( back );
- }
-
-
- /*
- attempts to apply a rule. If an applicable rule is found, returns a
- pointer to a (new) struct which can be added to the defnlist
- An applicable rule is one in which target ext matches, and a source file
- exists
- */
-
- char ext[INMAXSH]; /*place to store the extension*/
-
- struct defnrec *tryrules(string) /*check for user defined rules*/
- char *string;
- {
-
-
- struct rulerec *rulep;
- struct defnrec *trydef(),*construct();
- int found,i;
- char s[INMAXSH];
-
- strcpy(s,string);
- if ( tmake ) fprintf(stderr,"tryrules\(%s\) ",string);
- for (i=0;notnull(s[i]) && s[i] != '.';i++) ; /*skip to beginning of ext */
- if (isnull(s[i])) {
- /*target has no extension*/
- if ( tmake ) fprintf(stderr,"failed\n");
- return(NULL);
- }
- s[i++] = NUL; /*truncate the object and advance to the extension*/
- strcpy(ext,s + i );
-
- if (rulelist == NULL)
- return(trydef(s,ext)); /*try default rules*/
- else{
- rulep = rulelist;
- while ( TRUE ){
- if ((strcmp(ext,rulep->targ) == 0) && exists(s,rulep->dep)) {
- found = TRUE;break;
- }
- else if (rulep->nextrule != NULL){
- rulep = rulep->nextrule;
- }
- else{
- found = FALSE;break;
- }
- }
- }
- if ( !found ) return(trydef(s,ext));
- /*found a user defined rule*/
- if ( tmake ) fprintf(stderr,"found user rule\n");
- return(construct(s,rulep,REPT_ERR)); /* make a new defnrec with this rule*/
- }
- struct defnrec *trydef(s,t) /*try the default rules*/
- char *s,*t;
- {
-
- struct rulerec *rulep;
- struct defnrec *construct();
- int found;
-
- if (dflt_rules == NULL)
- return(NULL);
- else{
- rulep = dflt_rules;
- while ( TRUE ){
- if ((strcmp(t,rulep->targ) == 0) && exists(s,rulep->dep)) {
- found = TRUE;
- break;
- }
- else if (rulep->nextrule != NULL)
- rulep = rulep->nextrule;
- else{
- found = FALSE;break;
- }
- }
- }
- if (!found) {
- if ( tmake ) fprintf(stderr,"fails\n");
- return(NULL);
- }
- /*found a default rule*/
- if ( tmake ) fprintf(stderr,"found a default rule\n");
- return(construct(s,rulep,IGN_ERR)); /* make a new defnrec with this rule, ignoring macros not defined*/
- }
-
-
- struct defnrec *construct(object,rulep,flag) /*construct definition from rule and return pointer to new memory containing it*/
- char *object;
- struct rulerec *rulep;
- int flag;
- {
-
- char buf[INMAXSH];
- struct defnrec *retval;
- struct llist *mkllist(),*mkexphow();
-
- retval = (struct defnrec *)get_mem((unsigned) sizeof(struct defnrec));
- strcpy(buf,object); /*object is the stem of the object*/
- strcat(buf,".");
- strcat(buf,rulep->targ);
- retval->name = mov_in(buf);
- strcpy(buf,object);
- strcat(buf,".");
- strcat(buf,rulep->dep);
- retval->dependson = mkllist(buf);
- retval->uptodate = FALSE;
- retval->modified = getmodified(retval->name,DEPENDANT);
- retval->nextdefn = NULL;
- retval->howto = mkexphow(rulep->rule,retval->name,flag);
- return(retval); /*whew*/
-
- }
-
-
- /* does the file exist? */
- exists(name,suffix)
- char *name,*suffix;
- {
- char t[INMAXSH];
-
- strcpy(t,name);
- strcat(t,".");
- strcat(t,suffix);
- return (getmodified(t,DEFINED) != 0L ? TRUE : FALSE );
- }
-
- /*debugging*/
- /* print the dependencies and command lines... */
- prtree()
- {
- struct defnrec *dummy;
- struct macrec *mdum;
- struct llist *dum2,*dum3,*rdum2;
- struct rulerec *rdum;
- int cnt;
- dummy = defnlist;
- while (dummy != NULL){
- fprintf(stderr,"name '%s' modified:%ld\n\n",dummy->name,dummy->modified);
- dum2 = dummy->dependson;
- fprintf(stderr," depends-on:");cnt =0;
- while (dum2 != NULL){
- fprintf(stderr,"'%s' ",dum2->name);cnt++;
- if (cnt == 5){
- cnt = 0;
- fprintf(stderr,"\n ");
- }
- dum2 = dum2->next;
- }
- printf("\n");
- dum3 = dummy->howto;
- while (dum3 != NULL){
- fprintf(stderr," command: %s\n",dum3->name);
- dum3 = dum3->next;
- }
- dummy = dummy->nextdefn;
- fprintf(stderr,"\n");
- }
- fprintf(stderr," *RULES*\n\n");
- fprintf(stderr,"src= dest= rule=\n");
- rdum = rulelist;
- while ( rdum != NULL ) {
- fprintf(stderr,"%4s %4s %s\n",rdum->dep,rdum->targ,rdum->rule->name);
- rdum2 = rdum->rule->next;
- while ( rdum2 != NULL ) {
- fprintf(stderr," %s\n",rdum2->name);
- rdum2 = rdum2->next;
- }
- rdum = rdum->nextrule;
- }
- /* default rules */
- for ( cnt = 0 ; cnt < NDRULES ; cnt++ ) {
- rdum = rulelist;
- while ( rdum != NULL ) {
- if ( (strcmp(rdum->dep,dflt_rules[cnt].dep) == 0) &&
- (strcmp(rdum->targ,dflt_rules[cnt].targ) == 0) ) break;
- rdum = rdum->nextrule;
- }
- if ( rdum == NULL ) {
- fprintf(stderr,"%4s %4s %s\n",dflt_rules[cnt].dep,dflt_rules[cnt].targ,dflt_rules[cnt].rule->name);
- rdum2 = dflt_rules[cnt].rule->next;
- while ( rdum2 != NULL ) {
- fprintf(stderr," %s\n",rdum2->name);
- rdum2 = rdum2->next;
- }
- }
- }
- mdum = maclist;
- if ( mdum == NULL )
- fprintf(stderr,"\n *NO MACROS*\n");
- else {
- fprintf(stderr,"\n *MACROS*\n\n");
- fprintf(stderr," macro expansion\n");
- while ( mdum != NULL ) {
- fprintf(stderr," %7s %s\n",mdum->name,mdum->mexpand);
- mdum = mdum->nextmac;
- }
- }
- } /*debug*/
-
- /* VARARGS */
- error(s1,s2)
- char *s1,*s2;
- {
- fprintf(stderr,"%s: ",whoami);
- fprintf(stderr,s1,s2);
- fprintf(stderr,"\n");
- if (stopOnErr) exit(-1);
- else return;
- }
-
- error2(s1,s2,s3)
- char *s1,*s2,*s3;
- {
- fprintf(stderr,"%s: ",whoami);
- fprintf(stderr,s1,s2,s3);
- fprintf(stderr,"\n");
- if (stopOnErr) exit(-1);
- else return;
- }
- /* VARARGS */
- panic(s1,s2)
- char *s1,*s2;
- {
- fprintf(stderr,"%s: ",whoami);
- fprintf(stderr,s1,s2);
- fprintf(stderr,"\n");
- exit(-1);
- }
-
- char *extrac_comp(r)
- char *r;
- {
- /* extract the compiler from a rule */
- int i,k,x,end,mark;
- char *retval,temp[INMAXSH];
-
- i = k = 0;
- while ( isspace(r[i]) ) i++;/*skip WS*/
-
- while ( !isspace(r[i]) && notnull(r[i]) ) temp[k++] = r[i++];
- temp[k] = NUL;
- mark = i;
-
- if ( notnull(r[i]) ) {
- while ( notnull(r[i]) && r[i] != BKSLSH ) i++;/* skip to backslash */
- if ( notnull(r[i]) && r[++i] == ';') strcat(temp,r+i-2);
- }
- retval = mov_in(temp);
-
- /* if the rule is <compiler><WS><whatever><numpasses> , fill
- new_c_rule with "cc <whatever>"
- */
- strcpy(temp,"cc ");
- if ( isnull(r[i]) ) end = i;
- else end = i-1;
- for ( x = mark ; x < end ; x++ ) temp[3+x-mark] = r[x];
- temp[3+x-mark] = NUL;
- new_c_rule = mov_in(temp);
-
- return(retval);
- }