home *** CD-ROM | disk | FTP | other *** search
- /*T mdep - generate a list of make dependencies */
- /*F mdep.c ***********************************************************
- *
- * mdep.c
- *
- * generate the list of make dependencies for a source file. The
- * program can optionally do recursive expansions (for includes that
- * include includes) and suppress expansion of specific files.
- *
- * This program was written for and tested ONLY on SYSTEM III. While
- * there is the possibility that it will work on other systems, it
- * is not assured.
- *
- * Permission to use, modify, and pass along this program is granted
- * as long as this notice is included.
- *
- * (c) 1985 Steven List
- * Benetics Corporation
- * Mountain View, CA
- * {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
- *
- *********************************************************************/
- /*E*/
- /*S some global declarations and stuff */
- /*Page Eject */
- #ifdef BSD
- # define strchr index
- # define strrchr rindex
- #endif BSD
-
- char *Allocate ();
- char *ReAllocate ();
-
- int mstrcmp ();
- int pstrcmp ();
-
- #include <sys/types.h>
- #include <sys/dir.h>
- #include <stdio.h>
-
- /* ------------------------------------------------------------ */
- /* some standard defines - easier to include than change */
- /* ------------------------------------------------------------ */
-
- #define EQ ==
- #define NE !=
- #define GT >
- #define GE >=
- #define LT <
- #define LE <=
- #define OR ||
- #define AND &&
-
- #define TRUE 1
- #define FALSE 0
- #define YES 1
- #define NO 0
-
- #define SPACE ' '
- #define NUL '\0'
-
- typedef unsigned char BOOL;
-
- #define INULL -32768
- #define LNULL -2147483648
-
- #define MAX(a,b) ((a) > (b) ? (a) : (b))
- #define MIN(a,b) ((a) < (b) ? (a) : (b))
- #define ABS(a) ((a) >= 0 ? (a) : -(a))
-
- int MAXDIRS = 10;
- int MAXNOEXP = 10;
- int MAXFILES = 128;
-
- /* ------------------------------------------------------------ */
- /* a description of each file in the search path */
- /* ------------------------------------------------------------ */
-
- struct file
- {
- char name[DIRSIZ+1];
- int dirind;
- } *file;
-
- /* ------------------------------------------------------------ */
- /* counts of directories and files under consideration */
- /* ------------------------------------------------------------ */
-
- int nfil = 0;
- int ndir = 0;
-
- /* ------------------------------------------------------------ */
- /* the list of directories searched */
- /* ------------------------------------------------------------ */
-
- char **dirs;
-
- /* ------------------------------------------------------------ */
- /* exclusion table and counter */
- /* ------------------------------------------------------------ */
-
- char **noexp; /* exclusion list */
- int nx = 0; /* number of exclusions */
-
- /* ------------------------------------------------------------ */
- /* some stuff to handle #ifdef/#else/#endif */
- /* ------------------------------------------------------------ */
-
- char **deftab; /* list of objects defined */
- int ndef = 0; /* number of objects defined */
-
- BOOL recursion = FALSE;
-
- char *pgm;
-
- /*S main - control all processing, and do a lot of it */
- /*H main *************************************************************
- *
- * main
- *
- * process the command line, set up the lists of files, and then
- * process the input file(s).
- *
- *********************************************************************/
- /*E*/
- main (ac, av)
- register int ac;
- char *av[];
- {
- int fcmp (); /* compare two file entries */
- register int i; /* general purpose stuff */
- int strcmp (); /* compare two strings */
-
- char *strchr ();
- char *strrchr ();
-
- /* getopt stuff */
-
- extern char *optarg;
- extern int optind;
-
- /* ------------------------------------------------------------ */
- /* for logging and stuff, set up program name (basename only) */
- /* ------------------------------------------------------------ */
-
- if (pgm = strrchr (av[0], '/')) pgm++;
- else pgm = av[0];
-
- /* ------------------------------------------------------------ */
- /* provide initial allocations of space for tables/lists */
- /* ------------------------------------------------------------ */
-
- dirs = (char **) Allocate (MAXDIRS, sizeof (char *));
- file = (struct file *) Allocate (MAXFILES, sizeof (struct file));
- noexp = (char **) Allocate (MAXNOEXP, sizeof (char *));
- deftab = (char **) Allocate (1, sizeof (char *));
-
- /* ------------------------------------------------------------ */
- /* put the current directory in first - same as C compiler */
- /* ------------------------------------------------------------ */
-
- dirs[ndir] = (char *) Allocate (1, 2);
- strcpy (dirs[ndir], "."); /* first is always current directory */
- dirlist (dirs[ndir++]);
- /*Page Eject*/
- /* ------------------------------------------------------------ */
- /* process the command line options */
- /* ------------------------------------------------------------ */
-
- while ( (i = getopt (ac, av, "D:I:x:r")) NE EOF)
- {
- switch (i)
- {
- case 'D': /* define objects */
- deftab[ndef] = (char *)
- Allocate (1, strlen (optarg) + 1);
- strcpy (deftab[ndef], optarg);
- deftab = (char **)
- ReAllocate (deftab, (++ndef) * sizeof (char *));
- break;
- case 'I': /* search directory - like cc */
- ndir++;
- if (!dirlist (optarg))
- {
- dirs[ndir-1] = (char *)
- Allocate (1, strlen (optarg) + 1);
- strcpy (dirs[ndir-1], optarg);
- if (ndir GE MAXDIRS)
- {
- MAXDIRS += 10;
- dirs = (char **) ReAllocate (dirs,
- MAXDIRS * sizeof (char *));
- }
- }
- else ndir--;
- break;
- case 'x': /* a file to exclude */
- noexp[nx] = (char *) Allocate (1, strlen (optarg) + 3);
- strcpy (noexp[nx], optarg);
- if (!strrchr (optarg, '.')) strcat (noexp[nx], ".h");
- nx++;
- if (nx GE MAXNOEXP)
- {
- MAXNOEXP += 10;
- noexp = (char **) ReAllocate (noexp,
- MAXNOEXP * sizeof (char *));
- }
- break;
- case 'r': /* turn on recursive search */
- recursion = TRUE;
- break;
- default:
- fprintf (stderr,
- "<%s> unknown argument - %c\n", pgm, i);
- break;
- }
- }
- /*Page Eject*/
- /* ------------------------------------------------------------ */
- /* add /usr/include as the last of the directories - as cc */
- /* ------------------------------------------------------------ */
-
- dirs[ndir] = (char *) Allocate (1, strlen ("/usr/include") + 1);
- strcpy (dirs[ndir], "/usr/include");
- dirlist (dirs[ndir++]);
-
- /* ------------------------------------------------------------ */
- /* sort the include file list for use with bsearch */
- /* ------------------------------------------------------------ */
-
- qsort (file, nfil, sizeof(struct file), fcmp);
-
- /* ------------------------------------------------------------ */
- /* if we are doing recursive searches, also sort the exclusions */
- /* ------------------------------------------------------------ */
-
- if (recursion) qsort (noexp, nx, sizeof noexp[0], pstrcmp);
-
- /* ------------------------------------------------------------ */
- /* if there are any definitions, sort the define table */
- /* ------------------------------------------------------------ */
-
- if (ndef) qsort (deftab, ndef, sizeof (char *), pstrcmp);
-
- /* ------------------------------------------------------------ */
- /* Now that we've complete the tedious job of setting up, */
- /* process each remaining command line argument (they are */
- /* expected to be C source file names) */
- /* ------------------------------------------------------------ */
-
- for (i = optind; i LT ac; i++)
- {
- dofile (av[i], FALSE);
- }
-
- exit (0);
- }
- /*S dirlist - expand a directory name into a list of include files */
- /*H dirlist **********************************************************
- *
- * dirlist
- *
- * Examine each entry in a directory. If a file is an include file
- * (name ends with .h), include it and the directory index in the
- * file list.
- *
- *********************************************************************/
- /*E*/
- dirlist (dnam)
- register char *dnam; /* directory path name */
- {
- register int i; /* general purpose stuff */
-
- register char c; /* ditto */
- register char *ptr; /* again */
-
- char *strrchr (); /* find char from end */
-
- static char *fn = "dirlist"; /* function name for logging */
-
- register FILE *dir; /* directory file stream */
-
- struct direct direct; /* place to read entries into */
-
- /* ------------------------------------------------------------ */
- /* attempt to open the directory file - exit on error */
- /* ------------------------------------------------------------ */
-
- if ( (dir = fopen (dnam, "r")) EQ NULL)
- {
- fprintf (stderr,
- "dirlist: unable to open directory %s for read\n", dnam);
- return (1);
- }
- else
- {
- /* ------------------------------------------------------------ */
- /* read each directory entry */
- /* if the entry is active */
- /* if the file is an include file (*.h) */
- /* copy the name and directory index into the file list */
- /* ------------------------------------------------------------ */
-
- while (fread (&direct, sizeof direct, 1, dir) EQ 1)
- {
- if (direct.d_ino)
- {
- for (ptr = &direct.d_name[DIRSIZ-1]; !*ptr; ptr--);
-
- if (*ptr EQ 'h' AND *(ptr-1) EQ '.')
- {
- strncpy (file[nfil].name, direct.d_name, DIRSIZ+1);
- file[nfil].dirind = ndir - 1;
- nfil++;
-
- /* ------------------------------------------------------------ */
- /* if we're out of space in the list, allocate some more */
- /* ------------------------------------------------------------ */
-
- if (nfil GE MAXFILES)
- {
- MAXFILES += 50;
- file = (struct file *) ReAllocate (file,
- MAXFILES * sizeof (struct file));
- }
- }
- }
- }
- fclose (dir);
- }
-
- return (0);
- }
- /*S dofile - process an input (C source) file */
- /*H dofile ***********************************************************
- *
- * dofile
- *
- * examine each line of the input file. If the first char is either
- * # or $ (UNIFY includes, for those of us who use it) and the next
- * word is include, look for the named file. If the input file name
- * is `-', read from standard input and provide a default dependency
- * name.
- *
- *********************************************************************/
- /*E*/
- dofile (fnam, suppress)
- char *fnam; /* input file name */
- register BOOL suppress; /* true if this is called for */
- /* recursive expansion and file name*/
- /* has already been printed */
- {
- register FILE *curfile; /* current input file stream */
-
- char dep[80]; /* place for dependency object name */
- register char *c; /* temp pointer */
- register char *cd; /* temp pointer */
- static char *fn = "dofile"; /* function name for logging */
- char lbuf[120]; /* input line buffer */
- register char *suffix; /* pointer to file name suffix */
- char tname[80]; /* place to build full name */
-
- register int count = 0; /* number of things matched - sscanf*/
-
- register struct file *iname; /* pointer to matching file */
-
- struct file *bsearch ();
-
- register int i; /* general purpose stuff */
- register BOOL skip = FALSE; /* true if skipping because of DEF */
-
- int strcmp ();
-
- BOOL first = TRUE; /* true for initial condition */
-
- /* ------------------------------------------------------------ */
- /* open the current file if it is not stdin */
- /* ------------------------------------------------------------ */
-
- if (strcmp (fnam, "-") EQ 0)
- {
- curfile = stdin;
- fnam = "standardin.c";
- }
- else
- {
- curfile = fopen (fnam, "r");
- }
-
- if (curfile EQ NULL)
- {
- fprintf (stderr, "<%s> _error_ cannot open %s\n", fn, fnam);
- }
- else
- {
- /* ------------------------------------------------------------ */
- /* look at each line in the file and process those beginning */
- /* with a legal include statement */
- /* ------------------------------------------------------------ */
-
- while (fgets (lbuf, sizeof lbuf, curfile) EQ lbuf)
- {
- skip = ckdef (lbuf, skip);
- if (skip) continue;
- count = sscanf (lbuf, "%*[#$] include%s", dep);
- if (count EQ 1)
- {
- /* ------------------------------------------------------------ */
- /* if this is the first time in, print out the file name */
- /* ------------------------------------------------------------ */
-
- if (first AND !suppress)
- {
- suffix = &fnam[strlen(fnam)-1];
- if (*suffix EQ 'c') *suffix = 'o';
- printf ("%s: ", fnam);
- first = FALSE;
- }
- /* ------------------------------------------------------------ */
- /* clean up the dependency name */
- /* ------------------------------------------------------------ */
-
- c = cd = dep;
- while ((*c = *(++cd)) NE '>' AND *c NE '"') c++;
- *c = NUL;
-
- /* ------------------------------------------------------------ */
- /* if the include is sys/something.h, assume that it's from */
- /* /usr/include/sys, since this is the 99.9% case */
- /* ------------------------------------------------------------ */
-
- if (strncmp (dep, "sys/", 4) EQ 0)
- {
- printf ("\\\n\t\t/usr/include/%s ", dep);
- }
- else if (strchr (dep, '/'))
- {
- printf ("\\\n\t\t%s ", dep);
- }
- else
- {
- /* ------------------------------------------------------------ */
- /* look for the include file name in the list of known files */
- /* ------------------------------------------------------------ */
-
- iname = bsearch (dep, file, nfil,
- sizeof(struct file), strcmp);
- if (iname)
- {
- /* ------------------------------------------------------------ */
- /* since there might be more than one copy of the include file */
- /* back up to the first (bsearch will just find one) */
- /* ------------------------------------------------------------ */
-
- while (iname GT file)
- {
- if (strcmp (iname, iname - 1) EQ 0)
- iname--;
- else
- break;
- }
- printf ("\\\n\t\t%s/%s ",
- dirs[iname->dirind], dep);
- /* ------------------------------------------------------------ */
- /* if recursive search was requested and the file is not */
- /* in the exclusion list, then look for its includes */
- /* ------------------------------------------------------------ */
-
- if (recursion AND
- !bsearch (dep, noexp, nx,
- sizeof (char *), mstrcmp))
- {
- sprintf (tname,
- "%s/%s", dirs[iname->dirind], dep);
- dofile (tname, TRUE);
- }
- }
- /* ------------------------------------------------------------ */
- /* things that have paths in them, either relative or absolute, */
- /* will be passed through as is. since this is generally */
- /* contrary to standard coding practice, it should be ok for */
- /* the majority of the cases */
- /* ------------------------------------------------------------ */
-
- else
- {
- printf ("\\\n\t\t%s ", dep);
- }
- }
- }
- }
- if (!suppress) printf ("\n");
- fclose (curfile);
- }
- }
- /*S fcmp - compare two file list entries */
- /*H fcmp *************************************************************
- *
- * fcmp
- *
- * a comparison function for qsort to call
- *
- *********************************************************************/
- /*E*/
- fcmp (f1, f2)
- struct file *f1;
- struct file *f2;
- {
- register int i;
-
- if (i = strncmp (f1->name, f2->name, sizeof f1->name))
- return i;
- else
- return f1->dirind - f2->dirind;
- }
- /*S Allocate - call calloc and process return */
- /*H Allocate *********************************************************
- *
- * Allocate
- *
- * veneer over calloc to handle bad returns
- *
- *********************************************************************/
- /*E*/
- char *
- Allocate (nelem, size)
- register int nelem;
- register int size;
- {
- extern char *calloc ();
-
- register char *to;
-
- if (!(to = calloc (nelem, size)))
- {
- fprintf (stderr,
- "%s: allocation failure - %d * %d\n",
- pgm, nelem, size);
- exit (99);
- }
-
- return to;
- }
- /*S ReAllocate - call calloc and process return */
- /*H ReAllocate *******************************************************
- *
- * ReAllocate
- *
- * veneer over realloc to handle bad returns
- *
- *********************************************************************/
- /*E*/
- char *
- ReAllocate (oldp, size)
- register char *oldp;
- register int size;
- {
- extern char *realloc ();
-
- register char *to;
-
- if (!(to = realloc (oldp, size)))
- {
- fprintf (stderr,
- "%s: reallocation failure - %d\n",
- pgm, size);
- exit (99);
- }
-
- return to;
- }
- /*S ckdef - check for #ifdef/ifndef/else/endif line */
- /*H ckdef ************************************************************
- *
- * ckdef
- *
- * Look at the line and return the appropriate status depending on
- * whether or not a preprocessor symbol is defined or not.
- *
- *********************************************************************/
- /*E*/
- ckdef (buf, skip)
- register char *buf; /* line to check */
- register BOOL skip; /* current state of skip */
- {
- char sym[40]; /* defined symbol if found */
-
- char lbuf[120]; /* local buffer */
-
- register int count = 0; /* return from sscanf */
-
- count = sscanf (buf, "%*[#$]%s", lbuf);
-
- if (count EQ 1)
- {
- if (!skip AND !strcmp (lbuf, "ifdef"))
- {
- sscanf (buf, "%*[#$]%*s%s", sym);
- skip = !(BOOL)bsearch (sym, deftab, ndef,
- sizeof(char *), mstrcmp);
- }
- else if (!skip AND !strcmp (lbuf, "ifndef"))
- {
- sscanf (buf, "%*[#$]%*s%s", sym);
- skip = (BOOL)bsearch (sym, deftab,
- ndef, sizeof(char *), mstrcmp);
- }
- else if (!strcmp (lbuf, "else"))
- {
- skip = !skip;
- }
- else if (skip AND !strcmp (lbuf, "endif"))
- {
- skip = !skip;
- }
- }
-
- return skip;
- }
- /*S mstrcmp - compare two strings given one direct and one indirect */
- /*H mstrcmp **********************************************************
- *
- * mstrcmp
- *
- * for use with bsearch, this assumes that the arguments are a
- * string address and a pointer to a string address. This is
- * used to allow the comparison of a string to a string pointed
- * to by an element of `noexp'.
- *
- *********************************************************************/
- /*E*/
- mstrcmp (s1, s2)
- register char *s1;
- register char **s2;
- {
- return strcmp (s1, *s2);
- }
- /*S pstrcmp - compare two strings given pointers to pointers */
- /*H pstrcmp **********************************************************
- *
- * pstrcmp
- *
- * for use with qsort and bsearch, this assumes that the arguments
- * passed are pointers to the string addresses rather than the
- * addresses of the strings
- *
- *********************************************************************/
- /*E*/
- pstrcmp (s1, s2)
- register char **s1;
- register char **s2;
- {
- return strcmp (*s1, *s2);
- }
-