home *** CD-ROM | disk | FTP | other *** search
/ The C Users' Group Library 1994 August / wc-cdrom-cusersgrouplibrary-1994-08.iso / vol_300 / 312_01 / aincdep.awk < prev    next >
Text File  |  1990-04-22  |  13KB  |  283 lines

  1. #  HEADER:        ;
  2. #  TITLE:         Makefile dependency generator;
  3. #  DATE:          09/28/1989;
  4. #  VERSION:       1.2;
  5. #  DESCRIPTION:   "An AWK program which finds included files in an assembly
  6. #                 language source file and builds a dependency list.  This
  7. #                 dependency list is a component of a make-file.  The list
  8. #                 consists of the source file name followed by a colon and
  9. #                 then all of the files which it includes (and also
  10. #                 those which are included by the included files, &c.)
  11. #                 The last item is a compile-command.";
  12. #
  13. #  KEYWORDS:      Makefile, make, include, dependency generator;
  14. #  SYSTEM:        MS-DOS, UNIX;
  15. #  WARNINGS:      "This is for Intel's assembler, not MASM.
  16. #                 Doesn't handle directory names embedded within
  17. #                 $include(here).  Doesn't handle preprocessor $if.. blocks
  18. #                 or $include statements which are "commented out."
  19. #                 PolyAwk will generate false matches to lines
  20. #                 beginning with non-ASCII (i.e. 128..256) chars."
  21. #                 Filenames are case sensitive.";
  22. #  FILENAME:      AINCDEP.AWK;
  23. #  SEE-ALSO:      TLR2MAK.AWK, CF2MAK.AWK, CINCDEP.AWK, LBI2MAK.AWK;
  24. #  AUTHORS:       James Yehle;
  25. #  COMPILERS:     PolyAWK, Mortice Kern AWK, Rob Duff's PC-AWK 2.0,
  26. #                 In any case, must be 1985 awk (not 1977);
  27. # ============================================================================
  28. #
  29. # aincdep.awk         Last modified  Sep 28, 1989  22:31
  30. #
  31. #   Scans an assembly source file for all "$include" dependencies
  32. #   This scanning process involves all nested include files, too.
  33. #
  34. #   Usage is:
  35. #     awk -f [path]aincdep.awk [path]src_file.c objname=[path]filename
  36. #        cc=assemble_comd ccf=[p][n][e] [>[path]outfile]
  37. #     Pathnames must contain trailing separator, e.g. "s:asm\inc\"
  38. #     Order of command-line parameters (save for "-f ..." 
  39. #      and srcfile.c) is irrelevant, but identifiers must be in lower case.
  40. #     "src_file.asm" may be replaced by special "__NOFILE__"
  41. #     cc is the assembly command
  42. #     ccf controls whether directory path (p) precedes filename in
  43. #         the assemble command line, and whether extension is added (e)
  44. #
  45. #   Output is:
  46. #     [path]src_file.obj: [path]src_file[.ext] [path]included_file1 linecont
  47. #                         [path]included_file2 [path]included_file3 ...
  48. #     <\t>comd [path]src_file[.ext]
  49. #     <\n>
  50. #   For __NOFILE__, output is:
  51. #     [path]src_file.obj:
  52. #     <\n>
  53. #     <\n>
  54. #
  55. #  Jim Yehle
  56. #
  57. # . . . Revision history . . . . . . . . . . . . . . . . . . . . . . . . . . .
  58. #
  59. #  1.2  Sep 10 89  JRY  Added legal-filename-char regular expression
  60. #  1.1  Aug 17 89  JRY  Added add_fnexist option (as internal directive)
  61. #                       If an included file can't be found, aincdep now
  62. #                        beeps and prints an error to CO, then continues
  63. #                        without scanning the file for nested inclusions.
  64. #                        (It adds it to the dependency list.)
  65. #                        Also added an optimization:  if addfile() sees
  66. #                        that a file is already in the list, then it has
  67. #                        already been scanned, so it isn't done again.
  68. #                       Added "verbose" CO output as debug level 1.
  69. #  1.0  Jul 22 89  JRY  Made aincdep for PL/M files; adapted from
  70. #                        C dependency scanner cincdep.awk.
  71. # . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . .
  72. #
  73. # Notes about this program:
  74. #  It assumes Intel ASM286 assembler syntax
  75. #  It doesn't make any attempt to switch out $If() Then (...) Fi blocks.
  76. #  It is powerless to cover files $Included in the assembler's command-line
  77. #  It has no facilities for an include-file directory to be specified
  78. #   (since iRMX's assembler has none)
  79. #
  80. # Here are the syntax rules for $Include() (or $IC()):
  81. #  Control lines begin with $ in column 1
  82. #   and end with or end-of-line or a semicolon before end-of-line
  83. #  Multiple controls (immediately) follow the $, separated by space/tabs
  84. #  Only one "include" control is allowed per line
  85. #
  86. # What I can't deal with:
  87. #  "include(...)" as a parameter within some other control
  88. #   e.g. "title 'include(blah)' "
  89. # ============================================================================
  90. #
  91.  
  92. BEGIN {
  93.    co = "CON"       # Console-out: MS-DOS "CON", iRMX ":co:", unix "/dev/tty"
  94.    linecont = " \\" # Line-continuation EOL char: snake " /", unix make "\\"
  95.    debug = 0        # 0=off, 1=verbose, 2=main-level debug, 3= adds functions
  96.    use_fnexist = 1  # Add nonexistent header files to dependency list?
  97.    fname_chars = "[^\\\\ :]" # Any single legal char in a file name.
  98.    #  (Must exclude directory path separator character! (DOS \, UNIX /) )
  99.  
  100.    printf( "aincdep.awk  ASMx86 $include dependency scanner  v 1.2") >co
  101.    objfile = get_cl_param( "objname=", 0)
  102.    if (debug) printf( "objfile = '%s'\n", objfile) > co
  103.    cc = get_cl_param( "cc=", 0)
  104.    if (debug) printf( "cc = '%s'\n", cc) > co
  105.    ccf = get_cl_param( "ccf=", 0)
  106.    if (debug) printf( "ccf = '%s'\n", ccf) > co
  107.    if (ARGV[1] == "__NOFILE__") {
  108.       if (debug)                    
  109.          printf( "\n__NOFILE__: Empty dependency list generated.\n") > co
  110.       else
  111.          printf( "  (of __NOFILE__)\n") > co
  112.       exit # Hop to END; srcfile is still an empty string & flist is empty
  113.    }
  114.    # 1st in list of ARGV[]'s is source file (FILENAME not set in BEGIN section)
  115.    fullsrcfile = ARGV[1]
  116.    # Split primary source file name into Path, Name, and Extension components
  117.    split_filename( fullsrcfile, srcfile, fname_chars)
  118.    if (debug)
  119.       printf( "\n Scanning primary source file '%s%s%s'\n",
  120.               srcfile["path"], srcfile["name"], srcfile["ext"]) > co
  121.    else
  122.       printf( "  (of %s%s%s)\n",
  123.               srcfile["path"], srcfile["name"], srcfile["ext"]) > co
  124.    if (debug) printf( "srcfile[\"path\"] = \"%s\"\n", srcfile["path"]) > co
  125.    if (debug) printf( "srcfile[\"name\"] = \"%s\"\n", srcfile["name"]) > co
  126.    if (debug) printf( "srcfile[\"ext\"] = \"%s\"\n", srcfile["ext"]) > co
  127. }
  128. #
  129. /^\$[^;]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][ \t]*\(.*\)/ {
  130.    if (debug) printf( "$include control line: $0='%s'\n", $0) > co
  131.    extract_include_filename()  # into $1
  132.    if (debug) printf( " extracted filename = '%s'\n", $1) > co
  133.    # Check for nested inclusions by scanning included file for $Include's
  134.    scanfile( $1)
  135. }
  136. /^\$[^;]*[Ii][Cc][ \t]*\(.*\)/ {
  137.    if (debug) printf( "$include control line: $0='%s'\n", $0) > co
  138.    extract_ic_filename()  # into $1
  139.    if (debug) printf( " extracted filename = '%s'\n", $1) > co
  140.    # Check for nested inclusions by scanning included file for $Include's
  141.    scanfile( $1)
  142. }
  143.  
  144. # Produce the dependency list printout
  145. END {
  146.    # Print primary (object) file name before list (left of colon),
  147.    # Print primary source file name (*.c) as first item in list.
  148.    printf( "%s: %s", objfile, fullsrcfile )
  149.    if (debug)  printf( "%s: %s", objfile, fullsrcfile) >co
  150.    linelen = length(objfile) + 2 + length(fullsrcfile)
  151.  
  152.    for (i=1; i in flist; i++) {
  153.       # If line will be too long, put out a line-continuation char and newline
  154.       if (linelen + 1 + length(flist[i]) + length(linecont)  > 79) {
  155.          printf( "%s\n", linecont)
  156.          if (debug)  printf( "%s\n", linecont) >co
  157.          # On the new line, tab out to underneath the first included file name
  158.          for (linelen=0; linelen<length(objfile)+1; ++linelen) {
  159.             printf(" ")
  160.             if (debug)  printf(" ") >co
  161.          }
  162.       }
  163.       printf( " %s",  flist[i] )
  164.       if (debug)  printf( " %s",  flist[i] ) >co
  165.       linelen += length(flist[i]) + 1
  166.       }
  167.  
  168.    # Build the assemble command line's only parameter: the filename
  169.    #  depending on options specified in ccf command-line param
  170.    assemble_comd_filename = sprintf( "%s%s%s",
  171.                                     ccf ~ /[Pp]/? srcfile["path"] : "",
  172.                                     ccf ~ /[Nn]/? srcfile["name"] : "",
  173.                                     ccf ~ /[Ee]/? srcfile["ext"]  : "" );
  174.    if (debug) 
  175.       printf( "\nassemble_comd_filename = \"%s\"", assemble_comd_filename) > co
  176.    printf( "\n\t%s %s\n\n", cc, assemble_comd_filename)
  177. if (debug)    printf( "\n\t%s %s\n\n", cc, assemble_comd_filename) >co
  178. }
  179. #
  180. function scanfile( filename,  # <- parameters
  181.                    glr)     { # <- local variables
  182.    # glr is a local variable: getline return value.
  183.    glr = getline <filename
  184.    if (glr == -1) { # Error opening file.. assume doesn't exist
  185.      printf( "\007AINCDEP.AWK error:  cannot open file %s\n", filename)  > co
  186.      if (use_fnexist) # Put it in list anyway, if you say so
  187.         addfile( filename,  flist )
  188.      return # Can't scan this file
  189.    }
  190.    # File has been found (its name is in filename) and opened.
  191.    addfile( filename, flist)
  192.    while (glr == 1) {
  193.       if ($0 ~ /^\$[^;]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][ \t]*\(.*\)/ ) {
  194.          extract_include_filename()
  195.          scanfile( $1)
  196.       }
  197.       if ($0 ~ /^\$[^;]*[Ii][Cc][ \t]*\(.*\)/ ) {
  198.          extract_ic_filename()
  199.          scanfile( $1)
  200.       }
  201.       glr = getline <filename
  202.    }
  203.    close( filename)
  204. }
  205. #
  206. function extract_include_filename() {
  207.    # Takes $0 as input; produces extracted filename in $1
  208.    if (debug>2)
  209.       printf( " extract_include_filename() entered: $0='%s'\n", $0) > co
  210.    # Delete "$...include(" from $0
  211.    # This forces re-parsing, making $1 into (unquoted) filename.
  212.    sub( /^\$[^;]*[Ii][Nn][Cc][Ll][Uu][Dd][Ee][ \t]*\([ \t]*/, "")
  213.    sub( /[ \t]*\).*$/, "")
  214.    # Filename, stripped of either type of quote char, is now $1 (also $0)
  215. }
  216. function extract_ic_filename() {
  217.    # Takes $0 as input; produces extracted filename in $1
  218.    if (debug>2)
  219.       printf( " extract_ic_filename() entered: $0='%s'\n", $0) > co
  220.    # Delete "$...ic(" from $0
  221.    # This forces re-parsing, making $1 into (unquoted) filename.
  222.    sub( /^\$[^;]*[Ii][Cc][ \t]*\([ \t]*/, "")
  223.    sub( /[ \t]*\).*$/, "")
  224.    # Filename, stripped of either type of quote char, is now $1 (also $0)
  225. }
  226.  
  227. function addfile( filename, flist,    flix) {
  228.    # filename is a string to be added to flist[]
  229.    # flist[] is an array of strings to which addfile() appends a file name
  230.    # flix is a (local) index into flist[]
  231.    for (flix=1; flix in flist; flix++)
  232.       if (flist[flix] == filename) # Already in list--
  233.          return                    #  don't add a duplicate
  234.    flist[flix] = filename
  235. }
  236. #
  237. function get_cl_param( parname,  # Which parameter ya lookin' fer? (e.g. "blah=")
  238.                        optional) # Is it an optional parameter?
  239. # Search the ARGV[] array for a command-line parameter beginning w/ parname
  240. # If optional is 0, aborts program if not found
  241. # Returns the string to the right of the '='
  242. {
  243.    for (i in ARGV)
  244.       if ( match(ARGV[i],parname) )
  245.          return substr( ARGV[i], length(parname)+1 )
  246.  
  247.    if (optional)
  248.       return ""
  249.  
  250.    printf( "pincdep.awk usage error:  Command-line parameter '%s' missing\n",
  251.            parname )                                                      > co
  252.    exit 1  # Abort
  253. }
  254. #
  255. function split_filename( name,        # In: The full file name
  256.                          shards,      # Out:array which receives ["path"],
  257.                                       #     ["name"] and ["ext"] members
  258.                          fname_chars, # In: Regular expression which matches
  259.                                       #     any single file-name character.
  260.                                       #     (must exclude directory separator)
  261.                          # Local variables:
  262.                          pnsep,       # Path/Name separator (1st char of Name)
  263.                          nesep)       # Name/Extension separator (1st Ext char)
  264.  
  265. # Split a file name into three components: Path, Name, and Extension 
  266. {
  267.    pnsep = match( name, fname_chars"*$")
  268.    shards["path"] = substr( name, 1, pnsep-1)
  269.    nesep = match( name, "\\."fname_chars"*$")
  270.    if (debug>2)
  271.       print "in \"" name "\", name starts @ " pnsep ", ext @ " nesep >co
  272.    if (nesep==0) {
  273.       shards["name"] = substr( name, pnsep)
  274.       shards["ext"] = ""
  275.    }
  276.    else {
  277.       shards["name"] = substr( name, pnsep, nesep-pnsep)
  278.       shards["ext"] = substr( name, nesep)
  279.    }
  280. }
  281.  
  282.  
  283.