|
DataMuseum.dkPresents historical artifacts from the history of: DKUUG/EUUG Conference tapes |
This is an automatic "excavation" of a thematic subset of
See our Wiki for more about DKUUG/EUUG Conference tapes Excavated with: AutoArchaeologist - Free & Open Source Software. |
top - metrics - downloadIndex: T m
Length: 16381 (0x3ffd) Types: TextFile Names: »maketd.c«
└─⟦a0efdde77⟧ Bits:30001252 EUUGD11 Tape, 1987 Spring Conference Helsinki └─⟦this⟧ »EUUGD11/euug-87hel/sec8/ease/maketd/maketd.c«
/* maketd - MAKE Transitive Dependencies. * (This is a lie - the dependencies are not transitive, but "all" * dependencies are correctly made.) * * Based loosely on a shell script by Stephan Bechtolsheim, svb@purdue * Other Makefile related features have been added or merged in from * other programs. * * Written & hacked by Stephen Uitti, PUCC staff, ach@pucc-j, 1985 * maketd is copyright (C) Purdue University, 1985 * * removed some of Steve's good, but unnecessary, options in favor * of more compile time flags & better implicit rules in the makefile * dinked: -q -e -E -k * Kevin S Braunsdorf, PUCC UNIX Group 1986 (ksb@j.cc.purdue.edu) * * Permission is hereby given for its free reproduction and * modification for non-commercial purposes, provided that this * notice and all embedded copyright notices be retained. * Commercial organisations may give away copies as part of their * systems provided that they do so without charge, and that they * acknowledge the source of the software. */ #include <sys/types.h> #include <sys/param.h> #include <sys/file.h> /* for access */ #ifdef BSD2_9 #include <ndir.h> /* for MAXPATHLEN, MAXNAMLEN */ #endif #ifdef BSD4_2 #include <sys/dir.h> /* for MAXNAMLEN in 4.2 */ #endif #include <ctype.h> /* for isupper */ #include <stdio.h> extern char *rindex(), *index(), *strcat(), *strcpy(); #include "srtunq.h" #include "abrv.h" #include "nshpopen.h" #include "maketd.h" #ifndef CPP #define CPP "/lib/cpp " #endif CPP not in Makefile /* forward functions */ void msoio(); /* open output file */ void rdwr(); /* read old Makefile into new */ void mkdepend(); /* does the real work */ /* globals */ char *prgnm; /* our program name */ FILE *makefd; /* makefile stream */ int alldep = FALSE; /* -a all - /usr/include too */ char *targetname = NULL; /* -t target name for next file */ char *destsuffix = ".o"; /* -s suffix for targets */ int header = TRUE; /* print header & trailer */ int usestdout = FALSE; /* -d use stdout for makefile */ int forcehead = FALSE; /* -f force header/trailer */ int makenseen = FALSE; /* output file has been specified */ char *makename = "makefile"; /* -m default file for edit */ int backedup = FALSE; /* for interupt recovery */ char backupfn[MAXNAMLEN+1]; /* backup file name */ int ismakeopen = FALSE; /* if the output file is open */ char objpath[MAXPATHLEN+1]; /* -o prepended to .o's */ int nonlocalo = FALSE; /* -nonlocalo objects in source dir */ int replace = FALSE; /* -r replace depends in Makefile */ char cppflags[BUFSIZ]; /* -D, -I, -U flags to pass to cpp */ int shortincl = TRUE; /* -x do abreviations */ int verbose = FALSE; /* -v verbage for the debugger */ static char sopts[] = "abdfhrxv"; /* single char opts */ static SRTUNQ u; /* unique include files */ char usage[] = "Usage: maketd [-a -b -d -f -h -mMAKEFILE -nonlocalo -oDIR -r -sSUFFIX\n\ -tTARGETNAME -x -v -Iincludedir -Ddefine -Uundefine file...]\n"; char helptext[] = "-a\tdo all dependencies, including /usr/include\n\ -b\tgenerate binary, rather than object related dependencies\n\ -d\tdependencies to stdout, rather than Makefile\n\ -f\tforce header/trailer (use with -d)\n\ -h\thelp (this text)\n\ -m\tspecify MAKEFILE for edit\n\ -nonlocalo Objects live in source directory\n\ -o\tprepend DIR to target: DIR/a.o: foo.h\n\ -r\treplace dependencies for a target\n\ -s\tchange suffix target's SUFFIX: a.SUFFIX: foo.h\n\ -t\tchange target's basename: TARGET.o: foo.h\n\ -x\tdon't abbreviate includes\n\ -v\tprint extra verbose (debug) output to stderr\n\ -I\tspecify include directory, as in /lib/cpp\n\ -D\tspecify defines, as in /lib/cpp\n\ -U\tspecify undefines, as in /lib/cpp\n"; char deplin[] = "# DO NOT DELETE THIS LINE - make depend DEPENDS ON IT\n"; char searchdep[] = "# DO NOT DELETE THIS LINE"; char trailer[] = "\n# *** Do not add anything here - It will go away. ***\n"; /* some init & argv parsing */ main(argc, argv) register int argc; register char **argv; { register a; /* argv subscript */ register i; /* tmp */ register len; /* length of current argument */ register files = FALSE; /* files ever seen */ register char *q; /* tmp */ /* prgnm = program name, for error printing */ if ((prgnm = rindex(argv[0], '/')) == NULL) prgnm = argv[0]; else prgnm++; catchsig(); /* init signal traps */ srtinit(&abrv); /* init abbreviations tree */ for (a = 1; a < argc; a++) { /* argv prepass: find all -I's */ if (argv[a][0] == '-' && argv[a][1] == 'I' && strlen(&argv[a][2]) > 2) if ((q = srtin(&abrv, hincl(&argv[a][2]), lngsrt)) != NULL) fprintf(stderr, "%s: %s - %s\n", prgnm, q, &argv[a][2]); } cppflags[0] = '\0'; /* terminate cpp flags string */ objpath[0] = '\0'; /* init object path */ srtinit(&u); /* init sorting database tag */ for (a = 1; a < argc; a++) { len = strlen(argv[a]); if (argv[a][0] == '-' && len > 2 && index(sopts, argv[a][1]) != NULL) err("options must be listed seperately - '%s'\n", argv[a]); if (len > 1 && argv[a][0] == '-') { switch (argv[a][1]) { case 'D': /* /lib/cpp flags to pass */ case 'I': case 'U': if (strlen(cppflags) + strlen(argv[a]) + 2 > BUFSIZ) err("too many cpp flags - buffer overflow"); strcat(cppflags, argv[a]); strcat(cppflags, " "); /* add a space separator */ break; case 'a': /* /usr/include deps too */ alldep = TRUE; break; case 'b': /* target has no suffix */ destsuffix = ""; break; case 'd': /* don't edit Makefile */ if (ismakeopen) err("Makefile already open, -d must precede filenames"); if (makenseen) err("Conflict - check -d and -m options"); makenseen = TRUE; usestdout = TRUE; if (!forcehead) header = FALSE; /* don't do header & trailer */ break; case 'f': /* force header/trailer */ forcehead = TRUE; header = TRUE; break; case 'h': /* help */ fputs(usage, stdout); fputs(helptext, stdout); exit(0); break; case 'm': /* specify makefile name for edit */ if (ismakeopen) err("Makefile already open, -m must precede filenames"); if (makenseen) err("Conflict, check -m and -d options."); if (strlen(makename) == 0) err("-m option requires file name."); makenseen = TRUE; makename = &argv[a][2]; break; case 'n': /* objects reside with sources */ if (strcmp("nonlocalo", &argv[a][1]) != 0) err("bad -n option"); /* what a crock of an option */ if (objpath[0] != '\0') err("nonlocalo conflict - check -o's"); nonlocalo = TRUE; break; case 'o': if (nonlocalo) err("object path conflict - check -o's and -nonlocalo's"); strcpy(objpath, &argv[a][2]); i = strlen(objpath); if (i == 0) err("-o requires path string."); if (i >= MAXPATHLEN) err("Object path too long: max is %d.", MAXPATHLEN); if (objpath[i - 1] != '/') strcat(objpath, "/"); break; case 'r': /* replace mode */ if (ismakeopen) err("Makefile already open, -r must precede filenames"); replace = TRUE; break; case 's': /* destination suffix */ destsuffix = &argv[a][2]; break; case 't': /* set target's basename */ targetname = &argv[a][2]; if (len <= 2) err("target option requires name."); break; case 'v': /* user wants to hear noise */ verbose = TRUE; break; case 'x': /* don't abbrev. */ if (files) err("-x option must preceed all files."); shortincl = FALSE; break; default: err("Unknown option %s.", argv[a]); } /* end switch */ } else { /* must be a filename */ if (verbose) fprintf(stderr, "%s: working on %s.\n", prgnm, argv[a]); files = TRUE; /* at least one file seen */ if (replace && a != argc - 1) err("Only one file allowed with -r (edit aborted)"); mkdepend(argv[a]); /* file to process */ targetname = NULL; /* affect only one file */ } /* if option */ } /* for argv */ if (ismakeopen && header) fputs(trailer, makefd); /* do not delete... */ #if DEL_BACKUP if (backedup) if (unlink(backupfn)) err("Can't delete backup file %s on completion", backupfn); #endif DEL_BACKUP if (!files) err("No files to process, use -h for full help.\n%s", usage); exit(0); /* exit status - good */ } /* msoio - Make Sure Output Is Open. * Interacts strongly via globals: makefd, backedup, backupfn, makename, * header, ismakeopen */ void msoio(targ) char *targ; /* if -r, is target name */ { FILE *tmpfd; /* temp file desc for -d */ char buf[BUFSIZ]; /* for reading the makefile */ if (ismakeopen) return; ismakeopen = TRUE; /* will be: all errs are fatal */ if (usestdout) { makefd = stdout; if (header) { fputc('\n', makefd); /* one blank line */ fputs(deplin, makefd); /* the first line */ } /* scan "makefile" or "Makefile" for include defines */ if (access(makename, R_OK) != 0) { makename[0] = 'M'; /* try Makefile */ if (access(makename, R_OK) != 0) return; /* just punt */ } if ((tmpfd = fopen(makename, "r")) == NULL) return; /* just punt */ while (fgets(buf, BUFSIZ, tmpfd) != NULL) srchincl(buf); /* scan whole file */ fclose(tmpfd); return; } /* ... if standard out */ /* !makenseen means (default) try "makefile" then "Makefile" */ if (!makenseen && access(makename, F_OK) != 0) makename[0] = 'M'; /* try Makefile */ /* side effect: "Makefile" will be created if neither exist */ if (access(makename, F_OK) == 0) { /* if makefile exits */ strcpy(backupfn, makename); /* get rid of .bak */ strcat(backupfn, ".bak"); if (access(backupfn, F_OK) == 0) { if (unlink(backupfn)) err("Can't remove %s for pre-edit\n", backupfn); } if (link(makename, backupfn)) /* mv makefile to .bak */ err("Can't link %s to %s.", backupfn, makename); backedup = TRUE; /* for interupt status */ if (unlink(makename)) err("Can't unlink %s during rename.", makename); } else { backupfn[0] = '\0'; /* no copy (no makefile) */ } if ((makefd = fopen(makename, "w")) == NULL) err("Can't open output file '%s' for write.", makename); if (backupfn[0] != '\0') /* if no .bak file - done */ rdwr(targ); /* read/write Makefile */ else fputs(deplin, makefd); /* must start with this */ } /* create beginging of new Makefile by reading old one */ void rdwr(targ) char *targ; { register FILE *oldfd; /* file pointer for .old */ char rwbuf[BUFSIZ]; /* temp for read/write */ register tlen; /* targ length */ register puntln = FALSE; /* punt current line? */ register contln = FALSE; /* previous line ended with '\'? */ register blankln = 0; /* number of blank lines seen */ register srchsn = FALSE; /* search line seen? */ if ((oldfd = fopen(backupfn, "r")) == NULL) err("Can't open backup copy of %s\n", makename); tlen = strlen(targ); while (fgets(rwbuf, BUFSIZ, oldfd) != NULL) { /* until EOF */ if (!srchsn) { if (strncmp(searchdep, rwbuf, (sizeof searchdep) - 1) == 0) { srchsn = TRUE; fputs(deplin, makefd); /* re-write this line */ if (!replace) break; continue; /* don't print this line */ } } else { if (strcmp("\n", rwbuf) == 0) { if (!puntln) blankln++; contln = FALSE; puntln = FALSE; continue; /* don't output this blank line */ } if (!contln) { if (strncmp(targ, rwbuf, tlen) == 0) puntln = TRUE; else if (strcmp(&trailer[1], rwbuf) == 0) puntln = TRUE; } if (lastlnch(rwbuf) == '\\') contln = TRUE; else contln = FALSE; } /* if srchsn */ if (!puntln) { srchincl(&rwbuf[0]); /* search this line for defines */ if (blankln != 0) { /* compress mult blank lines to one */ putc('\n', makefd); blankln = 0; } fputs(rwbuf, makefd); /* non targ lines */ } } /* while fgets */ if (!srchsn) /* deplin never found */ fputs(deplin, makefd); /* so write one */ (void) fclose(oldfd); /* close the .old file for gigles */ } #define MAXCOL 78 /* output width max for makefile */ /* mkdepend - name is historical, but does the "real work" */ void mkdepend(infile) char *infile; { register char *p; /* temp pointer */ register char *q; /* temp pointer */ register char *r; /* temp pointer */ register FILE *cppfd; /* file desc for /lib/cpp */ char buf[BUFSIZ]; /* temp buff */ char basename[MAXNAMLEN+1]; /* just the file name */ register oplen; /* length target & path */ register le; /* length of current output line */ register char *targ; /* target's name */ register i; /* tmp for index */ register firstln; /* first line of a list */ if ((p = rindex(infile, '/')) == NULL) /* past path */ p = infile; else p++; if (nonlocalo && p != infile) { /* objpath = source path */ for (q = objpath, r = infile; r < p;) *q++ = *r++; *q = '\0'; /* null terminate */ } strcpy(basename, p); if ((p = rindex(basename, '.')) != NULL) *p = '\0'; /* remove trailing ".*" */ if (targetname != NULL) /* set up target's name */ targ = targetname; else targ = basename; if (makename == NULL) { makename = "Makefile"; if (access(makename, F_OK) != 0) makename[0] = 'm'; /* not a real check */ } msoio(targ); /* Make Sure Output Is Open */ abrvsetup(); /* create abrev table, write defs. */ if (access(infile, R_OK) != 0) { fprintf(stderr, "%s: Can't open input file '%s', skipped.\n", prgnm, infile); return; } (void)strcpy(buf, CPP); /* build cpp cmd line */ #if CPP_M strcat(buf, "-M "); /* -M flag - does dependencies */ #endif if (strlen(buf) + strlen(cppflags) + strlen(infile) + 1 > BUFSIZ) err("cpp command line buffer overflow"); (void)strcat(buf, cppflags); /* add command flags */ (void)strcat(buf, infile); /* add file name */ srtfree(&u); /* init insertion sorter */ if (verbose) fprintf(stderr, "%s: cpp line is '%s'\n", prgnm, buf); if ((cppfd = nshpopen(buf, "r")) == NULL) err("Can't open pipe for %s", buf); #if CPP_M while (fgets(buf, BUFSIZ, cppfd) != NULL) { if ((p = index(buf, ':')) == NULL) err("cpp -M format error - colon"); p++; /* pass colon */ if (*p++ != SPC) err("cpp -M format error - space"); p = hincl(p); /* skip any uglies in include path */ if (!alldep && strncmp("/usr/include", p, 12) == 0) continue; /* ignore /usr/include... stuff */ if (index(p, '\n') != NULL) /* replace newline with EOS */ *index(p, '\n') = '\0'; if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */ fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */ } #else while (fgets(buf, BUFSIZ, cppfd) != NULL) { if (buf[0] != '#') /* must start with '#' */ continue; if ((p = index(buf, '"')) == NULL) /* find first double quote */ continue; p++; p = hincl(p); /* skip any uglies in include path */ if (index(p, '"') != NULL) /* terminate the file name */ *index(p, '"') = '\0'; if (!alldep && strncmp("/usr/include", p, 12) == 0) continue; /* ignore /usr/include... stuff */ if ((q = srtin(&u, p, (int (*)())0)) != NULL) /* insert into list */ fprintf(stderr, "%s: %s - %s\n", prgnm, q, p); /* warning */ } #endif srtgti(&u); /* init for srtgets */ /* 2 for colon space */ oplen = strlen(objpath) + strlen(targ) + strlen(destsuffix) + 2; le = MAXCOL; /* force new line output */ firstln = TRUE; /* first line of a file entry */ while ((p = srtgets(&u)) != NULL) { /* write out the entries */ if (shortincl) if ((i = findabr(p)) != MXABR) /* i = found index or MXABR */ p += abrvlen[i] - 2; if (le + strlen(p) >= MAXCOL) { if (firstln) { le = oplen; fprintf(makefd, "\n%s%s%s: ", objpath, targ, destsuffix); firstln = FALSE; } else { le = 8; fprintf(makefd, " \\\n\t"); } } else { fputc(SPC, makefd); } if (shortincl && i != MXABR) { fprintf(makefd, "$%c", 'A' + i); p += 2; /* right place */ le += 2; } fputs(p, makefd); le += 1 + strlen(p); } fputc('\n', makefd); /* end with newline */ nshpclose(cppfd); /* end of that file */ }