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

  1. /***************************************************************************
  2. *striphdr.c - Program to read source files and produce alphabetised
  3. * listing of header blocks, telling which files they came
  4. * from.
  5. *
  6. * Copyright (c) 1983-2001, Microsoft Corporation. All rights reserved.
  7. *
  8. *Author: Tom Corbett, Brian Lewis - Microsoft Corp.
  9. *
  10. *Usage: striphdr [switches] file {file ...}
  11. * Accepts native code or C source; determines source
  12. * type based on filename suffix.
  13. * Wildcards may be used in the file names.
  14. *
  15. * switches:
  16. *
  17. * -m process module headers only
  18. * -b process both procedure and module headers
  19. * [default is procedure headers only]
  20. * -l process only first line of each header
  21. * -n process none of header (i.e. lists only function name)
  22. * -s <name> process named section only (may be used with -l)
  23. * [default is to process whole header]
  24. * -d delete processed section from input file
  25. * -q quiet, do not print headers (useful only with -d)
  26. * -x <ext> gives extension for output file when -d used
  27. * [default: .new]
  28. * -r remove revision histories from file headers
  29. * (equivalent to -m -d -q -s "Revision History")
  30. *
  31. *Purpose:
  32. * Given a list of Native code and/or C sources, strip out routine or module
  33. * headers and produce an alphabetised listing of the headers, telling where
  34. * (filename) each header came from. Optionally, delete part or all of the
  35. * headers from the source file.
  36. *
  37. * For each file on the command line (wildcards may be used), striphdr reads
  38. * the file, and records information from the file and/or procedure headers.
  39. * This information is then sorted by procedure name/file name, and printed
  40. * to stdout, with an indication of which file each procedure is from. If
  41. * the -d flag is activated, the information is also deleted from the input
  42. * file and the new file placed in a file with the same name but the
  43. * extension .new (this extension can be changed with the -x switch). The
  44. * actual input file is also left as is. When using the -d switch, -q will
  45. * eliminate the output, so that only the deleting action takes place. By
  46. * default only the procedure headers are scanned, the -m and -b switches
  47. * change this. By default all the information in a header is printed or
  48. * deleted, the -l, -n, and -s switches change this. The -r switch is an
  49. * abbreviation which will remove revision histories from the file headers.
  50. *
  51. * Input filenames with suffixes of .c or .h are assumed to contain C source,
  52. * and suffixes of .asm or .inc imply native code source. Routine or module
  53. * names must be on the first or second line following the start of header;
  54. * if on the second line then the first line must contain only whitespace
  55. * after an optional '*' (if C source) or ';' (if native code source).
  56. * Routine names can contain a return type and parameters; multiple entry
  57. * point should be seperated by commas. Header start and end symbols must
  58. * start in the left-most column. Module headers and routine headers are
  59. * marked in the same manner; position relative to the beginning of file is
  60. * used to determine which header type is appropriate.
  61. *
  62. * Source is detabbed (1 tab assumed to equal 4 spaces in C, 8 spaces in native
  63. * code) and routine names are parsed to ensure that the correct name is
  64. * grabbed for sorting.
  65. *
  66. * C Headers are started with a '/' characters in the first column followed
  67. * by at least 3 '*' characters, and are ended with at least 4 '*' characters
  68. * followed by a '/'. Each line within a header must begin with a '*', except
  69. * lines beginning with '#if', '#else', or '#endif'. Module headers must be
  70. * preceded with nothing except (perhaps) blank lines; if any non-blank lines
  71. * are found prior to the first header in a module, it is assumed that the
  72. * header belongs to a routine, otherwise, to the entire module.
  73. *
  74. * Native code headers are started by a ';' followed by at least 3 '*'
  75. * characters, and the header end is denoted by a ';' followed by at least
  76. * 4 '*' characters. There must be a ';' character in the left-most column of
  77. * every line of the header block; the only exception to this is that the '
  78. * if', 'else', and 'endif' switches are allowed inside header blocks. Module
  79. * headers can be preceded with any number of blank lines, a TITLE statement,
  80. * a NAME statement, and/or a PAGE statement; if anything else is
  81. * encountered, subsequent headers will be assumed to be routine headers.
  82. *
  83. * Sections within a header must have a title beginning on the 2nd
  84. * character of the line, and the section is assumed to extend to the next
  85. * line with a non-blank character in position 2.
  86. *
  87. * No non-header comments should begin in column 1 with '/***' in C or
  88. * ';***' in native code; this will confuse striphdr.
  89. *
  90. *
  91. *Revision History:
  92. *
  93. * 01-01-83 TOMC Created [tomc]
  94. * 09-09-85 BL Modified to allow the option of stripping module headers
  95. * instead of routine headers via the -m switch
  96. * 09-30-85 BL Modified to accept either C Source or native code source.
  97. * Modified to detab C Source assuming 3 spaces per tab.
  98. * Modified to parse C Routine names properly, allowing
  99. * types, macros, etc. to precede routine names.
  100. * Modified to make the sorting be case insensitive.
  101. * 11-12-85 BL Fixed bug that caused 1st char to always be removed from
  102. * headers, and that caused problems when a blank line follows
  103. * header starts.
  104. * 06-01-87 PHG fixed GetNonBlank()
  105. * allowed 'title' and 'Title" as well as 'TITLE'
  106. * allowed NAME, PAGE as well as TITLE
  107. * made tab expansion for both ASM and C files
  108. * both C and ASM procedure names can have args,
  109. * multiple entries
  110. * simplified some code and a few minor bug fixes
  111. * added -b, -n, -s, -d, -q, -x, -r switches
  112. * 05-10-90 JCR Accept .cxx/.hxx files (C++ support), misc cleanup
  113. * 04-06-95 SKS Accept .cpp/.hpp as equivalent to .cxx/.hxx, respectively
  114. ***************************************************************************/
  115. #include <stdio.h>
  116. #include <stdlib.h>
  117. #include <string.h>
  118. #include <io.h>
  119. #include <direct.h>
  120. #define TRUE 1
  121. #define FALSE 0
  122. #define NAMBUFSZ 20000 /* size of buffer for holding all procedure names */
  123. #define LINEBUFSZ 250 /* maximum size of 1 physical line */
  124. #define MAXENT 3000 /* maximum number of procedure entry points */
  125. #define MAXFUNCS 2000 /* maximum number of function headers */
  126. /* abort codes */
  127. #define NMBUFOV 0 /* name buffer table overflow */
  128. #define FILENF 1 /* file not found */
  129. #define FUNCSOV 2 /* function table overflow */
  130. #define ENTOV 3 /* entry table overflow */
  131. #define FILENO 4 /* cannot open file */
  132. #define OUTSPACE 5 /* out of disk space */
  133. /* tab sizes, pagelength */
  134. #define TABSIZE_C 4
  135. #define TABSIZE_ASM 8 /* tab sizes for code */
  136. #define PAGELEN 60 /* pagelength for page breaks; 60 for HP LaserJet */
  137. struct {
  138. char *entname; /* name of entry point */
  139. int funcid; /* function index for this entry point */
  140. char printed; /* flag to ensure each entry printed just once */
  141. }
  142. entry [MAXENT];
  143. int nentries; /* number of entries parsed so far */
  144. struct {
  145. char *filename; /* name of file which contains this function */
  146. long filepos; /* seek position on file "temp" */
  147. int nlines; /* number of lines in function header */
  148. }
  149. func [MAXFUNCS];
  150. int nfuncs; /* number of function parsed so far */
  151. long ofpos; /* output file seek position */
  152. char linebuf[LINEBUFSZ];
  153. char nambuf[NAMBUFSZ]; /* buffer for holding function names */
  154. int nambufi; /* next free byte in nambuf */
  155. char fEof;
  156. FILE *ofd; /* output file descriptor */
  157. FILE *ifd; /* input file descriptor */
  158. FILE *cfd; /* copy file descriptor */
  159. FILE *fopen();
  160. int outline; /* output line number (1..PAGELEN) for page ejects */
  161. int fDelete = FALSE; /* TRUE if copy and delete instead of display */
  162. int fGetModNams = FALSE; /* TRUE if strip module names */
  163. int fGetProcNams = TRUE; /* TRUE if strip procedure names */
  164. int fC_Source; /* TRUE if we're processing C source, false if .asm */
  165. int fDoAll = TRUE; /* TRUE if we process all of header */
  166. int fDoFirst = FALSE; /* TRUE if we process first line of header */
  167. int fDoSection = FALSE; /* TRUE if we process named section of header */
  168. int fQuiet = FALSE; /* TRUE is quiet mode */
  169. char SectionHead[80]; /* Section name */
  170. char CopyExt[4] = "new"; /* extension of new files */
  171. char *szFilenameCur; /* name of file being read (for error reporting) */
  172. /***
  173. *MyAbort(code, s) - abort program with message
  174. *Purpose:
  175. * abort the program with correct message.
  176. *
  177. *Entry:
  178. * code = error code
  179. * s = filename for code == FILENF
  180. *
  181. *Exit:
  182. * exits to DOS
  183. *
  184. *Exceptions:
  185. *
  186. *******************************************************************************/
  187. void MyAbort(code, s)
  188. int code;
  189. char *s;
  190. {
  191. fprintf(stderr, "Fatal Error - ");
  192. if (code == NMBUFOV)
  193. fprintf(stderr, "NAME Buffer overflow\n");
  194. if (code == FILENF)
  195. fprintf(stderr, "File not found: %s\n", s);
  196. if (code == FUNCSOV)
  197. fprintf(stderr, "Function table overflow\n");
  198. if (code == ENTOV)
  199. fprintf(stderr, "Entry table overflow\n");
  200. if (code == FILENO)
  201. fprintf(stderr, "Cannot open file: %s\n", s);
  202. if (code == OUTSPACE)
  203. fprintf(stderr, "Out of disk space\n", s);
  204. exit(code);
  205. } /* MyAbort */
  206. /***
  207. *FindIfC(szFile) - find if filename if C or ASM
  208. *
  209. *Purpose:
  210. * Set global flag fC_Source to TRUE if the filename ends in
  211. * .c, .h, .cxx (.cpp), or .hxx (.hpp); FALSE if it ends in .asm or .inc.
  212. * The extension comparison is NOT case senstive. If none of
  213. * these are found, don't set the flag,and return FALSE,
  214. * else return TRUE.
  215. *
  216. *Exit:
  217. * sets flag fC_Source
  218. * returns FALSE if neither C nor ASM source
  219. * returns TRUE if fC_Source set
  220. ********************************************************************/
  221. FindIfC(szFile)
  222. char *szFile;
  223. {
  224. int cbFileName = strlen(szFile);
  225. char *pbPastName = szFile + cbFileName; /* points at NULL at string end */
  226. if ((!_stricmp (".c", pbPastName - 2)) ||
  227. (!_stricmp (".h", pbPastName - 2)) ||
  228. (!_stricmp (".s", pbPastName - 2)) ||
  229. (!_stricmp (".cpp", pbPastName - 4)) ||
  230. (!_stricmp (".hpp", pbPastName - 4)) ||
  231. (!_stricmp (".cxx", pbPastName - 4)) ||
  232. (!_stricmp (".hxx", pbPastName - 4)))
  233. fC_Source = TRUE; /* file is assumed to be C source */
  234. else if ((!_stricmp (".asm", pbPastName - 4)) ||
  235. (!_stricmp (".inc", pbPastName - 4)))
  236. fC_Source = FALSE; /* file is assumed to be Native Code source */
  237. else return (FALSE); /* didn't find an appropriate suffix */
  238. return (TRUE);
  239. } /* FindIfC */
  240. /***
  241. *MakeCopyfileName(filename, copyname) - make copyfile name from input name
  242. *
  243. *Purpose:
  244. * Put the copy file suffix onto a file name
  245. *
  246. *Entry:
  247. * filename = input file name
  248. *
  249. *Exit:
  250. * copyname = filled in with copy file name
  251. *
  252. *Exceptions:
  253. *
  254. *******************************************************************************/
  255. void MakeCopyfileName(filename, copyname)
  256. char *filename, *copyname;
  257. {
  258. char *p;
  259. strcpy(copyname, filename);
  260. p = copyname + strlen(copyname);
  261. while (*(--p) != '.')
  262. ; /* p points to '.' */
  263. *(p+1) = '\0'; /* cut off string after '.' */
  264. strcat(copyname, CopyExt); /* put on copy file extension */
  265. }
  266. /***
  267. *linelen(pLine)
  268. *
  269. *Purpose:
  270. * Return the number of characters in a passed line. The line terminator
  271. * ('\n') is not included in the count.
  272. *
  273. *Entry:
  274. * pLine = a pointer to the first char in the line.
  275. *Exit:
  276. * returns the number of characters in the line (an int).
  277. ***************************************************************************/
  278. int linelen(pLine)
  279. char *pLine;
  280. {
  281. register int index;
  282. for (index = 0; *(pLine + index) != '\n'; index++);
  283. return (index);
  284. }
  285. static int cLinesRead;
  286. static char fInHeader = FALSE;
  287. /***
  288. *ReadLine(copyit) - read line and analyze it
  289. *
  290. *Purpose:
  291. * read 1 line from input file into 'linebuf'.
  292. * if copyit == TRUE, copy previous line to copy file
  293. *
  294. *Entry:
  295. * copyit = TRUE means copy the line to the copy file
  296. *
  297. *Exit:
  298. * returns -1 for EOF,
  299. * 0 for vanilla lines,
  300. * if C Source,
  301. * 1 for lines which begin "/***" (start of header)
  302. * 2 for lines which begin "/****" (end of header)
  303. * if Native Code Source,
  304. * 1 for lines which begin ";***" (start of header)
  305. * 2 for lines which begin ";****" (end of header)
  306. *
  307. ***************************************************************************/
  308. int ReadLine(copyit)
  309. int copyit; /* TRUE = copy line to copy file */
  310. {
  311. register int i;
  312. register int cbLine;
  313. if (copyit) {
  314. if (fputs(linebuf, cfd) == EOF)
  315. MyAbort(OUTSPACE);
  316. } /* copy previous line if requested */
  317. if ((fgets(linebuf, LINEBUFSZ, ifd)) == NULL) {
  318. fEof = TRUE;
  319. return(-1);
  320. }
  321. cLinesRead++;
  322. cbLine = linelen(linebuf);
  323. if ((linebuf[0] == ';') && (!fC_Source)) { /* native code comment */
  324. if ((linebuf[1] == '*') && (linebuf[2] == '*') && (linebuf[3] == '*'))
  325. /* know we have either start or end of a header */
  326. if (fInHeader) {
  327. fInHeader = FALSE;
  328. if (linebuf[4] == '*')
  329. return (2); /* valid end of header */
  330. /* error, got start of header when we're already in a header */
  331. fprintf(stderr, "Unterminated header for function: %s\n",
  332. entry[nentries].entname);
  333. fprintf(stderr, " before line %d of file %s\n",
  334. cLinesRead, szFilenameCur);
  335. }
  336. else { /* have a valid start of header */
  337. fInHeader = TRUE;
  338. return (1);
  339. }
  340. }
  341. else if ((linebuf[0] == '/') && (fC_Source)) { /* C code comment? */
  342. if ((linebuf[1] == '*') && (linebuf[2] == '*') && (linebuf[3] == '*'))
  343. if (fInHeader) {
  344. /* error, got start of header when we're already in a header */
  345. fprintf(stderr, "Unterminated header for function: %s\n",
  346. entry[nentries].entname);
  347. fprintf(stderr, " before line %d of file %s\n",
  348. cLinesRead, szFilenameCur);
  349. }
  350. else {
  351. fInHeader = TRUE;
  352. return (1); /* valid start of header */
  353. }
  354. }
  355. else if ((linebuf[0] == '*') && (fC_Source)) { /* C code comment? */
  356. for (i = 1; (i < cbLine) && (linebuf[i] == '*'); i++);
  357. if ((linebuf[i] == '/') && (i > 3)) { /* have a valid end of header */
  358. if (fInHeader) {
  359. fInHeader = FALSE;
  360. return (2);
  361. }
  362. /* got a header terminator when we weren't within a header */
  363. fprintf(stderr, "Illegal termination to header for function: %s",
  364. entry[nentries].entname);
  365. fprintf(stderr, " in line %d of file %s\n",
  366. cLinesRead, szFilenameCur);
  367. } /* if */
  368. } /* else if */
  369. return(0); /* vanilla line */
  370. } /* ReadLine */
  371. /***
  372. *WriteLine(pb, of) - write a line and expand tabs
  373. *
  374. *Purpose:
  375. * Write a zero terminated string to file 'of'.
  376. * If we're writing C Source header lines, detab them as we go.
  377. *
  378. *Entry:
  379. * pb = points to 1st byte of 0-terminated string.
  380. * of = aft index for destination file.
  381. *
  382. *Exit:
  383. * 'ofpos' is bumped to reflect current output file position.
  384. *
  385. ***************************************************************************/
  386. void WriteLine(pb, of)
  387. register char *pb;
  388. FILE *of;
  389. {
  390. register int linepos = 0; /* column position on output line */
  391. int modTS; /* linepos mod tabSize */
  392. int cSpaces; /* number of spaces to print to next tab stop */
  393. int index; /* 'for' index for printing spaces */
  394. int tabSize; /* current tab size */
  395. if (fC_Source)
  396. tabSize = TABSIZE_C;
  397. else
  398. tabSize = TABSIZE_ASM;
  399. while (*pb != '\0') {
  400. if (*pb == '\t') { /* if a tab character found */
  401. modTS = linepos % tabSize;
  402. cSpaces = tabSize - modTS;
  403. for (index = 0; index < cSpaces; index++) {
  404. fputc(' ', of);
  405. linepos++;
  406. }
  407. } /* if */
  408. else {
  409. fputc(*pb, of);
  410. linepos++;
  411. }
  412. pb++;
  413. } /* while */
  414. if (ferror(of))
  415. MyAbort(OUTSPACE);
  416. ofpos = ftell(of); /* update output file seek position for next line */
  417. } /* WriteLine */
  418. /***
  419. *SwitchFound(s) - see if IF, ELSE, ENDIF switch on this line
  420. *
  421. *Purpose: return TRUE if an "if", "else", or "endif" are identified at
  422. * the start of string 's'. This is used to check to see if a
  423. * header line which doesn't start with ';' is an assembler switch.
  424. *Entry:
  425. * s = pointer to a char which represents the string to be checked.
  426. *
  427. *Exit:
  428. * returns TRUE if the string matches "if", "else", or "endif" of either
  429. * upper or lower case, FALSE otherwise.
  430. ***************************************************************************/
  431. SwitchFound(s)
  432. char *s;
  433. {
  434. if (fC_Source) {
  435. /* strncmp returns 0 (which maps to FALSE) iff a match was found */
  436. if (strncmp(s, "#if", 3) &&
  437. strncmp(s, "#IF", 3) &&
  438. strncmp(s, "#else", 5) &&
  439. strncmp(s, "#ELSE", 5) &&
  440. strncmp(s, "#endif", 6) &&
  441. strncmp(s, "#ENDIF", 6))
  442. return (FALSE);
  443. }
  444. else {
  445. if (strncmp(s, "if", 2) &&
  446. strncmp(s, "IF", 2) &&
  447. strncmp(s, "else", 4) &&
  448. strncmp(s, "ELSE", 4) &&
  449. strncmp(s, "endif", 5) &&
  450. strncmp(s, "ENDIF", 5))
  451. return (FALSE);
  452. }
  453. return (TRUE);
  454. }
  455. /***
  456. *GetNonBlank(copyit) - read line, find first non blank character
  457. *
  458. *Purpose:
  459. * Read in a line; return linebuf index if non-blank line found, -1 otherwise
  460. *
  461. *Entry:
  462. * copyit = TRUE means copy line to copy file
  463. *
  464. *Exit:
  465. * returns -1 if blank line read
  466. * return index of first non-whitespace char otherwise
  467. *
  468. ***************************************************************************/
  469. GetNonBlank(copyit)
  470. int copyit; /* copy lines to copy file if TRUE */
  471. {
  472. register int i;
  473. register int cbLine;
  474. if (ReadLine(copyit) == -1) {
  475. return(-1);
  476. }
  477. cbLine = linelen(linebuf);
  478. for (i = 0; ((linebuf[i] == ' ') || (linebuf[i] == '\t')) &&
  479. (i < cbLine); i++);
  480. if (i >= cbLine)
  481. return (-1);
  482. else
  483. return (i);
  484. } /* GetNonBlank */
  485. /***
  486. *ReadToHeader() - reads to beginning of next header
  487. *
  488. *Purpose:
  489. * Reads to beginning of next header or EOF
  490. *
  491. *Entry:
  492. *
  493. *Exit:
  494. * Returns -1 if at EOF, 0 if at a header
  495. *
  496. ************************************************************************/
  497. int ReadToHeader()
  498. {
  499. while (!fEof && ReadLine(fDelete) != 1)
  500. ;
  501. if (fEof)
  502. return -1; /* at EOF */
  503. else
  504. return 0; /* at beginning of header */
  505. }
  506. /***
  507. *Get1stHdr() - read to first header
  508. *
  509. *Purpose:
  510. * Read lines until the first header is found. Return TRUE if this is
  511. * the header for the module, or FALSE if no module header is found.
  512. *
  513. * In C Sources, we assume that if the first non-blank line in the source
  514. * starts with '/***', then it's the start of a module header.
  515. * In Native-Code Sources, we assume that there can exist any number
  516. * of blank lines, optionally followed by a TITLE statement, followed
  517. * by any number of blanks lines, and then by the module header if
  518. * it exists.
  519. *
  520. *Entry:
  521. * NONE
  522. *Exit:
  523. * TRUE if module header found, FALSE otherwise. Note that if fEof is found,
  524. * FALSE is returned, and if !fEof and no module header is found, this
  525. * routine will read in lines until the first routine header is found,or
  526. * fEof.
  527. ***************************************************************************/
  528. Get1stHdr()
  529. {
  530. register int index;
  531. register int i;
  532. while (((index = GetNonBlank(fDelete)) == -1) && (!fEof))
  533. ;
  534. if (fEof) {
  535. fprintf(stderr, "warning: no file header on file ");
  536. fprintf(stderr, "%s\n", szFilenameCur);
  537. return (FALSE);
  538. }
  539. /* now, index is set into linebuf for a non-blank character */
  540. if (fC_Source) { /* if header exists, must be first non-blank line */
  541. if ((linebuf[0] == '/') && (linebuf[1] == '*') &&
  542. (linebuf[2] == '*') && (linebuf[3] == '*')) {
  543. fInHeader = TRUE;
  544. return (TRUE);
  545. }
  546. else {
  547. /* read to start of first header, tell caller no module header found */
  548. ReadToHeader();
  549. fprintf(stderr, "warning: no file header on file ");
  550. fprintf(stderr, "%s\n", szFilenameCur);
  551. return (FALSE);
  552. }
  553. }
  554. /* must be native-code source - - - can have a TITLE line with blank
  555. lines before and after it - - - all prior to module header */
  556. for (i = 1; i <= 3; ++i) { /* do thrice, might have TITLE, NAME, and PAGE */
  557. if (strncmp("TITLE", linebuf + index, 5) == 0 ||
  558. strncmp("title", linebuf + index, 5) == 0 ||
  559. strncmp("Title", linebuf + index, 5) == 0 ||
  560. strncmp("NAME", linebuf + index, 4) == 0 ||
  561. strncmp("name", linebuf + index, 4) == 0 ||
  562. strncmp("Name", linebuf + index, 4) == 0 ||
  563. strncmp("PAGE", linebuf + index, 4) == 0 ||
  564. strncmp("Page", linebuf + index, 4) == 0 ||
  565. strncmp("page", linebuf + index, 4) == 0)
  566. { /* found TITLE, NAME, or PAGE statement */
  567. while (((index = GetNonBlank(fDelete)) == -1) && (!fEof))
  568. ;
  569. if (fEof) {
  570. fprintf(stderr, "warning: no file header on file ");
  571. fprintf(stderr, "%s\n", szFilenameCur);
  572. return (FALSE);
  573. }
  574. }
  575. }
  576. /* if there was a TITLE and/or NAME statement, we've eaten it,
  577. and any following blank lines;
  578. must now have module header, if it exists */
  579. if ((linebuf[0] == ';') && (linebuf[1] == '*') &&
  580. (linebuf[2] == '*') && (linebuf[3] == '*')) {
  581. fInHeader = TRUE;
  582. return (TRUE);
  583. }
  584. else {
  585. /* read to start of first header, tell caller no module header found */
  586. ReadToHeader();
  587. fprintf(stderr, "warning: no file header on file ");
  588. fprintf(stderr, "%s\n", szFilenameCur);
  589. return (FALSE);
  590. }
  591. } /* Get1stHdr */
  592. /***
  593. *AdvanceOne(s) - advance one char if one whitespace or comment token
  594. *
  595. *Purpose:
  596. * 's' points to the first character in an input line; if it's a whitespace
  597. * token or a comment token, return a pointer to the next character in the
  598. * line, otherwise, return 's' unchanged.
  599. *
  600. *Entry:
  601. * s = ptr to first char in input line
  602. *
  603. *Exit:
  604. * returns ptr the next char if *s is whatspace, ';', or '*',
  605. * otherwise returns s
  606. *
  607. *******************************************************************************/
  608. char *AdvanceOne(s)
  609. char *s;
  610. {
  611. if (*s == '*') {
  612. if (fC_Source)
  613. s++;
  614. }
  615. else if (*s == ';') {
  616. if (!fC_Source)
  617. s++;
  618. }
  619. else if ((*s == ' ') || (*s == '\t'))
  620. s++;
  621. return(s);
  622. } /* AdvanceOne */
  623. /***
  624. *FuncNamePtr(pbName) - find function name from this or next line
  625. *
  626. *Purpose:
  627. * Given a pointer into the current header line, return a pointer to
  628. * the first non-blank or comment symbol; if none found in the existing
  629. * line, read in another and try that one.
  630. * if a C routine line, skip any types, etc., and return a pointer to
  631. * the filename itself.
  632. *
  633. * If a C routine line:
  634. * -------------------
  635. * Assumes that C routine names will end with a left paren.
  636. * Allows left parens in a summary of purpose if said summary is
  637. * preceded by a '-' which comes after the routine name.
  638. * Assumes that there are 1 or 0 spaces between the the routine name
  639. * and the mandatory left paren.
  640. *
  641. *Entry:
  642. * pbName = a pointer to the place to begin searching in linebuf.
  643. *Exit:
  644. * Returns a pointer to the filename.
  645. *
  646. ***************************************************************************/
  647. char *FuncNamePtr(pbName)
  648. register char *pbName;
  649. {
  650. register int cbLine;
  651. char *pbTmp;
  652. int iStart;
  653. /* first, see if we have a blank line - if so, read in another one,
  654. and assume that it has the filename; don't check that one ... */
  655. pbTmp = AdvanceOne(pbName);
  656. cbLine = linelen(pbTmp);
  657. for (iStart = 0; ((*(pbTmp+iStart) == ' ') || (*(pbTmp+iStart) == ' ')) &&
  658. (iStart < cbLine); iStart++);
  659. if (iStart >= cbLine) {
  660. if (ReadLine(fDelete) != 0) { /* then we got a procedure end w/out a name! */
  661. if (fEof)
  662. fprintf(stderr, "EOF not expected\n");
  663. else
  664. fprintf(stderr, "Illegal header termination\n");
  665. fprintf(stderr,
  666. " in line %d of file %s\n", cLinesRead, szFilenameCur);
  667. return((char *)-1);
  668. }
  669. pbName = linebuf;
  670. }
  671. /* now, assume that there is a filename somewhere at or after pbName */
  672. iStart = 0;
  673. while (*(pbName+iStart) != '(' && *(pbName+iStart) != '-' &&
  674. *(pbName+iStart) != ',' && *(pbName+iStart) != '\n')
  675. ++iStart; /* search fwd for '(', '-', ',' or '\n' */
  676. do {
  677. --iStart;
  678. }
  679. while ((*(pbName+iStart) == ' ' || *(pbName+iStart) == '\t') &&
  680. iStart > 0);
  681. /* search back through whitespace */
  682. while (*(pbName+iStart) != ' ' && *(pbName+iStart) != '\t' &&
  683. *(pbName+iStart) != ';' && *(pbName+iStart) != '*')
  684. --iStart;
  685. /* search back to beginning of name */
  686. ++iStart; /* point to first letter of name */
  687. return (pbName+iStart); /* return pointer to name */
  688. } /* FuncNamePtr */
  689. /***
  690. *MyReadFile(pbNam) - read file and remember headers
  691. *
  692. *Purpose:
  693. * Read one entire file, stripping out and remembering function headers
  694. * or module headers, as appropriate.
  695. *
  696. ***************************************************************************/
  697. void MyReadFile(char *pbNam)
  698. {
  699. char CopyName[65]; /* name of copy file */
  700. char *s, done, backout;
  701. int funci, svnfuncs, svnentries;
  702. int inmodhdr; /* TRUE if in module header, else FALSE */
  703. int insection; /* TRUE if in scetion to process */
  704. int onfirst; /* TRUE if on first line of header */
  705. szFilenameCur = pbNam;
  706. if ((ifd = fopen(pbNam, "r")) <= 0)
  707. MyAbort(FILENF, pbNam);
  708. linebuf[0] = '\0'; /* make linebuf blank so file copying works */
  709. fEof = FALSE;
  710. cLinesRead = 0;
  711. if (!FindIfC(pbNam)) { /* filename had invalid suffix */
  712. fprintf(stderr, "Illegal suffix for file %s", pbNam);
  713. fprintf(stderr, "; must have .c or .asm suffix\n");
  714. fclose(ifd);
  715. return;
  716. }
  717. if (fDelete) {
  718. MakeCopyfileName(pbNam, CopyName); /* put the right extension on */
  719. cfd = fopen(CopyName, "w");
  720. if (cfd == NULL)
  721. MyAbort(FILENO, CopyName); /* can't open file */
  722. }
  723. inmodhdr = Get1stHdr();
  724. if (inmodhdr && !fGetModNams) {
  725. /* don't want module header */
  726. ReadToHeader(); /* skip module header */
  727. inmodhdr = FALSE;
  728. }
  729. /* we are currently at the beginning of a new header.
  730. copy it to file TEMP, remember all entry points in NAMBUF. */
  731. while (!fEof && (inmodhdr || fGetProcNams)) {
  732. svnfuncs = nfuncs;
  733. svnentries = nentries;
  734. if (++nfuncs >= MAXFUNCS)
  735. MyAbort(FUNCSOV);
  736. func[nfuncs].filename = pbNam;
  737. func[nfuncs].nlines = 0;
  738. func[nfuncs].filepos = ofpos;
  739. if (ReadLine(fDelete) == -1)
  740. done = TRUE; /* got end-of-file */
  741. else
  742. done = FALSE;
  743. funci = nfuncs;
  744. s = linebuf;
  745. while (!done) {
  746. if (++nentries >= MAXENT)
  747. MyAbort(ENTOV);
  748. entry[nentries].entname = nambuf + nambufi;
  749. entry[nentries].printed = FALSE;
  750. entry[nentries].funcid = funci;
  751. s = FuncNamePtr(s);
  752. if (s == (char *)-1) {
  753. fprintf(stderr, "Error found in line %d of file %s\n",
  754. cLinesRead, szFilenameCur);
  755. s = linebuf;
  756. }
  757. while ((*s != '\0') && /* transfer function name to nambuf */
  758. (*s != ',') &&
  759. (*s != '(') &&
  760. (*s != ' ') &&
  761. (*s != '\n') &&
  762. (*s != '\t') &&
  763. (nambufi < (NAMBUFSZ - 2))) {
  764. nambuf[nambufi++] = *(s++);
  765. }
  766. if (nambufi >= (NAMBUFSZ - 2))
  767. MyAbort(NMBUFOV, NULL);
  768. nambuf[nambufi++] = '\0';
  769. /* make all secondary entry points reference primary entry point */
  770. if (funci >= 0)
  771. funci = -1 - nentries;
  772. /* next we see if another entry point exists */
  773. while (*s == ' ' || *s == '\t')
  774. ++s; /* skip whitespace */
  775. if (*s == '(') {
  776. do {
  777. ++s;
  778. }
  779. while (*s != ')' && *s != '\n'); /* skip param list */
  780. ++s; /* goto next character */
  781. }
  782. while (*s == ' ' || *s == '\t')
  783. ++s; /* skip whitespace */
  784. if (*(s++) != ',')
  785. done = TRUE; /* no more entry pts */
  786. else {
  787. ++s;
  788. done = FALSE;
  789. }
  790. } /* while !done */
  791. backout = FALSE;
  792. if (fDoAll || fDoFirst)
  793. insection = TRUE;
  794. else
  795. insection = FALSE; /* are we in the correct section */
  796. onfirst = TRUE; /* on first line */
  797. do {
  798. s = linebuf;
  799. if ((!fC_Source && (*s != ';') && !SwitchFound(s)) ||
  800. (fC_Source && (*s != '*') && !SwitchFound(s))) {
  801. /* Illegal Header Format, leave garbage in file TEMP,
  802. but restore nfuncs and nentries to previous values
  803. and backout of this header gracefully. */
  804. fprintf(stderr, "Invalid Header for function: %s",
  805. entry[nentries].entname);
  806. fprintf(stderr, " in line %d", cLinesRead);
  807. fprintf(stderr, ", in file: %s\n", pbNam);
  808. nfuncs = svnfuncs;
  809. nentries = svnentries;
  810. backout = TRUE;
  811. }
  812. s = AdvanceOne(s);
  813. if (!fDoAll && fDoSection && !onfirst && *s != ' ' && *s != '\t' && *s != '\n') {
  814. /* now at a section beginning -- and it's significant */
  815. if (insection)
  816. insection = FALSE; /* come to end of section */
  817. else if (strncmp(s, SectionHead, strlen(SectionHead)) == 0)
  818. insection = TRUE; /* come to beginning of section */
  819. }
  820. /* if in the section, don't copy, but write to TEMP */
  821. if (insection) {
  822. WriteLine(s, ofd);
  823. func[nfuncs].nlines++;
  824. ReadLine(FALSE);
  825. }
  826. else {
  827. ReadLine(fDelete);
  828. }
  829. if (onfirst && !fDoAll)
  830. insection = FALSE;
  831. onfirst = FALSE; /* no longer on first line */
  832. }
  833. while ((!fEof) && (!backout) && fInHeader);
  834. /* skip to start of next function header */
  835. if (fGetProcNams)
  836. ReadToHeader();
  837. inmodhdr = FALSE;
  838. } /* while !fEof etc. */
  839. while (!fEof) {
  840. ReadLine(fDelete);
  841. } /* read rest of file */
  842. if (fInHeader) {
  843. /* Error: reached EOF with unterminated header */
  844. fInHeader = FALSE;
  845. fprintf(stderr,
  846. "Error: function %s not terminated before end-of-file in %s\n",
  847. entry[nentries].entname, szFilenameCur);
  848. }
  849. fclose(ifd);
  850. fclose(cfd);
  851. } /* MyReadFile */
  852. /***
  853. *PrintSep() - print a seperator
  854. *
  855. *Purpose:
  856. * Output a some lines which mark function header boundaries.
  857. *
  858. ***************************************************************************/
  859. void PrintSep(void)
  860. {
  861. printf("---------------------------------------");
  862. printf("----------------------------------------\n");
  863. } /* PrintSep */
  864. /***
  865. *PrintEntry(i) - print out an entry point header/module header
  866. *
  867. *Purpose:
  868. * Prints the given header out
  869. *
  870. ***************************************************************************/
  871. PrintEntry(i)
  872. int i;
  873. {
  874. int linecnt, m, entrysize;
  875. if ((m = entry[i].funcid) >= 0)
  876. entrysize = 4 + func[m].nlines; /* primary entry point */
  877. else
  878. entrysize = 4; /* secondary entry point */
  879. if (outline + entrysize > PAGELEN && outline > 1) {
  880. while (outline > PAGELEN)
  881. outline -= PAGELEN;
  882. while (outline <= PAGELEN) {
  883. printf("\n");
  884. outline++;
  885. }
  886. outline = 1;
  887. }
  888. printf("\n");
  889. PrintSep();
  890. printf("%s - ", entry[i].entname);
  891. if (m < 0)
  892. printf("see %s\n", entry[-1-m].entname);
  893. else
  894. printf("File: %s\n", func[m].filename);
  895. PrintSep();
  896. outline = outline + 4;
  897. if (m < 0 || func[m].nlines == 0)
  898. return(0);
  899. fseek(ifd, func[m].filepos, 0);
  900. fEof = FALSE;
  901. linecnt = func[m].nlines;
  902. ReadLine(FALSE);
  903. do {
  904. WriteLine(linebuf, stdout);
  905. outline++;
  906. ReadLine(FALSE);
  907. }
  908. while ((!fEof) && ((--linecnt) > 0));
  909. } /* PrintEntry */
  910. #if 0
  911. /***************************************************************************
  912. *_stricmp(pbLeft, pbRight) - case insensitive string compare
  913. *
  914. *Purpose:
  915. * Case-insensitive string comparison.
  916. *
  917. *Entry:
  918. * pbLeft, pbRight = ptrs to strings to compare
  919. *
  920. *Exit:
  921. * Return 0 if left string == right string, -1 if left string less than
  922. * right string, 1 otherwise
  923. *
  924. *NOTE:
  925. * This routine is provided because not all C runtime libraries support
  926. * this; specifically, MS C for DOS does have this routine, but
  927. * on a 68k it doesn't seem to be there.
  928. *
  929. ***************************************************************************/
  930. char *malloc();
  931. #define isLcase(c) (((c) >= 'a') && ((c) <= 'z'))
  932. #define upit(c) ((isLcase(c))? (c) - 'a' + 'A' : (c))
  933. _stricmp(pbLeft, pbRight)
  934. char *pbLeft, *pbRight;
  935. {
  936. int cbLeft = strlen(pbLeft);
  937. int cbRight = strlen(pbRight);
  938. char *pbUCleft = malloc(cbLeft +1);
  939. char *pbUCright = malloc(cbRight +1);
  940. register char *pbSrc;
  941. register char *pbDst;
  942. register int i, retval;
  943. pbDst = pbUCleft;
  944. pbSrc = pbLeft;
  945. for (i = 0; i <= cbLeft; i++, pbDst++, pbSrc++)
  946. *pbDst = (char)upit(*pbSrc);
  947. pbDst = pbUCright;
  948. pbSrc = pbRight;
  949. for (i = 0; i <= cbRight; i++, pbDst++, pbSrc++)
  950. *pbDst = (char)upit(*pbSrc);
  951. retval = strcmp(pbUCleft, pbUCright);
  952. free(pbUCright);
  953. free(pbUCleft);
  954. return(retval);
  955. } /* strless */
  956. #endif /* 0 */
  957. /***************************************************************************
  958. * SortFunctions()
  959. *
  960. * Purpose:
  961. * Print sorted list of functions headers.
  962. *
  963. ***************************************************************************/
  964. void SortFunctions(void)
  965. {
  966. int i, j, low;
  967. ifd = fopen("temp", "r");
  968. i = -1;
  969. while (++i <= nentries) {
  970. low = 0;
  971. j = -1;
  972. while (++j <= nentries) {
  973. if (!entry[j].printed) {
  974. if (entry[low].printed)
  975. low = j;
  976. else if (0 > _stricmp(entry[j].entname, entry[low].entname))
  977. low = j;
  978. }
  979. }
  980. PrintEntry(low);
  981. entry[low].printed = TRUE;
  982. }
  983. } /* SortFunctions */
  984. /***
  985. *UsageError() - print out usage
  986. *Purpose:
  987. * prints out the usage guidelines
  988. *
  989. *Entry:
  990. *
  991. *Exit:
  992. * exits to DOS
  993. *
  994. *Exceptions:
  995. *
  996. *******************************************************************************/
  997. void UsageError(void)
  998. {
  999. printf("Usage: striphdr [switches] file {file ...}\n\n");
  1000. printf(" Accepts native code or C source; determines source\n");
  1001. printf(" type based on filename suffix.\n");
  1002. printf(" Wildcards may be used in the file names.\n");
  1003. printf("\n");
  1004. printf("Switches:\n");
  1005. printf(" -m process module headers only\n");
  1006. printf(" -b processes both procedure and module headers\n");
  1007. printf(" [default is procedure headers only]\n");
  1008. printf(" -l processes only first line of each header\n");
  1009. printf(" -n processes none of header (i.e. lists only function name)\n");
  1010. printf(" -s <name> processes named section only (may be used with -l)\n");
  1011. printf(" [default is to process whole header]\n");
  1012. printf(" -d delete processed section from input file\n");
  1013. printf(" -q quiet, do not print headers (useful only with -d)\n");
  1014. printf(" -x <ext> gives extension for output file when -d used\n");
  1015. printf(" [default: .new]\n");
  1016. printf(" -r remove revision histories from file headers\n");
  1017. printf(" (equivalent to -m -d -q -s \"Revision History\")\n");
  1018. exit(-1);
  1019. } /* UsageError */
  1020. void gdir( char * dst, char * src)
  1021. {
  1022. int i;
  1023. for ( i = strlen(src) -1; i >= 0 && (src[i] != '\\'); i--);
  1024. strncpy(dst, src, i);
  1025. dst[i] = 0;
  1026. }
  1027. /***
  1028. *main() - parse command line and process all file
  1029. *
  1030. *Purpose:
  1031. * To run the other procedures based on the command line.
  1032. *
  1033. *******************************************************************************/
  1034. int main(int argc, char *argv[])
  1035. {
  1036. int filei;
  1037. int fScanningSwitches = TRUE;
  1038. char base_dir[256], curr_dir[256];
  1039. long h_find;
  1040. struct _finddata_t f_data;
  1041. nfuncs = -1;
  1042. nentries = -1;
  1043. nambufi = 0;
  1044. ofpos = 0;
  1045. filei = 1;
  1046. outline = 1;
  1047. if (argc == 1) /* no args given - print usage message and quit */
  1048. UsageError();
  1049. while (fScanningSwitches) {
  1050. if (filei >= argc) {
  1051. fScanningSwitches = FALSE;
  1052. }
  1053. else if (_stricmp("-d", argv[filei]) == 0) {
  1054. fDelete = TRUE;
  1055. filei++;
  1056. }
  1057. else if (_stricmp("-q", argv[filei]) == 0) {
  1058. fQuiet = TRUE;
  1059. filei++;
  1060. }
  1061. else if (_stricmp("-n", argv[filei]) == 0) {
  1062. fDoFirst = fDoSection = fDoAll = FALSE;
  1063. filei++;
  1064. }
  1065. else if (_stricmp("-m", argv[filei]) == 0) {
  1066. fGetModNams = TRUE;
  1067. fGetProcNams = FALSE;
  1068. filei++;
  1069. }
  1070. else if (_stricmp("-b", argv[filei]) == 0) {
  1071. fGetModNams = TRUE;
  1072. fGetProcNams = TRUE;
  1073. filei++;
  1074. }
  1075. else if (_stricmp("-l", argv[filei]) == 0) {
  1076. fDoFirst = TRUE;
  1077. fDoAll = FALSE;
  1078. filei++;
  1079. }
  1080. else if (_stricmp("-s", argv[filei]) == 0) {
  1081. fDoSection = TRUE;
  1082. fDoAll = FALSE;
  1083. filei++;
  1084. if (filei >= argc)
  1085. UsageError();
  1086. strcpy(SectionHead, argv[filei]); /* copy section header in */
  1087. filei++;
  1088. }
  1089. else if (_stricmp("-x", argv[filei]) == 0) {
  1090. filei++;
  1091. if (argv[filei][0] == '.')
  1092. strncpy(CopyExt, argv[filei]+1, 3); /* skip '.' */
  1093. else
  1094. strncpy(CopyExt, argv[filei], 3);
  1095. CopyExt[3] = '\0'; /* terminate string */
  1096. filei++;
  1097. }
  1098. else if (_stricmp("-r", argv[filei]) == 0) {
  1099. fDelete = TRUE;
  1100. fGetModNams = TRUE;
  1101. fGetProcNams = FALSE;
  1102. fDoAll = FALSE;
  1103. fDoSection = TRUE;
  1104. fQuiet = TRUE;
  1105. strcpy(SectionHead, "Revision History");
  1106. filei++;
  1107. }
  1108. else if (*(argv[filei]) == '-')
  1109. UsageError();
  1110. else
  1111. fScanningSwitches = FALSE;
  1112. }
  1113. if (filei >= argc)
  1114. UsageError(); /* no files specified */
  1115. if (fQuiet)
  1116. ofd = fopen("nul", "w"); /* in quiet mode, so no need to save the headers */
  1117. else
  1118. ofd = fopen("temp", "w");
  1119. if (ofd == NULL)
  1120. MyAbort(FILENO, "temp"); /* can't open file */
  1121. filei--;
  1122. if ( _getcwd(base_dir, 255) == NULL)
  1123. exit(0);
  1124. while (++filei < argc) {
  1125. gdir(curr_dir, argv[filei]);
  1126. if (_chdir(curr_dir) == -1) {
  1127. printf("%s: %s\n", curr_dir, strerror(errno));
  1128. exit(0);
  1129. }
  1130. if ( (h_find = _findfirst(argv[filei], &f_data)) == -1)
  1131. continue;
  1132. do
  1133. {
  1134. MyReadFile(f_data.name);
  1135. } while ( _findnext(h_find, &f_data) == 0);
  1136. _findclose(h_find);
  1137. if (_chdir(base_dir) == -1) {
  1138. printf("%s: %s\n", curr_dir, strerror(errno));
  1139. exit(0);
  1140. }
  1141. }
  1142. fclose(ofd);
  1143. if (!fQuiet)
  1144. SortFunctions();
  1145. return 0 ;
  1146. }