Leaked source code of windows server 2003
You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.
 
 
 
 
 
 

1288 lines
39 KiB

/***************************************************************************
*striphdr.c - Program to read source files and produce alphabetised
* listing of header blocks, telling which files they came
* from.
*
* Copyright (c) 1983-2001, Microsoft Corporation. All rights reserved.
*
*Author: Tom Corbett, Brian Lewis - Microsoft Corp.
*
*Usage: striphdr [switches] file {file ...}
* Accepts native code or C source; determines source
* type based on filename suffix.
* Wildcards may be used in the file names.
*
* switches:
*
* -m process module headers only
* -b process both procedure and module headers
* [default is procedure headers only]
* -l process only first line of each header
* -n process none of header (i.e. lists only function name)
* -s <name> process named section only (may be used with -l)
* [default is to process whole header]
* -d delete processed section from input file
* -q quiet, do not print headers (useful only with -d)
* -x <ext> gives extension for output file when -d used
* [default: .new]
* -r remove revision histories from file headers
* (equivalent to -m -d -q -s "Revision History")
*
*Purpose:
* Given a list of Native code and/or C sources, strip out routine or module
* headers and produce an alphabetised listing of the headers, telling where
* (filename) each header came from. Optionally, delete part or all of the
* headers from the source file.
*
* For each file on the command line (wildcards may be used), striphdr reads
* the file, and records information from the file and/or procedure headers.
* This information is then sorted by procedure name/file name, and printed
* to stdout, with an indication of which file each procedure is from. If
* the -d flag is activated, the information is also deleted from the input
* file and the new file placed in a file with the same name but the
* extension .new (this extension can be changed with the -x switch). The
* actual input file is also left as is. When using the -d switch, -q will
* eliminate the output, so that only the deleting action takes place. By
* default only the procedure headers are scanned, the -m and -b switches
* change this. By default all the information in a header is printed or
* deleted, the -l, -n, and -s switches change this. The -r switch is an
* abbreviation which will remove revision histories from the file headers.
*
* Input filenames with suffixes of .c or .h are assumed to contain C source,
* and suffixes of .asm or .inc imply native code source. Routine or module
* names must be on the first or second line following the start of header;
* if on the second line then the first line must contain only whitespace
* after an optional '*' (if C source) or ';' (if native code source).
* Routine names can contain a return type and parameters; multiple entry
* point should be seperated by commas. Header start and end symbols must
* start in the left-most column. Module headers and routine headers are
* marked in the same manner; position relative to the beginning of file is
* used to determine which header type is appropriate.
*
* Source is detabbed (1 tab assumed to equal 4 spaces in C, 8 spaces in native
* code) and routine names are parsed to ensure that the correct name is
* grabbed for sorting.
*
* C Headers are started with a '/' characters in the first column followed
* by at least 3 '*' characters, and are ended with at least 4 '*' characters
* followed by a '/'. Each line within a header must begin with a '*', except
* lines beginning with '#if', '#else', or '#endif'. Module headers must be
* preceded with nothing except (perhaps) blank lines; if any non-blank lines
* are found prior to the first header in a module, it is assumed that the
* header belongs to a routine, otherwise, to the entire module.
*
* Native code headers are started by a ';' followed by at least 3 '*'
* characters, and the header end is denoted by a ';' followed by at least
* 4 '*' characters. There must be a ';' character in the left-most column of
* every line of the header block; the only exception to this is that the '
* if', 'else', and 'endif' switches are allowed inside header blocks. Module
* headers can be preceded with any number of blank lines, a TITLE statement,
* a NAME statement, and/or a PAGE statement; if anything else is
* encountered, subsequent headers will be assumed to be routine headers.
*
* Sections within a header must have a title beginning on the 2nd
* character of the line, and the section is assumed to extend to the next
* line with a non-blank character in position 2.
*
* No non-header comments should begin in column 1 with '/***' in C or
* ';***' in native code; this will confuse striphdr.
*
*
*Revision History:
*
* 01-01-83 TOMC Created [tomc]
* 09-09-85 BL Modified to allow the option of stripping module headers
* instead of routine headers via the -m switch
* 09-30-85 BL Modified to accept either C Source or native code source.
* Modified to detab C Source assuming 3 spaces per tab.
* Modified to parse C Routine names properly, allowing
* types, macros, etc. to precede routine names.
* Modified to make the sorting be case insensitive.
* 11-12-85 BL Fixed bug that caused 1st char to always be removed from
* headers, and that caused problems when a blank line follows
* header starts.
* 06-01-87 PHG fixed GetNonBlank()
* allowed 'title' and 'Title" as well as 'TITLE'
* allowed NAME, PAGE as well as TITLE
* made tab expansion for both ASM and C files
* both C and ASM procedure names can have args,
* multiple entries
* simplified some code and a few minor bug fixes
* added -b, -n, -s, -d, -q, -x, -r switches
* 05-10-90 JCR Accept .cxx/.hxx files (C++ support), misc cleanup
* 04-06-95 SKS Accept .cpp/.hpp as equivalent to .cxx/.hxx, respectively
***************************************************************************/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <io.h>
#include <direct.h>
#define TRUE 1
#define FALSE 0
#define NAMBUFSZ 20000 /* size of buffer for holding all procedure names */
#define LINEBUFSZ 250 /* maximum size of 1 physical line */
#define MAXENT 3000 /* maximum number of procedure entry points */
#define MAXFUNCS 2000 /* maximum number of function headers */
/* abort codes */
#define NMBUFOV 0 /* name buffer table overflow */
#define FILENF 1 /* file not found */
#define FUNCSOV 2 /* function table overflow */
#define ENTOV 3 /* entry table overflow */
#define FILENO 4 /* cannot open file */
#define OUTSPACE 5 /* out of disk space */
/* tab sizes, pagelength */
#define TABSIZE_C 4
#define TABSIZE_ASM 8 /* tab sizes for code */
#define PAGELEN 60 /* pagelength for page breaks; 60 for HP LaserJet */
struct {
char *entname; /* name of entry point */
int funcid; /* function index for this entry point */
char printed; /* flag to ensure each entry printed just once */
}
entry [MAXENT];
int nentries; /* number of entries parsed so far */
struct {
char *filename; /* name of file which contains this function */
long filepos; /* seek position on file "temp" */
int nlines; /* number of lines in function header */
}
func [MAXFUNCS];
int nfuncs; /* number of function parsed so far */
long ofpos; /* output file seek position */
char linebuf[LINEBUFSZ];
char nambuf[NAMBUFSZ]; /* buffer for holding function names */
int nambufi; /* next free byte in nambuf */
char fEof;
FILE *ofd; /* output file descriptor */
FILE *ifd; /* input file descriptor */
FILE *cfd; /* copy file descriptor */
FILE *fopen();
int outline; /* output line number (1..PAGELEN) for page ejects */
int fDelete = FALSE; /* TRUE if copy and delete instead of display */
int fGetModNams = FALSE; /* TRUE if strip module names */
int fGetProcNams = TRUE; /* TRUE if strip procedure names */
int fC_Source; /* TRUE if we're processing C source, false if .asm */
int fDoAll = TRUE; /* TRUE if we process all of header */
int fDoFirst = FALSE; /* TRUE if we process first line of header */
int fDoSection = FALSE; /* TRUE if we process named section of header */
int fQuiet = FALSE; /* TRUE is quiet mode */
char SectionHead[80]; /* Section name */
char CopyExt[4] = "new"; /* extension of new files */
char *szFilenameCur; /* name of file being read (for error reporting) */
/***
*MyAbort(code, s) - abort program with message
*Purpose:
* abort the program with correct message.
*
*Entry:
* code = error code
* s = filename for code == FILENF
*
*Exit:
* exits to DOS
*
*Exceptions:
*
*******************************************************************************/
void MyAbort(code, s)
int code;
char *s;
{
fprintf(stderr, "Fatal Error - ");
if (code == NMBUFOV)
fprintf(stderr, "NAME Buffer overflow\n");
if (code == FILENF)
fprintf(stderr, "File not found: %s\n", s);
if (code == FUNCSOV)
fprintf(stderr, "Function table overflow\n");
if (code == ENTOV)
fprintf(stderr, "Entry table overflow\n");
if (code == FILENO)
fprintf(stderr, "Cannot open file: %s\n", s);
if (code == OUTSPACE)
fprintf(stderr, "Out of disk space\n", s);
exit(code);
} /* MyAbort */
/***
*FindIfC(szFile) - find if filename if C or ASM
*
*Purpose:
* Set global flag fC_Source to TRUE if the filename ends in
* .c, .h, .cxx (.cpp), or .hxx (.hpp); FALSE if it ends in .asm or .inc.
* The extension comparison is NOT case senstive. If none of
* these are found, don't set the flag,and return FALSE,
* else return TRUE.
*
*Exit:
* sets flag fC_Source
* returns FALSE if neither C nor ASM source
* returns TRUE if fC_Source set
********************************************************************/
FindIfC(szFile)
char *szFile;
{
int cbFileName = strlen(szFile);
char *pbPastName = szFile + cbFileName; /* points at NULL at string end */
if ((!_stricmp (".c", pbPastName - 2)) ||
(!_stricmp (".h", pbPastName - 2)) ||
(!_stricmp (".s", pbPastName - 2)) ||
(!_stricmp (".cpp", pbPastName - 4)) ||
(!_stricmp (".hpp", pbPastName - 4)) ||
(!_stricmp (".cxx", pbPastName - 4)) ||
(!_stricmp (".hxx", pbPastName - 4)))
fC_Source = TRUE; /* file is assumed to be C source */
else if ((!_stricmp (".asm", pbPastName - 4)) ||
(!_stricmp (".inc", pbPastName - 4)))
fC_Source = FALSE; /* file is assumed to be Native Code source */
else return (FALSE); /* didn't find an appropriate suffix */
return (TRUE);
} /* FindIfC */
/***
*MakeCopyfileName(filename, copyname) - make copyfile name from input name
*
*Purpose:
* Put the copy file suffix onto a file name
*
*Entry:
* filename = input file name
*
*Exit:
* copyname = filled in with copy file name
*
*Exceptions:
*
*******************************************************************************/
void MakeCopyfileName(filename, copyname)
char *filename, *copyname;
{
char *p;
strcpy(copyname, filename);
p = copyname + strlen(copyname);
while (*(--p) != '.')
; /* p points to '.' */
*(p+1) = '\0'; /* cut off string after '.' */
strcat(copyname, CopyExt); /* put on copy file extension */
}
/***
*linelen(pLine)
*
*Purpose:
* Return the number of characters in a passed line. The line terminator
* ('\n') is not included in the count.
*
*Entry:
* pLine = a pointer to the first char in the line.
*Exit:
* returns the number of characters in the line (an int).
***************************************************************************/
int linelen(pLine)
char *pLine;
{
register int index;
for (index = 0; *(pLine + index) != '\n'; index++);
return (index);
}
static int cLinesRead;
static char fInHeader = FALSE;
/***
*ReadLine(copyit) - read line and analyze it
*
*Purpose:
* read 1 line from input file into 'linebuf'.
* if copyit == TRUE, copy previous line to copy file
*
*Entry:
* copyit = TRUE means copy the line to the copy file
*
*Exit:
* returns -1 for EOF,
* 0 for vanilla lines,
* if C Source,
* 1 for lines which begin "/***" (start of header)
* 2 for lines which begin "/****" (end of header)
* if Native Code Source,
* 1 for lines which begin ";***" (start of header)
* 2 for lines which begin ";****" (end of header)
*
***************************************************************************/
int ReadLine(copyit)
int copyit; /* TRUE = copy line to copy file */
{
register int i;
register int cbLine;
if (copyit) {
if (fputs(linebuf, cfd) == EOF)
MyAbort(OUTSPACE);
} /* copy previous line if requested */
if ((fgets(linebuf, LINEBUFSZ, ifd)) == NULL) {
fEof = TRUE;
return(-1);
}
cLinesRead++;
cbLine = linelen(linebuf);
if ((linebuf[0] == ';') && (!fC_Source)) { /* native code comment */
if ((linebuf[1] == '*') && (linebuf[2] == '*') && (linebuf[3] == '*'))
/* know we have either start or end of a header */
if (fInHeader) {
fInHeader = FALSE;
if (linebuf[4] == '*')
return (2); /* valid end of header */
/* error, got start of header when we're already in a header */
fprintf(stderr, "Unterminated header for function: %s\n",
entry[nentries].entname);
fprintf(stderr, " before line %d of file %s\n",
cLinesRead, szFilenameCur);
}
else { /* have a valid start of header */
fInHeader = TRUE;
return (1);
}
}
else if ((linebuf[0] == '/') && (fC_Source)) { /* C code comment? */
if ((linebuf[1] == '*') && (linebuf[2] == '*') && (linebuf[3] == '*'))
if (fInHeader) {
/* error, got start of header when we're already in a header */
fprintf(stderr, "Unterminated header for function: %s\n",
entry[nentries].entname);
fprintf(stderr, " before line %d of file %s\n",
cLinesRead, szFilenameCur);
}
else {
fInHeader = TRUE;
return (1); /* valid start of header */
}
}
else if ((linebuf[0] == '*') && (fC_Source)) { /* C code comment? */
for (i = 1; (i < cbLine) && (linebuf[i] == '*'); i++);
if ((linebuf[i] == '/') && (i > 3)) { /* have a valid end of header */
if (fInHeader) {
fInHeader = FALSE;
return (2);
}
/* got a header terminator when we weren't within a header */
fprintf(stderr, "Illegal termination to header for function: %s",
entry[nentries].entname);
fprintf(stderr, " in line %d of file %s\n",
cLinesRead, szFilenameCur);
} /* if */
} /* else if */
return(0); /* vanilla line */
} /* ReadLine */
/***
*WriteLine(pb, of) - write a line and expand tabs
*
*Purpose:
* Write a zero terminated string to file 'of'.
* If we're writing C Source header lines, detab them as we go.
*
*Entry:
* pb = points to 1st byte of 0-terminated string.
* of = aft index for destination file.
*
*Exit:
* 'ofpos' is bumped to reflect current output file position.
*
***************************************************************************/
void WriteLine(pb, of)
register char *pb;
FILE *of;
{
register int linepos = 0; /* column position on output line */
int modTS; /* linepos mod tabSize */
int cSpaces; /* number of spaces to print to next tab stop */
int index; /* 'for' index for printing spaces */
int tabSize; /* current tab size */
if (fC_Source)
tabSize = TABSIZE_C;
else
tabSize = TABSIZE_ASM;
while (*pb != '\0') {
if (*pb == '\t') { /* if a tab character found */
modTS = linepos % tabSize;
cSpaces = tabSize - modTS;
for (index = 0; index < cSpaces; index++) {
fputc(' ', of);
linepos++;
}
} /* if */
else {
fputc(*pb, of);
linepos++;
}
pb++;
} /* while */
if (ferror(of))
MyAbort(OUTSPACE);
ofpos = ftell(of); /* update output file seek position for next line */
} /* WriteLine */
/***
*SwitchFound(s) - see if IF, ELSE, ENDIF switch on this line
*
*Purpose: return TRUE if an "if", "else", or "endif" are identified at
* the start of string 's'. This is used to check to see if a
* header line which doesn't start with ';' is an assembler switch.
*Entry:
* s = pointer to a char which represents the string to be checked.
*
*Exit:
* returns TRUE if the string matches "if", "else", or "endif" of either
* upper or lower case, FALSE otherwise.
***************************************************************************/
SwitchFound(s)
char *s;
{
if (fC_Source) {
/* strncmp returns 0 (which maps to FALSE) iff a match was found */
if (strncmp(s, "#if", 3) &&
strncmp(s, "#IF", 3) &&
strncmp(s, "#else", 5) &&
strncmp(s, "#ELSE", 5) &&
strncmp(s, "#endif", 6) &&
strncmp(s, "#ENDIF", 6))
return (FALSE);
}
else {
if (strncmp(s, "if", 2) &&
strncmp(s, "IF", 2) &&
strncmp(s, "else", 4) &&
strncmp(s, "ELSE", 4) &&
strncmp(s, "endif", 5) &&
strncmp(s, "ENDIF", 5))
return (FALSE);
}
return (TRUE);
}
/***
*GetNonBlank(copyit) - read line, find first non blank character
*
*Purpose:
* Read in a line; return linebuf index if non-blank line found, -1 otherwise
*
*Entry:
* copyit = TRUE means copy line to copy file
*
*Exit:
* returns -1 if blank line read
* return index of first non-whitespace char otherwise
*
***************************************************************************/
GetNonBlank(copyit)
int copyit; /* copy lines to copy file if TRUE */
{
register int i;
register int cbLine;
if (ReadLine(copyit) == -1) {
return(-1);
}
cbLine = linelen(linebuf);
for (i = 0; ((linebuf[i] == ' ') || (linebuf[i] == '\t')) &&
(i < cbLine); i++);
if (i >= cbLine)
return (-1);
else
return (i);
} /* GetNonBlank */
/***
*ReadToHeader() - reads to beginning of next header
*
*Purpose:
* Reads to beginning of next header or EOF
*
*Entry:
*
*Exit:
* Returns -1 if at EOF, 0 if at a header
*
************************************************************************/
int ReadToHeader()
{
while (!fEof && ReadLine(fDelete) != 1)
;
if (fEof)
return -1; /* at EOF */
else
return 0; /* at beginning of header */
}
/***
*Get1stHdr() - read to first header
*
*Purpose:
* Read lines until the first header is found. Return TRUE if this is
* the header for the module, or FALSE if no module header is found.
*
* In C Sources, we assume that if the first non-blank line in the source
* starts with '/***', then it's the start of a module header.
* In Native-Code Sources, we assume that there can exist any number
* of blank lines, optionally followed by a TITLE statement, followed
* by any number of blanks lines, and then by the module header if
* it exists.
*
*Entry:
* NONE
*Exit:
* TRUE if module header found, FALSE otherwise. Note that if fEof is found,
* FALSE is returned, and if !fEof and no module header is found, this
* routine will read in lines until the first routine header is found,or
* fEof.
***************************************************************************/
Get1stHdr()
{
register int index;
register int i;
while (((index = GetNonBlank(fDelete)) == -1) && (!fEof))
;
if (fEof) {
fprintf(stderr, "warning: no file header on file ");
fprintf(stderr, "%s\n", szFilenameCur);
return (FALSE);
}
/* now, index is set into linebuf for a non-blank character */
if (fC_Source) { /* if header exists, must be first non-blank line */
if ((linebuf[0] == '/') && (linebuf[1] == '*') &&
(linebuf[2] == '*') && (linebuf[3] == '*')) {
fInHeader = TRUE;
return (TRUE);
}
else {
/* read to start of first header, tell caller no module header found */
ReadToHeader();
fprintf(stderr, "warning: no file header on file ");
fprintf(stderr, "%s\n", szFilenameCur);
return (FALSE);
}
}
/* must be native-code source - - - can have a TITLE line with blank
lines before and after it - - - all prior to module header */
for (i = 1; i <= 3; ++i) { /* do thrice, might have TITLE, NAME, and PAGE */
if (strncmp("TITLE", linebuf + index, 5) == 0 ||
strncmp("title", linebuf + index, 5) == 0 ||
strncmp("Title", linebuf + index, 5) == 0 ||
strncmp("NAME", linebuf + index, 4) == 0 ||
strncmp("name", linebuf + index, 4) == 0 ||
strncmp("Name", linebuf + index, 4) == 0 ||
strncmp("PAGE", linebuf + index, 4) == 0 ||
strncmp("Page", linebuf + index, 4) == 0 ||
strncmp("page", linebuf + index, 4) == 0)
{ /* found TITLE, NAME, or PAGE statement */
while (((index = GetNonBlank(fDelete)) == -1) && (!fEof))
;
if (fEof) {
fprintf(stderr, "warning: no file header on file ");
fprintf(stderr, "%s\n", szFilenameCur);
return (FALSE);
}
}
}
/* if there was a TITLE and/or NAME statement, we've eaten it,
and any following blank lines;
must now have module header, if it exists */
if ((linebuf[0] == ';') && (linebuf[1] == '*') &&
(linebuf[2] == '*') && (linebuf[3] == '*')) {
fInHeader = TRUE;
return (TRUE);
}
else {
/* read to start of first header, tell caller no module header found */
ReadToHeader();
fprintf(stderr, "warning: no file header on file ");
fprintf(stderr, "%s\n", szFilenameCur);
return (FALSE);
}
} /* Get1stHdr */
/***
*AdvanceOne(s) - advance one char if one whitespace or comment token
*
*Purpose:
* 's' points to the first character in an input line; if it's a whitespace
* token or a comment token, return a pointer to the next character in the
* line, otherwise, return 's' unchanged.
*
*Entry:
* s = ptr to first char in input line
*
*Exit:
* returns ptr the next char if *s is whatspace, ';', or '*',
* otherwise returns s
*
*******************************************************************************/
char *AdvanceOne(s)
char *s;
{
if (*s == '*') {
if (fC_Source)
s++;
}
else if (*s == ';') {
if (!fC_Source)
s++;
}
else if ((*s == ' ') || (*s == '\t'))
s++;
return(s);
} /* AdvanceOne */
/***
*FuncNamePtr(pbName) - find function name from this or next line
*
*Purpose:
* Given a pointer into the current header line, return a pointer to
* the first non-blank or comment symbol; if none found in the existing
* line, read in another and try that one.
* if a C routine line, skip any types, etc., and return a pointer to
* the filename itself.
*
* If a C routine line:
* -------------------
* Assumes that C routine names will end with a left paren.
* Allows left parens in a summary of purpose if said summary is
* preceded by a '-' which comes after the routine name.
* Assumes that there are 1 or 0 spaces between the the routine name
* and the mandatory left paren.
*
*Entry:
* pbName = a pointer to the place to begin searching in linebuf.
*Exit:
* Returns a pointer to the filename.
*
***************************************************************************/
char *FuncNamePtr(pbName)
register char *pbName;
{
register int cbLine;
char *pbTmp;
int iStart;
/* first, see if we have a blank line - if so, read in another one,
and assume that it has the filename; don't check that one ... */
pbTmp = AdvanceOne(pbName);
cbLine = linelen(pbTmp);
for (iStart = 0; ((*(pbTmp+iStart) == ' ') || (*(pbTmp+iStart) == ' ')) &&
(iStart < cbLine); iStart++);
if (iStart >= cbLine) {
if (ReadLine(fDelete) != 0) { /* then we got a procedure end w/out a name! */
if (fEof)
fprintf(stderr, "EOF not expected\n");
else
fprintf(stderr, "Illegal header termination\n");
fprintf(stderr,
" in line %d of file %s\n", cLinesRead, szFilenameCur);
return((char *)-1);
}
pbName = linebuf;
}
/* now, assume that there is a filename somewhere at or after pbName */
iStart = 0;
while (*(pbName+iStart) != '(' && *(pbName+iStart) != '-' &&
*(pbName+iStart) != ',' && *(pbName+iStart) != '\n')
++iStart; /* search fwd for '(', '-', ',' or '\n' */
do {
--iStart;
}
while ((*(pbName+iStart) == ' ' || *(pbName+iStart) == '\t') &&
iStart > 0);
/* search back through whitespace */
while (*(pbName+iStart) != ' ' && *(pbName+iStart) != '\t' &&
*(pbName+iStart) != ';' && *(pbName+iStart) != '*')
--iStart;
/* search back to beginning of name */
++iStart; /* point to first letter of name */
return (pbName+iStart); /* return pointer to name */
} /* FuncNamePtr */
/***
*MyReadFile(pbNam) - read file and remember headers
*
*Purpose:
* Read one entire file, stripping out and remembering function headers
* or module headers, as appropriate.
*
***************************************************************************/
void MyReadFile(char *pbNam)
{
char CopyName[65]; /* name of copy file */
char *s, done, backout;
int funci, svnfuncs, svnentries;
int inmodhdr; /* TRUE if in module header, else FALSE */
int insection; /* TRUE if in scetion to process */
int onfirst; /* TRUE if on first line of header */
szFilenameCur = pbNam;
if ((ifd = fopen(pbNam, "r")) <= 0)
MyAbort(FILENF, pbNam);
linebuf[0] = '\0'; /* make linebuf blank so file copying works */
fEof = FALSE;
cLinesRead = 0;
if (!FindIfC(pbNam)) { /* filename had invalid suffix */
fprintf(stderr, "Illegal suffix for file %s", pbNam);
fprintf(stderr, "; must have .c or .asm suffix\n");
fclose(ifd);
return;
}
if (fDelete) {
MakeCopyfileName(pbNam, CopyName); /* put the right extension on */
cfd = fopen(CopyName, "w");
if (cfd == NULL)
MyAbort(FILENO, CopyName); /* can't open file */
}
inmodhdr = Get1stHdr();
if (inmodhdr && !fGetModNams) {
/* don't want module header */
ReadToHeader(); /* skip module header */
inmodhdr = FALSE;
}
/* we are currently at the beginning of a new header.
copy it to file TEMP, remember all entry points in NAMBUF. */
while (!fEof && (inmodhdr || fGetProcNams)) {
svnfuncs = nfuncs;
svnentries = nentries;
if (++nfuncs >= MAXFUNCS)
MyAbort(FUNCSOV);
func[nfuncs].filename = pbNam;
func[nfuncs].nlines = 0;
func[nfuncs].filepos = ofpos;
if (ReadLine(fDelete) == -1)
done = TRUE; /* got end-of-file */
else
done = FALSE;
funci = nfuncs;
s = linebuf;
while (!done) {
if (++nentries >= MAXENT)
MyAbort(ENTOV);
entry[nentries].entname = nambuf + nambufi;
entry[nentries].printed = FALSE;
entry[nentries].funcid = funci;
s = FuncNamePtr(s);
if (s == (char *)-1) {
fprintf(stderr, "Error found in line %d of file %s\n",
cLinesRead, szFilenameCur);
s = linebuf;
}
while ((*s != '\0') && /* transfer function name to nambuf */
(*s != ',') &&
(*s != '(') &&
(*s != ' ') &&
(*s != '\n') &&
(*s != '\t') &&
(nambufi < (NAMBUFSZ - 2))) {
nambuf[nambufi++] = *(s++);
}
if (nambufi >= (NAMBUFSZ - 2))
MyAbort(NMBUFOV, NULL);
nambuf[nambufi++] = '\0';
/* make all secondary entry points reference primary entry point */
if (funci >= 0)
funci = -1 - nentries;
/* next we see if another entry point exists */
while (*s == ' ' || *s == '\t')
++s; /* skip whitespace */
if (*s == '(') {
do {
++s;
}
while (*s != ')' && *s != '\n'); /* skip param list */
++s; /* goto next character */
}
while (*s == ' ' || *s == '\t')
++s; /* skip whitespace */
if (*(s++) != ',')
done = TRUE; /* no more entry pts */
else {
++s;
done = FALSE;
}
} /* while !done */
backout = FALSE;
if (fDoAll || fDoFirst)
insection = TRUE;
else
insection = FALSE; /* are we in the correct section */
onfirst = TRUE; /* on first line */
do {
s = linebuf;
if ((!fC_Source && (*s != ';') && !SwitchFound(s)) ||
(fC_Source && (*s != '*') && !SwitchFound(s))) {
/* Illegal Header Format, leave garbage in file TEMP,
but restore nfuncs and nentries to previous values
and backout of this header gracefully. */
fprintf(stderr, "Invalid Header for function: %s",
entry[nentries].entname);
fprintf(stderr, " in line %d", cLinesRead);
fprintf(stderr, ", in file: %s\n", pbNam);
nfuncs = svnfuncs;
nentries = svnentries;
backout = TRUE;
}
s = AdvanceOne(s);
if (!fDoAll && fDoSection && !onfirst && *s != ' ' && *s != '\t' && *s != '\n') {
/* now at a section beginning -- and it's significant */
if (insection)
insection = FALSE; /* come to end of section */
else if (strncmp(s, SectionHead, strlen(SectionHead)) == 0)
insection = TRUE; /* come to beginning of section */
}
/* if in the section, don't copy, but write to TEMP */
if (insection) {
WriteLine(s, ofd);
func[nfuncs].nlines++;
ReadLine(FALSE);
}
else {
ReadLine(fDelete);
}
if (onfirst && !fDoAll)
insection = FALSE;
onfirst = FALSE; /* no longer on first line */
}
while ((!fEof) && (!backout) && fInHeader);
/* skip to start of next function header */
if (fGetProcNams)
ReadToHeader();
inmodhdr = FALSE;
} /* while !fEof etc. */
while (!fEof) {
ReadLine(fDelete);
} /* read rest of file */
if (fInHeader) {
/* Error: reached EOF with unterminated header */
fInHeader = FALSE;
fprintf(stderr,
"Error: function %s not terminated before end-of-file in %s\n",
entry[nentries].entname, szFilenameCur);
}
fclose(ifd);
fclose(cfd);
} /* MyReadFile */
/***
*PrintSep() - print a seperator
*
*Purpose:
* Output a some lines which mark function header boundaries.
*
***************************************************************************/
void PrintSep(void)
{
printf("---------------------------------------");
printf("----------------------------------------\n");
} /* PrintSep */
/***
*PrintEntry(i) - print out an entry point header/module header
*
*Purpose:
* Prints the given header out
*
***************************************************************************/
PrintEntry(i)
int i;
{
int linecnt, m, entrysize;
if ((m = entry[i].funcid) >= 0)
entrysize = 4 + func[m].nlines; /* primary entry point */
else
entrysize = 4; /* secondary entry point */
if (outline + entrysize > PAGELEN && outline > 1) {
while (outline > PAGELEN)
outline -= PAGELEN;
while (outline <= PAGELEN) {
printf("\n");
outline++;
}
outline = 1;
}
printf("\n");
PrintSep();
printf("%s - ", entry[i].entname);
if (m < 0)
printf("see %s\n", entry[-1-m].entname);
else
printf("File: %s\n", func[m].filename);
PrintSep();
outline = outline + 4;
if (m < 0 || func[m].nlines == 0)
return(0);
fseek(ifd, func[m].filepos, 0);
fEof = FALSE;
linecnt = func[m].nlines;
ReadLine(FALSE);
do {
WriteLine(linebuf, stdout);
outline++;
ReadLine(FALSE);
}
while ((!fEof) && ((--linecnt) > 0));
} /* PrintEntry */
#if 0
/***************************************************************************
*_stricmp(pbLeft, pbRight) - case insensitive string compare
*
*Purpose:
* Case-insensitive string comparison.
*
*Entry:
* pbLeft, pbRight = ptrs to strings to compare
*
*Exit:
* Return 0 if left string == right string, -1 if left string less than
* right string, 1 otherwise
*
*NOTE:
* This routine is provided because not all C runtime libraries support
* this; specifically, MS C for DOS does have this routine, but
* on a 68k it doesn't seem to be there.
*
***************************************************************************/
char *malloc();
#define isLcase(c) (((c) >= 'a') && ((c) <= 'z'))
#define upit(c) ((isLcase(c))? (c) - 'a' + 'A' : (c))
_stricmp(pbLeft, pbRight)
char *pbLeft, *pbRight;
{
int cbLeft = strlen(pbLeft);
int cbRight = strlen(pbRight);
char *pbUCleft = malloc(cbLeft +1);
char *pbUCright = malloc(cbRight +1);
register char *pbSrc;
register char *pbDst;
register int i, retval;
pbDst = pbUCleft;
pbSrc = pbLeft;
for (i = 0; i <= cbLeft; i++, pbDst++, pbSrc++)
*pbDst = (char)upit(*pbSrc);
pbDst = pbUCright;
pbSrc = pbRight;
for (i = 0; i <= cbRight; i++, pbDst++, pbSrc++)
*pbDst = (char)upit(*pbSrc);
retval = strcmp(pbUCleft, pbUCright);
free(pbUCright);
free(pbUCleft);
return(retval);
} /* strless */
#endif /* 0 */
/***************************************************************************
* SortFunctions()
*
* Purpose:
* Print sorted list of functions headers.
*
***************************************************************************/
void SortFunctions(void)
{
int i, j, low;
ifd = fopen("temp", "r");
i = -1;
while (++i <= nentries) {
low = 0;
j = -1;
while (++j <= nentries) {
if (!entry[j].printed) {
if (entry[low].printed)
low = j;
else if (0 > _stricmp(entry[j].entname, entry[low].entname))
low = j;
}
}
PrintEntry(low);
entry[low].printed = TRUE;
}
} /* SortFunctions */
/***
*UsageError() - print out usage
*Purpose:
* prints out the usage guidelines
*
*Entry:
*
*Exit:
* exits to DOS
*
*Exceptions:
*
*******************************************************************************/
void UsageError(void)
{
printf("Usage: striphdr [switches] file {file ...}\n\n");
printf(" Accepts native code or C source; determines source\n");
printf(" type based on filename suffix.\n");
printf(" Wildcards may be used in the file names.\n");
printf("\n");
printf("Switches:\n");
printf(" -m process module headers only\n");
printf(" -b processes both procedure and module headers\n");
printf(" [default is procedure headers only]\n");
printf(" -l processes only first line of each header\n");
printf(" -n processes none of header (i.e. lists only function name)\n");
printf(" -s <name> processes named section only (may be used with -l)\n");
printf(" [default is to process whole header]\n");
printf(" -d delete processed section from input file\n");
printf(" -q quiet, do not print headers (useful only with -d)\n");
printf(" -x <ext> gives extension for output file when -d used\n");
printf(" [default: .new]\n");
printf(" -r remove revision histories from file headers\n");
printf(" (equivalent to -m -d -q -s \"Revision History\")\n");
exit(-1);
} /* UsageError */
void gdir( char * dst, char * src)
{
int i;
for ( i = strlen(src) -1; i >= 0 && (src[i] != '\\'); i--);
strncpy(dst, src, i);
dst[i] = 0;
}
/***
*main() - parse command line and process all file
*
*Purpose:
* To run the other procedures based on the command line.
*
*******************************************************************************/
int main(int argc, char *argv[])
{
int filei;
int fScanningSwitches = TRUE;
char base_dir[256], curr_dir[256];
long h_find;
struct _finddata_t f_data;
nfuncs = -1;
nentries = -1;
nambufi = 0;
ofpos = 0;
filei = 1;
outline = 1;
if (argc == 1) /* no args given - print usage message and quit */
UsageError();
while (fScanningSwitches) {
if (filei >= argc) {
fScanningSwitches = FALSE;
}
else if (_stricmp("-d", argv[filei]) == 0) {
fDelete = TRUE;
filei++;
}
else if (_stricmp("-q", argv[filei]) == 0) {
fQuiet = TRUE;
filei++;
}
else if (_stricmp("-n", argv[filei]) == 0) {
fDoFirst = fDoSection = fDoAll = FALSE;
filei++;
}
else if (_stricmp("-m", argv[filei]) == 0) {
fGetModNams = TRUE;
fGetProcNams = FALSE;
filei++;
}
else if (_stricmp("-b", argv[filei]) == 0) {
fGetModNams = TRUE;
fGetProcNams = TRUE;
filei++;
}
else if (_stricmp("-l", argv[filei]) == 0) {
fDoFirst = TRUE;
fDoAll = FALSE;
filei++;
}
else if (_stricmp("-s", argv[filei]) == 0) {
fDoSection = TRUE;
fDoAll = FALSE;
filei++;
if (filei >= argc)
UsageError();
strcpy(SectionHead, argv[filei]); /* copy section header in */
filei++;
}
else if (_stricmp("-x", argv[filei]) == 0) {
filei++;
if (argv[filei][0] == '.')
strncpy(CopyExt, argv[filei]+1, 3); /* skip '.' */
else
strncpy(CopyExt, argv[filei], 3);
CopyExt[3] = '\0'; /* terminate string */
filei++;
}
else if (_stricmp("-r", argv[filei]) == 0) {
fDelete = TRUE;
fGetModNams = TRUE;
fGetProcNams = FALSE;
fDoAll = FALSE;
fDoSection = TRUE;
fQuiet = TRUE;
strcpy(SectionHead, "Revision History");
filei++;
}
else if (*(argv[filei]) == '-')
UsageError();
else
fScanningSwitches = FALSE;
}
if (filei >= argc)
UsageError(); /* no files specified */
if (fQuiet)
ofd = fopen("nul", "w"); /* in quiet mode, so no need to save the headers */
else
ofd = fopen("temp", "w");
if (ofd == NULL)
MyAbort(FILENO, "temp"); /* can't open file */
filei--;
if ( _getcwd(base_dir, 255) == NULL)
exit(0);
while (++filei < argc) {
gdir(curr_dir, argv[filei]);
if (_chdir(curr_dir) == -1) {
printf("%s: %s\n", curr_dir, strerror(errno));
exit(0);
}
if ( (h_find = _findfirst(argv[filei], &f_data)) == -1)
continue;
do
{
MyReadFile(f_data.name);
} while ( _findnext(h_find, &f_data) == 0);
_findclose(h_find);
if (_chdir(base_dir) == -1) {
printf("%s: %s\n", curr_dir, strerror(errno));
exit(0);
}
}
fclose(ofd);
if (!fQuiet)
SortFunctions();
return 0 ;
}