home *** CD-ROM | disk | FTP | other *** search
- An Incremental Compilation Package in C by Dave Taylor
-
- /** depends.c **/
-
- /** This program tweaks with the last modified dates of the files in the
- current directory based on what files include what other files. The end
- result of this is that the 'create' program can recompile as needed based
- on the modification of not just the source file but also the included
- files too!
-
- Depends allows the following flags;
- -d show a dependency tree similar to "make' expects
- -m generate a real 'makefile'
- -n no execute. Display commands to be used only.
- -s show times. Display last modified times of files.
- -v verbose. Running commentary during file parsing.
-
- (C) Copyright 1986, 1987 by Dave Taylor
- **/
-
- #include <stdio.h>
- #include <ndir.h> /* directory stuff */
- #include <errno.h> /* system error */
- #include <sys/types.h> /* more types!!! */
- #include <sys/stat.h> /* stat stuff... */
-
- #define MAXFILES 250 /* max files total in dir */
- #define FNAMELEN 20 /* max file name length */
- #define SLEN 80 /* regular length string... */
-
- DIR *dirp; /* directory structure... */
- struct direct *dp; /* file entry in directory */
-
- struct dir_rec {
- char name[FNAMELEN]; /* name of the file */
- long time; /* last modified time */
- int changed; /* has it changed? */
- int checked; /* has it been checked? */
- } directory[MAXFILES];
-
- int count = 0, /* how many files in directory? */
- no_execute = 0, /* -n (no execute) flag set */
- verbose = 0, /* -v (verbose) flag set... */
- dependencies = 0, /* -d (dependencies) flag set.. */
- makefile = 0, /* -m (makefile) flag set.. */
- show_times = 0; /* -s (show times) flag set */
-
- extern int errno; /* system error number */
-
- char *makefile_header[] = {
- "# Custom makefile generated by the 'depends' program",
- "#",
- "# The following might need to be customized...",
- " ",
- "CC = cc",è "CFLAGS = -O",
- "PC = pc",
- "PFLAGS = -O",
- "LIBS =",
- "DEFS =",
- " ",
- "# The following should be changed to the final name of the binary",
- "TARGET = a.out",
- " ",
- "",
- };
-
- char *cc_line = {"\n\t$(CC) $(CFLAGS) $(DEFS) %s\n\n" };
- char *pc_line = {"\n\t$(PC) $(PFLAGS) $(DEFS) %s\n\n" };
- char *link_line = {"\t$(CC) $(CFLAGS) $(DEFS) $(OBJS) -o $(TARGET) $(LIBS)\n" };
-
- char compile_command[SLEN] = { "" };
-
- int strcmp(), compare();
- char *strcpy(), *ctime(), *strncpy();
- void qsort(), exit();
-
- main(argc, argv)
- int argc;
- char *argv[];
- {
- register int i;
-
- parse_arguments(argc, argv); /* starting arguments... */
-
- initially_read_in_directory(); /* start up stuff */
-
- get_file_modification_dates(); /* read file dates */
-
- /** if the user wants to see the dates spin through and
- spit 'em all out! **/
-
- if (show_times)
- for (i=0; i < count; i++)
- if (suffix(".c", directory[i].name) ||
- suffix(".h", directory[i].name) ||
- suffix(".p", directory[i].name)) /* a legit file? */
- printf("%-15s %s", directory[i].name,
- ctime(&directory[i].time));
-
- /** now let's go through and check all the source files **/
-
- for (i=0; i < count; i++)
- if (suffix(".c", directory[i].name) ||
- suffix(".p", directory[i].name)) /* a source file? */
- figure_out_includes(i, 1);
-
- change_file_dates(); /* based on internal modifications... */
-
- fini(); /* all done! */è
- exit(0);
- }
-
- parse_arguments(argc, argv)
- int argc;
- char *argv[];
- {
- /** parse the starting arguments setting the flags etc as specified...
- fail from this routine if bad args! **/
-
- int c;
- extern int optind, opterr;
-
- opterr = 0; /* supress getopt error message! */
-
- while ((c = getopt(argc, argv, "dhmnvs")) != EOF)
- switch (c) {
- case 'd' : dependencies++; break;
- case 'm' : makefile++; no_execute++; break;
- case 'n' : no_execute++; break;
- case 'v' : verbose++; break;
- case 's' : show_times++; break;
- case 'h' :
- default : fprintf(stderr, "Usage: %s [-dhmnvs]\n", argv[0]);
- fprintf(stderr, "where:\n\
- -d\t\tdepends - show dependencies in 'make'-style format\n\
- -h\t\thelp - give some help on the starting flags\n\
- -m\t\tmake - actually generate a real makefile\n\
- -n\t\tno-action - just list what would be done\n\
- -v\t\tverbose - show all includes in verbose format\n\
- -s\t\tshow times of all files checked\n");
- exit(1);
- }
-
- if ((makefile && verbose) || (dependencies && verbose)) {
- fprintf(stderr, "That combination of flags doesn't make sense.\n");
- exit(1);
- }
- }
-
- initially_read_in_directory()
- {
- /* initialize the system variables and read in and sort the current
- directory... */
-
- dirp = opendir("."); /* current directory */
-
- while (read_directory(directory[count++].name) && count < MAXFILES)
- directory[count-1].changed = 0;
-
- if (count >= MAXFILES) {
- fprintf(stderr,
- "*** Warning: read more files than this program can deal with! ***\n");
- fprintf(stderr,è "*** Depends continuing, but it might be wrong! ***\n");
- }
-
- qsort(directory, (unsigned) --count, sizeof ( directory[0] ), compare);
-
- if (makefile)
- initialize_makefile();
- }
-
- fini()
- {
- /* close everything and let's leave! */
-
- if (makefile)
- finish_makefile();
-
- closedir(dirp);
- }
-
- initialize_makefile()
- {
- /** outputs all the leading Makefile information as appropriate **/
-
- /* first off, let's dump the makefile_header stuff... */
-
- register int i, len;
- char buffer[SLEN];
-
- for (i=0; strlen(makefile_header[i]) > 0; i++)
- puts(makefile_header[i]);
-
- /* next, we'll need to output "HDRS", "SRCS" and "OBJS" ... */
-
- printf("HDRS = ");
-
- for (len=8, i=0; i < count; i++)
- if (suffix(".h", directory[i].name)) {
- if (strlen(directory[i].name) + len > 75) {
- printf(" \\n\t");
- len = 8;
- }
- printf("%s ", directory[i].name);
- len += strlen(directory[i].name)+1;
- }
-
- putchar('\n');
-
- printf("SRCS = ");
-
- for (len = 8, i=0; i < count; i++)
- if (suffix(".c", directory[i].name)||suffix(".p", directory[i].name)){
- if (strlen(directory[i].name) + len > 75) {
- printf(" \\n\t");
- len = 8;
- }è printf("%s ", directory[i].name);
- len += strlen(directory[i].name)+1;
- }
-
- putchar('\n');
-
- printf("OBJS = ");
-
- for (len = 8, i=0; i < count; i++)
- if (suffix(".c", directory[i].name)||suffix(".p", directory[i].name)){
- if (strlen(directory[i].name) + len > 75) {
- printf(" \\n\t");
- len = 8;
- }
- strcpy(buffer, directory[i].name);
- buffer[strlen(buffer)-1] = 'o'; /* make it a '.o' file! */
- printf("%s ", buffer);
- len += strlen(buffer)+1;
- }
-
- printf("\n\n");
-
- /* and the default binary target... */
-
- printf("$(TARGET): $(OBJS) $(SRCS) $(HDRS)\n%s\n\n",
- link_line);
-
- }
-
- finish_makefile()
- {
- /** adds some standard stuff to the end of the makefile **/
-
- printf(compile_command);
- printf("clean: $(OBJS)\n\trm -f $(OBJS)\n\n");
- printf("lint:\n\tlint $(SRCS) > LINT.OUT\n\n");
- printf("listing:\n\tlpr $(SRCS)\n");
- }
-
- get_file_modification_dates()
- {
- /** do a 'stat' on each file in this directory, saving the last
- modified date of each in the directory structure... **/
-
- struct stat buffer;
- register int i;
-
- for (i = 0; i < count ; i++)
- if ((stat(directory[i].name, &buffer)) != 0) {
- fprintf(stderr,"** could not stat %s [%d] **\n",
- directory[i].name, errno);
- exit(errno);
- }
- else {
- directory[i].time = buffer.st_mtime;è }
- }
-
- figure_out_includes(index, cnt)
- int index, cnt;
- {
- /** read the specified file, get all the files that this fellow
- includes, then change the 'time' of the file entry in the
- 'directory' structure based on the times of the files it includes.
- 'cnt' is the nesting depth that we're currently at (for verbose
- output and other I/O miscellany).
- **/
-
- FILE *thefile;
- char buffer[SLEN];
- int findex, i;
-
- if (verbose)
- if (cnt == 1)
- printf("Checking file \"%s\"\n", directory[index].name);
- else {
- for (i=0;i<cnt;i++)
- printf(" ");
- printf("includes file \"%s\"\n", directory[index].name);
- }
-
- if (cnt == 1 && makefile) {
- if (strlen(compile_command) > 0)
- printf(compile_command);
- if (suffix(".c", directory[index].name))
- sprintf(compile_command, cc_line, directory[index].name);
- else
- sprintf(compile_command, pc_line, directory[index].name);
- }
-
- if (dependencies || (makefile && cnt > 1))
- printf("%s%s ", directory[index].name, cnt==1?":":"");
- else if (makefile && cnt == 1) {
- strcpy(buffer, directory[index].name);
- buffer[strlen(buffer)-1] = 'o';
- printf("%s: %s ", buffer, directory[index].name);
- }
-
- if (!verbose && !dependencies && !makefile && directory[index].checked)
- return;
-
- if ((thefile = fopen(directory[index].name,"r")) == NULL) {
- fprintf(stderr,"*** could not open file %s for reading [%d] ! ***\n",
- directory[index].name, errno);
- exit(errno);
- }
-
- /** okay, now let's loop through this thing and try to get all the
- #include lines... **/
- è while (fgets(buffer, SLEN, thefile) != NULL) {
- if (buffer[0] == '#') /* hmmm...a compiler directive... */
- if ((findex = check_for_include(buffer)) != -1) {
- figure_out_includes(findex, cnt+1); /* recurse... */
- if (directory[index].time < directory[findex].time) {
- directory[index].time = directory[findex].time;
- directory[index].changed++;
- }
- }
- }
-
- directory[index].checked++;
-
- if (dependencies && cnt==1) printf("\n");
-
- (void) fclose(thefile);
- }
-
- change_file_dates()
- {
- /** Change the files that have the 'changed' bit set, meaning that their
- modified times are wrong based on the files they include... **/
-
- register int i;
- struct utimbuf {
- long actime; /* last accessed time */
- long modtime; /* last modified time */
- } time_struct;
-
- for (i=0; i < count; i++)
- if (directory[i].changed) {
- printf("\ttouch %s\n", directory[i].name);
- if (! no_execute) {
- time_struct.actime = directory[i].time;
- time_struct.modtime= directory[i].time;
- if (utime(directory[i].name, &time_struct) != 0) {
- fprintf(stderr,"*** could not change file times [%d] ***\n",
- errno);
- exit(errno);
- }
- }
- }
- }
-
- int
- check_for_include(line)
- char *line;
- {
- /** Line is an m4 directive line - this routine figures out if it is
- an 'include' line, and if so, what file is being included. If the
- file included is contained within this directory, then this routine
- will return the index, otherwise it will return -1 if an error.
- **/
-
- char *line_ptr, *word, *strtok();è int i;
-
- line[0] = ' '; /* remove the '#' */
-
- /* this first section is so we can have "# include" as well
- as "#include" ... we simply get the first word token via
- calls to 'strtok()' */
-
- line_ptr = (char *) line; /* gets the address */
-
- if ((word = strtok(line_ptr," \t")) != NULL) {
- if (strcmp(word, "include") != 0)
- return(-1);
- }
- else
- return(-1);
-
- /** to get to here, it must be an include line and the internal strtok
- pointer must be pointing at the filename surrounded by quotes or
- '<>' characters... (note that the " in the strtok call will also
- suffice to remove the quotes from the filename too) **/
-
- if ((word = strtok(NULL, "\t \"")) != NULL) {
- if (word[0] == '<')
- return(-1);
- }
- else
- return(-1);
-
- /** to get to here, it must have included the file that is specified
- as 'word' currently, and that file must be a specified file in
- the local directory. **/
-
- for (i=0; i < strlen(word); i++)
- if (word[i] == '/')
- return(-1);
-
- /** now, finally, we know that 'word' must be a file in the
- current directory, so we merely need to find it's index
- into the directory structure of this program and return
- it! **/
-
- for (i=0; i < count; i++)
- if (strcmp(word, directory[i].name) == 0)
- return(i);
-
- /* it wasn't in there??? */
-
- fprintf(stderr,"*** couldn't find %s in directory! ***\n",
- word);
- return(-1);
- }
-
- int
- read_directory(buffer)èchar *buffer;
- {
- /** return the next name in the directory... returns zero when
- we're out of entries. **/
-
- if ((dp = readdir(dirp)) != NULL)
- strncpy(buffer, dp->d_name, FNAMELEN);
-
- return(dp != NULL? 1 : 0);
- }
-
- int
- suffix(sf, string)
- char *sf, *string;
- {
- /** returns true iff the suffix of 'string' is 'sf' **/
-
- register int i, j;
-
- i = strlen(string);
- j = strlen(sf);
-
- while (string[i] == sf[j] && j > 0) {
- i--;
- j--;
- }
-
- return(sf[0] == string[i] && j == 0);
- }
-
- int
- compare(a, b)
- struct dir_rec *a, *b;
- {
- /** strcmp on name field (for sort routine) **/
-
- return( strcmp( a->name, b->name ));
- }