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 >
Wrap
C/C++ Source or Header
|
1992-05-03
|
45KB
|
1,194 lines
/*
EPSHeader
File: tags.c
Author: J. Kercheval
Created: Sun, 03/31/1991 14:59:48
*/
/*
EPSRevision History
J. Kercheval Sun, 03/31/1991 16:24:01 creation
J. Kercheval Sun, 03/31/1991 16:43:18 allow @filename listfile syntax
J. Kercheval Tue, 05/14/1991 19:46:50 add tag_type
J. Kercheval Wed, 05/15/1991 18:19:22 add -m and -o parameters
J. Kercheval Wed, 05/15/1991 19:23:42 correctly parse for logfile
J. Kercheval Wed, 05/15/1991 22:22:33 add the sort module
J. Kercheval Thu, 05/16/1991 22:47:04 move file IO to fileio.c
J. Kercheval Wed, 06/26/1991 23:03:55 move back to standard IO
J. Kercheval Thu, 06/27/1991 21:43:11 create tags.h
J. Kercheval Fri, 07/12/1991 23:04:23 revise command line parsing
J. Kercheval Sat, 07/13/1991 11:29:02 update Usage()
J. Kercheval Sat, 07/13/1991 12:47:34 finish argf parsing
J. Kercheval Sat, 07/13/1991 13:06:16 move input routines to input.c
J. Kercheval Sun, 07/14/1991 19:18:36 finish DoTags
J. Kercheval Wed, 07/17/1991 22:18:58 allow append file logging
J. Kercheval Thu, 07/18/1991 18:53:31 use fully qualified input pathname
J. Kercheval Fri, 07/19/1991 20:15:43 allow sort only and non-sort options
J. Kercheval Sun, 07/21/1991 17:38:00 add post processing
J. Kercheval Mon, 07/22/1991 17:35:08 tweak log output and interface
J. Kercheval Sat, 07/27/1991 20:38:36 remove ASM public flag and post processing hooks
J. Kercheval Sat, 08/17/1991 23:03:47 enable c tagging
J. Kercheval Sun, 08/25/1991 22:49:55 fix bug in ASM flag parsing
J. Kercheval Thu, 08/29/1991 23:30:47 add CRC checking for virus check
J. Kercheval Sat, 08/31/1991 23:56:02 add prototype flag
J. Kercheval Thu, 09/05/1991 01:29:13 add input file name tracking
J. Kercheval Thu, 09/05/1991 01:29:42 add -t flag
J. Kercheval Thu, 09/05/1991 02:01:28 finish tag output logic
J. Kercheval Thu, 09/05/1991 20:07:45 move arglist processing to seperate module
J. Kercheval Thu, 09/05/1991 20:13:50 move MergeFile() to tagio.c
J. Kercheval Tue, 09/10/1991 23:24:27 add ctrl-c handler
J. Kercheval Wed, 09/11/1991 01:45:35 add usage comments for extern switch
J. Kercheval Tue, 09/17/1991 19:43:23 add support for case_sensitive flag
J. Kercheval Wed, 09/25/1991 13:42:28 support sorted arglists
J. Kercheval Wed, 09/25/1991 16:02:18 check for duplicate file names at the command line level
J. Kercheval Wed, 09/25/1991 22:47:37 supress tag file merge if not input files found
J. Kercheval Tue, 10/01/1991 19:30:26 close all open files in external_cleanup()
J. Kercheval Thu, 10/03/1991 13:55:09 add exclude file processing
J. Kercheval Thu, 10/03/1991 16:46:07 improve list file parsing
J. Kercheval Sat, 10/05/1991 10:56:18 add switch summary to usage
J. Kercheval Sat, 04/25/1992 01:36:19 add junk tagging for C
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <signal.h>
#include "flags.h"
#include "log.h"
#include "wildfile.h"
#include "sort.h"
#include "ctag.h"
#include "asmtag.h"
#include "tagio.h"
#include "viruscrc.h"
#include "arglist.h"
#define Author "J. Kercheval"
#define Version "Tags Generator V1.8"
#define CompileDate __TIMESTAMP__
/* The following variables are pointers to the temporary filenames used as
* an intermediary files. These are globals for use in external_cleanup()
* to delete any temporary files. */
char *tmp_filename = NULL;
char *tmp_tagfilename = NULL;
/*----------------------------------------------------------------------------
*
* Print Usage
*
---------------------------------------------------------------------------*/
void Usage(char *fname)
{
fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
fname);
fprintf(stdout, " -h,-? for extended usage output to stdout\n");
fprintf(stdout, " @LISTFILE for list file of input file names\n");
fprintf(stdout, " -x{EXCLUDEFILE|@LISTFILE} to exclude files\n");
fprintf(stdout, " -tTAGFILE to merge to a particular tag file\n");
fprintf(stdout, " -lLOGFILE for log file (-l overwrites, -L appends)\n");
fprintf(stdout, " -o[e5gsm] for output format\n");
fprintf(stdout, " -a[fdlmsu] to specify assembly tagging\n");
fprintf(stdout, " -c[dmstekuvcfpxi] to specify C tagging\n");
fprintf(stdout, " -j will suppress junk output filter\n");
fprintf(stdout, " -q will suppress normal status output\n");
fprintf(stdout, " -r use relative pathnames in output\n");
fprintf(stdout, " -n do not sort the tag output\n");
fprintf(stdout, " -i use a case sensitive sort\n");
fprintf(stdout, " -m for merge sort of the existing sorted files\n");
fprintf(stdout, " -s sort input files only\n");
exit(1);
}
/*----------------------------------------------------------------------------
*
* Print Extended Usage
*
---------------------------------------------------------------------------*/
void Help(char *fname)
{
char usage[][85] =
{
" -h or -? to obtain this help screen\n",
" @LISTFILE for list file of input file names. A list file is in the form",
" of a response file (ie. a list of files seperated by some delimiter).",
" The allowed delimiters for file seperation are '+', ',', ';' and normal",
" whitespace. This file allows commented lines by preceding any comment",
" with a pound sign (#). A comment is from the '#' to the end of the",
" line and may start after any whitespace character\n",
" -x{EXCLUDEFILE|@LISTFILE} excludes the files specified by EXCLUDEFILE",
" or exclude all files listed in LISTFILE.\n",
" -tTAGFILE to output to a (possibly existing) tag file and will result in",
" previous tags for input files being removed from the output file.",
" This tagfile is assumed to be in one of this utilities output formats.",
" if -m or -s are used this switch is ignored (all output is to stdout).\n",
" -lLOGFILE for output to a log file in a LISTFILE format suitable as input.",
" behavior regarding existing files is determined by the case of the switch.",
" -l creates and outputs to a file overwriting any currently existing file",
" -L appends all output to the logfile if there is an already existing file\n",
" -o[options] for output format to stdout or the tag file if -t switch is used",
" e Epsilon >= V6.0 ( tokenString \\t fileName \\t characterOffset \\t line )",
" 5 Epsilon <= V5.03 ( tokenString;fileName;characterOffset )",
" g GNU tag ( tokenString \\t fileName \\t /$line^/ )",
" s Space-Delimited ( tokenString fileName lineNumber )",
" m MicroSoft Error ( tokenString fileName(lineNumber) )\n",
" -a[options] to specify assembly tagging and to detail the token types.",
" Default tagging is -afdlmsu (80x86 assembly using MASM/TASM syntax)",
" f procedure labels ( token proc )( proc token )",
" d definition labels ( token equ const )( token db declaration )",
" l local labels ( token label )( label token )( token: )",
" m macro labels ( token macro )( macro token )",
" s struc labels ( token struc )( struc token )",
" u union labels ( token union )( union token )\n",
" -c[options] to specify C tagging and to detail the token types. Default",
" tagging options are -cdmstekuvcfpxi (standard ANSI 2.0 C/C++). Note that",
" use of the -cx and the -ci switch are modifiers and will only be effective",
" when other options are used (ie. -cpx must be specified to obtain extern",
" prototypes, -cx alone yields nothing). Note that the -cx and -ci modifier",
" has no effect for define and macro tags which are tagged only according",
" to the -cd and -cm switches respectively. Additionally the -cx modifier",
" is ignored for function tags. The order of all of these options is not",
" significant.",
" d defines ( #define token statement )",
" m macro labels ( #define token() statement )",
" s struct globals ( struct token {} )",
" t typedef globals ( typedef declaration token, token, ... )",
" e enum globals ( enum token {} )",
" k enum konstants ( enum { token, token, token, ...} )",
" u union globals ( union token {} )",
" v global variable ( declaration token, token = {}, token, ... )",
" c global class ( class token: {} )",
" f function definitions ( token() declaration {} )",
" p prototypes ( token(, )",
" i static declarations ( static declaration )",
" x extern defines ( extern declaration )",
" ( extern \"C\" declaration )",
" ( extern \"C\" { declaration; declaration; ... } )\n",
" -j will suppress junk filtering used during token output",
" -q will suppress normal output to stderr and program version information",
" -r use relative pathnames in output rather than fully qualified path names",
" -n do not sort the tag output (Often used in conjunction with GNU style tags)",
" -i use a case sensitive sort (Normally a case insensitive sort is used)\n",
" The following result only in sorting of the input files (no tagging is done).",
" Output is to stdout only (-t is ignored) when using these switches.",
" -m for merge sort of the specified existing files (assumed to be sorted)",
" -s sort input files only, all files are assumed to be in an unsorted state\n",
" The TMP environment variable is used for temporary files. The default for",
" tags is to use C style tagging, the Epsilon tag file format, to sort",
" the output before finally placing it in the output file (or stdout if -t",
" is not used) and to be verbose and log activity to stderr.",
" Each file specified on the command line or within a LISTFILE will be tagged",
" only once regardless of the number of times it appears on the command",
" line (This includes LISTFILEs as well as filenames and the files listed",
" within LISTFILEs).",
" All of the switches may be specified anywhere on the command line and with",
" the exception of the style switches (-a, -c) are not position dependent.",
" The style switches are active only for input files which fall after them",
" on the command line and allows the specification of different tagging",
" styles and types on a file by file basis.",
" Input file and LISTFILE specifications allow the use of *IX shell style",
" expressions (A subset of the standard UNIX regular expression syntax).",
" This allows input file names such as \"*\", \"*t?*.c\" and \"*[e-gxyz]*\".",
" Note that \"*\" in this case is completely equivalent to \"*.*\" in normal",
" DOS usage. The use of \"*.\" will obtain files without extensions.",
" This utility performs a CRC validation on itself to prevent corruption and",
" viral infection from outside influences. Modification of this file in",
" any way will result in a failure of the internal CRC check. On CRC",
" failure the program will exit with a warning message.",
"\0"
};
int i; /* index into help text array */
fprintf(stdout, "\n%s %s -- %s\n\n", Version, CompileDate, Author);
fprintf(stdout, "Usage: %s {[OPTIONS] [SOURCEFILE|@LISTFILE]}\n\n",
fname);
for (i = 0; usage[i][0]; i++) {
fprintf(stdout, "%s\n", usage[i]);
}
exit(1);
}
/*----------------------------------------------------------------------------
*
* external_cleanup() removes the temporary file used here
*
---------------------------------------------------------------------------*/
void external_cleanup(void)
{
fcloseall();
if (tmp_filename != NULL)
remove(tmp_filename);
if (tmp_tagfilename != NULL)
remove(tmp_tagfilename);
}
/*----------------------------------------------------------------------------
*
* CtrlCHandler() cleans up and aborts
*
---------------------------------------------------------------------------*/
void __cdecl CtrlCHandler(int sig)
{
/* Disallow CTRL+C during handler. */
signal(SIGINT, SIG_IGN);
/* cleanup and abort */
external_cleanup();
abort();
}
/*----------------------------------------------------------------------------
*
* nextfile takes the list_file parameter and finds the next filename from
* the opened listfile.
*
---------------------------------------------------------------------------*/
BOOLEAN nextfile(FILE * list_file, char *fname, int max_length)
{
char white[] =
{
" \t\n\f\v\b\r,+;#"
}; /* valid whitespace characters */
char delim[] =
{
" \t\n\f\v\b\r,+;"
}; /* end of filename characters */
char *s; /* temporary char pointer */
char c; /* temporary char variable */
int length; /* current length of fname */
/* init */
s = fname;
*s = '\0';
length = 0;
c = (char) fgetc(list_file);
/* if end of file then we are done */
if (feof(list_file))
return FALSE;
/* pass over whitespace */
while (strchr(white, c)) {
if (c == '#') {
while (c != '\n') {
c = (char) fgetc(list_file);
if (feof(list_file))
return FALSE;
}
}
c = (char) fgetc(list_file);
if (feof(list_file))
return FALSE;
}
/* get the filename */
while (!strchr(delim, c)) {
/* don't add to fname if maximum length reached */
if (length < max_length - 1) {
*s++ = c;
length++;
}
c = (char) fgetc(list_file);
if (feof(list_file)) {
*s = '\0';
return TRUE;
}
}
/* success */
*s = '\0';
return TRUE;
}
/*----------------------------------------------------------------------------
*
* Process() tags the input stream from the input file and outputs to a
* temporary file which is registered in argf.
*
---------------------------------------------------------------------------*/
void Process(FILE * infile, char *infname, FILE * outfile, Flags * flags)
{
/* log the input filename */
log_message(infname);
switch (flags->tag_type) {
case C: /* use C type parsing */
CTags(infile, infname, outfile, flags);
break;
case ASM: /* use ASM type parsing */
ASMTags(infile, infname, outfile, flags);
break;
default:
break;
}
}
/*----------------------------------------------------------------------------
*
* SingleFileProcess() tags a single file and outputs to a temporary file
* registered in argf. Wildcards are allowed as file names.
*
---------------------------------------------------------------------------*/
void SingleFileProcess(char *pathname, Flags * flags,
FILE * outfile, ArgList argInput,
ArgList argInputRaw)
{
char fname[MAXPATH + 1]; /* the current file name */
char full_pathname[MAXPATH + 1]; /* the full path and filename */
char tmpstr[2 * MAXPATH + 1]; /* error string */
struct file_info_struct ff; /* the file find structure */
FILE *input_file; /* the input file being worked on */
/* initialize ff */
strcpy(ff.file_pattern, pathname);
ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
_FA_HIDDEN | _FA_SYSTEM;
/* find the initial file matching pattern */
if (!find_firstfile(&ff)) {
/* bad file name */
sprintf(tmpstr, "# Could not find the file '%s'", pathname);
log_message(tmpstr);
}
else {
/* loop through all matching files in the parameter */
do {
/* make the file name */
strcpy(fname, ff.file_path);
strcat(fname, ff.file.name);
/* get the fully qualified pathname if wanted */
if (!flags->use_relative_pathnames) {
_fullpath(full_pathname, fname, MAXPATH);
}
else {
strcpy(full_pathname, fname);
}
/* convert pathname to lower case */
strlwr(full_pathname);
/* register the original input file name after verifying that we
* have not previously processed this file */
if (!ArgIsMember(argInputRaw, full_pathname)) {
ArgRegisterName(argInput, full_pathname);
ArgRegisterName(argInputRaw, full_pathname);
/* Try to open the file */
if ((input_file = fopen(fname, "r")) == (FILE *) NULL) {
sprintf(tmpstr,
"# Could not open %s for Tagging", fname);
log_message(tmpstr);
}
else {
/* perform the needed tagging function */
Process(input_file, full_pathname, outfile, flags);
/* close the input file */
fclose(input_file);
}
}
} while (find_nextfile(&ff));
}
}
/*----------------------------------------------------------------------------
*
* BatchFileProcess() tags a list of files within the file given. Wildcards
* are allowed in the listing file and as the listing file name.
*
---------------------------------------------------------------------------*/
void BatchFileProcess(char *pathname, Flags * flags,
FILE * outfile, ArgList argInput,
ArgList argInputRaw)
{
FILE *list_file; /* file with list of files */
char list_filename[MAXPATH + 1]; /* the current file name */
char input_filename[MAXPATH + 1]; /* the current file name */
char tmpstr[2 * MAXPATH + 1]; /* error string */
struct file_info_struct ff; /* the file find structure */
/* initialize ff */
strcpy(ff.file_pattern, pathname);
ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
_FA_HIDDEN | _FA_SYSTEM;
/* find the initial file matching pattern */
if (!find_firstfile(&ff)) {
/* bad file name */
sprintf(tmpstr,
"# Could not find the listfile '%s'", pathname);
log_message(tmpstr);
}
else {
/* loop through all available list files with pathname */
do {
/* make the file name */
strcpy(list_filename, ff.file_path);
strcat(list_filename, ff.file.name);
/* open the list file and parse the file */
if ((list_file = fopen(list_filename, "r")) ==
(FILE *) NULL) {
sprintf(tmpstr,
"# Could not open %s as a listfile", list_filename);
log_message(tmpstr);
}
else {
/* output the file we are parsing */
sprintf(tmpstr,
"# Opening listfile %s", list_filename);
log_message(tmpstr);
/* loop while there are more filenames in the file */
while (nextfile(list_file, input_filename, MAXPATH + 1)) {
/* do not tag this file set if seen before */
if (!ArgIsMember(argInputRaw, input_filename)) {
/* tag the obtained file path */
SingleFileProcess(input_filename, flags,
outfile, argInput, argInputRaw);
/* register the input file as seen in the list file */
ArgRegisterArg(argInputRaw, input_filename);
}
}
/* close the list file */
fclose(list_file);
}
} while (find_nextfile(&ff));
}
}
/*----------------------------------------------------------------------------
*
* SingleFileExclude() places a single file into argInputRaw ArgList to
* exclude a file from further processing. Wildcards are allowed as file
* names.
*
---------------------------------------------------------------------------*/
void SingleFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
{
char fname[MAXPATH + 1]; /* the current file name */
char full_pathname[MAXPATH + 1]; /* the full path and filename */
struct file_info_struct ff; /* the file find structure */
/* initialize ff */
strcpy(ff.file_pattern, pathname);
ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
_FA_HIDDEN | _FA_SYSTEM;
/* find the initial file matching pattern */
if (find_firstfile(&ff)) {
/* loop through all matching files in the parameter */
do {
/* make the file name */
strcpy(fname, ff.file_path);
strcat(fname, ff.file.name);
/* get the fully qualified pathname if wanted */
if (!flags->use_relative_pathnames) {
_fullpath(full_pathname, fname, MAXPATH);
}
else {
strcpy(full_pathname, fname);
}
/* convert pathname to lower case */
strlwr(full_pathname);
/* register the original input file name after verifying that we
* have not previously processed this file */
if (!ArgIsMember(argInputRaw, full_pathname)) {
ArgRegisterName(argInputRaw, full_pathname);
}
} while (find_nextfile(&ff));
}
}
/*----------------------------------------------------------------------------
*
* BatchFileExclude() places a list of files within the argInputRaw ArgList
* to inhibit processing of those files. Wildcards are allowed in the
* listing file and as the listing file name.
*
---------------------------------------------------------------------------*/
void BatchFileExclude(char *pathname, Flags * flags, ArgList argInputRaw)
{
FILE *list_file; /* file with list of files */
char list_filename[MAXPATH + 1]; /* the current file name */
char input_filename[MAXPATH + 1]; /* the current file name */
struct file_info_struct ff; /* the file find structure */
/* initialize ff */
strcpy(ff.file_pattern, pathname);
ff.file_attributes = _FA_NORMAL | _FA_READONLY | _FA_ARCHIVE |
_FA_HIDDEN | _FA_SYSTEM;
/* find the initial file matching pattern */
if (!find_firstfile(&ff)) {
/* bad file name */
fprintf(stderr,
"# Could not find the Exclude listfile '%s'", pathname);
exit(1);
}
else {
/* loop through all available list files with pathname */
do {
/* make the file name */
strcpy(list_filename, ff.file_path);
strcat(list_filename, ff.file.name);
/* open the list file and parse the file */
if ((list_file = fopen(list_filename, "r")) ==
(FILE *) NULL) {
fprintf(stderr,
"# Could not open %s as an Exclude listfile",
list_filename);
exit(1);
}
else {
/* make the file name */
strcpy(list_filename, ff.file_path);
strcat(list_filename, ff.file.name);
/* loop while there are more filenames in the file */
while (nextfile(list_file, input_filename, MAXPATH + 1)) {
/* do not register this file set if seen before */
if (!ArgIsMember(argInputRaw, input_filename)) {
/* exclude the obtained file path */
SingleFileExclude(input_filename, flags, argInputRaw);
/* register the input file as seen in the list file */
ArgRegisterArg(argInputRaw, input_filename);
}
}
/* close the list file */
fclose(list_file);
}
} while (find_nextfile(&ff));
}
}
/*----------------------------------------------------------------------------
*
* Validate() calls the CRC validation routines and exits with a warning if
* there are problems.
*
---------------------------------------------------------------------------*/
void Validate(char *filename)
{
/* validate the executable against the internally stored CRC */
switch (validatecrc(filename)) {
case CRC_VALID:
break;
case CRC_INVALID:
case CRC_ISZERO:
/* internal failure */
fprintf(stderr,
"This executable fails internal CRC checking due to ");
fprintf(stderr,
"external modification. \n");
fprintf(stderr,
"Please validate this copy and scan for virus ");
fprintf(stderr, "infection.\n");
exit(1);
break;
case CRC_NOMEM:
fprintf(stderr,
"Error - Out of Memory\n");
exit(1);
break;
case CRC_FILEERR:
fprintf(stderr,
"Error - Program file not found\n");
exit(1);
break;
default:
break;
}
}
/*----------------------------------------------------------------------------
*
* main loops through the parameter list and calls the appropriate parsers
*
---------------------------------------------------------------------------*/
int __cdecl main(int argc, char *argv[])
{
Flags flags;
char log_filename[MAXPATH]; /* log file name */
char output_filename[MAXPATH]; /* the tag file to output to */
char tmpstr[2 * MAXPATH + 1]; /* error and temp string */
char *environ_ptr; /* holds pointer to TMP variable */
int environ_len; /* holds length of TMP variable */
ArgList argSort; /* the list of files sent to sort */
ArgList argInput; /* the list of input files */
ArgList argInputRaw; /* the list of command line input files and
* files which are excluded */
struct tm *now; /* clock variables */
time_t cur_clock;
unsigned int i; /* temp looping var */
int switch_count; /* the number of switches found */
char drive[5], dir[255], fname[10], ext[5];
FILE *output_stream; /* the output stream */
FILE *tag_stream; /* the stream for temporary output */
/* Register CTRL+C handler. */
signal(SIGINT, CtrlCHandler);
/* validate the executable against the internally stored CRC */
Validate(argv[0]);
/* obtain parts of the startup path */
_splitpath(argv[0], drive, dir, fname, ext);
/* if not enough parameters than Usage() */
if (argc < 2)
Usage(fname);
/* compute the current time */
time(&cur_clock);
now = localtime(&cur_clock);
/* initialize flags structure */
init_flags(&flags);
/* the initial file stuff */
log_filename[0] = '\0';
output_filename[0] = '\0';
output_stream = stdout;
/* get the TMP environment variable */
environ_ptr = getenv("TMP");
environ_len = strlen(environ_ptr);
/* obtain the intermediate tag filename */
if (environ_len &&
environ_ptr[environ_len - 1] != '\\' &&
environ_ptr[environ_len - 1] != '/')
tmp_tagfilename = tempnam("\\", "tg");
else
tmp_tagfilename = tempnam("", "tg");
/* verify filename allocation */
if (tmp_tagfilename == NULL) {
fprintf(stderr, "# Could not create temporary files for output");
exit(1);
}
/* init arglist variable */
argSort = CreateArgList(ARGLIST_NORMAL);
argInput = CreateArgList(ARGLIST_SORTED);
argInputRaw = CreateArgList(ARGLIST_SORTED);
/* preparse for global switches */
switch_count = 0;
for (i = 1; i < (unsigned) argc; i++) {
switch (argv[i][0]) {
case '/':
case '-':
switch_count++;
switch (argv[i][1]) {
case 'l': /* tag from file list */
case 'L':
/* filename must hug the switch */
if (strlen(argv[i] + 2)) {
strcpy(log_filename, argv[i] + 2);
}
else {
fprintf(stderr,
"# -l switch used incorrectly\n");
exit(1);
}
/* set overwrite flag */
if (argv[i][1] == 'l') {
flags.log_overwrite = TRUE;
}
else {
flags.log_overwrite = FALSE;
}
break;
case 't': /* send to tag file */
case 'T':
/* filename must hug the switch */
if (strlen(argv[i] + 2)) {
strcpy(output_filename, argv[i] + 2);
if (environ_len &&
environ_ptr[environ_len - 1] != '\\' &&
environ_ptr[environ_len - 1] != '/')
tmp_filename = tempnam("\\", "tg");
else
tmp_filename = tempnam("", "tg");
/* verify filename allocation */
if (tmp_filename == NULL) {
fprintf(stderr,
"# Could not create temporary files for output");
exit(1);
}
}
else {
fprintf(stderr,
"# -t switch used incorrectly\n");
exit(1);
}
/* set output flag */
flags.output_file = TRUE;
break;
case 'j': /* do not use junk filters */
case 'J':
flags.filter_junk = FALSE;
break;
case 'n': /* do not sort the output */
case 'N':
/* set tag_type */
flags.sort_tags = FALSE;
break;
case 'm': /* merge files only */
case 'M':
/* set tag_type */
flags.tag_type = MERGE;
break;
case 's': /* sort files only */
case 'S':
/* set tag_type */
flags.tag_type = SORT;
break;
case 'o': /* output format specifier follows */
case 'O': /* the last format found is the one */
/* set the option modifier */
parse_output_flags(argv[i], &flags);
break;
case 'r': /* output format specifier follows */
case 'R': /* the last format found is the one */
/* set to use relative pathnames */
flags.use_relative_pathnames = TRUE;
break;
case 'q': /* use quiet mode (no logging to stderr) */
case 'Q':
flags.quiet = TRUE;
break;
case 'i': /* use case sensitive sort */
case 'I':
flags.case_sensitive = TRUE;
break;
case 'x': /* exclude this file or filelist */
case 'X':
/* filename must hug the switch */
if (!strlen(argv[i] + 2)) {
fprintf(stderr,
"# -x switch used incorrectly\n");
exit(1);
}
else {
/* check if list file exclude or normal file
* exclude */
if (argv[i][2] != '@') {
/* this is a particular exclusion */
/* do not use this Exclude file if seen
* previously */
if (!ArgIsMember(argInputRaw, argv[i] + 2)) {
/* process the Exclude file */
SingleFileExclude(argv[i] + 2, &flags,
argInputRaw);
/* register the input list file as seen
* on the command line */
ArgRegisterArg(argInputRaw, argv[i] + 2);
}
}
else {
/* this is an exclusion list file */
if (strlen(argv[i] + 3)) {
/* do not use this Exclude list file if
* seen previously */
if (!ArgIsMember(argInputRaw,
argv[i] + 3)) {
/* process the list file */
BatchFileExclude(argv[i] + 3, &flags,
argInputRaw);
/* register the input list file as
* seen on the command line */
ArgRegisterArg(argInputRaw,
argv[i] + 3);
}
}
else {
fprintf(stderr,
"# @ syntax error");
exit(1);
}
}
}
break;
case 'h':
case 'H':
case '?':
Help(fname);
break;
default:
break;
}
break;
default:
break;
}
}
/* exit if no input files specified */
if (switch_count == argc - 1) {
fprintf(stderr,
"# No input files specified\n");
exit(1);
}
/* open the log file */
if (!log_open(log_filename, flags.quiet, flags.log_overwrite)) {
fprintf(stderr,
"# Could not open %s as a logfile\n", log_filename);
exit(1);
}
/* open the temporary tag file */
if ((tag_stream = fopen(tmp_tagfilename, "w")) ==
(FILE *) NULL) {
sprintf(tmpstr,
"# Internal error opening temporary files");
log_message(tmpstr);
exit(1);
}
/* print initial messages */
sprintf(tmpstr, "# %s %s -- %s", Version, CompileDate, Author);
log_message(tmpstr);
sprintf(tmpstr, "# Tagging performed: %s#", asctime(now));
log_message(tmpstr);
if (flags.tag_type == MERGE) {
log_message("# Merging previously processed tag files");
}
if (flags.tag_type == SORT) {
log_message("# Sorting input files only");
}
/* enter the main loop */
for (argc--, argv++; argc; argc--, argv++) {
/* parse the argument list */
switch (argv[0][0]) {
case '@':
if (strlen(argv[0] + 1)) {
/* do not use this list file if seen previously */
if (!ArgIsMember(argInputRaw, argv[0] + 1)) {
/* process the list file */
BatchFileProcess(argv[0] + 1, &flags,
tag_stream, argInput,
argInputRaw);
/* register the input list file as seen on the
* command line */
ArgRegisterArg(argInputRaw, argv[0] + 1);
}
break;
}
else {
log_message("# @ syntax error");
}
break;
case '/':
case '-':
switch (argv[0][1]) {
case 'a': /* use ASM tagging scheme */
case 'A':
/* ignore if merge or sort tag_types */
if (flags.tag_type != MERGE &&
flags.tag_type != SORT) {
/* set the option flags */
parse_ASM_flags(*argv, &flags);
}
break;
case 'c': /* use C tagging scheme */
case 'C':
/* ignore if merge or sort tag_types */
if (flags.tag_type != MERGE &&
flags.tag_type != SORT) {
/* set the option flags */
parse_C_flags(*argv, &flags);
}
break;
default:
break;
}
break;
default:
/* this is a file parameter */
/* do not tag this file set if seen previously */
if (!ArgIsMember(argInputRaw, *argv)) {
/* process the file */
SingleFileProcess(*argv, &flags, tag_stream,
argInput, argInputRaw);
/* register the input file as seen on the command line */
ArgRegisterArg(argInputRaw, *argv);
}
break;
}
}
/* free the command line input arglist */
DestroyArgList(argInputRaw);
/* close the intermediate tag file */
fclose(tag_stream);
/* do the sorting and collating */
if (argInput->num_args) {
/* register elements needed for the sort module unless no sorting is
* requested */
if (flags.sort_tags) {
/* register the file name in argf */
ArgRegisterArg(argSort, argv[0]);
/* add the sort parameters to beginning of the name register
* array */
ArgRegisterArg(argSort, "-u"); /* delete duplicate lines */
/* if not a case sensitive sort then register case fold */
if (!flags.case_sensitive)
ArgRegisterArg(argSort, "-f"); /* fold to lower case */
/* if merge then add argument to sort parameters */
if (flags.tag_type == MERGE)
ArgRegisterArg(argSort, "-m"); /* merge sort files */
/* if output file specified then tmp_filename as output */
if (flags.output_file &&
flags.tag_type != MERGE &&
flags.tag_type != SORT) {
sprintf(tmpstr, "-o%s", tmp_filename);
ArgRegisterArg(argSort, tmpstr);
}
if (flags.tag_type == MERGE ||
flags.tag_type == SORT) {
/* copy the names from ArgInput to ArgSort */
ArgCopy(argSort, argInput);
}
else {
/* register the intermediate tag file to be sorted */
ArgRegisterName(argSort, tmp_tagfilename);
}
/* log the activity */
if (flags.tag_type == MERGE) {
log_message("# Merging Input Files...");
}
else {
log_message("# Sorting ...");
}
/* perform the sort */
sort_main(argSort->num_args, argSort->argv);
}
else {
/* register the intermediate tag file to be sorted */
ArgRegisterName(argSort, tmp_tagfilename);
/* open a temporary file if using an output file */
if (flags.output_file) {
/* open the file before writing it */
if ((output_stream = fopen(tmp_filename, "w")) ==
(FILE *) NULL) {
sprintf(tmpstr,
"# Internal error opening temporary files");
log_message(tmpstr);
exit(1);
}
}
/* output the results */
ArgToOutputStream(output_stream, argSort);
/* close the output file if necessary */
if (flags.output_file) {
fclose(output_stream);
}
}
}
/* merge the temporary output file and the current tag file */
if (flags.output_file &&
argInput->num_args) {
log_message("# Merging into tag file ...");
MergeFile(tmp_filename, output_filename, argInput, &flags);
}
/* delete the temporary file if used and free its memory */
if (flags.output_file) {
remove(tmp_filename);
free(tmp_filename);
}
/* delete the intermediate tags file and free its memory */
remove(tmp_tagfilename);
free(tmp_tagfilename);
/* list the number of files tagged and closing message */
sprintf(tmpstr,
"# Tagging operation complete with %u file(s) tagged\n",
argInput->num_args);
log_message(tmpstr);
/* free the arglist structures */
DestroyArgList(argSort);
DestroyArgList(argInput);
/* close the log file */
log_close();
/* successful exit */
return (0);
}