home *** CD-ROM | disk | FTP | other *** search
/ The World of Computer Software / World_Of_Computer_Software-02-385-Vol-1of3.iso / t / tags18.zip / SHELL.C < prev    next >
C/C++ Source or Header  |  1992-05-03  |  45KB  |  1,194 lines

  1. /*
  2.  EPSHeader
  3.  
  4.    File: tags.c
  5.    Author: J. Kercheval
  6.    Created: Sun, 03/31/1991  14:59:48
  7. */
  8. /*
  9.  EPSRevision History
  10.  
  11.    J. Kercheval  Sun, 03/31/1991  16:24:01  creation
  12.    J. Kercheval  Sun, 03/31/1991  16:43:18  allow @filename listfile syntax
  13.    J. Kercheval  Tue, 05/14/1991  19:46:50  add tag_type
  14.    J. Kercheval  Wed, 05/15/1991  18:19:22  add -m and -o parameters
  15.    J. Kercheval  Wed, 05/15/1991  19:23:42  correctly parse for logfile
  16.    J. Kercheval  Wed, 05/15/1991  22:22:33  add the sort module
  17.    J. Kercheval  Thu, 05/16/1991  22:47:04  move file IO to fileio.c
  18.    J. Kercheval  Wed, 06/26/1991  23:03:55  move back to standard IO
  19.    J. Kercheval  Thu, 06/27/1991  21:43:11  create tags.h
  20.    J. Kercheval  Fri, 07/12/1991  23:04:23  revise command line parsing
  21.    J. Kercheval  Sat, 07/13/1991  11:29:02  update Usage()
  22.    J. Kercheval  Sat, 07/13/1991  12:47:34  finish argf parsing
  23.    J. Kercheval  Sat, 07/13/1991  13:06:16  move input routines to input.c
  24.    J. Kercheval  Sun, 07/14/1991  19:18:36  finish DoTags
  25.    J. Kercheval  Wed, 07/17/1991  22:18:58  allow append file logging
  26.    J. Kercheval  Thu, 07/18/1991  18:53:31  use fully qualified input pathname
  27.    J. Kercheval  Fri, 07/19/1991  20:15:43  allow sort only and non-sort options
  28.    J. Kercheval  Sun, 07/21/1991  17:38:00  add post processing
  29.    J. Kercheval  Mon, 07/22/1991  17:35:08  tweak log output and interface
  30.    J. Kercheval  Sat, 07/27/1991  20:38:36  remove ASM public flag and post processing hooks
  31.    J. Kercheval  Sat, 08/17/1991  23:03:47  enable c tagging
  32.    J. Kercheval  Sun, 08/25/1991  22:49:55  fix bug in ASM flag parsing
  33.    J. Kercheval  Thu, 08/29/1991  23:30:47  add CRC checking for virus check
  34.    J. Kercheval  Sat, 08/31/1991  23:56:02  add prototype flag
  35.    J. Kercheval  Thu, 09/05/1991  01:29:13  add input file name tracking
  36.    J. Kercheval  Thu, 09/05/1991  01:29:42  add -t flag
  37.    J. Kercheval  Thu, 09/05/1991  02:01:28  finish tag output logic
  38.    J. Kercheval  Thu, 09/05/1991  20:07:45  move arglist processing to seperate module
  39.    J. Kercheval  Thu, 09/05/1991  20:13:50  move MergeFile() to tagio.c
  40.    J. Kercheval  Tue, 09/10/1991  23:24:27  add ctrl-c handler
  41.    J. Kercheval  Wed, 09/11/1991  01:45:35  add usage comments for extern switch
  42.    J. Kercheval  Tue, 09/17/1991  19:43:23  add support for case_sensitive flag
  43.    J. Kercheval  Wed, 09/25/1991  13:42:28  support sorted arglists
  44.    J. Kercheval  Wed, 09/25/1991  16:02:18  check for duplicate file names at the command line level
  45.    J. Kercheval  Wed, 09/25/1991  22:47:37  supress tag file merge if not input files found
  46.    J. Kercheval  Tue, 10/01/1991  19:30:26  close all open files in external_cleanup()
  47.    J. Kercheval  Thu, 10/03/1991  13:55:09  add exclude file processing
  48.    J. Kercheval  Thu, 10/03/1991  16:46:07  improve list file parsing
  49.    J. Kercheval  Sat, 10/05/1991  10:56:18  add switch summary to usage
  50.    J. Kercheval  Sat, 04/25/1992  01:36:19  add junk tagging for C
  51. */
  52.  
  53. #include <stdlib.h>
  54. #include <stdio.h>
  55. #include <string.h>
  56. #include <time.h>
  57. #include <signal.h>
  58.  
  59. #include "flags.h"
  60. #include "log.h"
  61. #include "wildfile.h"
  62. #include "sort.h"
  63. #include "ctag.h"
  64. #include "asmtag.h"
  65. #include "tagio.h"
  66. #include "viruscrc.h"
  67. #include "arglist.h"
  68.  
  69.  
  70. #define Author "J. Kercheval"
  71. #define Version "Tags Generator V1.8"
  72. #define CompileDate __TIMESTAMP__
  73.  
  74.  
  75. /* The following variables are pointers to the temporary filenames used as
  76.  * an intermediary files.  These are globals for use in external_cleanup()
  77.  * to delete any temporary files. */
  78. char *tmp_filename = NULL;
  79. char *tmp_tagfilename = NULL;
  80.  
  81.  
  82. /*----------------------------------------------------------------------------
  83.  *
  84.  * Print Usage
  85.  *
  86.  ---------------------------------------------------------------------------*/
  87.  
  88. void Usage(char *fname)
  89. {
  90.  
  91.     fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
  92.     fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
  93.             fname);
  94.     fprintf(stdout, "  -h,-? for extended usage output to stdout\n");
  95.     fprintf(stdout, "  @LISTFILE for list file of input file names\n");
  96.     fprintf(stdout, "  -x{EXCLUDEFILE|@LISTFILE} to exclude files\n");
  97.     fprintf(stdout, "  -tTAGFILE to merge to a particular tag file\n");
  98.     fprintf(stdout, "  -lLOGFILE for log file (-l overwrites, -L appends)\n");
  99.     fprintf(stdout, "  -o[e5gsm] for output format\n");
  100.     fprintf(stdout, "  -a[fdlmsu] to specify assembly tagging\n");
  101.     fprintf(stdout, "  -c[dmstekuvcfpxi] to specify C tagging\n");
  102.     fprintf(stdout, "  -j will suppress junk output filter\n");
  103.     fprintf(stdout, "  -q will suppress normal status output\n");
  104.     fprintf(stdout, "  -r use relative pathnames in output\n");
  105.     fprintf(stdout, "  -n do not sort the tag output\n");
  106.     fprintf(stdout, "  -i use a case sensitive sort\n");
  107.     fprintf(stdout, "  -m for merge sort of the existing sorted files\n");
  108.     fprintf(stdout, "  -s sort input files only\n");
  109.     
  110.     exit(1);
  111. }
  112.  
  113.  
  114. /*----------------------------------------------------------------------------
  115.  *
  116.  * Print Extended Usage
  117.  *
  118.  ---------------------------------------------------------------------------*/
  119.  
  120. void Help(char *fname)
  121. {
  122.     char usage[][85] =
  123.     {
  124.         "  -h or -? to obtain this help screen\n",
  125.         "  @LISTFILE for list file of input file names.  A list file is in the form",
  126.         "     of a response file (ie. a list of files seperated by some delimiter).",
  127.         "     The allowed delimiters for file seperation are '+', ',', ';' and normal",
  128.         "     whitespace.  This file allows commented lines by preceding any comment",
  129.         "     with a pound sign (#).  A comment is from the '#' to the end of the",
  130.         "     line and may start after any whitespace character\n",
  131.         "  -x{EXCLUDEFILE|@LISTFILE} excludes the files specified by EXCLUDEFILE",
  132.         "     or exclude all files listed in LISTFILE.\n",
  133.         "  -tTAGFILE to output to a (possibly existing) tag file and will result in",
  134.         "     previous tags for input files being removed from the output file.",
  135.         "     This tagfile is assumed to be in one of this utilities output formats.",
  136.         "     if -m or -s are used this switch is ignored (all output is to stdout).\n",
  137.         "  -lLOGFILE for output to a log file in a LISTFILE format suitable as input.",
  138.         "    behavior regarding existing files is determined by the case of the switch.",
  139.         "    -l  creates and outputs to a file overwriting any currently existing file",
  140.         "    -L  appends all output to the logfile if there is an already existing file\n",
  141.         "  -o[options] for output format to stdout or the tag file if -t switch is used",
  142.         "     e  Epsilon >= V6.0  ( tokenString \\t fileName \\t characterOffset \\t line )",
  143.         "     5  Epsilon <= V5.03 ( tokenString;fileName;characterOffset )",
  144.         "     g  GNU tag          ( tokenString \\t fileName \\t /$line^/ )",
  145.         "     s  Space-Delimited  ( tokenString fileName lineNumber )",
  146.         "     m  MicroSoft Error  ( tokenString fileName(lineNumber) )\n",
  147.         "  -a[options] to specify assembly tagging and to detail the token types.",
  148.         "     Default tagging is -afdlmsu (80x86 assembly using MASM/TASM syntax)",
  149.         "     f  procedure labels       ( token proc )( proc token )",
  150.         "     d  definition labels      ( token equ const )( token db declaration )",
  151.         "     l  local labels           ( token label )( label token )( token: )",
  152.         "     m  macro labels           ( token macro )( macro token )",
  153.         "     s  struc labels           ( token struc )( struc token )",
  154.         "     u  union labels           ( token union )( union token )\n",
  155.         "  -c[options] to specify C tagging and to detail the token types. Default",
  156.         "     tagging options are -cdmstekuvcfpxi (standard ANSI 2.0 C/C++). Note that",
  157.         "     use of the -cx and the -ci switch are modifiers and will only be effective",
  158.         "     when other options are used (ie. -cpx must be specified to obtain extern",
  159.         "     prototypes, -cx alone yields nothing).  Note that the -cx and -ci modifier",
  160.         "     has no effect for define and macro tags which are tagged only according",
  161.         "     to the -cd and -cm switches respectively.  Additionally the -cx modifier",
  162.         "     is ignored for function tags.  The order of all of these options is not",
  163.         "     significant.",
  164.         "     d  defines                ( #define token statement )",
  165.         "     m  macro labels           ( #define token() statement )",
  166.         "     s  struct globals         ( struct token {} )",
  167.         "     t  typedef globals        ( typedef declaration token, token, ... )",
  168.         "     e  enum globals           ( enum token {} )",
  169.         "     k  enum konstants         ( enum { token, token, token, ...} )",
  170.         "     u  union globals          ( union token {} )",
  171.         "     v  global variable        ( declaration token, token = {}, token, ... )",
  172.         "     c  global class           ( class token: {} )",
  173.         "     f  function definitions   ( token() declaration {} )",
  174.         "     p  prototypes             ( token(, )",
  175.         "     i  static declarations    ( static declaration )",
  176.         "     x  extern defines         ( extern declaration )",
  177.         "                               ( extern \"C\" declaration )",
  178.         "                               ( extern \"C\" { declaration; declaration; ... } )\n",
  179.         "  -j will suppress junk filtering used during token output",
  180.         "  -q will suppress normal output to stderr and program version information",
  181.         "  -r use relative pathnames in output rather than fully qualified path names",
  182.         "  -n do not sort the tag output (Often used in conjunction with GNU style tags)",
  183.         "  -i use a case sensitive sort (Normally a case insensitive sort is used)\n",
  184.         "  The following result only in sorting of the input files (no tagging is done).",
  185.         "     Output is to stdout only (-t is ignored) when using these switches.",
  186.         "     -m for merge sort of the specified existing files (assumed to be sorted)",
  187.         "     -s sort input files only, all files are assumed to be in an unsorted state\n",
  188.         "  The TMP environment variable is used for temporary files.  The default for",
  189.         "     tags is to use C style tagging, the Epsilon tag file format, to sort",
  190.         "     the output before finally placing it in the output file (or stdout if -t",
  191.         "     is not used) and to be verbose and log activity to stderr.",
  192.         "  Each file specified on the command line or within a LISTFILE will be tagged",
  193.         "     only once regardless of the number of times it appears on the command",
  194.         "     line (This includes LISTFILEs as well as filenames and the files listed",
  195.         "     within LISTFILEs).",
  196.         "  All of the switches may be specified anywhere on the command line and with",
  197.         "     the exception of the style switches (-a, -c) are not position dependent.",
  198.         "     The style switches are active only for input files which fall after them",
  199.         "     on the command line and allows the specification of different tagging",
  200.         "     styles and types on a file by file basis.",
  201.         "  Input file and LISTFILE specifications allow the use of *IX shell style",
  202.         "     expressions (A subset of the standard UNIX regular expression syntax).",
  203.         "     This allows input file names such as \"*\", \"*t?*.c\" and \"*[e-gxyz]*\".",
  204.         "     Note that \"*\" in this case is completely equivalent to \"*.*\" in normal",
  205.         "     DOS usage. The use of \"*.\" will obtain files without extensions.",
  206.         "  This utility performs a CRC validation on itself to prevent corruption and",
  207.         "     viral infection from outside influences.  Modification of this file in",
  208.         "     any way will result in a failure of the internal CRC check.  On CRC",
  209.         "     failure the program will exit with a warning message.",
  210.         "\0"
  211.     };
  212.  
  213.     int i;                      /* index into help text array */
  214.  
  215.     fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
  216.     fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
  217.             fname);
  218.  
  219.     for (i = 0; usage[i][0]; i++) {
  220.         fprintf(stdout, "%s\n", usage[i]);
  221.     }
  222.  
  223.     exit(1);
  224. }
  225.  
  226.  
  227. /*----------------------------------------------------------------------------
  228.  *
  229.  * external_cleanup() removes the temporary file used here
  230.  *
  231.  ---------------------------------------------------------------------------*/
  232.  
  233. void external_cleanup(void)
  234. {
  235.     fcloseall();
  236.     if (tmp_filename != NULL)
  237.         remove(tmp_filename);
  238.     if (tmp_tagfilename != NULL)
  239.         remove(tmp_tagfilename);
  240. }
  241.  
  242.  
  243. /*----------------------------------------------------------------------------
  244.  *
  245.  * CtrlCHandler() cleans up and aborts
  246.  *
  247.  ---------------------------------------------------------------------------*/
  248.  
  249. void __cdecl CtrlCHandler(int sig)
  250. {
  251.     /* Disallow CTRL+C during handler. */
  252.     signal(SIGINT, SIG_IGN);
  253.  
  254.     /* cleanup and abort */
  255.     external_cleanup();
  256.     abort();
  257. }
  258.  
  259.  
  260. /*----------------------------------------------------------------------------
  261.  *
  262.  * nextfile takes the list_file parameter and finds the next filename from
  263.  * the opened listfile.
  264.  *
  265.  ---------------------------------------------------------------------------*/
  266.  
  267. BOOLEAN nextfile(FILE * list_file, char *fname, int max_length)
  268. {
  269.     char white[] =
  270.     {
  271.         " \t\n\f\v\b\r,+;#"
  272.     };                          /* valid whitespace characters */
  273.  
  274.     char delim[] =
  275.     {
  276.         " \t\n\f\v\b\r,+;"
  277.     };                          /* end of filename characters */
  278.  
  279.     char *s;                    /* temporary char pointer */
  280.     char c;                     /* temporary char variable */
  281.  
  282.     int length;                 /* current length of fname */
  283.  
  284.     /* init */
  285.     s = fname;
  286.     *s = '\0';
  287.     length = 0;
  288.  
  289.     c = (char) fgetc(list_file);
  290.  
  291.     /* if end of file then we are done */
  292.     if (feof(list_file))
  293.         return FALSE;
  294.  
  295.     /* pass over whitespace */
  296.     while (strchr(white, c)) {
  297.         if (c == '#') {
  298.             while (c != '\n') {
  299.                 c = (char) fgetc(list_file);
  300.                 if (feof(list_file))
  301.                     return FALSE;
  302.             }
  303.         }
  304.         c = (char) fgetc(list_file);
  305.         if (feof(list_file))
  306.             return FALSE;
  307.     }
  308.  
  309.     /* get the filename */
  310.     while (!strchr(delim, c)) {
  311.  
  312.         /* don't add to fname if maximum length reached */
  313.         if (length < max_length - 1) {
  314.             *s++ = c;
  315.             length++;
  316.         }
  317.         c = (char) fgetc(list_file);
  318.         if (feof(list_file)) {
  319.             *s = '\0';
  320.             return TRUE;
  321.         }
  322.     }
  323.  
  324.     /* success */
  325.     *s = '\0';
  326.     return TRUE;
  327. }
  328.  
  329.  
  330. /*----------------------------------------------------------------------------
  331.  *
  332.  * Process() tags the input stream from the input file and outputs to a
  333.  * temporary file which is registered in argf.
  334.  *
  335.  ---------------------------------------------------------------------------*/
  336.  
  337. void Process(FILE * infile, char *infname, FILE * outfile, Flags * flags)
  338. {
  339.     /* log the input filename */
  340.     log_message(infname);
  341.  
  342.     switch (flags->tag_type) {
  343.  
  344.         case C:         /* use C type parsing */
  345.             CTags(infile, infname, outfile, flags);
  346.             break;
  347.  
  348.         case ASM:               /* use ASM type parsing */
  349.             ASMTags(infile, infname, outfile, flags);
  350.             break;
  351.  
  352.         default:
  353.             break;
  354.     }
  355. }
  356.  
  357.  
  358. /*----------------------------------------------------------------------------
  359.  *
  360.  * SingleFileProcess() tags a single file and outputs to a temporary file
  361.  * registered in argf.  Wildcards are allowed as file names.
  362.  *
  363.  ---------------------------------------------------------------------------*/
  364.  
  365. void SingleFileProcess(char *pathname, Flags * flags,
  366.                         FILE * outfile, ArgList argInput,
  367.                         ArgList argInputRaw)
  368. {
  369.     char fname[MAXPATH + 1];    /* the current file name */
  370.     char full_pathname[MAXPATH + 1];    /* the full path and filename */
  371.     char tmpstr[2 * MAXPATH + 1];       /* error string */
  372.  
  373.     struct file_info_struct ff; /* the file find structure */
  374.  
  375.     FILE *input_file;           /* the input file being worked on */
  376.  
  377.     /* initialize ff */
  378.     strcpy(ff.file_pattern, pathname);
  379.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  380.         _FA_HIDDEN | _FA_SYSTEM;
  381.  
  382.     /* find the initial file matching pattern */
  383.     if (!find_firstfile(&ff)) {
  384.  
  385.         /* bad file name */
  386.         sprintf(tmpstr, "# Could not find the file '%s'", pathname);
  387.         log_message(tmpstr);
  388.     }
  389.     else {
  390.  
  391.         /* loop through all matching files in the parameter */
  392.         do {
  393.  
  394.             /* make the file name */
  395.             strcpy(fname, ff.file_path);
  396.             strcat(fname, ff.file.name);
  397.  
  398.             /* get the fully qualified pathname if wanted */
  399.             if (!flags->use_relative_pathnames) {
  400.                 _fullpath(full_pathname, fname, MAXPATH);
  401.             }
  402.             else {
  403.                 strcpy(full_pathname, fname);
  404.             }
  405.  
  406.             /* convert pathname to lower case */
  407.             strlwr(full_pathname);
  408.  
  409.             /* register the original input file name after verifying that we
  410.              * have not previously processed this file */
  411.             if (!ArgIsMember(argInputRaw, full_pathname)) {
  412.  
  413.                 ArgRegisterName(argInput, full_pathname);
  414.                 ArgRegisterName(argInputRaw, full_pathname);
  415.  
  416.                 /* Try to open the file */
  417.                 if ((input_file = fopen(fname, "r")) == (FILE *) NULL) {
  418.                     sprintf(tmpstr,
  419.                             "# Could not open %s for Tagging", fname);
  420.                     log_message(tmpstr);
  421.                 }
  422.                 else {
  423.  
  424.                     /* perform the needed tagging function */
  425.                     Process(input_file, full_pathname, outfile, flags);
  426.  
  427.                     /* close the input file */
  428.                     fclose(input_file);
  429.                 }
  430.             }
  431.  
  432.         } while (find_nextfile(&ff));
  433.     }
  434. }
  435.  
  436.  
  437. /*----------------------------------------------------------------------------
  438.  *
  439.  * BatchFileProcess() tags a list of files within the file given.  Wildcards
  440.  * are allowed in the listing file and as the listing file name.
  441.  *
  442.  ---------------------------------------------------------------------------*/
  443.  
  444. void BatchFileProcess(char *pathname, Flags * flags,
  445.                        FILE * outfile, ArgList argInput,
  446.                        ArgList argInputRaw)
  447. {
  448.     FILE *list_file;            /* file with list of files */
  449.  
  450.     char list_filename[MAXPATH + 1];    /* the current file name */
  451.     char input_filename[MAXPATH + 1];   /* the current file name */
  452.     char tmpstr[2 * MAXPATH + 1];       /* error string */
  453.     struct file_info_struct ff; /* the file find structure */
  454.  
  455.     /* initialize ff */
  456.     strcpy(ff.file_pattern, pathname);
  457.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  458.         _FA_HIDDEN | _FA_SYSTEM;
  459.  
  460.     /* find the initial file matching pattern */
  461.     if (!find_firstfile(&ff)) {
  462.  
  463.         /* bad file name */
  464.         sprintf(tmpstr,
  465.                 "# Could not find the listfile '%s'", pathname);
  466.         log_message(tmpstr);
  467.     }
  468.     else {
  469.  
  470.         /* loop through all available list files with pathname */
  471.         do {
  472.  
  473.             /* make the file name */
  474.             strcpy(list_filename, ff.file_path);
  475.             strcat(list_filename, ff.file.name);
  476.  
  477.             /* open the list file and parse the file */
  478.             if ((list_file = fopen(list_filename, "r")) ==
  479.                 (FILE *) NULL) {
  480.                 sprintf(tmpstr,
  481.                         "# Could not open %s as a listfile", list_filename);
  482.                 log_message(tmpstr);
  483.             }
  484.             else {
  485.  
  486.                 /* output the file we are parsing */
  487.                 sprintf(tmpstr,
  488.                         "# Opening listfile %s", list_filename);
  489.                 log_message(tmpstr);
  490.  
  491.                 /* loop while there are more filenames in the file */
  492.                 while (nextfile(list_file, input_filename, MAXPATH + 1)) {
  493.  
  494.                     /* do not tag this file set if seen before */
  495.                     if (!ArgIsMember(argInputRaw, input_filename)) {
  496.  
  497.                         /* tag the obtained file path */
  498.                         SingleFileProcess(input_filename, flags,
  499.                                           outfile, argInput, argInputRaw);
  500.  
  501.                         /* register the input file as seen in the list file */
  502.                         ArgRegisterArg(argInputRaw, input_filename);
  503.                     }
  504.                 }
  505.  
  506.                 /* close the list file */
  507.                 fclose(list_file);
  508.             }
  509.         } while (find_nextfile(&ff));
  510.     }
  511. }
  512.  
  513.  
  514. /*----------------------------------------------------------------------------
  515.  *
  516.  * SingleFileExclude() places a single file into argInputRaw ArgList to
  517.  * exclude a file from further processing.  Wildcards are allowed as file
  518.  * names.
  519.  *
  520.  ---------------------------------------------------------------------------*/
  521.  
  522. void SingleFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
  523. {
  524.     char fname[MAXPATH + 1];    /* the current file name */
  525.     char full_pathname[MAXPATH + 1];    /* the full path and filename */
  526.     struct file_info_struct ff; /* the file find structure */
  527.  
  528.     /* initialize ff */
  529.     strcpy(ff.file_pattern, pathname);
  530.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  531.         _FA_HIDDEN | _FA_SYSTEM;
  532.  
  533.     /* find the initial file matching pattern */
  534.     if (find_firstfile(&ff)) {
  535.  
  536.         /* loop through all matching files in the parameter */
  537.         do {
  538.  
  539.             /* make the file name */
  540.             strcpy(fname, ff.file_path);
  541.             strcat(fname, ff.file.name);
  542.  
  543.             /* get the fully qualified pathname if wanted */
  544.             if (!flags->use_relative_pathnames) {
  545.                 _fullpath(full_pathname, fname, MAXPATH);
  546.             }
  547.             else {
  548.                 strcpy(full_pathname, fname);
  549.             }
  550.  
  551.             /* convert pathname to lower case */
  552.             strlwr(full_pathname);
  553.  
  554.             /* register the original input file name after verifying that we
  555.              * have not previously processed this file */
  556.             if (!ArgIsMember(argInputRaw, full_pathname)) {
  557.  
  558.                 ArgRegisterName(argInputRaw, full_pathname);
  559.             }
  560.  
  561.         } while (find_nextfile(&ff));
  562.     }
  563. }
  564.  
  565.  
  566. /*----------------------------------------------------------------------------
  567.  *
  568.  * BatchFileExclude() places a list of files within the argInputRaw ArgList
  569.  * to inhibit processing of those files.  Wildcards are allowed in the
  570.  * listing file and as the listing file name.
  571.  *
  572.  ---------------------------------------------------------------------------*/
  573.  
  574. void BatchFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
  575. {
  576.     FILE *list_file;            /* file with list of files */
  577.  
  578.     char list_filename[MAXPATH + 1];    /* the current file name */
  579.     char input_filename[MAXPATH + 1];   /* the current file name */
  580.     struct file_info_struct ff; /* the file find structure */
  581.  
  582.     /* initialize ff */
  583.     strcpy(ff.file_pattern, pathname);
  584.     ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
  585.         _FA_HIDDEN | _FA_SYSTEM;
  586.  
  587.     /* find the initial file matching pattern */
  588.     if (!find_firstfile(&ff)) {
  589.  
  590.         /* bad file name */
  591.         fprintf(stderr,
  592.                 "# Could not find the Exclude listfile '%s'", pathname);
  593.         exit(1);
  594.     }
  595.     else {
  596.  
  597.         /* loop through all available list files with pathname */
  598.         do {
  599.  
  600.             /* make the file name */
  601.             strcpy(list_filename, ff.file_path);
  602.             strcat(list_filename, ff.file.name);
  603.  
  604.             /* open the list file and parse the file */
  605.             if ((list_file = fopen(list_filename, "r")) ==
  606.                 (FILE *) NULL) {
  607.                 fprintf(stderr,
  608.                         "# Could not open %s as an Exclude listfile",
  609.                         list_filename);
  610.                 exit(1);
  611.             }
  612.             else {
  613.  
  614.                 /* make the file name */
  615.                 strcpy(list_filename, ff.file_path);
  616.                 strcat(list_filename, ff.file.name);
  617.  
  618.                 /* loop while there are more filenames in the file */
  619.                 while (nextfile(list_file, input_filename, MAXPATH + 1)) {
  620.  
  621.                     /* do not register this file set if seen before */
  622.                     if (!ArgIsMember(argInputRaw, input_filename)) {
  623.  
  624.                         /* exclude the obtained file path */
  625.                         SingleFileExclude(input_filename, flags, argInputRaw);
  626.  
  627.                         /* register the input file as seen in the list file */
  628.                         ArgRegisterArg(argInputRaw, input_filename);
  629.                     }
  630.                 }
  631.  
  632.                 /* close the list file */
  633.                 fclose(list_file);
  634.             }
  635.  
  636.         } while (find_nextfile(&ff));
  637.     }
  638. }
  639.  
  640.  
  641. /*----------------------------------------------------------------------------
  642.  *
  643.  * Validate() calls the CRC validation routines and exits with a warning if
  644.  * there are problems.
  645.  *
  646.  ---------------------------------------------------------------------------*/
  647.  
  648. void Validate(char *filename)
  649. {
  650.     /* validate the executable against the internally stored CRC */
  651.     switch (validatecrc(filename)) {
  652.  
  653.             case CRC_VALID:
  654.  
  655.             break;
  656.  
  657.         case CRC_INVALID:
  658.         case CRC_ISZERO:
  659.  
  660.             /* internal failure */
  661.             fprintf(stderr,
  662.                     "This executable fails internal CRC checking due to ");
  663.             fprintf(stderr,
  664.                     "external modification. \n");
  665.             fprintf(stderr,
  666.                     "Please validate this copy and scan for virus ");
  667.             fprintf(stderr, "infection.\n");
  668.             exit(1);
  669.             break;
  670.  
  671.         case CRC_NOMEM:
  672.  
  673.             fprintf(stderr,
  674.                     "Error - Out of Memory\n");
  675.             exit(1);
  676.             break;
  677.  
  678.         case CRC_FILEERR:
  679.  
  680.             fprintf(stderr,
  681.                     "Error - Program file not found\n");
  682.             exit(1);
  683.             break;
  684.  
  685.         default:
  686.  
  687.             break;
  688.     }
  689. }
  690.  
  691.  
  692. /*----------------------------------------------------------------------------
  693.  *
  694.  * main loops through the parameter list and calls the appropriate parsers
  695.  *
  696.  ---------------------------------------------------------------------------*/
  697.  
  698. int __cdecl main(int argc, char *argv[])
  699. {
  700.     Flags flags;
  701.  
  702.     char log_filename[MAXPATH]; /* log file name */
  703.     char output_filename[MAXPATH];      /* the tag file to output to */
  704.     char tmpstr[2 * MAXPATH + 1];       /* error and temp string */
  705.  
  706.     char *environ_ptr;          /* holds pointer to TMP variable */
  707.     int environ_len;            /* holds length of TMP variable */
  708.  
  709.     ArgList argSort;            /* the list of files sent to sort */
  710.     ArgList argInput;           /* the list of input files */
  711.     ArgList argInputRaw;        /* the list of command line input files and
  712.                                  * files which are excluded */
  713.  
  714.     struct tm *now;             /* clock variables */
  715.     time_t cur_clock;
  716.  
  717.     unsigned int i;             /* temp looping var */
  718.     int switch_count;           /* the number of switches found */
  719.  
  720.     char drive[5], dir[255], fname[10], ext[5];
  721.  
  722.     FILE *output_stream;        /* the output stream */
  723.     FILE *tag_stream;           /* the stream for temporary output */
  724.  
  725.     /* Register CTRL+C handler. */
  726.     signal(SIGINT, CtrlCHandler);
  727.  
  728.     /* validate the executable against the internally stored CRC */
  729.     Validate(argv[0]);
  730.  
  731.     /* obtain parts of the startup path */
  732.     _splitpath(argv[0], drive, dir, fname, ext);
  733.  
  734.     /* if not enough parameters than Usage() */
  735.     if (argc < 2)
  736.         Usage(fname);
  737.  
  738.     /* compute the current time */
  739.     time(&cur_clock);
  740.     now = localtime(&cur_clock);
  741.  
  742.     /* initialize flags structure */
  743.     init_flags(&flags);
  744.  
  745.     /* the initial file stuff */
  746.     log_filename[0] = '\0';
  747.     output_filename[0] = '\0';
  748.     output_stream = stdout;
  749.  
  750.     /* get the TMP environment variable */
  751.     environ_ptr = getenv("TMP");
  752.     environ_len = strlen(environ_ptr);
  753.  
  754.     /* obtain the intermediate tag filename */
  755.     if (environ_len &&
  756.         environ_ptr[environ_len - 1] != '\\' &&
  757.         environ_ptr[environ_len - 1] != '/')
  758.         tmp_tagfilename = tempnam("\\", "tg");
  759.     else
  760.         tmp_tagfilename = tempnam("", "tg");
  761.  
  762.     /* verify filename allocation */
  763.     if (tmp_tagfilename == NULL) {
  764.         fprintf(stderr, "# Could not create temporary files for output");
  765.         exit(1);
  766.     }
  767.  
  768.     /* init arglist variable */
  769.     argSort = CreateArgList(ARGLIST_NORMAL);
  770.     argInput = CreateArgList(ARGLIST_SORTED);
  771.     argInputRaw = CreateArgList(ARGLIST_SORTED);
  772.  
  773.     /* preparse for global switches */
  774.     switch_count = 0;
  775.     for (i = 1; i < (unsigned) argc; i++) {
  776.  
  777.         switch (argv[i][0]) {
  778.  
  779.             case '/':
  780.             case '-':
  781.                 switch_count++;
  782.                 switch (argv[i][1]) {
  783.                     case 'l':   /* tag from file list */
  784.                     case 'L':
  785.  
  786.                         /* filename must hug the switch */
  787.                         if (strlen(argv[i] + 2)) {
  788.                             strcpy(log_filename, argv[i] + 2);
  789.                         }
  790.                         else {
  791.                             fprintf(stderr,
  792.                                     "# -l switch used incorrectly\n");
  793.                             exit(1);
  794.                         }
  795.  
  796.                         /* set overwrite flag */
  797.                         if (argv[i][1] == 'l') {
  798.                             flags.log_overwrite = TRUE;
  799.                         }
  800.                         else {
  801.                             flags.log_overwrite = FALSE;
  802.                         }
  803.  
  804.                         break;
  805.  
  806.                     case 't':   /* send to tag file */
  807.                     case 'T':
  808.  
  809.                         /* filename must hug the switch */
  810.                         if (strlen(argv[i] + 2)) {
  811.                             strcpy(output_filename, argv[i] + 2);
  812.                             if (environ_len &&
  813.                                 environ_ptr[environ_len - 1] != '\\' &&
  814.                                 environ_ptr[environ_len - 1] != '/')
  815.                                 tmp_filename = tempnam("\\", "tg");
  816.                             else
  817.                                 tmp_filename = tempnam("", "tg");
  818.  
  819.                             /* verify filename allocation */
  820.                             if (tmp_filename == NULL) {
  821.                                 fprintf(stderr,
  822.                                         "# Could not create temporary files for output");
  823.                                 exit(1);
  824.                             }
  825.                         }
  826.                         else {
  827.                             fprintf(stderr,
  828.                                     "# -t switch used incorrectly\n");
  829.                             exit(1);
  830.                         }
  831.  
  832.                         /* set output flag */
  833.                         flags.output_file = TRUE;
  834.                         break;
  835.  
  836.                     case 'j':   /* do not use junk filters */
  837.                     case 'J':
  838.  
  839.                         flags.filter_junk = FALSE;
  840.                         break;
  841.  
  842.                     case 'n':   /* do not sort the output */
  843.                     case 'N':
  844.  
  845.                         /* set tag_type */
  846.                         flags.sort_tags = FALSE;
  847.                         break;
  848.  
  849.                     case 'm':   /* merge files only */
  850.                     case 'M':
  851.  
  852.                         /* set tag_type */
  853.                         flags.tag_type = MERGE;
  854.                         break;
  855.  
  856.                     case 's':   /* sort files only */
  857.                     case 'S':
  858.  
  859.                         /* set tag_type */
  860.                         flags.tag_type = SORT;
  861.                         break;
  862.  
  863.                     case 'o':   /* output format specifier follows */
  864.                     case 'O':   /* the last format found is the one */
  865.  
  866.                         /* set the option modifier */
  867.                         parse_output_flags(argv[i], &flags);
  868.                         break;
  869.  
  870.                     case 'r':   /* output format specifier follows */
  871.                     case 'R':   /* the last format found is the one */
  872.  
  873.                         /* set to use relative pathnames */
  874.                         flags.use_relative_pathnames = TRUE;
  875.                         break;
  876.  
  877.                     case 'q':   /* use quiet mode (no logging to stderr) */
  878.                     case 'Q':
  879.                         flags.quiet = TRUE;
  880.                         break;
  881.  
  882.                     case 'i':   /* use case sensitive sort */
  883.                     case 'I':
  884.                         flags.case_sensitive = TRUE;
  885.                         break;
  886.  
  887.                     case 'x':   /* exclude this file or filelist */
  888.                     case 'X':
  889.                         /* filename must hug the switch */
  890.                         if (!strlen(argv[i] + 2)) {
  891.                             fprintf(stderr,
  892.                                     "# -x switch used incorrectly\n");
  893.                             exit(1);
  894.                         }
  895.                         else {
  896.  
  897.                             /* check if list file exclude or normal file
  898.                              * exclude */
  899.  
  900.                             if (argv[i][2] != '@') {
  901.  
  902.                                 /* this is a particular exclusion */
  903.                                 /* do not use this Exclude file if seen
  904.                                  * previously */
  905.                                 if (!ArgIsMember(argInputRaw, argv[i] + 2)) {
  906.  
  907.                                     /* process the Exclude file */
  908.                                     SingleFileExclude(argv[i] + 2, &flags,
  909.                                                       argInputRaw);
  910.  
  911.                                     /* register the input list file as seen
  912.                                      * on the command line */
  913.                                     ArgRegisterArg(argInputRaw, argv[i] + 2);
  914.                                 }
  915.                             }
  916.                             else {
  917.  
  918.                                 /* this is an exclusion list file */
  919.                                 if (strlen(argv[i] + 3)) {
  920.  
  921.                                     /* do not use this Exclude list file if
  922.                                      * seen previously */
  923.                                     if (!ArgIsMember(argInputRaw,
  924.                                                      argv[i] + 3)) {
  925.  
  926.                                         /* process the list file */
  927.                                         BatchFileExclude(argv[i] + 3, &flags,
  928.                                                          argInputRaw);
  929.  
  930.                                         /* register the input list file as
  931.                                          * seen on the command line */
  932.                                         ArgRegisterArg(argInputRaw,
  933.                                                        argv[i] + 3);
  934.                                     }
  935.                                 }
  936.                                 else {
  937.                                     fprintf(stderr,
  938.                                             "# @ syntax error");
  939.                                     exit(1);
  940.                                 }
  941.                             }
  942.                         }
  943.                         break;
  944.  
  945.                     case 'h':
  946.                     case 'H':
  947.                     case '?':
  948.                         Help(fname);
  949.                         break;
  950.  
  951.                     default:
  952.                         break;
  953.                 }
  954.                 break;
  955.  
  956.             default:
  957.                 break;
  958.         }
  959.     }
  960.  
  961.     /* exit if no input files specified */
  962.     if (switch_count == argc - 1) {
  963.         fprintf(stderr,
  964.                 "# No input files specified\n");
  965.         exit(1);
  966.     }
  967.  
  968.     /* open the log file */
  969.     if (!log_open(log_filename, flags.quiet, flags.log_overwrite)) {
  970.         fprintf(stderr,
  971.                 "# Could not open %s as a logfile\n", log_filename);
  972.         exit(1);
  973.     }
  974.  
  975.     /* open the temporary tag file */
  976.     if ((tag_stream = fopen(tmp_tagfilename, "w")) ==
  977.         (FILE *) NULL) {
  978.         sprintf(tmpstr,
  979.                 "# Internal error opening temporary files");
  980.         log_message(tmpstr);
  981.         exit(1);
  982.     }
  983.  
  984.     /* print initial messages */
  985.     sprintf(tmpstr, "# %s %s -- %s", Version, CompileDate, Author);
  986.     log_message(tmpstr);
  987.     sprintf(tmpstr, "# Tagging performed: %s#", asctime(now));
  988.     log_message(tmpstr);
  989.  
  990.     if (flags.tag_type == MERGE) {
  991.         log_message("# Merging previously processed tag files");
  992.     }
  993.  
  994.     if (flags.tag_type == SORT) {
  995.         log_message("# Sorting input files only");
  996.     }
  997.  
  998.     /* enter the main loop */
  999.     for (argc--, argv++; argc; argc--, argv++) {
  1000.  
  1001.         /* parse the argument list */
  1002.         switch (argv[0][0]) {
  1003.             case '@':
  1004.                 if (strlen(argv[0] + 1)) {
  1005.  
  1006.                     /* do not use this list file if seen previously */
  1007.                     if (!ArgIsMember(argInputRaw, argv[0] + 1)) {
  1008.  
  1009.                         /* process the list file */
  1010.                         BatchFileProcess(argv[0] + 1, &flags,
  1011.                                          tag_stream, argInput,
  1012.                                          argInputRaw);
  1013.  
  1014.                         /* register the input list file as seen on the
  1015.                          * command line */
  1016.                         ArgRegisterArg(argInputRaw, argv[0] + 1);
  1017.                     }
  1018.                     break;
  1019.                 }
  1020.                 else {
  1021.                     log_message("# @ syntax error");
  1022.                 }
  1023.                 break;
  1024.  
  1025.             case '/':
  1026.             case '-':
  1027.                 switch (argv[0][1]) {
  1028.                     case 'a':   /* use ASM tagging scheme */
  1029.                     case 'A':
  1030.  
  1031.                         /* ignore if merge or sort tag_types */
  1032.                         if (flags.tag_type != MERGE &&
  1033.                             flags.tag_type != SORT) {
  1034.  
  1035.                             /* set the option flags */
  1036.                             parse_ASM_flags(*argv, &flags);
  1037.                         }
  1038.                         break;
  1039.  
  1040.                     case 'c':   /* use C tagging scheme */
  1041.                     case 'C':
  1042.  
  1043.                         /* ignore if merge or sort tag_types */
  1044.                         if (flags.tag_type != MERGE &&
  1045.                             flags.tag_type != SORT) {
  1046.  
  1047.                             /* set the option flags */
  1048.                             parse_C_flags(*argv, &flags);
  1049.                         }
  1050.                         break;
  1051.  
  1052.                     default:
  1053.                         break;
  1054.                 }
  1055.                 break;
  1056.  
  1057.             default:
  1058.  
  1059.                 /* this is a file parameter */
  1060.                 /* do not tag this file set if seen previously */
  1061.                 if (!ArgIsMember(argInputRaw, *argv)) {
  1062.  
  1063.                     /* process the file */
  1064.                     SingleFileProcess(*argv, &flags, tag_stream,
  1065.                                       argInput, argInputRaw);
  1066.  
  1067.                     /* register the input file as seen on the command line */
  1068.                     ArgRegisterArg(argInputRaw, *argv);
  1069.                 }
  1070.                 break;
  1071.         }
  1072.     }
  1073.  
  1074.     /* free the command line input arglist */
  1075.     DestroyArgList(argInputRaw);
  1076.  
  1077.     /* close the intermediate tag file */
  1078.     fclose(tag_stream);
  1079.  
  1080.     /* do the sorting and collating */
  1081.     if (argInput->num_args) {
  1082.  
  1083.         /* register elements needed for the sort module unless no sorting is
  1084.          * requested */
  1085.         if (flags.sort_tags) {
  1086.  
  1087.             /* register the file name in argf */
  1088.             ArgRegisterArg(argSort, argv[0]);
  1089.  
  1090.             /* add the sort parameters to beginning of the name register
  1091.              * array */
  1092.             ArgRegisterArg(argSort, "-u");      /* delete duplicate lines */
  1093.  
  1094.             /* if not a case sensitive sort then register case fold */
  1095.             if (!flags.case_sensitive)
  1096.                 ArgRegisterArg(argSort, "-f");  /* fold to lower case */
  1097.  
  1098.             /* if merge then add argument to sort parameters */
  1099.             if (flags.tag_type == MERGE)
  1100.                 ArgRegisterArg(argSort, "-m");  /* merge sort files */
  1101.  
  1102.             /* if output file specified then tmp_filename as output */
  1103.             if (flags.output_file &&
  1104.                 flags.tag_type != MERGE &&
  1105.                 flags.tag_type != SORT) {
  1106.                 sprintf(tmpstr, "-o%s", tmp_filename);
  1107.                 ArgRegisterArg(argSort, tmpstr);
  1108.             }
  1109.  
  1110.             if (flags.tag_type == MERGE ||
  1111.                 flags.tag_type == SORT) {
  1112.  
  1113.                 /* copy the names from ArgInput to ArgSort */
  1114.                 ArgCopy(argSort, argInput);
  1115.             }
  1116.             else {
  1117.                 /* register the intermediate tag file to be sorted */
  1118.                 ArgRegisterName(argSort, tmp_tagfilename);
  1119.             }
  1120.  
  1121.             /* log the activity */
  1122.             if (flags.tag_type == MERGE) {
  1123.                 log_message("# Merging Input Files...");
  1124.             }
  1125.             else {
  1126.                 log_message("# Sorting ...");
  1127.             }
  1128.  
  1129.             /* perform the sort */
  1130.             sort_main(argSort->num_args, argSort->argv);
  1131.         }
  1132.         else {
  1133.  
  1134.             /* register the intermediate tag file to be sorted */
  1135.             ArgRegisterName(argSort, tmp_tagfilename);
  1136.  
  1137.             /* open a temporary file if using an output file */
  1138.             if (flags.output_file) {
  1139.  
  1140.                 /* open the file before writing it */
  1141.                 if ((output_stream = fopen(tmp_filename, "w")) ==
  1142.                     (FILE *) NULL) {
  1143.                     sprintf(tmpstr,
  1144.                             "# Internal error opening temporary files");
  1145.                     log_message(tmpstr);
  1146.                     exit(1);
  1147.                 }
  1148.             }
  1149.  
  1150.             /* output the results */
  1151.             ArgToOutputStream(output_stream, argSort);
  1152.  
  1153.             /* close the output file if necessary */
  1154.             if (flags.output_file) {
  1155.                 fclose(output_stream);
  1156.             }
  1157.         }
  1158.     }
  1159.  
  1160.  
  1161.     /* merge the temporary output file and the current tag file */
  1162.     if (flags.output_file &&
  1163.         argInput->num_args) {
  1164.         log_message("# Merging into tag file ...");
  1165.         MergeFile(tmp_filename, output_filename, argInput, &flags);
  1166.     }
  1167.  
  1168.     /* delete the temporary file if used and free its memory */
  1169.     if (flags.output_file) {
  1170.         remove(tmp_filename);
  1171.         free(tmp_filename);
  1172.     }
  1173.  
  1174.     /* delete the intermediate tags file and free its memory */
  1175.     remove(tmp_tagfilename);
  1176.     free(tmp_tagfilename);
  1177.  
  1178.     /* list the number of files tagged and closing message */
  1179.     sprintf(tmpstr,
  1180.             "# Tagging operation complete with %u file(s) tagged\n",
  1181.             argInput->num_args);
  1182.     log_message(tmpstr);
  1183.  
  1184.     /* free the arglist structures */
  1185.     DestroyArgList(argSort);
  1186.     DestroyArgList(argInput);
  1187.  
  1188.     /* close the log file */
  1189.     log_close();
  1190.  
  1191.     /* successful exit */
  1192.     return (0);
  1193. }
  1194.