home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 January / usenetsourcesnewsgroupsinfomagicjanuary1994.iso / sources / unix / volume1 / cpg+mdep / mdep.c < prev   
Encoding:
C/C++ Source or Header  |  1986-11-30  |  19.5 KB  |  655 lines

  1. /*T mdep - generate a list of make dependencies */
  2. /*F mdep.c ***********************************************************
  3. *
  4. *                                  mdep.c
  5. *
  6. *  generate the list of make dependencies for a source file.  The
  7. *  program can optionally do recursive expansions (for includes that
  8. *  include includes) and suppress expansion of specific files.
  9. *
  10. *  This program was written for and tested ONLY on SYSTEM III.  While
  11. *  there is the possibility that it will work on other systems, it
  12. *  is not assured.
  13. *
  14. *  Permission to use, modify, and pass along this program is granted
  15. *  as long as this notice is included.
  16. *
  17. *  (c) 1985        Steven List
  18. *               Benetics Corporation
  19. *               Mountain View, CA
  20. *               {cdp,greipa,idi,oliveb,sun,tolerant}!bene!luke!steven
  21. *
  22. *********************************************************************/
  23. /*E*/
  24. /*S some global declarations and stuff */
  25. /*Page Eject */
  26. #ifdef BSD
  27. #    define    strchr    index
  28. #    define    strrchr    rindex
  29. #endif BSD
  30.  
  31. char    *Allocate ();
  32. char    *ReAllocate ();
  33.  
  34. int        mstrcmp ();
  35. int        pstrcmp ();
  36.  
  37. #include    <sys/types.h>
  38. #include    <sys/dir.h>
  39. #include    <stdio.h>
  40.  
  41. /* ------------------------------------------------------------ */
  42. /* some standard defines - easier to include than change        */
  43. /* ------------------------------------------------------------ */
  44.  
  45. #define EQ ==
  46. #define NE !=
  47. #define GT >
  48. #define GE >=
  49. #define LT <
  50. #define LE <=
  51. #define OR ||
  52. #define AND &&
  53.  
  54. #define TRUE 1
  55. #define FALSE 0
  56. #define YES 1
  57. #define NO 0
  58.  
  59. #define SPACE ' '
  60. #define NUL '\0'
  61.  
  62. typedef unsigned char   BOOL;
  63.  
  64. #define INULL -32768
  65. #define LNULL -2147483648
  66.  
  67. #define MAX(a,b) ((a) > (b) ? (a) : (b))
  68. #define MIN(a,b) ((a) < (b) ? (a) : (b))
  69. #define ABS(a) ((a) >= 0 ? (a) : -(a))
  70.  
  71. int        MAXDIRS = 10;
  72. int        MAXNOEXP = 10;
  73. int        MAXFILES = 128;
  74.  
  75.     /* ------------------------------------------------------------ */
  76.     /* a description of each file in the search path                */
  77.     /* ------------------------------------------------------------ */
  78.  
  79. struct  file
  80. {
  81.     char    name[DIRSIZ+1];
  82.     int     dirind;
  83. }    *file;
  84.  
  85.     /* ------------------------------------------------------------ */
  86.     /* counts of directories and files under consideration          */
  87.     /* ------------------------------------------------------------ */
  88.  
  89. int        nfil = 0;
  90. int        ndir = 0;
  91.  
  92.     /* ------------------------------------------------------------ */
  93.     /* the list of directories searched                             */
  94.     /* ------------------------------------------------------------ */
  95.  
  96. char    **dirs;
  97.  
  98.     /* ------------------------------------------------------------ */
  99.     /* exclusion table and counter                                  */
  100.     /* ------------------------------------------------------------ */
  101.  
  102. char    **noexp;                /* exclusion list                */
  103. int        nx = 0;                    /* number of exclusions            */
  104.  
  105.     /* ------------------------------------------------------------ */
  106.     /* some stuff to handle #ifdef/#else/#endif                     */
  107.     /* ------------------------------------------------------------ */
  108.  
  109. char    **deftab;            /* list of objects defined                */
  110. int        ndef = 0;            /* number of objects defined            */
  111.  
  112. BOOL    recursion = FALSE;
  113.  
  114. char    *pgm;
  115.  
  116. /*S main - control all processing, and do a lot of it */
  117. /*H main *************************************************************
  118. *
  119. *                                   main
  120. *
  121. *  process the command line, set up the lists of files, and then 
  122. *  process the input file(s).
  123. *
  124. *********************************************************************/
  125. /*E*/
  126. main (ac, av)
  127. register int     ac;
  128. char    *av[];
  129. {
  130.     int             fcmp ();        /* compare two file entries        */
  131.     register int    i;                /* general purpose stuff        */
  132.     int                strcmp ();        /* compare two strings            */
  133.  
  134.     char    *strchr ();
  135.     char    *strrchr ();
  136.  
  137.     /* getopt stuff */
  138.  
  139.     extern char *optarg;
  140.     extern int  optind;
  141.  
  142.     /* ------------------------------------------------------------ */
  143.     /* for logging and stuff, set up program name (basename only)   */
  144.     /* ------------------------------------------------------------ */
  145.  
  146.     if (pgm = strrchr (av[0], '/')) pgm++;
  147.     else pgm = av[0];
  148.  
  149.     /* ------------------------------------------------------------ */
  150.     /* provide initial allocations of space for tables/lists        */
  151.     /* ------------------------------------------------------------ */
  152.  
  153.     dirs = (char **) Allocate (MAXDIRS, sizeof (char *));
  154.     file = (struct file *) Allocate (MAXFILES, sizeof (struct file));
  155.     noexp = (char **) Allocate (MAXNOEXP, sizeof (char *));
  156.     deftab = (char **) Allocate (1, sizeof (char *));
  157.  
  158.     /* ------------------------------------------------------------ */
  159.     /* put the current directory in first - same as C compiler      */
  160.     /* ------------------------------------------------------------ */
  161.  
  162.     dirs[ndir] = (char *) Allocate (1, 2);
  163.     strcpy (dirs[ndir], ".");      /* first is always current directory    */
  164.     dirlist (dirs[ndir++]);
  165. /*Page Eject*/
  166.     /* ------------------------------------------------------------ */
  167.     /* process the command line options                             */
  168.     /* ------------------------------------------------------------ */
  169.  
  170.     while ( (i = getopt (ac, av, "D:I:x:r")) NE EOF)
  171.     {
  172.         switch (i)
  173.         {
  174.             case    'D':            /* define objects                */
  175.                 deftab[ndef] = (char *)
  176.                     Allocate (1, strlen (optarg) + 1);
  177.                 strcpy (deftab[ndef], optarg);
  178.                 deftab = (char **)
  179.                     ReAllocate (deftab, (++ndef) * sizeof (char *));
  180.                 break;
  181.             case    'I':            /* search directory - like cc    */
  182.                 ndir++;
  183.                 if (!dirlist (optarg)) 
  184.                 {
  185.                     dirs[ndir-1] = (char *)
  186.                         Allocate (1, strlen (optarg) + 1);
  187.                     strcpy (dirs[ndir-1], optarg);
  188.                     if (ndir GE MAXDIRS)
  189.                     {
  190.                         MAXDIRS += 10;
  191.                         dirs = (char **) ReAllocate (dirs,
  192.                                         MAXDIRS * sizeof (char *));
  193.                     }
  194.                 }
  195.                 else ndir--;
  196.                 break;
  197.             case    'x':            /* a file to exclude            */
  198.                 noexp[nx] = (char *) Allocate (1, strlen (optarg) + 3);
  199.                 strcpy (noexp[nx], optarg);
  200.                 if (!strrchr (optarg, '.')) strcat (noexp[nx], ".h");
  201.                 nx++;
  202.                 if (nx GE MAXNOEXP)
  203.                 {
  204.                     MAXNOEXP += 10;
  205.                     noexp = (char **) ReAllocate (noexp,
  206.                                         MAXNOEXP * sizeof (char *));
  207.                 }
  208.                 break;
  209.             case    'r':            /* turn on recursive search        */
  210.                 recursion = TRUE;
  211.                 break;
  212.             default:
  213.                 fprintf (stderr,
  214.                     "<%s> unknown argument - %c\n", pgm, i);
  215.                 break;
  216.         }
  217.     }
  218. /*Page Eject*/
  219.     /* ------------------------------------------------------------ */
  220.     /* add /usr/include as the last of the directories - as cc      */
  221.     /* ------------------------------------------------------------ */
  222.  
  223.     dirs[ndir] = (char *) Allocate (1, strlen ("/usr/include") + 1);
  224.     strcpy (dirs[ndir], "/usr/include");
  225.     dirlist (dirs[ndir++]);
  226.  
  227.     /* ------------------------------------------------------------ */
  228.     /* sort the include file list for use with bsearch              */
  229.     /* ------------------------------------------------------------ */
  230.  
  231.     qsort (file, nfil, sizeof(struct file), fcmp);
  232.  
  233.     /* ------------------------------------------------------------ */
  234.     /* if we are doing recursive searches, also sort the exclusions */
  235.     /* ------------------------------------------------------------ */
  236.  
  237.     if (recursion) qsort (noexp, nx, sizeof noexp[0], pstrcmp);
  238.  
  239.     /* ------------------------------------------------------------ */
  240.     /* if there are any definitions, sort the define table          */
  241.     /* ------------------------------------------------------------ */
  242.  
  243.     if (ndef) qsort (deftab, ndef, sizeof (char *), pstrcmp);
  244.  
  245.     /* ------------------------------------------------------------ */
  246.     /* Now that we've complete the tedious job of setting up,       */
  247.     /*  process each remaining command line argument (they are      */
  248.     /*  expected to be C source file names)                         */
  249.     /* ------------------------------------------------------------ */
  250.  
  251.     for (i = optind; i LT ac; i++)
  252.     {
  253.         dofile (av[i], FALSE);
  254.     }
  255.  
  256.     exit (0);
  257. }
  258. /*S dirlist - expand a directory name into a list of include files */
  259. /*H dirlist **********************************************************
  260. *
  261. *                                   dirlist
  262. *
  263. *  Examine each entry in a directory.  If a file is an include file
  264. *  (name ends with .h), include it and the directory index in the
  265. *  file list.
  266. *
  267. *********************************************************************/
  268. /*E*/
  269. dirlist (dnam)
  270. register char    *dnam;            /* directory path name                */
  271. {
  272.     register int    i;            /* general purpose stuff            */
  273.  
  274.     register char   c;            /* ditto                            */
  275.     register char   *ptr;        /* again                            */
  276.  
  277.     char    *strrchr ();        /* find char from end                */
  278.  
  279.     static char   *fn = "dirlist";    /* function name for logging    */
  280.  
  281.     register FILE    *dir;        /* directory file stream            */
  282.  
  283.     struct direct direct;        /* place to read entries into        */
  284.  
  285.     /* ------------------------------------------------------------ */
  286.     /* attempt to open the directory file - exit on error           */
  287.     /* ------------------------------------------------------------ */
  288.  
  289.     if ( (dir = fopen (dnam, "r")) EQ NULL)
  290.     {
  291.         fprintf (stderr,
  292.             "dirlist: unable to open directory %s for read\n", dnam);
  293.         return (1);
  294.     }
  295.     else
  296.     {
  297.     /* ------------------------------------------------------------ */
  298.     /* read each directory entry                                    */
  299.     /* if the entry is active                                       */
  300.     /*  if the file is an include file (*.h)                        */
  301.     /*   copy the name and directory index into the file list       */
  302.     /* ------------------------------------------------------------ */
  303.  
  304.         while (fread (&direct, sizeof direct, 1, dir) EQ 1)
  305.         {
  306.             if (direct.d_ino)
  307.             {
  308.                 for (ptr = &direct.d_name[DIRSIZ-1]; !*ptr; ptr--);
  309.  
  310.                 if (*ptr EQ 'h' AND *(ptr-1) EQ '.')
  311.                 {
  312.                     strncpy (file[nfil].name, direct.d_name, DIRSIZ+1);
  313.                     file[nfil].dirind = ndir - 1;
  314.                     nfil++;
  315.  
  316.     /* ------------------------------------------------------------ */
  317.     /* if we're out of space in the list, allocate some more        */
  318.     /* ------------------------------------------------------------ */
  319.  
  320.                     if (nfil GE MAXFILES)
  321.                     {
  322.                         MAXFILES += 50;
  323.                         file = (struct file *) ReAllocate (file,
  324.                                     MAXFILES * sizeof (struct file));
  325.                     }
  326.                 }
  327.             }
  328.         }
  329.         fclose (dir);
  330.     }
  331.  
  332.     return (0);
  333. }
  334. /*S dofile - process an input (C source) file */
  335. /*H dofile ***********************************************************
  336. *
  337. *                                   dofile
  338. *
  339. *  examine each line of the input file.  If the first char is either
  340. *  # or $ (UNIFY includes, for those of us who use it) and the next
  341. *  word is include, look for the named file.  If the input file name
  342. *  is `-', read from standard input and provide a default dependency
  343. *  name.
  344. *
  345. *********************************************************************/
  346. /*E*/
  347. dofile (fnam, suppress)
  348. char    *fnam;                    /* input file name                    */
  349. register BOOL    suppress;        /* true if this is called for        */
  350.                                 /* recursive expansion and file name*/
  351.                                 /* has already been printed            */
  352. {
  353.     register FILE    *curfile;    /* current input file stream        */
  354.  
  355.     char    dep[80];            /* place for dependency object name    */
  356.     register char *c;            /* temp pointer                        */
  357.     register char *cd;            /* temp pointer                        */
  358.     static char *fn = "dofile";    /* function name for logging        */
  359.     char    lbuf[120];            /* input line buffer                */
  360.     register char    *suffix;    /* pointer to file name suffix        */
  361.     char    tname[80];            /* place to build full name            */
  362.  
  363.     register int count = 0;        /* number of things matched - sscanf*/
  364.  
  365.     register struct  file *iname;    /* pointer to matching file        */
  366.  
  367.     struct  file *bsearch ();
  368.  
  369.     register int     i;            /* general purpose stuff            */
  370.     register BOOL skip = FALSE;    /* true if skipping because of DEF    */
  371.  
  372.     int     strcmp ();
  373.  
  374.     BOOL    first = TRUE;        /* true for initial condition        */
  375.  
  376.     /* ------------------------------------------------------------ */
  377.     /* open the current file if it is not stdin                     */
  378.     /* ------------------------------------------------------------ */
  379.  
  380.     if (strcmp (fnam, "-") EQ 0)
  381.     {
  382.         curfile = stdin;
  383.         fnam = "standardin.c";
  384.     }
  385.     else
  386.     {
  387.         curfile = fopen (fnam, "r");
  388.     }
  389.  
  390.     if (curfile EQ NULL)
  391.     {
  392.         fprintf (stderr, "<%s> _error_ cannot open %s\n", fn, fnam);
  393.     }
  394.     else
  395.     {
  396.     /* ------------------------------------------------------------ */
  397.     /* look at each line in the file and process those beginning    */
  398.     /*  with a legal include statement                              */
  399.     /* ------------------------------------------------------------ */
  400.  
  401.         while (fgets (lbuf, sizeof lbuf, curfile) EQ lbuf)
  402.         {
  403.             skip = ckdef (lbuf, skip);
  404.             if (skip) continue;
  405.             count = sscanf (lbuf, "%*[#$] include%s", dep);
  406.             if (count EQ 1)
  407.             {
  408.     /* ------------------------------------------------------------ */
  409.     /* if this is the first time in, print out the file name        */
  410.     /* ------------------------------------------------------------ */
  411.  
  412.                 if (first AND !suppress)
  413.                 {
  414.                     suffix = &fnam[strlen(fnam)-1];
  415.                     if (*suffix EQ 'c') *suffix = 'o';
  416.                     printf ("%s: ", fnam);
  417.                     first = FALSE;
  418.                 }
  419.     /* ------------------------------------------------------------ */
  420.     /* clean up the dependency name                                 */
  421.     /* ------------------------------------------------------------ */
  422.  
  423.                 c = cd = dep;
  424.                 while ((*c = *(++cd)) NE '>' AND *c NE '"') c++;
  425.                 *c = NUL;
  426.  
  427.     /* ------------------------------------------------------------ */
  428.     /* if the include is sys/something.h, assume that it's from     */
  429.     /*   /usr/include/sys, since this is the 99.9% case             */
  430.     /* ------------------------------------------------------------ */
  431.  
  432.                 if (strncmp (dep, "sys/", 4) EQ 0)
  433.                 {
  434.                     printf ("\\\n\t\t/usr/include/%s ", dep);
  435.                 }
  436.                 else if (strchr (dep, '/'))
  437.                 {
  438.                     printf ("\\\n\t\t%s ", dep);
  439.                 }
  440.                 else
  441.                 {
  442.     /* ------------------------------------------------------------ */
  443.     /* look for the include file name in the list of known files    */
  444.     /* ------------------------------------------------------------ */
  445.  
  446.                     iname = bsearch (dep, file, nfil,
  447.                                 sizeof(struct file), strcmp);
  448.                     if (iname)
  449.                     {
  450.     /* ------------------------------------------------------------ */
  451.     /* since there might be more than one copy of the include file  */
  452.     /*  back up to the first (bsearch will just find one)           */
  453.     /* ------------------------------------------------------------ */
  454.  
  455.                         while (iname GT file)
  456.                         {
  457.                             if (strcmp (iname, iname - 1) EQ 0)
  458.                                 iname--;
  459.                             else
  460.                                 break;
  461.                         }
  462.                         printf ("\\\n\t\t%s/%s ",
  463.                             dirs[iname->dirind], dep);
  464.     /* ------------------------------------------------------------ */
  465.     /* if recursive search was requested and the file is not        */
  466.     /*  in the exclusion list, then look for its includes           */
  467.     /* ------------------------------------------------------------ */
  468.  
  469.                         if (recursion AND
  470.                             !bsearch (dep, noexp, nx,
  471.                                     sizeof (char *), mstrcmp))
  472.                         {
  473.                             sprintf (tname,
  474.                                 "%s/%s", dirs[iname->dirind], dep);
  475.                             dofile (tname, TRUE);
  476.                         }
  477.                     }
  478.     /* ------------------------------------------------------------ */
  479.     /* things that have paths in them, either relative or absolute, */
  480.     /*   will be passed through as is.  since this is generally     */
  481.     /*   contrary to standard coding practice, it should be ok for  */
  482.     /*   the majority of the cases                                  */
  483.     /* ------------------------------------------------------------ */
  484.  
  485.                     else
  486.                     {
  487.                         printf ("\\\n\t\t%s ", dep);
  488.                     }
  489.                 }
  490.             }
  491.         }
  492.         if (!suppress) printf ("\n");
  493.         fclose (curfile);
  494.     }
  495. }
  496. /*S fcmp - compare two file list entries */
  497. /*H fcmp *************************************************************
  498. *
  499. *                                   fcmp
  500. *
  501. *  a comparison function for qsort to call
  502. *
  503. *********************************************************************/
  504. /*E*/
  505. fcmp (f1, f2)
  506. struct file *f1;
  507. struct file *f2;
  508. {
  509.     register int i;
  510.  
  511.     if (i = strncmp (f1->name, f2->name, sizeof f1->name))
  512.         return i;
  513.     else
  514.         return f1->dirind - f2->dirind;
  515. }
  516. /*S Allocate - call calloc and process return */
  517. /*H Allocate *********************************************************
  518. *
  519. *                                   Allocate
  520. *
  521. *  veneer over calloc to handle bad returns
  522. *
  523. *********************************************************************/
  524. /*E*/
  525. char *
  526. Allocate (nelem, size)
  527. register int nelem;
  528. register int size;
  529. {
  530.     extern char *calloc ();
  531.  
  532.     register char *to;
  533.  
  534.     if (!(to = calloc (nelem, size)))
  535.     {
  536.         fprintf (stderr,
  537.             "%s: allocation failure - %d * %d\n",
  538.             pgm, nelem, size);
  539.         exit (99);
  540.     }
  541.  
  542.     return to;
  543. }
  544. /*S ReAllocate - call calloc and process return */
  545. /*H ReAllocate *******************************************************
  546. *
  547. *                                   ReAllocate
  548. *
  549. *  veneer over realloc to handle bad returns
  550. *
  551. *********************************************************************/
  552. /*E*/
  553. char *
  554. ReAllocate (oldp, size)
  555. register char *oldp;
  556. register int size;
  557. {
  558.     extern char *realloc ();
  559.  
  560.     register char *to;
  561.  
  562.     if (!(to = realloc (oldp, size)))
  563.     {
  564.         fprintf (stderr,
  565.             "%s: reallocation failure - %d\n",
  566.             pgm, size);
  567.         exit (99);
  568.     }
  569.  
  570.     return to;
  571. }
  572. /*S ckdef - check for #ifdef/ifndef/else/endif line */
  573. /*H ckdef ************************************************************
  574. *
  575. *                                   ckdef
  576. *
  577. *  Look at the line and return the appropriate status depending on
  578. *  whether or not a preprocessor symbol is defined or not.
  579. *
  580. *********************************************************************/
  581. /*E*/
  582. ckdef (buf, skip)
  583. register char *buf;                /* line to check                    */
  584. register BOOL skip;                /* current state of skip            */
  585. {
  586.     char    sym[40];            /* defined symbol if found            */
  587.  
  588.     char    lbuf[120];            /* local buffer                        */
  589.  
  590.     register int count = 0;        /* return from sscanf                */
  591.  
  592.     count = sscanf (buf, "%*[#$]%s", lbuf);
  593.  
  594.     if (count EQ 1)
  595.     {
  596.         if (!skip AND !strcmp (lbuf, "ifdef"))
  597.         {
  598.             sscanf (buf, "%*[#$]%*s%s", sym);
  599.             skip = !(BOOL)bsearch (sym, deftab, ndef,
  600.                     sizeof(char *), mstrcmp);
  601.         }
  602.         else if (!skip AND !strcmp (lbuf, "ifndef"))
  603.         {
  604.             sscanf (buf, "%*[#$]%*s%s", sym);
  605.             skip = (BOOL)bsearch (sym, deftab,
  606.                     ndef, sizeof(char *), mstrcmp);
  607.         }
  608.         else if (!strcmp (lbuf, "else"))
  609.         {
  610.             skip = !skip;
  611.         }
  612.         else if (skip AND !strcmp (lbuf, "endif"))
  613.         {
  614.             skip = !skip;
  615.         }
  616.     }
  617.  
  618.     return skip;
  619. }
  620. /*S mstrcmp - compare two strings given one direct and one indirect */
  621. /*H mstrcmp **********************************************************
  622. *
  623. *                                   mstrcmp
  624. *
  625. *  for use with bsearch, this assumes that the arguments are a
  626. *  string address and a pointer to a string address.  This is
  627. *  used to allow the comparison of a string to a string pointed
  628. *  to by an element of `noexp'.
  629. *
  630. *********************************************************************/
  631. /*E*/
  632. mstrcmp (s1, s2)
  633. register char *s1;
  634. register char **s2;
  635. {
  636.     return strcmp (s1, *s2);
  637. }
  638. /*S pstrcmp - compare two strings given pointers to pointers */
  639. /*H pstrcmp **********************************************************
  640. *
  641. *                                   pstrcmp
  642. *
  643. *  for use with qsort and bsearch, this assumes that the arguments
  644. *  passed are pointers to the string addresses rather than the
  645. *  addresses of the strings
  646. *
  647. *********************************************************************/
  648. /*E*/
  649. pstrcmp (s1, s2)
  650. register char **s1;
  651. register char **s2;
  652. {
  653.     return strcmp (*s1, *s2);
  654. }
  655.