home *** CD-ROM | disk | FTP | other *** search
/ OS/2 Shareware BBS: 10 Tools / 10-Tools.zip / makdep4d.zip / MAKDPDOS.ZIP / MAKEDEP.C < prev    next >
C/C++ Source or Header  |  1994-09-28  |  18KB  |  553 lines

  1. // --------------------------------------------------------------------------
  2. //
  3. //  File:      MAKEDEP.C
  4. //  Product:   MAKEDEP program
  5. //  Author:    Sulyok Péter (C) 1994.
  6. //  Compiler:  Borland C\C++ 3.1
  7. //             Borland C\C++ 4.02
  8. //             Microsoft C 6.00A
  9. //             Microsoft C\C++ 7.00
  10. //             Watcom C 9.0
  11. //  Notes:     Generate dependency list of C and assembly programs
  12. //             for MAKE.
  13. //
  14. // --------------------------------------------------------------------------
  15.  
  16. // Include files ------------------------------------------------------------
  17. #include <stdio.h>
  18. #include <stdlib.h>
  19. #include <dos.h>
  20. #include <io.h>
  21. #include <string.h>
  22. #include <malloc.h>
  23. #include <exparg.h>
  24.  
  25. // Constants ----------------------------------------------------------------
  26. #ifdef MAXPATH
  27. #undef MAXPATH
  28. #endif
  29. #define MAXPATH         128                  // Maximal size of path.
  30. #define MAXNUM          50                   // Maximum number of path.
  31.  
  32. #define EXTNUM          6                    // Number of source file extensions.
  33. #define LSIZE           256                  // Line size.
  34.  
  35. #define DOS_ERROR       1                    // Error code to DOS.
  36. #define DOS_OK          0                    // OK code to DOS.
  37.  
  38. #define ASM_TYPE        0                    // Source is an assembly file.
  39. #define C_TYPE          1                    // Source is a C file.
  40.  
  41. #define TRUE            1                    // True value.
  42. #define FALSE           0                    // False value.
  43.  
  44. #define usage           "MAKEDEP dependecies generator, SP (C) 1994.\n" \
  45.                         "Usage:   MAKEDEP [-option ...] objectfile [outputfile]\n"         \
  46.                         "Options:\n"                                                       \
  47.                         "   -a                Append to outputfile\n"                      \
  48.                         "   -sPATH[;PATH...]  Source file search directories\n"            \
  49.                         "   -iPATH[;PATH...]  Include file search directories\n"           \
  50.                         "   -n                Ignore include file if not found\n"          \
  51.                         "   -d                Do not write objectfile\n"                   \
  52.                         "   -b                Write depencies base name\n"                 \
  53.                         "   -u                Use upper case\n"                            \
  54.                         "   -l                Use lower case\n"                            \
  55.                         "   -h,-?             This text\n"                                 \
  56.                         "   @respfile         Response file for options"
  57.  
  58. #define backslash(s)                   \
  59.    if ( (s)[strlen((s))-1] != '\\' ) { \
  60.       unsigned int pos;                \
  61.       pos = strlen((s));               \
  62.       (s)[pos]   = '\\';               \
  63.       (s)[pos+1] = '\0';               \
  64.       }
  65.  
  66. // Local variables ----------------------------------------------------------
  67. static short source_num = 0;                 // Number of source directories.
  68. static char  source_dirs[MAXNUM][MAXPATH];   // Array of source directories.
  69. static char  source_type = C_TYPE;           // Type of source file.
  70. static char  *source_exts[EXTNUM] = {        // Source file extensions.
  71.    ".c",
  72.    ".cc",
  73.    ".cpp",
  74.    ".asm",
  75.    ".as",
  76.    ".a"
  77. };
  78.  
  79. static short include_num = 0;                // Number of include directories.
  80. static char  include_dirs[MAXNUM][MAXPATH];  // Array of include directories.
  81.  
  82. static short depend_num = 0;                 // Number of dependent file.
  83. static char  depends[MAXNUM][MAXPATH];       // Array of dependent file.
  84.  
  85. static char  source_file[MAXPATH] = { 0 };   // Full source file name.
  86. static char  object_file[MAXPATH] = { 0 };   // Object file name.
  87. static char  depend_file[MAXPATH] = { 0 };   // Dependency output file name.
  88.  
  89. static char  append_mode   = FALSE;          // Append mode flag.
  90. static char  ignore_mode   = FALSE;          // Ignore mode flag.
  91. static char  depend_mode   = FALSE;          // Dependency only mode flag.
  92. static char  upper_mode    = FALSE;          // Upper case mode.
  93. static char  lower_mode    = FALSE;          // Lower case mode.
  94. static char  basename_mode = FALSE;          // Base name mode flag.
  95.  
  96. #ifdef __TURBOC__
  97. extern unsigned _stklen = 10000;             // We use recursive calls !
  98. #endif
  99.  
  100. // Local functions ---------------------------------------------------------
  101. static char *next_white(char *s);
  102. static char *next_nonwhite(char *s);
  103. static void search_source_file(void);
  104. static void search_include_file(char *name);
  105. static void make_depend_files(char *name);
  106. static void write_depend_files(void);
  107.  
  108. // --------------------------------------------------------------------------
  109. //  Name:      next_nonwhite
  110. //  Input:     char *s                       string
  111. //  Output:    char *                        next position
  112. //                                           NULL if EOS
  113. //  Notes:     Search the next nonwhitespace character in string.
  114. // --------------------------------------------------------------------------
  115. static char *next_nonwhite(char *s)
  116. {
  117.    // Check the string.
  118.    while( *s ) {
  119.  
  120.       // If this is a whitespace character than continue the loop.
  121.       if ( (*s == ' ') || (*s == 9) || (*s == '\n') || (*s == '\r') ) {
  122.          s++;
  123.          continue;
  124.          } // if
  125.  
  126.       // Found a none whitespace character.
  127.       return s;
  128.  
  129.       } // while
  130.  
  131.    return NULL;
  132. }
  133.  
  134. // --------------------------------------------------------------------------
  135. //  Name:      next_white
  136. //  Input:     char *s                       string
  137. //  Output:    char *                        next position
  138. //                                           NULL if EOS
  139. //  Notes:     Search the next whitespace character in string.
  140. // --------------------------------------------------------------------------
  141. static char *next_white(char *s)
  142. {
  143.    // Check the string.
  144.    while( *s ) {
  145.  
  146.       // Found a whitespace character.
  147.       if ( (*s == ' ') || (*s == 9) || (*s == '\n') || (*s == '\r') )
  148.          return s;
  149.  
  150.       // Else continue the loop.
  151.       s++;
  152.       } // while
  153.  
  154.    return NULL;
  155. }
  156.  
  157. // --------------------------------------------------------------------------
  158. //  Name:      search_source_file
  159. //  Input:     void
  160. //  Output:    void
  161. //  Notes:     Search the original source file from the object file name.
  162. // --------------------------------------------------------------------------
  163. static void search_source_file(void)
  164. {
  165.    short    i, j;
  166.    char     tmp[MAXPATH];
  167.    char     drive[_MAX_DRIVE], dir[_MAX_DIR],
  168.             name[_MAX_FNAME], ext[_MAX_EXT];
  169.    struct   find_t find;
  170.  
  171.    // Split object file name to its components.
  172.    _splitpath(object_file, drive, dir, name, ext);
  173.  
  174.    // Try to find in all source directory.
  175.    for(i=0; i<source_num; i++) {
  176.  
  177.       // Try to open with every source file extension.
  178.       for(j=0; j<EXTNUM; j++) {
  179.  
  180.          // Make the full source file name.
  181.          _makepath(tmp, NULL, source_dirs[i], name, source_exts[j]);
  182.  
  183.          // Try to locate the source file.
  184.          if ( !_dos_findfirst(tmp, _A_ARCH|_A_RDONLY|_A_HIDDEN, &find) ) {
  185.             strcpy(source_file, tmp);
  186.             source_type = ( source_exts[j][1] == 'a' ) ? ASM_TYPE : C_TYPE;
  187.             return;
  188.             } // if
  189.  
  190.          } //for
  191.       } // for
  192.  
  193.    // If source file not found.
  194.    printf("Source file not found for %s.\n", object_file);
  195.    exit(DOS_ERROR);
  196. }
  197.  
  198. // --------------------------------------------------------------------------
  199. //  Name:      search_include_file
  200. //  Input:     char *name                    include file name
  201. //  Output:    void
  202. //  Notes:     Search the the given include file in the include directories.
  203. // --------------------------------------------------------------------------
  204. static void search_include_file(char *name)
  205. {
  206.    int      i, j;
  207.    char     tmp[MAXPATH];
  208.    struct   find_t find;
  209.  
  210.    // Try to find in all include directory.
  211.    for(i=0; i<include_num; i++) {
  212.  
  213.       // Make the full name.
  214.       strcpy(tmp, include_dirs[i]);
  215.       strcat(tmp, name);
  216.  
  217.       // Try to locate the include file.
  218.       if ( !_dos_findfirst(tmp, _A_ARCH|_A_RDONLY|_A_HIDDEN, &find) ) {
  219.  
  220.          // Check if it appears in the dependecy list.
  221.          for(j=0; j<depend_num; j++)
  222.             if ( !strcmp(depends[j], tmp) )
  223.                return;
  224.  
  225.          // It is a new dependent file.
  226.          if ( depend_num == MAXNUM ) {
  227.             puts("Too many dependent file.");
  228.             exit(DOS_ERROR);
  229.             } // if
  230.          strcpy(depends[depend_num++], tmp);
  231.          return;
  232.          } // if
  233.  
  234.       } // for
  235.  
  236.    // If include file not found.
  237.    if ( !ignore_mode ) {
  238.       printf("Cannot locate %s include file.\n", name);
  239.       exit(DOS_ERROR);
  240.       } // if
  241. }
  242.  
  243. // --------------------------------------------------------------------------
  244. //  Name:      make_depend_files
  245. //  Input:     char *name                    source file name
  246. //  Output:    void
  247. //  Notes:     Search the dependencies of the given source file.
  248. // --------------------------------------------------------------------------
  249. static void make_depend_files(char *name)
  250. {
  251.    FILE  *sf;
  252.    char  line[LSIZE];
  253.    char  *s, *e;
  254.    int   i, first, last;
  255.  
  256.    // Register the first dependent file.
  257.    first = depend_num;
  258.  
  259.    // Open source file.
  260.    if ( (sf = fopen(name, "rt")) == NULL ) {
  261.       printf("Unable to open %s file.\n", name);
  262.       exit(DOS_ERROR);
  263.       } // if
  264.  
  265.    // Scan source file for include statments.
  266.    while( fgets(line, LSIZE, sf) ) {
  267.  
  268.       // Go to first nonwhitespace character in line.
  269.       if ( (s = next_nonwhite(line)) == NULL )
  270.          continue;
  271.  
  272.       // Process an assembly line.
  273.       if ( source_type == ASM_TYPE ) {
  274.  
  275.          // This is an include statment ?
  276.          if ( !strnicmp(s, "include", 7) ) {
  277.             s += 7;
  278.  
  279.             // Search begin of include file name.
  280.             if ( (s = next_nonwhite(s)) == NULL )
  281.                continue;
  282.  
  283.             // Search end of include file name.
  284.             if ( (e= next_white(s)) == NULL )
  285.                continue;
  286.             *e = '\0';
  287.  
  288.             // Search full path of include file.
  289.             search_include_file(s);
  290.             } // if
  291.  
  292.          } // if
  293.  
  294.       // Process a C line.
  295.       if ( source_type == C_TYPE ) {
  296.  
  297.          // This is an #include statment ?
  298.          if ( !strnicmp(s, "#include", 8) ) {
  299.             s += 8;
  300.  
  301.             // Search begin of include file name.
  302.             if ( (s = next_nonwhite(s)) == NULL )
  303.                continue;
  304.             s++;
  305.  
  306.             // Search end of include file name.
  307.             if ( (e = strchr(s, '>')) == NULL )
  308.                if ( (e = strchr(s, '"')) == NULL )
  309.                   continue;
  310.             *e = '\0';
  311.  
  312.             // Search full path of include file.
  313.             search_include_file(s);
  314.             } // if
  315.  
  316.          } // if
  317.  
  318.       } // while
  319.  
  320.    // Register the last dependent file.
  321.    last = depend_num;
  322.  
  323.    // Close the source file.
  324.    fclose(sf);
  325.  
  326.    // Check include files in this source file.
  327.    if ( first < last )
  328.       for(i=first; i<last; i++)
  329.          make_depend_files(depends[i]);
  330. }
  331.  
  332. // --------------------------------------------------------------------------
  333. //  Name:      write_depend_files
  334. //  Input:     void
  335. //  Output:    void
  336. //  Notes:     Write list of dependent files to the given file or stdout.
  337. // --------------------------------------------------------------------------
  338. static void write_depend_files(void)
  339. {
  340.    int  i;
  341.    FILE *output;
  342.    char drive[_MAX_DRIVE], dir[_MAX_DIR],
  343.         name[_MAX_FNAME], ext[_MAX_EXT];
  344.  
  345.    // Output is stdout.
  346.    if ( !depend_file[0] ) {
  347.       output = stdout;
  348.       } // if
  349.  
  350.    // Output is a file.
  351.    else {
  352.       char *mode;
  353.       mode = ( append_mode ) ? "a+t" : "w+t";
  354.       if ( (output = fopen(depend_file, mode)) == NULL ) {
  355.          printf("Unable to open %s.", depend_file);
  356.          exit(DOS_ERROR);
  357.          } // if
  358.       } // else
  359.  
  360.    // Use upper case if need.
  361.    if ( upper_mode ) {
  362.       strupr(object_file);
  363.       for(i=0; i<depend_num; i++)
  364.          strupr(depends[i]);
  365.       } // if
  366.  
  367.    // Use lower case if need.
  368.    if ( lower_mode ) {
  369.       strlwr(object_file);
  370.       for(i=0; i<depend_num; i++)
  371.          strlwr(depends[i]);
  372.       } // if
  373.  
  374.    // Write object file name too if need.
  375.    if ( !depend_mode )
  376.       fprintf(output, "%s: ", object_file);
  377.  
  378.    // Write dependecies to output.
  379.    for(i=0; i<depend_num; i++) {
  380.       if ( !basename_mode )
  381.          fprintf(output, "%s ", depends[i]);
  382.       else {
  383.          char tmp[MAXPATH];
  384.          _splitpath(depends[i], drive, dir, name, ext);
  385.          _makepath(tmp, NULL, NULL, name, ext);
  386.          fprintf(output, "%s ", tmp);
  387.          } // else
  388.       } // for
  389.  
  390.    // Close output.
  391.    fprintf(output, "\n");
  392.    fclose(output);
  393. }
  394.  
  395. // --------------------------------------------------------------------------
  396. //  Name:      main
  397. //  Input:     int   argc                    number of arguments
  398. //             char  *argv[]                 list of argument
  399. //  Output:    void
  400. //  Notes:     The main() function.
  401. // --------------------------------------------------------------------------
  402. void main(int argc, char *argv[])
  403. {
  404.    int  i;
  405.    char *s, *d;
  406.  
  407.    // Expand command line.
  408.    switch( exparg(&argc, &argv) ) {
  409.       case -1:
  410.          puts("Not enough memory to load response file.");
  411.          exit(DOS_ERROR);
  412.       case -2:
  413.          puts("Unable to load response file.");
  414.          exit(DOS_ERROR);
  415.       } // switch
  416.  
  417.    // If not enough command line argument.
  418.    if ( argc < 2 ) {
  419.       puts("Not enough argument (use -h for help).");
  420.       exit(DOS_ERROR);
  421.       } // if
  422.  
  423.    // Check all argument.
  424.    for(i=1; i<argc; i++) {
  425.  
  426.       // If argument is an option.
  427.       if ( (argv[i][0] == '-') || (argv[i][0] == '/') ) {
  428.          switch( argv[i][1] ) {
  429.  
  430.             case '?' :
  431.             case 'h' :
  432.             case 'H' :
  433.                puts(usage);
  434.                exit(DOS_OK);
  435.                break;
  436.  
  437.             case 'a' :
  438.             case 'A' :
  439.                append_mode = TRUE;
  440.                break;
  441.  
  442.             case 'n' :
  443.             case 'N' :
  444.                ignore_mode = TRUE;
  445.                break;
  446.  
  447.             case 'd' :
  448.             case 'D' :
  449.                depend_mode = TRUE;
  450.                break;
  451.  
  452.             case 'b' :
  453.             case 'B' :
  454.                basename_mode = TRUE;
  455.                break;
  456.  
  457.             case 'u' :
  458.             case 'U' :
  459.                lower_mode = FALSE;
  460.                upper_mode = TRUE;
  461.                break;
  462.  
  463.             case 'l' :
  464.             case 'L' :
  465.                upper_mode = FALSE;
  466.                lower_mode = TRUE;
  467.                break;
  468.  
  469.             case 's' :
  470.             case 'S' :
  471.                s = &argv[i][2];
  472.                while( (d = strchr(s, ';')) != NULL ) {
  473.                   *d++ = '\0';
  474.                   strcpy(source_dirs[source_num], s);
  475.                   backslash(source_dirs[source_num]);
  476.                   source_num++;
  477.                   s = d;
  478.                   } // while
  479.                strcpy(source_dirs[source_num], s);
  480.                backslash(source_dirs[source_num]);
  481.                source_num++;
  482.                break;
  483.  
  484.             case 'i' :
  485.             case 'I' :
  486.                s = &argv[i][2];
  487.                while( (d = strchr(s, ';')) != NULL ) {
  488.                   *d++ = '\0';
  489.                   strcpy(include_dirs[include_num], s);
  490.                   backslash(include_dirs[include_num]);
  491.                   include_num++;
  492.                   s = d;
  493.                   } // while
  494.                strcpy(include_dirs[include_num], s);
  495.                backslash(include_dirs[include_num]);
  496.                include_num++;
  497.                break;
  498.  
  499.             default:
  500.                printf("Unknown argument %s (use -h for help).\n", argv[i]);
  501.                exit(DOS_ERROR);
  502.             } // switch
  503.  
  504.          } // if
  505.  
  506.       // If argument is a file name.
  507.       else {
  508.  
  509.          // First time get the object file name.
  510.          if ( !object_file[0]  ) {
  511.             strcpy(object_file, argv[i]);
  512.             continue;
  513.             } // if
  514.  
  515.          // Second time get the dependencies file name.
  516.          if ( !depend_file[0]  ) {
  517.             strcpy(depend_file, argv[i]);
  518.             continue;
  519.             } // if
  520.  
  521.          puts("Too many file name (use -h for help).");
  522.          exit(DOS_ERROR);
  523.          } // else
  524.  
  525.       } // for
  526.  
  527.    // If object file missing.
  528.    if ( !object_file[0]  ) {
  529.       puts("Missing object file name (use -h for help).");
  530.       exit(DOS_ERROR);
  531.       } // if
  532.  
  533.    // Always use the current directory.
  534.    include_dirs[include_num++][0] = '\0';
  535.    source_dirs[source_num++][0]   = '\0';
  536.  
  537.    // Search the original source file.
  538.    search_source_file();
  539.  
  540.    // First dependcy is the source file.
  541.    strcpy(depends[depend_num++], source_file);
  542.  
  543.    // Make list of depenencies.
  544.    make_depend_files(source_file);
  545.  
  546.    // Write out list of dependencies.
  547.    write_depend_files();
  548.  
  549.    exit(DOS_OK);
  550. }
  551.  
  552. // End ----------------------------------------------------------------------
  553.