home *** CD-ROM | disk | FTP | other *** search
/ Source Code 1994 March / Source_Code_CD-ROM_Walnut_Creek_March_1994.iso / compsrcs / reviewed / volume02 / cextract / part05 < prev    next >
Encoding:
Internet Message Format  |  1992-11-02  |  56.7 KB

  1. From: Adam Bryant <adb@cs.bu.edu>
  2. Subject: v02i043: cextract - (Ver. 1.7) C prototyper/header file generator, Part05/05
  3. Newsgroups: comp.sources.reviewed
  4. Approved: csr@calvin.dgbt.doc.ca
  5.  
  6. Submitted-by: Adam Bryant <adb@cs.bu.edu>
  7. Posting-number: Volume 2, Issue 43
  8. Archive-name: cextract/part05
  9. Supersedes: cextract: Volume 1, Issue 4-8
  10.  
  11. #! /bin/sh
  12. # This is a shell archive.  Remove anything before this line, then unpack
  13. # it by saving it into a file and typing "sh file".  To overwrite existing
  14. # files, type "sh file -c".  You can also feed this as standard input via
  15. # unshar, or by typing "sh <file", e.g..  If this archive is complete, you
  16. # will see the following message at the end:
  17. #        "End of archive 5 (of 5)."
  18. # Contents:  parse.c
  19. # Wrapped by adb@csa on Fri Oct 30 16:20:37 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'parse.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'parse.c'\"
  23. else
  24. echo shar: Extracting \"'parse.c'\" \(54378 characters\)
  25. sed "s/^X//" >'parse.c' <<'END_OF_FILE'
  26. X/*
  27. X *
  28. X * main parsing routines for the cextract/cextdoc programs.
  29. X * Also includes a number of generic routines applicable to both.
  30. X *
  31. X * These routines provide the methods used to extract comments,
  32. X * prototypes and function names from C source files.
  33. X *
  34. X * Copyright (c) 1990, 1991, 1992 by Adam Bryant
  35. X *
  36. X * The only restrictions on the use of these routines is that they not
  37. X * be used for monetary gain, and that this copyright notice be left
  38. X * intact.
  39. X *
  40. X * Note:  These programs may be freely used to extract code and/or
  41. X *        documentation at proprietary/corporate sites, as long as the
  42. X *        actual source code is not used within any proprietary code.
  43. X *
  44. X *        The generated output (header) files are distributable in any
  45. X *        manner desired as they are based on the scanned source code,
  46. X *        not my program.
  47. X */
  48. X/*
  49. X * Version history:
  50. X *
  51. X * Changes for Version 0.40 of both cextract and cextdoc:
  52. X *    - implemented new out_char() interface.
  53. X *    - first comments will not be shown if no functions exist.
  54. X *    - implemented concatenation of comments.
  55. X *    - implemented troff output for cextdoc portion.
  56. X *
  57. X * Changes for Version 0.41 of both cextract and cextdoc:
  58. X *    - switched the NO_SETBUFFER to SETBUFFER, making non-use standard.
  59. X *    - added in the DO_VARARGS code to automatically account for the
  60. X *      the variable argument setup in parsing.
  61. X *
  62. X * Changes for Version 0.42 of both:
  63. X *    - made the DO_VARARGS code the default.  (removed #ifdefs)
  64. X *
  65. X * Changes for Version 0.50 (1/18/91) of both:
  66. X *    - added the configuration file code.
  67. X *    - removed much of the DEBUG print statements from stable code.
  68. X *    - made the bad syntax encounters exit the program.
  69. X *
  70. X * Changes for Version 0.51 (1/21/91) of both:
  71. X *    - implemented code to allow compilation on VAX VMS systems.
  72. X *
  73. X * Changes for Version 0.60 (4/15/91) of both:
  74. X *    - more VMS stuff, and addition of files: patchlevel.h,
  75. X *      README, and INSTALL.
  76. X *    - removed all other DEBUG statements.
  77. X *    - left the SETBUFFER code in place, but removed mention
  78. X *      of it from the Makefile, since there was no noticable
  79. X *      speed enhancement through its use.
  80. X *    - upgraded to version 6.0 for release to comp.sources.reviewed.
  81. X *
  82. X * Changes for Version 1.0 (4/17/91-5/3/91) of both:
  83. X *    - removed most system definitions from cproto.h and replaced
  84. X *      with more includes of system header files.  But, there are
  85. X *      still a number of system functions which are not in the header
  86. X *      files on at least Sun systems.
  87. X *    - now use the "is_switch()" function to parse the command line
  88. X *      arguments.  This allowed me to use both '-' and '/' on VMS
  89. X *      systems to avoid confusion in the manual pages.
  90. X *    - simplified the Makefile, especially for the "make install".
  91. X *    - fixed various mispellings/misphrasings in error messages.
  92. X *    - checked the argument in calls to free() within pop_proto().
  93. X *    - configuration files will be checked for in the following order:
  94. X *        system file, home directory, current directory.
  95. X *      any encountered will be read in.  This will allow overriding
  96. X *      of customization options in a logical order.
  97. X *    - implemented switch to control how the config files are read in.
  98. X *    - redid the manual pages and split out the customization section
  99. X *      into its own manual page.
  100. X *    - adjusted the comment capturing code to assure that it doesn't
  101. X *      misassign comments to the wrong functions.
  102. X *    - fixed one minor memory leak.
  103. X *    - adjust system configuration file locations.
  104. X *    - redid VMS popen() and pclose() to assure unique temporary file.
  105. X *    - added in an "err_msg()" routine to call perror() if it exits.
  106. X *    - made sure to check return value of all calls to fputs().
  107. X *    - merged "cextdoc" into "cextract".
  108. X *    - added verbose command line options with same format as the
  109. X *      configuration commands.
  110. X *    - now use the "+" and "-" switches to indicate on and off.
  111. X *    - added a number of new options to support the new merged
  112. X *      programs and to allow displaying of settings.
  113. X *    - added a -Hstring to indicate replacement of the sequence:
  114. X *
  115. X *          #ifndef __CEXTRACT__
  116. X *            ... output ...
  117. X *          #endif
  118. X *
  119. X *      with:
  120. X *
  121. X *          #ifndef string
  122. X *          #define string
  123. X *            ... output ...
  124. X *          #endif
  125. X *
  126. X *    - wrote up a VMS help file for cextract.
  127. X *
  128. X * Version 1.1: Okay, so there were still more changes needed. :-)
  129. X *    - fixed more occurances of proceed instead of precede.
  130. X *    - fixed typos of "it's" instead of "its".
  131. X *    - removed empty targets from Makefile
  132. X *    - add sed facility to Makefile to properly configure man pages.
  133. X *    - wrote a ".so" implementation for cextdoc manual instead of
  134. X *      prior hard link method.
  135. X *    - added a MANDIR variable to the Makefile.
  136. X *    - tweaked the documentation in a few places.
  137. X *    - allow the "!" or "no-" (Non-VMS) or "no" (VMS) prefix to
  138. X *      command line options.
  139. X *    - use "sys$login:" as HOME directory on VMS systems, if HOME
  140. X *      environment variable is not defined.
  141. X *    - changed the "sys$system:" to "sys$library".
  142. X *    - fixed typo of "fclose(*stream)" in the VMS pclose.
  143. X *    - adjusted the VMS qualifier building to build /define=(a,b,c), etc.
  144. X *    - added in a "remove-names" option to eliminate variable names
  145. X *      from the parameter list output.
  146. X *    - fixed strncmp() bug in the check for the "replace" option.
  147. X *    - fixed a number of calls to cfg_err() to pass cmd_line parameter.
  148. X *    - implemented better check for empty or "void" parameter lists.
  149. X *    - merged the void check and style determination into one routine
  150. X *      and called it diverge_style().
  151. X *    - changed a number of routines to use char* math instead of
  152. X *      array stepping using counters.
  153. X *    - added a configuration file section to the VMS help file.
  154. X *    - tweaked the cextract.1 and cextrc.5 manual pages a bit more.
  155. X *    - edited the README, INSTALL, and INSTALL.VMS files.
  156. X *    - implemented checks to be sure that the files to be parsed are
  157. X *      accessible before calling the C preprocessor.
  158. X *    - renamed the files as:
  159. X *         cproto.c     =>   parse.c
  160. X *         cproto.h     =>   xtract.h
  161. X *         cextract.c   =>   main.c
  162. X *      this was done to avoid some of the conflict with files
  163. X *      beginning with the same string of characters.
  164. X *    - made sure that "make test" tested the version in the current
  165. X *      directory.
  166. X *
  167. X * Version 1.2:  yet another pre-submission fix section.
  168. X *    - fixed a typo in the comments.
  169. X *    - separated the INSTALL definition in the Makefile into INSTBIN
  170. X *      and INSTMAN command to allow those systems without "install"
  171. X *      to perform installations properly.
  172. X *    - added "/exe=cextract" to the build.com link operation.
  173. X *    - fixed the character count in the copy_str() function.
  174. X *      [This fixes the misread on the "replace" operation].
  175. X *    - fixed up the "method" description in the README.
  176. X *    - added ${CEXTRACT} to the "test" (ala "make test") dependency.
  177. X *    - removed the "make links" and appended it to "make install"
  178. X *    - changed the "skip-config" command to "read-config".
  179. X *    - had one more go at the cextrc.5 manual page.
  180. X *    - tweaked the cextract.1 manual page as well.
  181. X *    - added check for declaration of array of function pointers.
  182. X *    - added code to parse structure declarations within function
  183. X *      parameter lists.  [why anyone would program like this is
  184. X *      beyond me, but hey, I like to support valid C.]
  185. X *    - made sure to only test for functions where a brace was
  186. X *      preceded by a semi-colon or a paranthesis.
  187. X *    - make sure to clear out the "code_info" array more often.
  188. X *    - increased the array sizes to allow for larger buffer space.
  189. X *      [temporary until implement dynamic memory routines.]
  190. X *    - created a TODO file and removed those items from the bottom
  191. X *      of the README file.
  192. X *    - shortened the BUGS section of the cextract.1 manual page.
  193. X *    - changed the program name check to strncmp() so VMS sites work.
  194. X *    - created a newbuild.com file and mentioned it in INSTALL.VMS.
  195. X *    - fixed errors in the newbuild.com file.
  196. X *    - added a mentioning of the '/' character for VMS options.
  197. X *    - cleaned up the README, INSTALL and other docs.
  198. X *
  199. X * Version 1.3:  first patch after comp.sources.reviewed
  200. X *    - fixed bug where comments within parameter list could cause a
  201. X *    function to be skipped.
  202. X *    - added both the CPP and CPP_COMMENTS flags to the Makefile.
  203. X *    - added patch from Martin Fouts (fouts@bozeman.clipper.ingr.com)
  204. X *    to provide simple changes to allow port to the CLIX OS.
  205. X *    - fixed stupid bug which caused the "-U" flag to not get parsed.
  206. X *    - changed the "#ifdef __STDC__" to the proper "#if __STDC__".
  207. X *    - wrote a new command and flag "build-config" to generate the system
  208. X *    configuration file automatically.  [-B or -b for build]
  209. X *    - made sure the replace macros do not contain duplicates.
  210. X *    - prevented the creation of duplicate '-D','-I', or '-U' entries.
  211. X *    - fixed the "macro_match()" function for all systems. [VMS?]
  212. X *    - reversed the definitions of CFLAGS and COPTS in the Makefile.
  213. X *    - made sure to test if substitution already took place in vargs_find().
  214. X *    - fixed the 'Q' flag so that it properly reads in any numeric.
  215. X *    - added a dependency for the system configuration file to the
  216. X *      "install" target, so that it can be automatically generated.
  217. X *    - fixed the INSTALL, INSTALL.VMS and documentation files to
  218. X *      properly cover the new configuration file building mechanism.
  219. X *    - implemented a better method for the NO_OPEN option.  This should
  220. X *      now work for all systems, not just VMS.
  221. X *    - fixed bug that the type of the function was not checked for
  222. X *      replacement.
  223. X *    - made sure that the subst macros where ordered as they came in.
  224. X *    - fixed bug with parameters for function pointers getting int
  225. X *      tagged on unnecessarily.
  226. X *
  227. X * Version 1.4:  [2/25/92-4/20/92]  Another iteration of fixes.
  228. X *    - allow any sort of text inside of brackets and parenthesis
  229. X *      in the variable declarations.
  230. X *    - fixed the fprintf formats in the font error messages.
  231. X *    - made sure to remove the use of register in prototype types.
  232. X *    - added the +Z option to allow for the compression of the output
  233. X *      using a macro.  [Also under the "merge-output" option.]
  234. X *    - separated functions into a third file [io.c] to reduce the
  235. X *      size of the other files.
  236. X *
  237. X * Version 1.5: [4/29/92-5/18/92] Second submission fixes.
  238. X *    - added ability to exclude all but static functions from search
  239. X *    to allow for the creation of header files for single files.
  240. X *    - fixed the documentation to reflex the new "static" feature.
  241. X *    - fixed some errors in the manual pages.
  242. X *    - adjusted the Makefile:  make echo, sed, nroff and install
  243. X *    configurable; had the "make test" command perform the diff
  244. X *    directly; enhanced the mkdir lines (is it portable?).
  245. X *    - fixed a bug in the out_str() function where it might have
  246. X *    accessed invalid data if the parameter str was NULL.
  247. X *    - for the SGI systems, added a "#define _POSIX_SOURCE" line.
  248. X *    - allow both "no-" and "no" for turning off options.
  249. X *    - implemented a "+W" ("+break-after-types") flag to separate
  250. X *    function type from the function name.
  251. X *    - implemented a "+w#" ("+wrap-parameters") flag to cause the
  252. X *    output of the parameter list to wrap after a given number of
  253. X *    characters.
  254. X *    - added the two new options to the documentation files.
  255. X *    - made use of minmatch_str's return value in io.c and cleaned up
  256. X *    some minor typos.
  257. X *    - fixed serious bug with the default settings for statics.
  258. X *    [Thanks to Jon Whellams for catching this.  *sigh*]
  259. X *    - major rewrite of the options system:
  260. X *      +  merged most of the options into a two dimensional array.
  261. X *      +  used this two-dimensional array to distinguish between
  262. X *         options used in extract mode and doc mode.
  263. X *      +  this makes it possible for the generated config files to
  264. X *         contain the proper "extract-only " or "doc-only "
  265. X *         prefixes.
  266. X *    - merged the two static flags into one flag with multiple
  267. X *    options, removing the confusing "-only-statics" flag.
  268. X *    - fixed the build_rc() routine to properly prefix "doc-only " or
  269. X *    "extract-only " to the output when appropriate.
  270. X *    - the mode ("extract", "doc", etc.) will no longer be written
  271. X *    when a configuration file is generated so "cextdoc" works.
  272. X *
  273. X * Version 1.6: [8/28/92] Third submission fixes.
  274. X *    - added line to set the permissions on the config file during install.
  275. X *    - regenerated the proto.h file to grab the main.c "parce.c" typo fix.
  276. X *    - fixed the documentation for the "-w#" flag. ["-w=#" --> "-w#"]
  277. X *    - for the INSTALL file, I now explicitly mention that installation
  278. X *    of the configuration file might need root permission.
  279. X *    - fixed outdated usages of pclose [pclose -> close_input].
  280. X *    - fixed the wrong usage of "command" in the "open_input" function.
  281. X *    - allow for alternative return values from system().
  282. X *    - make sure that multiple replacements can take place.
  283. X *    - fixed error with "replace" not recognizing "name" selection.
  284. X *    - made sure an error is printed if a bad "replace" format is seen.
  285. X *    - added support for // comments to begin future C++ support.
  286. X *    - provided a "strstr()" function for Xenix sites.
  287. X *    - expanded the "output-file" argument to support separate output
  288. X *    files for extraction and documentation modes.
  289. X *    - added the ability to select the C preprocessor at runtime.
  290. X *    - updated all of the documentation to reflect the above changes.
  291. X *    - preserve the doc/extract selection for macros and replace commands.
  292. X *
  293. X * Version 1.7: [10/30/92] Hopefully last enhancements before acceptance
  294. X *    - keep track of line numbers within the file being parsed.
  295. X *    - any syntax errors will be reported without aborting the file
  296. X *    parsing.
  297. X *    - syntax errors will be accurately reported by file and line number.
  298. X *    - added a check to test for too many left parenthesis.
  299. X *
  300. X */
  301. X#include "xtract.h"
  302. X
  303. X/* storage elements */
  304. XP_PROTO proto_list = NULL, proto_next = NULL;
  305. XP_MACRO macro_list = NULL, last_macro = NULL;
  306. XP_SUBST subst_list = NULL, last_subst = NULL;
  307. XFILE *fpin = NULL;
  308. Xchar code_info[MAX_SIZE+1], cfg_file[MID_SIZE];
  309. Xchar dummy_str[MID_SIZE], file_name[MID_SIZE];
  310. Xint arg_ch_count = 0;
  311. Xint out_file_flag = 0, comment_len = 0, dont_space = TRUE;
  312. Xchar start_comment[MAX_SIZE];
  313. Xchar prog_name[FNAME_SIZE];
  314. Xchar tmp_str[FNAME_SIZE];
  315. Xint dont_stop = FALSE;
  316. Xstatic char last_comment[MAX_SIZE];
  317. X
  318. X/* options for the different parsing methods */
  319. Xint global_opts[2][OPT_NUMBER];
  320. Xint doc_extract = DOC_NONE, cfg_switch = 7;
  321. X
  322. X/* variables for keeping track of things */
  323. Xchar errout_filename[MID_SIZE];
  324. Xint start_block = FALSE, files_parsed = 0, total_out = 0;
  325. Xint line_count = 0;
  326. X
  327. X/* default font values */
  328. Xchar ft_title[3] = "C";
  329. Xchar ft_comment[3] = "CO";
  330. Xchar ft_name[3] = "B";
  331. Xchar ft_plist[3] = "R";
  332. X
  333. X/* add a new substitution macro to the substitution list */
  334. Xvoid
  335. Xadd_subst(type, select, f_str, t_str)
  336. X  int type, select;
  337. X  char *f_str, *t_str;
  338. X{
  339. X  P_SUBST subst_tmp;
  340. X
  341. X  /* check for duplicates */
  342. X  for (subst_tmp = subst_list;
  343. X       subst_tmp != NULL;
  344. X       subst_tmp = subst_tmp->next) {
  345. X    if ((subst_tmp->submode == type) &&
  346. X    (subst_tmp->usewhen == select) &&
  347. X    (strcmp(subst_tmp->from_str, f_str) == 0)) {
  348. X
  349. X      /* can exit routine for complete matches */
  350. X      if (strcmp(subst_tmp->to_str, t_str) == 0) {
  351. X    return;
  352. X      }
  353. X
  354. X      /* otherwise just adjust the replacement */
  355. X      free(subst_tmp->to_str);
  356. X      if ((subst_tmp->to_str =
  357. X       (char *) malloc(sizeof(char) * (1 + strlen(t_str)))) == NULL) {
  358. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  359. X    exit(1);
  360. X      }
  361. X      strcpy(subst_tmp->to_str, t_str);      
  362. X      return;
  363. X
  364. X    }
  365. X  }
  366. X
  367. X  /* allocate the memory space */
  368. X  if ((subst_tmp = (P_SUBST) malloc(sizeof(S_SUBST))) == NULL) {
  369. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  370. X    exit(1);
  371. X  }
  372. X  if (subst_list == NULL) {
  373. X    subst_list = subst_tmp;
  374. X  }
  375. X  if ((subst_tmp->from_str =
  376. X       (char *) malloc(sizeof(char) * (1 + strlen(f_str)))) == NULL) {
  377. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  378. X    exit(1);
  379. X  }
  380. X  if ((subst_tmp->to_str =
  381. X       (char *) malloc(sizeof(char) * (1 + strlen(t_str)))) == NULL) {
  382. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  383. X    exit(1);
  384. X  }
  385. X
  386. X  /* now record the information */
  387. X  subst_tmp->submode = type;
  388. X  subst_tmp->usewhen = select;
  389. X  strcpy(subst_tmp->from_str, f_str);
  390. X  strcpy(subst_tmp->to_str, t_str);
  391. X
  392. X  /* place the new link at the end of the chain */
  393. X  subst_tmp->next = NULL;
  394. X  if (last_subst != NULL) {
  395. X    last_subst->next = subst_tmp;
  396. X  }
  397. X  last_subst = subst_tmp;
  398. X}
  399. X
  400. X/* add a new macro to the macro list */
  401. Xvoid
  402. Xadd_macro(select, str)
  403. X  int select;
  404. X  char *str;
  405. X{
  406. X  P_MACRO macro_tmp;
  407. X
  408. X  /* check for duplicate entries */
  409. X  for (macro_tmp = macro_list;
  410. X       macro_tmp != NULL;
  411. X       macro_tmp = macro_tmp->next) {
  412. X    /* no need to add something already there */
  413. X    if (strcmp(macro_tmp->m_str, str) == 0) {
  414. X      /* check for selection change */
  415. X      if (macro_tmp->usewhen != select) {
  416. X    macro_tmp->usewhen = 2;
  417. X      }
  418. X      return;
  419. X    }
  420. X  }
  421. X
  422. X  /* allocate the space */
  423. X  if ((macro_tmp = (P_MACRO) malloc(sizeof(S_MACRO))) == NULL) {
  424. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  425. X    exit(1);
  426. X  }
  427. X  if (macro_list == NULL) {
  428. X    macro_list = macro_tmp;
  429. X  }
  430. X  if ((macro_tmp->m_str =
  431. X       (char *) malloc(sizeof(char) * (strlen(str) + 1))) == NULL) {
  432. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  433. X    exit(1);
  434. X  }
  435. X  strcpy(macro_tmp->m_str, str);
  436. X  macro_tmp->usewhen = select;
  437. X  macro_tmp->next = NULL;
  438. X  if (last_macro != NULL) {
  439. X    last_macro->next = macro_tmp;
  440. X  }
  441. X  last_macro = macro_tmp;
  442. X}
  443. X
  444. X/* return TRUE if the macro definition is in the string */
  445. Xstatic int
  446. Xmacro_match(macro, str)
  447. X  char *macro, *str;
  448. X{
  449. X  static int deflen = -1;
  450. X  int i, len, hold = FALSE;
  451. X
  452. X  /* initialize */
  453. X  if (deflen == -1) {
  454. X    deflen = strlen(DEF_LEADER);
  455. X  }
  456. X
  457. X  /* check it */
  458. X  if (strncmp(macro, DEF_LEADER, deflen) == 0) {
  459. X    len = strlen(str);
  460. X    for (i = 0; i < len; i++) {
  461. X      if (macro[i + deflen] != str[i]) break;
  462. X    }
  463. X    if ((i == len) &&
  464. X    ((macro[i + deflen] == '=') ||
  465. X     (macro[i + deflen] == '\0'))) {
  466. X      hold = TRUE;
  467. X    }
  468. X  }
  469. X
  470. X  return(hold);
  471. X}
  472. X
  473. X/* if the matching definition is in the list, remove it */
  474. Xint
  475. Xremoved_macro(select, str)
  476. X  int select;
  477. X  char *str;
  478. X{
  479. X  P_MACRO macro_ptr, macro_tmp;
  480. X  int hold = FALSE;
  481. X
  482. X  /* go through the list */
  483. X  if ((macro_ptr = macro_list) != NULL) {
  484. X
  485. X    /* check the beginning element */
  486. X    if (macro_match(macro_ptr->m_str, str)) {
  487. X      if (macro_ptr->usewhen != select) {
  488. X    /* just return */
  489. X    return(FALSE);
  490. X      } else {
  491. X    macro_list = macro_list->next;
  492. X    macro_ptr->next = NULL;
  493. X    free(macro_ptr->m_str);
  494. X    free(macro_ptr);
  495. X    hold = TRUE;
  496. X      }
  497. X    }
  498. X
  499. X    /* check the rest */
  500. X    macro_tmp = macro_ptr->next;
  501. X    while (hold == FALSE && macro_tmp != NULL) {
  502. X      if (macro_match(macro_tmp->m_str, str)) {
  503. X    if (macro_ptr->usewhen != select) {
  504. X      /* just return */
  505. X      return(FALSE);
  506. X    } else {
  507. X      macro_ptr->next = macro_tmp->next;
  508. X      macro_tmp->next = NULL;
  509. X      free(macro_tmp->m_str);
  510. X      free(macro_tmp);
  511. X      hold = TRUE;
  512. X    }
  513. X      }
  514. X
  515. X      /* onto the next */
  516. X      macro_ptr = macro_tmp;
  517. X      macro_tmp = macro_tmp->next;
  518. X    }
  519. X  }
  520. X
  521. X  /* now assign the last_macro value and get back to work */
  522. X  if (hold == TRUE) {
  523. X    for (last_macro = macro_list;
  524. X     (last_macro != NULL) &&
  525. X     (last_macro->next != NULL);
  526. X     last_macro = last_macro->next) ;
  527. X  }
  528. X  return(hold);
  529. X}
  530. X
  531. X/* compare two strings considering cases the same */
  532. Xint
  533. Xstr_test (s1, s2)
  534. X  char *s1, *s2;
  535. X{
  536. X  int ch1, ch2;
  537. X
  538. X  for (; *s1 != '\0'; s1++, s2++) {
  539. X    ch1 = (islower(*s1) ? toupper(*s1) : *s1);
  540. X    ch2 = (islower(*s2) ? toupper(*s2) : *s2);
  541. X    if (ch1 != ch2) return(ch1 - ch2);
  542. X  }
  543. X  return(*s1 - *s2);
  544. X}
  545. X
  546. X/* sort the list of functions and their prototypes */
  547. Xvoid
  548. Xsort_proto()
  549. X{
  550. X  P_PROTO p2_ptr;
  551. X  int done = FALSE;
  552. X
  553. X  /* all done? */
  554. X  if ((proto_list == NULL) || (proto_list->next == NULL)) return;
  555. X
  556. X  /* go until done sorting */
  557. X  while (done == FALSE) {
  558. X
  559. X    /* initialize */
  560. X    proto_next = proto_list;
  561. X    done = TRUE;
  562. X
  563. X    /* test for initial swap */
  564. X    if ( str_test( proto_next->name, (proto_next->next)->name ) > 0) {
  565. X      proto_list = proto_next->next;
  566. X      proto_next->next = proto_list->next;
  567. X      proto_list->next = proto_next;
  568. X      proto_next = proto_list;
  569. X    }
  570. X    
  571. X    /* sort remaining linked list */
  572. X    for (; (proto_next->next)->next != NULL; proto_next = proto_next->next) {
  573. X      p2_ptr = (proto_next->next)->next;
  574. X      if ( str_test( (proto_next->next)->name, p2_ptr->name ) > 0) {
  575. X
  576. X    /* swap locations in list */
  577. X    (proto_next->next)->next = p2_ptr->next;
  578. X    p2_ptr->next = proto_next->next;
  579. X    proto_next->next = p2_ptr;
  580. X
  581. X    /* continue sort */
  582. X    done = FALSE;
  583. X      }
  584. X    }
  585. X
  586. X  }
  587. X}
  588. X
  589. X/* remove the top item on the stack */
  590. Xvoid
  591. Xpop_proto()
  592. X{
  593. X  P_PROTO tmp_proto = proto_list;
  594. X
  595. X  /* done? */
  596. X  if (proto_list == NULL) {
  597. X    proto_next = NULL;
  598. X    return;
  599. X  }
  600. X  if (proto_list == proto_next) {
  601. X    proto_next = NULL;
  602. X  }
  603. X
  604. X  /* now do it */
  605. X  proto_list = proto_list->next;
  606. X  tmp_proto->next = NULL;
  607. X  if (tmp_proto->name != NULL) free(tmp_proto->name);
  608. X  if (tmp_proto->ftype != NULL) free(tmp_proto->ftype);
  609. X  if (tmp_proto->fname != NULL) free(tmp_proto->fname);
  610. X  if (tmp_proto->plist != NULL) free(tmp_proto->plist);
  611. X  if (tmp_proto->comment != NULL) free(tmp_proto->comment);
  612. X  free(tmp_proto);
  613. X}
  614. X
  615. X/* initialize the page for troff output, if needed */
  616. Xvoid
  617. Xinit_roff(omode)
  618. X  int omode;
  619. X{
  620. X  static int init_done = FALSE;
  621. X
  622. X  /* perform the initialization */
  623. X  if (init_done == FALSE) {
  624. X    out_str(omode, ".sp 0.5i\n");
  625. X    out_str(omode, ".ps 10\n");
  626. X    out_str(omode, ".vs 12\n");
  627. X    out_str(omode, ".fp 1 ");
  628. X    out_str(omode, ft_title);
  629. X    out_str(omode, "\n.fp 2 ");
  630. X    out_str(omode, ft_comment);
  631. X    out_str(omode, "\n.fp 3 ");
  632. X    out_str(omode, ft_name);
  633. X    out_str(omode, "\n.fp 4 ");
  634. X    out_str(omode, ft_plist);
  635. X    out_char(omode, '\n');
  636. X    init_done = TRUE;
  637. X  }
  638. X}
  639. X
  640. X/* check preprocessor statement for line numbering changes */
  641. Xint
  642. Xpreprocessor_check()
  643. X{
  644. X  int curr_char = '#';
  645. X  int i, l, line_value;
  646. X  char temp_str[MID_SIZE], t2_str[MID_SIZE];
  647. X
  648. X  /* get the whole line */
  649. X  if (fgets(temp_str, MID_SIZE, fpin) != NULL) {
  650. X    /* first handle the exit */
  651. X    l = strlen(temp_str);
  652. X    curr_char = temp_str[l - 1];
  653. X
  654. X    /* now parse things */
  655. X    for (i = 0; i < l; i++) {
  656. X      if (isdigit(temp_str[i])) {
  657. X    if (sscanf(&(temp_str[i]), "%d %s", &line_value,
  658. X           t2_str) == 2) {
  659. X      line_count = line_value;
  660. X      l = strlen(t2_str);
  661. X      if (t2_str[l - 1] == '"') {
  662. X        t2_str[l - 1] = '\0';
  663. X      }
  664. X      if (t2_str[0] == '"') {
  665. X        i = 1;
  666. X      } else {
  667. X        i = 0;
  668. X      }
  669. X      strcpy(errout_filename, &(t2_str[i]));
  670. X    }
  671. X    break;
  672. X      } else if (!isspace(temp_str[i])) {
  673. X    if (strncmp(&(temp_str[i]), "line", 4) != 0) break;
  674. X    else {
  675. X      i += 3;
  676. X    }
  677. X      }
  678. X    }
  679. X  }
  680. X  return(curr_char);
  681. X}
  682. X
  683. X/* read and store all characters prior to end comment indicator */
  684. Xstatic void
  685. Xget_comment(tagon, head_str, cmt_str)
  686. X  int tagon;
  687. X  char head_str[], cmt_str[];
  688. X{
  689. X  int curr_ch;
  690. X  int prev_ch = ' ';
  691. X
  692. X  /* keep going until scan is complete */
  693. X  if (tagon == TRUE) {
  694. X    if (head_str[0] == '\0') {
  695. X      /* catenate side by side comments */
  696. X      comment_len -= 2;
  697. X    } else {
  698. X      /* insert intermediary white space and comment */
  699. X      for (curr_ch = 0;
  700. X       head_str[curr_ch] != '\0';
  701. X       curr_ch++) {
  702. X    cmt_str[comment_len++] = head_str[curr_ch];
  703. X      }
  704. X      cmt_str[comment_len++] = '/';
  705. X      cmt_str[comment_len++] = '*';
  706. X    }
  707. X  } else {
  708. X    comment_len = 0;
  709. X  }
  710. X  while ((curr_ch = getc(fpin)) != EOF) {
  711. X
  712. X    /* test for end of comment */
  713. X    if ((curr_ch == '/') && (prev_ch == '*')) {
  714. X      cmt_str[comment_len++] = '/';
  715. X      break;
  716. X    }
  717. X
  718. X    /* store it */
  719. X    cmt_str[comment_len++] = prev_ch = curr_ch;
  720. X    if (curr_ch == '\n') line_count++;
  721. X  }
  722. X
  723. X  /* close storage */
  724. X  cmt_str[comment_len] = '\0';
  725. X}
  726. X
  727. X/* structure to hold definitions */
  728. Xtypedef struct s_param {
  729. X  char *name;        /* the name of the variable */
  730. X  char *desc;        /* description string */
  731. X  struct s_param *next;    /* pointer to the next element */
  732. X} S_PARAM, *P_PARAM;
  733. XP_PARAM param_list;
  734. X
  735. X/* take all of the variables between the parenthesis and break them down */
  736. Xstatic int
  737. Xfill_param(str)
  738. X  char *str;
  739. X{
  740. X  int paren_loc, count, i, in_word = 1, len = strlen(str);
  741. X  P_PARAM last_param = NULL, param_tmp;
  742. X  char tempc[MID_SIZE];
  743. X
  744. X  /* initialize the list */
  745. X  param_list = NULL;
  746. X  paren_loc = 0;
  747. X  count = 0;
  748. X  tempc[0] = '\0';
  749. X  for (i = 1; i < len; i++) {
  750. X
  751. X    /* check for the end */
  752. X    if (str[i] == ')') {
  753. X      paren_loc = i;
  754. X      break;
  755. X    }
  756. X
  757. X    /* find a variable name; check for separators */
  758. X    if (str[i] == ',') {
  759. X
  760. X      /* check current information */
  761. X      if (in_word == 1) {
  762. X    syntax_err("empty variable list encountered");
  763. X    return(-1);
  764. X      }
  765. X      in_word = 1;
  766. X
  767. X      /* store the name */
  768. X      tempc[count] = '\0';
  769. X      count = 0;
  770. X      if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
  771. X    fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  772. X    exit(1);
  773. X      }
  774. X      if ((param_tmp->name =
  775. X       (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  776. X    fprintf(stderr, "Serious Error: Out of memory\n");
  777. X    exit(1);
  778. X      }
  779. X      strcpy(param_tmp->name, tempc);
  780. X      param_tmp->next = NULL;
  781. X      param_tmp->desc = NULL;
  782. X      if (param_list == NULL) {
  783. X    param_list = param_tmp;
  784. X    last_param = param_list;
  785. X      } else {
  786. X    last_param->next = param_tmp;
  787. X    last_param = param_tmp;
  788. X      }
  789. X
  790. X    } else if (str[i] == ' ') {
  791. X      if (in_word == 2) {
  792. X    in_word = 0;
  793. X      }
  794. X    } else if (id_char(str[i])) {
  795. X      if (in_word == 0) {
  796. X    syntax_err("invalid parameter list encountered");
  797. X    return(-1);
  798. X      }
  799. X      in_word = 2;
  800. X      tempc[count++] = str[i];
  801. X    } else {
  802. X      syntax_err("unable to parse the complex C code");
  803. X      return(-1);
  804. X    }
  805. X
  806. X  }
  807. X
  808. X  /* now store the last name if any was found */
  809. X  if (count != 0) {
  810. X
  811. X    /* store the name */
  812. X    tempc[count] = '\0';
  813. X    if ((param_tmp = (P_PARAM) malloc(sizeof(S_PARAM))) == NULL) {
  814. X      fprintf(stderr, "Serious Error: Memory Allocation Failure\n");
  815. X      exit(1);
  816. X    }
  817. X    if ((param_tmp->name =
  818. X     (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  819. X      fprintf(stderr, "Serious Error: Out of memory\n");
  820. X      exit(1);
  821. X    }
  822. X    strcpy(param_tmp->name, tempc);
  823. X    param_tmp->desc = NULL;
  824. X    param_tmp->next = NULL;
  825. X    if (param_list == NULL) {
  826. X      param_list = param_tmp;
  827. X      last_param = param_list;
  828. X    } else {
  829. X      last_param->next = param_tmp;
  830. X      last_param = param_tmp;
  831. X    }
  832. X  }
  833. X  return(paren_loc);
  834. X}
  835. X
  836. X/* remove any preceding and trailing spaces */
  837. Xvoid
  838. Xtrim_str(str)
  839. X  char *str;
  840. X{
  841. X  register int i = 0, j = 0;
  842. X  int last_space = -1;
  843. X
  844. X  /* trim leading spaces */
  845. X  while (isspace(str[i])) i++;
  846. X
  847. X  /* shift string */
  848. X  while (1) {
  849. X    if ((str[j] = str[i++]) == '\0') {
  850. X      break;
  851. X    } else if (isspace(str[j])) {
  852. X      last_space = j;
  853. X    } else {
  854. X      last_space = -1;
  855. X    }
  856. X    j++;
  857. X  }
  858. X
  859. X  /* now remove any trailing spaces */
  860. X  if (last_space != -1) {
  861. X    str[last_space] = '\0';
  862. X  }
  863. X}
  864. X
  865. X/* just go through and send out the entire parameter list */
  866. Xstatic int
  867. Xoldc_output()
  868. X{
  869. X  int count = 0, lcount = 0;
  870. X  P_PARAM param_tmp;
  871. X
  872. X  /* first test for the simple case */
  873. X  if (param_list == NULL) {
  874. X    strcpy(dummy_str, "void");
  875. X    return(4);
  876. X  }
  877. X  dummy_str[0] = '\0';
  878. X
  879. X  /* go through the list */
  880. X  while (param_list != NULL) {
  881. X
  882. X    /* add in separators */
  883. X    if (count++ > 0) {
  884. X
  885. X      strcat(dummy_str, ", ");
  886. X      lcount += 2;
  887. X
  888. X    }
  889. X
  890. X    /* check the type */
  891. X    if (param_list->desc != NULL) {
  892. X      trim_str(param_list->desc);
  893. X      strcat(dummy_str, param_list->desc);
  894. X      lcount += strlen(param_list->desc);
  895. X      free(param_list->desc);
  896. X    } else {
  897. X      if (get_option(OPT_NONAMES)) {
  898. X    strcat(dummy_str, "int");
  899. X    lcount += 3;
  900. X      } else if (strcmp("int", param_list->name)) {
  901. X    strcat(dummy_str, "int ");
  902. X    strcat(dummy_str, param_list->name);
  903. X    lcount += 4 + strlen(param_list->name);
  904. X      } else {
  905. X    strcat(dummy_str, param_list->name);
  906. X    lcount += strlen(param_list->name);
  907. X      }
  908. X    }
  909. X    free(param_list->name);
  910. X
  911. X    /* clean up storage */
  912. X    param_tmp = param_list;
  913. X    param_list = param_list->next;
  914. X    param_tmp->next = NULL;
  915. X    free(param_tmp);
  916. X
  917. X  }
  918. X
  919. X  /* finish it up */
  920. X  return(lcount);
  921. X}
  922. X
  923. X/* return the proper element */
  924. Xstatic P_PARAM
  925. Xvar_match(str)
  926. X  char *str;
  927. X{
  928. X  int i, len, len2;
  929. X  P_PARAM p_hold;
  930. X
  931. X  /* go through all of the items and find a match */
  932. X  len2 = strlen(str);
  933. X  p_hold = param_list;
  934. X  while (p_hold != NULL) {
  935. X
  936. X    /* check for a match */
  937. X    len = strlen(p_hold->name);
  938. X    for (i = 0; i < len2 - len + 1; i++) {
  939. X      /* check for the match */
  940. X      if (strncmp(str + i, p_hold->name, len) == 0) {
  941. X    /* found a match */
  942. X    if (!id_char(str[i + len])) {
  943. X      return(p_hold);
  944. X    }
  945. X      } else if (id_char(str[i])) {
  946. X    /* definite non-match */
  947. X    i = len2 - len + 1;
  948. X      }
  949. X    }
  950. X
  951. X    /* go to the next element */
  952. X    p_hold = p_hold->next;
  953. X  }
  954. X
  955. X  return(p_hold);
  956. X}
  957. X
  958. X/* remove the variable name from the given type and variable combo */
  959. Xstatic void
  960. Xkill_variable(str)
  961. X  char *str;
  962. X{
  963. X  register int i;
  964. X
  965. X  /* no need to breakdown this baby */
  966. X  if (strcmp(str, "...") == 0) return;
  967. X
  968. X  /* search for the variable name */
  969. X  trim_str(str);
  970. X  for (i = strlen(str) - 1; i >= 0; i--) {
  971. X
  972. X    /* found it */
  973. X    if (id_char(str[i])) {
  974. X
  975. X      /* clean it up */
  976. X      while ((i >= 0) &&
  977. X         id_char(str[i])) {
  978. X    str[i--] = ' ';
  979. X      }
  980. X      i++;
  981. X      trim_str(str + i);
  982. X      if (i == 0) {
  983. X    strcpy(str, "int");
  984. X      } else {
  985. X    trim_str(str);
  986. X      }
  987. X      break;
  988. X
  989. X    }
  990. X
  991. X  }
  992. X}
  993. X
  994. X/* separate and rebuild the ANSI format list */
  995. Xstatic int
  996. Xnewc_parse (i_str)
  997. X  char *i_str;
  998. X{
  999. X  char hold_str[MID_SIZE], hold2_str[MID_SIZE];
  1000. X  P_SUBST sub_tmp;
  1001. X  int depth, cnt = 0, len, i;
  1002. X
  1003. X  /* start the process */
  1004. X  dummy_str[0] = '\0';
  1005. X  do {
  1006. X
  1007. X    /* move along the input string */
  1008. X    switch (*i_str) {
  1009. X    case ',':
  1010. X    case '\0':
  1011. X      /* finish off this item */
  1012. X      if (cnt == 0) break;
  1013. X      hold_str[cnt] = '\0';
  1014. X
  1015. X      /* search for matches among the replacement code */
  1016. X      for (sub_tmp = subst_list;
  1017. X       sub_tmp != NULL;
  1018. X       sub_tmp = sub_tmp->next) {
  1019. X
  1020. X    /* check for usage */
  1021. X    if ((sub_tmp->usewhen != 2) &&
  1022. X        (sub_tmp->usewhen != (doc_extract != DOC_NONE))) continue;
  1023. X
  1024. X    /* check it */
  1025. X    len = strlen(sub_tmp->from_str);
  1026. X    switch (sub_tmp->submode) {
  1027. X    case SUBST_FULL:
  1028. X      /* the full string needs replacing? */
  1029. X      if (strcmp(hold_str, sub_tmp->from_str) == 0) {
  1030. X        strcpy(hold_str, sub_tmp->to_str);
  1031. X      }
  1032. X      break;
  1033. X    case SUBST_TYPE:
  1034. X      /* the type only needs replacing? */
  1035. X      if (strncmp(hold_str, sub_tmp->from_str, len) == 0) {
  1036. X        strcpy(hold2_str, hold_str + len);
  1037. X        strcpy(hold_str, sub_tmp->to_str);
  1038. X        strcat(hold_str, hold2_str);
  1039. X      }
  1040. X      break;
  1041. X    case SUBST_NAME:
  1042. X      /* the variable only needs replacing? WHY!? */
  1043. X      if ((cnt > len) &&
  1044. X          (strcmp(hold_str + cnt - len, sub_tmp->from_str) == 0)) {
  1045. X        hold_str[cnt - len] = '\0';
  1046. X        strcat(hold_str, sub_tmp->to_str);
  1047. X      }
  1048. X      break;
  1049. X    }
  1050. X      }
  1051. X
  1052. X      /* check for removal of register type */
  1053. X      if (strncmp(hold_str, "register ", 9) == 0) {
  1054. X    for (i = 0; i < 9; i++) {
  1055. X      hold_str[i] = ' ';
  1056. X    }
  1057. X      }
  1058. X
  1059. X      /* do we clean it? */
  1060. X      if (get_option(OPT_NONAMES)) {
  1061. X    kill_variable(hold_str);
  1062. X      } else {
  1063. X    trim_str(hold_str);
  1064. X      }
  1065. X
  1066. X      /* append to output */
  1067. X      if (dummy_str[0] != '\0') {
  1068. X    strcat(dummy_str, ", ");
  1069. X      }
  1070. X      strcat(dummy_str, hold_str);
  1071. X      cnt = 0;
  1072. X      break;
  1073. X    case '{':
  1074. X      /* collect up all of the type declaration */
  1075. X      depth = -1;
  1076. X      do {
  1077. X    hold_str[cnt++] = *i_str;
  1078. X    switch (*i_str) {
  1079. X    case '\0':
  1080. X      syntax_err("unexpected end of parameters");
  1081. X      return(-1);
  1082. X    case '{':
  1083. X      depth++;
  1084. X      break;
  1085. X    case '}':
  1086. X      depth--;
  1087. X      break;
  1088. X    default:
  1089. X      /* ignore me */
  1090. X      break;
  1091. X    }
  1092. X    i_str++;
  1093. X      } while ((depth > 0) ||
  1094. X           (*i_str != '}'));
  1095. X      hold_str[cnt++] = *i_str;
  1096. X      break;
  1097. X    case ' ':
  1098. X      if (cnt == 0) break;
  1099. X    default:
  1100. X      /* just copy it */
  1101. X      hold_str[cnt++] = *i_str;
  1102. X    }
  1103. X
  1104. X  } while (*(i_str++) != '\0');
  1105. X
  1106. X  /* give back the length */
  1107. X  return(strlen(dummy_str));
  1108. X}
  1109. X
  1110. X/* extract all of the parameters using old style format */
  1111. Xstatic int
  1112. Xoldc_parse(str)
  1113. X  char *str;
  1114. X{
  1115. X  int depth = 0, last_char = ')';
  1116. X  int start, count2, in_var;
  1117. X  P_PARAM p_tmp;
  1118. X  P_SUBST sub_tmp;
  1119. X
  1120. X  char type_name[MID_SIZE], var_name[MID_SIZE];
  1121. X  char oldvar_name[MID_SIZE], tempc[MID_SIZE];
  1122. X
  1123. X  /* build the parameter list */
  1124. X  if ((start = fill_param(str)) == -1) {
  1125. X    /* clean up and exit on error */
  1126. X    while (param_list != NULL) {
  1127. X      p_tmp = param_list;
  1128. X      param_list = param_list->next;
  1129. X      p_tmp->next = NULL;
  1130. X      free(p_tmp);
  1131. X    }
  1132. X    return(-1);
  1133. X  }
  1134. X  if (str[start] != ')') {
  1135. X    strcpy(dummy_str, "void");
  1136. X    return(4);
  1137. X  }
  1138. X
  1139. X  /* begin with non-space character */
  1140. X  for (str += start + 1; *str == ' '; str++) ;
  1141. X  count2 = 0;
  1142. X  in_var = FALSE;
  1143. X  type_name[0] = '\0';
  1144. X
  1145. X  /* now go through the entire structure */
  1146. X  for (; *str != '\0'; str++) {
  1147. X
  1148. X    switch (*str) {
  1149. X    case ' ':
  1150. X      /* add on to variable or append to type definition */
  1151. X      if (in_var == TRUE) {
  1152. X    var_name[count2++] = ' ';
  1153. X    break;
  1154. X      }
  1155. X      break;
  1156. X    case '{':
  1157. X      /* must be a struct declaration */
  1158. X      if ((depth != 0) ||
  1159. X      (in_var == TRUE)) {
  1160. X    syntax_err("unexpected left brace encountered");
  1161. X    return(-1);
  1162. X      }
  1163. X      depth = -1;
  1164. X      if (var_name[count2] != ' ') {
  1165. X    var_name[count2++] = ' ';
  1166. X      }
  1167. X      do {
  1168. X    var_name[count2++] = *str;
  1169. X    switch (*str) {
  1170. X    case '\0':
  1171. X      syntax_err("unable to parse the complex C structure");
  1172. X      return(-1);
  1173. X    case '{':
  1174. X      depth++;
  1175. X      break;
  1176. X    case '}':
  1177. X      depth--;
  1178. X      break;
  1179. X    default:
  1180. X      /* ignore me */
  1181. X      break;
  1182. X    }
  1183. X    str++;
  1184. X      } while ((depth > 0) ||
  1185. X           (*str != '}'));
  1186. X      goto saw_space;
  1187. X      break;
  1188. X    case ',':
  1189. X      /* just add on if between parenthesis */
  1190. X      if (depth != 0) {
  1191. X    var_name[count2++] = ',';
  1192. X    break;
  1193. X      }
  1194. X    case ';':
  1195. X      /* found end of declaration? */
  1196. X      var_name[count2] = '\0';
  1197. X      if ((depth != 0) || (type_name[0] == '\0')) {
  1198. X    syntax_err("unable to parse the complex C structure");
  1199. X    return(-1);
  1200. X      }
  1201. X      if (var_name[0] == '\0') {
  1202. X    syntax_err("unable to parse the complex C structure");
  1203. X    return(-1);
  1204. X      }
  1205. X
  1206. X      /* build the proper string */
  1207. X      trim_str(type_name);
  1208. X      strcpy(tempc, type_name);
  1209. X      strcat(tempc, " ");
  1210. X      trim_str(var_name);
  1211. X      strcpy(oldvar_name, var_name);
  1212. X      strcat(tempc, var_name);
  1213. X
  1214. X      /* search for matches among the replacement code */
  1215. X      for (sub_tmp = subst_list;
  1216. X       sub_tmp != NULL;
  1217. X       sub_tmp = sub_tmp->next) {
  1218. X    /* check it */
  1219. X    switch (sub_tmp->submode) {
  1220. X    case SUBST_FULL:
  1221. X      /* the full string needs replacing? */
  1222. X      if (strcmp(tempc, sub_tmp->from_str) == 0) {
  1223. X        strcpy(tempc, sub_tmp->to_str);
  1224. X      }
  1225. X      break;
  1226. X    case SUBST_TYPE:
  1227. X      /* the type only needs replacing? */
  1228. X      if (strcmp(type_name, sub_tmp->from_str) == 0) {
  1229. X        strcpy(tempc, sub_tmp->to_str);
  1230. X        strcpy(type_name, sub_tmp->to_str);
  1231. X        strcat(tempc, " ");
  1232. X        strcat(tempc, var_name);
  1233. X      }
  1234. X      break;
  1235. X    case SUBST_NAME:
  1236. X      /* the variable only needs replacing? WHY!? */
  1237. X      if (strcmp(var_name, sub_tmp->from_str) == 0) {
  1238. X        strcpy(tempc, type_name);
  1239. X        strcat(tempc, " ");
  1240. X        strcat(tempc, sub_tmp->to_str);
  1241. X        strcpy(var_name, sub_tmp->to_str);
  1242. X      }
  1243. X      break;
  1244. X    }
  1245. X      }
  1246. X
  1247. X      /* now find the proper variable name */
  1248. X      if ((p_tmp = var_match(oldvar_name)) == NULL) {
  1249. X    char temp_str[MID_SIZE];
  1250. X    sprintf(temp_str, "could not place variable %s properly",
  1251. X        oldvar_name);
  1252. X    syntax_err(temp_str);
  1253. X    return(-1);
  1254. X      }
  1255. X
  1256. X      /* now check for variable name removal */
  1257. X      if (get_option(OPT_NONAMES)) {
  1258. X    kill_variable(tempc);
  1259. X      }
  1260. X
  1261. X      /* set aside space */
  1262. X      if ((p_tmp->desc =
  1263. X       (char *) malloc(sizeof(char) * (strlen(tempc) + 1))) == NULL) {
  1264. X    fprintf(stderr, "Serious Memory Allocation Error\n");
  1265. X    exit(1);
  1266. X      }
  1267. X
  1268. X      /* now stow it */
  1269. X      strcpy(p_tmp->desc, tempc);
  1270. X
  1271. X      /* reset properly */
  1272. X      count2 = 0;
  1273. X      var_name[0] = '\0';
  1274. X      if (*str == ';') {
  1275. X    in_var = FALSE;
  1276. X    type_name[0] = '\0';
  1277. X      }
  1278. X      break;
  1279. X    case '*':
  1280. X      /* just append on, must now be in variable */
  1281. X      if ((last_char == ' ') && (in_var == FALSE)) {
  1282. X    in_var = TRUE;
  1283. X    goto saw_space;
  1284. X      } else if (in_var == FALSE) {
  1285. X    /* must push out type properly */
  1286. X    var_name[count2] = '\0';
  1287. X    count2 = 0;
  1288. X    if ((type_name[0] != '\0') &&
  1289. X        (type_name[strlen(type_name) - 1] != ' '))  {
  1290. X      strcat(type_name, " ");
  1291. X    }
  1292. X    if ((type_name[0] != '\0') ||
  1293. X        (strcmp(var_name, "register") != 0)) {
  1294. X      strcat(type_name, var_name);
  1295. X    }
  1296. X    var_name[0] = '\0';
  1297. X      }
  1298. X      in_var = TRUE;
  1299. X      var_name[count2++] = '*';
  1300. X      break;
  1301. X    case '(':
  1302. X    case '[':
  1303. X      /* count depth, assume balanced for both */
  1304. X      depth++;
  1305. X      if ((last_char == ' ') &&
  1306. X      (in_var == FALSE)) {
  1307. X    in_var = TRUE;
  1308. X    goto saw_space;
  1309. X      }
  1310. X      in_var = TRUE;
  1311. X      var_name[count2++] = *str;
  1312. X      break;
  1313. X    case ')':
  1314. X    case ']':
  1315. X      /* check depth */
  1316. X      depth--;
  1317. X      if (depth < 0) {
  1318. X    syntax_err("misbalanced parenthesis encountered");
  1319. X    return(-1);
  1320. X      }
  1321. X      if (last_char == ' ') goto saw_space;
  1322. X      var_name[count2++] = *str;
  1323. X      break;
  1324. X    default:
  1325. X      if (!id_char(*str) && (depth == 0)) {
  1326. X    syntax_err("unknown variable structure encountered");
  1327. X    return(-1);
  1328. X      }
  1329. X      /* check for just seeing space */
  1330. X      if (last_char == ' ' && in_var == FALSE) {
  1331. X
  1332. X      saw_space:
  1333. X    var_name[count2] = '\0';
  1334. X    count2 = 0;
  1335. X    if ((type_name[0] != '\0') &&
  1336. X        (type_name[strlen(type_name) - 1] != ' '))  {
  1337. X      strcat(type_name, " ");
  1338. X    }
  1339. X    if ((type_name[0] != '\0') ||
  1340. X        (strcmp(var_name, "register") != 0)) {
  1341. X      strcat(type_name, var_name);
  1342. X    }
  1343. X    var_name[0] = '\0';
  1344. X
  1345. X      }
  1346. X      var_name[count2++] = *str;
  1347. X      break;
  1348. X    }
  1349. X
  1350. X    /* save the last character */
  1351. X    last_char = *str;
  1352. X  }
  1353. X
  1354. X  /* now send everything out */
  1355. X  return(oldc_output());
  1356. X}
  1357. X
  1358. X/* function to determine if the parameter list is K&R, ANSI or empty */
  1359. Xstatic int
  1360. Xdiverge_style(str, len)
  1361. X  char *str;
  1362. X  int len;
  1363. X{
  1364. X  int void_fnd = FALSE, nspc_fnd = FALSE, in_word = 1;
  1365. X
  1366. X  /* perform the first simple test */
  1367. X  if (str[len - 1] == ';') return(2);
  1368. X
  1369. X  /* should have a right parenthesis now  */
  1370. X  if (str[len - 1] != ')') {
  1371. X    fprintf(stderr, "Expecting right paren in file %s\n", file_name);
  1372. X    return(1);
  1373. X  }
  1374. X
  1375. X  /* now check to see if it only lists all variables */
  1376. X  for (str++; *str != '\0'; str++) {
  1377. X
  1378. X    /* check for separators */
  1379. X    switch (*str) {
  1380. X    case ',':
  1381. X      /* variable separator */
  1382. X      if (in_word == 1) {
  1383. X    fprintf(stderr, "Empty variable list in file %s", file_name);
  1384. X    return(1);
  1385. X      }
  1386. X      nspc_fnd = TRUE;
  1387. X      in_word = 1;
  1388. X      break;
  1389. X    case ' ':
  1390. X      /* word separator */
  1391. X      if (in_word == 2) {
  1392. X    in_word = 0;
  1393. X      }
  1394. X      break;
  1395. X    case ')':
  1396. X      if (*(str + 1) != '\0') {
  1397. X    return(1);
  1398. X      }
  1399. X      break;
  1400. X    default:
  1401. X      /* check for variable name */
  1402. X      if ((void_fnd == FALSE) &&
  1403. X      (strncmp(str, "void", 4) == 0)) {
  1404. X    void_fnd = TRUE;
  1405. X    str += 3;
  1406. X    in_word = 2;
  1407. X      } else if (id_char(*str)) {
  1408. X    if (in_word == 0) {
  1409. X      return(1);
  1410. X    }
  1411. X    in_word = 2;
  1412. X    nspc_fnd = TRUE;
  1413. X      } else {
  1414. X    return(1);
  1415. X      }
  1416. X      break;
  1417. X    }
  1418. X  }
  1419. X  return((nspc_fnd == TRUE)? 2 : 0);
  1420. X}
  1421. X
  1422. X/* return length of function name... and store it in space provide */
  1423. Xstatic int
  1424. Xfind_name(out_name, in_desc, desc_len)
  1425. X  char *out_name, *in_desc;
  1426. X  int desc_len;
  1427. X{
  1428. X  int pos, count = 0;
  1429. X
  1430. X  /* find the end of the name */
  1431. X  for (pos = desc_len; pos > 0; pos--) {
  1432. X    if (id_char(in_desc[pos])) break;
  1433. X  }
  1434. X
  1435. X  /* find the length of the name */
  1436. X  while ((pos > 0) &&
  1437. X     (id_char(in_desc[pos]))) {
  1438. X    count++;
  1439. X    pos--;
  1440. X  }
  1441. X
  1442. X  /* copy it */
  1443. X  if (!id_char(in_desc[pos])) {
  1444. X    pos++;
  1445. X  } else {
  1446. X    count++;
  1447. X  }
  1448. X  strncpy(out_name, in_desc + pos, count);
  1449. X  out_name[count] = '\0';
  1450. X  return(count);
  1451. X}
  1452. X
  1453. X/* function to extract the function prototype from preceding characters */
  1454. Xstatic void
  1455. Xparse_func()
  1456. X{
  1457. X  P_SUBST sub_tmp;
  1458. X  P_PROTO tmp_proto;
  1459. X  int count, valid = TRUE, depth = 0, done = FALSE;
  1460. X  int sep_point = 0, typelen, cmpstt, len, dummy_len = 0;
  1461. X  char *func_declare, *func_list, name_space[MID_SIZE];
  1462. X
  1463. X  /* clean up the input string */
  1464. X  trim_str(code_info);
  1465. X  len = strlen(code_info);
  1466. X
  1467. X  /* now go backwards and find the first occurance */
  1468. X  /* of a right parenthesis without a '[', ',' or ';' after */
  1469. X  for (count = len - 1; done == FALSE && count > 0; count--) {
  1470. X
  1471. X    /* check for a select group of characters */
  1472. X    switch (code_info[count]) {
  1473. X    case ' ':
  1474. X      /* don't change validity for spaces */
  1475. X      break;
  1476. X    case ')':
  1477. X      /* check if it is a good match */
  1478. X      depth++;
  1479. X      if (depth == 1 && valid == TRUE) {
  1480. X    done = TRUE;
  1481. X      }
  1482. X      break;
  1483. X    case '(':
  1484. X      /* keep proper track of depth */
  1485. X      depth--;
  1486. X      if (depth < 0) {
  1487. X    syntax_err("too many left parenthesis encountered");
  1488. X    break;
  1489. X      }
  1490. X
  1491. X      /* watch for function pointers */
  1492. X      valid = FALSE;
  1493. X      break;
  1494. X    case '[':
  1495. X    case ';':
  1496. X    case ',':
  1497. X      /* any paranthesis before this is invalid */
  1498. X      valid = FALSE;
  1499. X      break;
  1500. X    case '=':
  1501. X      /* there should be no equal signs anywhere around this */
  1502. X      valid = FALSE;
  1503. X      count = 0;
  1504. X      break;
  1505. X    default:
  1506. X      /* it can now be a valid parenthesis */
  1507. X      valid = TRUE;
  1508. X      break;
  1509. X    }
  1510. X  }
  1511. X
  1512. X  /* get out if no function type was found */
  1513. X  if (done != TRUE) return;
  1514. X
  1515. X  /* now find the separation point for the function */
  1516. X  done = FALSE;
  1517. X  for (; done == FALSE && count > 0; count--) {
  1518. X    valid = code_info[count];
  1519. X    switch (valid) {
  1520. X    case ' ':
  1521. X      break;
  1522. X    case ')':
  1523. X      /* go deeper */
  1524. X      depth++;
  1525. X      break;
  1526. X    case '(':
  1527. X      /* rise higher */
  1528. X      depth--;
  1529. X      if (depth == 0) {
  1530. X    sep_point = count;
  1531. X    done = TRUE;
  1532. X      }
  1533. X      break;
  1534. X    default:
  1535. X      break;
  1536. X    }
  1537. X  }
  1538. X
  1539. X  /* confirm separation point */
  1540. X  if (done == FALSE) {
  1541. X    syntax_err("too many right parenthesis encountered");
  1542. X    return;
  1543. X  }
  1544. X
  1545. X  /* now find the start of the function declaration */
  1546. X  for (; count > 0; count--) {
  1547. X    if ((code_info[count] == ';') ||
  1548. X    (code_info[count] == '}')) break;
  1549. X    if (code_info[count] == '(') {
  1550. X      syntax_err("unexpected left parenthesis found while parsing parameters");
  1551. X      return;
  1552. X    }
  1553. X  }
  1554. X  if ((code_info[count] == ';') ||
  1555. X      (code_info[count] == '}')) count++;
  1556. X
  1557. X  /* gain space */
  1558. X  if ((func_list = (char *) malloc(sizeof(char) * (len - sep_point + 1)))
  1559. X      == NULL) {
  1560. X    fprintf(stderr, "Serious Error: Malloc failed\n");
  1561. X    exit(1);
  1562. X  }
  1563. X  if ((func_declare =
  1564. X       (char *) malloc(sizeof(char) * (sep_point - count + 1))) == NULL) {
  1565. X    fprintf(stderr, "Serious Error: Malloc failed\n");
  1566. X    exit(1);
  1567. X  }
  1568. X
  1569. X  /* now assign the locations */
  1570. X  strcpy(func_list, &(code_info[sep_point]));
  1571. X  strncpy(func_declare, &(code_info[count]), sep_point - count);
  1572. X  func_declare[sep_point - count] = '\0';
  1573. X  trim_str(func_list);
  1574. X  trim_str(func_declare);
  1575. X
  1576. X  /* find just the function name */
  1577. X  len = strlen(func_declare);
  1578. X  count = find_name(name_space, func_declare, len);
  1579. X
  1580. X  /* just leave if there is no function */
  1581. X  if (count == 0) {
  1582. X    free(func_list);
  1583. X    free(func_declare);
  1584. X    return;
  1585. X  }
  1586. X
  1587. X  /* check for statics which shouldn't be shown */
  1588. X  if (get_option(OPT_STATICMODE) != ANY_STATICS) {
  1589. X    if (!strncmp(func_declare, "static ", 7) ==
  1590. X    (get_option(OPT_STATICMODE) == NO_STATICS)) {
  1591. X      last_comment[0] = '\0';
  1592. X      comment_len = 0;
  1593. X      free(func_list);
  1594. X      free(func_declare);
  1595. X      return;
  1596. X    }
  1597. X  }
  1598. X
  1599. X  /* declare storage space for the function */
  1600. X  if ((tmp_proto = (P_PROTO) malloc(sizeof(S_PROTO))) == NULL) {
  1601. X    fprintf(stderr, "Memory allocation failure\n");
  1602. X    exit(1);
  1603. X  }
  1604. X  tmp_proto->next = NULL;
  1605. X  tmp_proto->name = NULL;
  1606. X  tmp_proto->ftype = NULL;
  1607. X  tmp_proto->fname = NULL;
  1608. X  tmp_proto->plist = NULL;
  1609. X  tmp_proto->comment = NULL;
  1610. X
  1611. X  /* place it in the list */
  1612. X  if ((proto_next == NULL) || (proto_list == NULL)) {
  1613. X    proto_next = proto_list = tmp_proto;
  1614. X  } else {
  1615. X    proto_next->next = tmp_proto;
  1616. X    proto_next = tmp_proto;
  1617. X  }
  1618. X  if ((proto_next->fname =
  1619. X       (char *) malloc(sizeof(char) * (strlen(file_name) + 2))) == NULL) {
  1620. X    fprintf(stderr, "Memory allocation error\n");
  1621. X    exit(1);
  1622. X  }
  1623. X  strcpy(proto_next->fname, file_name);
  1624. X
  1625. X  /* now copy any preceding comments if desired */
  1626. X  if (get_option(OPT_COMMENTS) &&
  1627. X      (last_comment[0] != '\0')) {
  1628. X    if ((proto_next->comment =
  1629. X     (char *) malloc(sizeof(char) * (comment_len + 5))) == NULL) {
  1630. X      fprintf(stderr, "Memory allocation error\n");
  1631. X      exit(1);
  1632. X    }
  1633. X    strcpy(proto_next->comment, "/*");
  1634. X    strcat(proto_next->comment, last_comment);
  1635. X    last_comment[0] = '\0';
  1636. X    comment_len = 0;
  1637. X  } else {
  1638. X    proto_next->comment = NULL;
  1639. X  }
  1640. X
  1641. X  /* check for the conversion of the type declaration */
  1642. X  if (count != len) {
  1643. X    if (strncmp("extern ", func_declare, 7) == 0) {
  1644. X      cmpstt = 7;
  1645. X    } else {
  1646. X      cmpstt = 0;
  1647. X    }
  1648. X    for (sub_tmp = subst_list;
  1649. X     sub_tmp != NULL;
  1650. X     sub_tmp = sub_tmp->next) {
  1651. X      /* check it */
  1652. X      if (sub_tmp->submode == SUBST_TYPE) {
  1653. X
  1654. X    /* compare */
  1655. X    typelen = strlen(sub_tmp->from_str);
  1656. X    if (strncmp(func_declare + cmpstt, sub_tmp->from_str, typelen) == 0) {
  1657. X      strcpy(tmp_str, sub_tmp->to_str);
  1658. X      strcat(tmp_str, func_declare + cmpstt + typelen);
  1659. X      strcpy(func_declare, tmp_str);
  1660. X      len += (strlen(sub_tmp->to_str) - typelen - cmpstt);
  1661. X    }
  1662. X
  1663. X      }
  1664. X    }
  1665. X  }
  1666. X
  1667. X  /* output extern if desired */
  1668. X  if (get_option(OPT_EXTERNS) &&
  1669. X      strncmp("extern ", func_declare, 7) != 0) {
  1670. X    strcpy(dummy_str, "extern ");
  1671. X    dummy_len = 7;
  1672. X  } else {
  1673. X    dummy_str[0] = '\0';
  1674. X    dummy_len = 0;
  1675. X  }
  1676. X
  1677. X  /* now check if the function type is an integer */
  1678. X  if (count == len) {
  1679. X    strcat(dummy_str, "int ");
  1680. X    strcat(dummy_str, func_declare);
  1681. X    dummy_len += 4 + len;
  1682. X  } else {
  1683. X    strcat(dummy_str, func_declare);
  1684. X    dummy_len += len;
  1685. X  }
  1686. X
  1687. X  /* store the function header */
  1688. X  if ((proto_next->ftype =
  1689. X       (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
  1690. X    fprintf(stderr, "Memory allocation error\n");
  1691. X    exit(1);
  1692. X  }
  1693. X  strcpy(proto_next->ftype, dummy_str);
  1694. X
  1695. X  /* the function string */
  1696. X  if ((proto_next->name =
  1697. X       (char *) malloc(sizeof(char) * (count + 2))) == NULL) {
  1698. X    fprintf(stderr, "Memory allocation error\n");
  1699. X    exit(1);
  1700. X  }
  1701. X  strcpy(proto_next->name, name_space);
  1702. X
  1703. X  /* now output empty list amount */
  1704. X  len = strlen(func_list);
  1705. X  switch (diverge_style(func_list, len)) {
  1706. X  case 0:
  1707. X    /* empty or "void" parameter list */
  1708. X    strcpy(dummy_str, "void");
  1709. X    dummy_len = 4;
  1710. X    break;
  1711. X  case 1:
  1712. X    /* ANSI C format! -- remove trailing parenthesis */
  1713. X    func_list[--len] = '\0';
  1714. X    if ((dummy_len = newc_parse(func_list + 1)) == -1) {
  1715. X      free(func_list);
  1716. X      free(func_declare);
  1717. X      pop_proto();
  1718. X      return;
  1719. X    }
  1720. X    break;
  1721. X  default:
  1722. X    /* K&R C format */
  1723. X    if ((dummy_len = oldc_parse(func_list)) == -1) {
  1724. X      free(func_list);
  1725. X      free(func_declare);
  1726. X      pop_proto();
  1727. X      return;
  1728. X    }
  1729. X    break;
  1730. X  }
  1731. X
  1732. X  /* store it */
  1733. X  if ((proto_next->plist =
  1734. X       (char *) malloc(sizeof(char) * (dummy_len + 2))) == NULL) {
  1735. X    fprintf(stderr, "Memory allocation error\n");
  1736. X    exit(1);
  1737. X  }
  1738. X  strcpy(proto_next->plist, dummy_str);
  1739. X
  1740. X  /* replace space */
  1741. X  free(func_list);
  1742. X  free(func_declare);
  1743. X}
  1744. X
  1745. X/* go through the file extracting functions */
  1746. Xvoid
  1747. Xparse_file()
  1748. X{
  1749. X  int curr_char, count = 0, was_comment = FALSE, may_flush = FALSE;
  1750. X  int depth = 0, num_comment = 0, temp_count = 0, temp_lines = 0;
  1751. X  char temp_list[MID_SIZE];
  1752. X  int prev_char = '\n', old_prev_real = ' ', prev_real = ' ';
  1753. X
  1754. X  /* go to it */
  1755. X  start_comment[0] = '\0';
  1756. X  last_comment[0] = '\0';
  1757. X  temp_list[0] = '\0';
  1758. X  while ((curr_char = getc(fpin)) != EOF) {
  1759. X
  1760. X    /* check depth first */
  1761. X    if (curr_char == '\n') line_count++;
  1762. X    if (depth == 0) {
  1763. X
  1764. X      /* process the characters */
  1765. X      if (curr_char == '#' && prev_char == '\n') {
  1766. X
  1767. X    /* nuke any preprocessor statements */
  1768. X    was_comment = FALSE;
  1769. X    prev_char = '#';
  1770. X    curr_char = preprocessor_check();
  1771. X
  1772. X      } else if (curr_char == '"') {
  1773. X
  1774. X    /* nuke string quotes -- must be on same line */
  1775. X    prev_char = curr_char;
  1776. X    count = 0;
  1777. X    while (!feof(fpin)) {
  1778. X      if ((curr_char = getc(fpin)) == '"') {
  1779. X        break;
  1780. X      } else if (curr_char == '\n') {
  1781. X        syntax_err("unexpected newline found in string");
  1782. X        line_count++;
  1783. X      } else if (curr_char == '\\') {
  1784. X        prev_char = curr_char;
  1785. X        curr_char = getc(fpin);
  1786. X      }
  1787. X      prev_char = curr_char;
  1788. X    }
  1789. X
  1790. X      } else if (curr_char == '\'') {
  1791. X
  1792. X    /* nuke character quotes -- must be on same line */
  1793. X    count = 0;
  1794. X    prev_char = curr_char;
  1795. X    while (!feof(fpin)) {
  1796. X      if ((curr_char = getc(fpin)) == '\'') {
  1797. X        break;
  1798. X      } else if (curr_char == '\n') {
  1799. X        syntax_err("unexpected newline in character constant");
  1800. X        line_count++;
  1801. X      } else if (curr_char == '\\') {
  1802. X        prev_char = curr_char;
  1803. X        curr_char = getc(fpin);
  1804. X      }
  1805. X      prev_char = curr_char;
  1806. X    }
  1807. X
  1808. X      } else if (curr_char == '*' && prev_char == '/') {
  1809. X
  1810. X    /* clear out commments; treat as spaces */
  1811. X    if (count > 0) count--;
  1812. X    if (was_comment == FALSE) {
  1813. X      num_comment++;
  1814. X      temp_count = 0;
  1815. X    } else {
  1816. X      temp_count--;
  1817. X      if ((get_option(OPT_SINGLECOMMENTS) == TRUE) &&
  1818. X          (temp_count > 0)) {
  1819. X        num_comment++;
  1820. X        was_comment = FALSE;
  1821. X        temp_count = 0;
  1822. X      }
  1823. X    }
  1824. X    temp_list[temp_count] = '\0';
  1825. X    curr_char = ' ';
  1826. X    if (get_option(OPT_COMMENTS) ||
  1827. X        ((num_comment == 1) &&
  1828. X         get_option(OPT_FIRSTCOMMENT))) {
  1829. X
  1830. X      /* process it */
  1831. X      if (num_comment == 1) {
  1832. X        get_comment(was_comment, temp_list, start_comment);
  1833. X      } else {
  1834. X        get_comment(was_comment, temp_list, last_comment);
  1835. X      }
  1836. X      was_comment = TRUE;
  1837. X      temp_lines = 0;
  1838. X      temp_count = (-1);
  1839. X
  1840. X    } else {
  1841. X
  1842. X      while ((curr_char = getc(fpin)) != EOF) {
  1843. X
  1844. X        /* test for end of comment */
  1845. X        if (curr_char == '\n') line_count++;
  1846. X        if ((curr_char == '/') && (prev_char == '*')) {
  1847. X          break;
  1848. X        }
  1849. X        prev_char = curr_char;
  1850. X      }
  1851. X      curr_char = ' ';
  1852. X
  1853. X    }
  1854. X    prev_real = old_prev_real;
  1855. X
  1856. X      } else if ((curr_char == '/') && (prev_char == '/')) {
  1857. X
  1858. X    /* just yank out any C++ comments */
  1859. X    if (count > 0) count--;
  1860. X    while ((curr_char = getc(fpin)) != EOF) {
  1861. X
  1862. X      /* test for end of comment */
  1863. X      if (curr_char == '\n') {
  1864. X        line_count++;
  1865. X        break;
  1866. X      }
  1867. X      prev_char = curr_char;
  1868. X
  1869. X    }
  1870. X    curr_char = ' ';
  1871. X    prev_real = old_prev_real;
  1872. X
  1873. X      } else if (curr_char == '{') {
  1874. X
  1875. X    /* reset recording process */
  1876. X    was_comment = FALSE;
  1877. X    may_flush = FALSE;
  1878. X    depth++;
  1879. X
  1880. X    /* now check if it is a function */
  1881. X    if ((prev_real == ';') ||
  1882. X        (prev_real == ')')) {
  1883. X
  1884. X      /* found end of function, struct, or union definition */
  1885. X      code_info[count] = '\0';
  1886. X      parse_func();
  1887. X      code_info[count = 0] = '\0';
  1888. X
  1889. X    } else {
  1890. X      code_info[count++] = '{';
  1891. X    }
  1892. X
  1893. X      } else if (curr_char == '}') {
  1894. X
  1895. X    syntax_err("extra right brace encountered");
  1896. X    break;
  1897. X
  1898. X      }
  1899. X
  1900. X      /* tag onto the list */
  1901. X      if (depth == 0) {
  1902. X
  1903. X    /* store the characters for later use */
  1904. X    if (isspace(curr_char) &&
  1905. X        (count != 0 && code_info[count - 1] != ' ')) {
  1906. X
  1907. X      /* combine any white space into a single space character */
  1908. X      code_info[count++] = ' ';
  1909. X
  1910. X    } else if (!isspace(curr_char)) {
  1911. X
  1912. X      /* store any other type directly */
  1913. X      if (curr_char != '/') {
  1914. X        was_comment = FALSE;
  1915. X        temp_count = 0;
  1916. X        temp_lines = 0;
  1917. X      }
  1918. X      code_info[count++] = curr_char;
  1919. X      old_prev_real = prev_real;
  1920. X      prev_real = curr_char;
  1921. X
  1922. X    }
  1923. X
  1924. X    /* count the lead in */
  1925. X    if (was_comment == TRUE) {
  1926. X
  1927. X      /* no multiple newlines */
  1928. X      if (curr_char == '\n') {
  1929. X        if (temp_lines == 0) {
  1930. X          temp_lines = 1;
  1931. X        } else {
  1932. X          temp_lines = 0;
  1933. X          temp_count = -1;
  1934. X          was_comment = FALSE;
  1935. X        }
  1936. X      }
  1937. X
  1938. X      /* check beginning */
  1939. X      if (temp_count >= 0) {
  1940. X        temp_list[temp_count] = curr_char;
  1941. X      }
  1942. X      temp_count++;
  1943. X
  1944. X    }
  1945. X
  1946. X    /* now note what was last encountered */ 
  1947. X    prev_char = curr_char;
  1948. X
  1949. X      }
  1950. X
  1951. X    } else {
  1952. X
  1953. X      /* keep track of depth and got through code otherwise */
  1954. X      if (curr_char == '#' && prev_char == '\n') {
  1955. X
  1956. X    /* nuke any preprocessor statements */
  1957. X    prev_char = '#';
  1958. X    curr_char = preprocessor_check();
  1959. X
  1960. X      } else if (curr_char == '"') {
  1961. X
  1962. X    /* nuke string quotes -- must be on same line */
  1963. X    may_flush = TRUE;
  1964. X    while (!feof(fpin)) {
  1965. X      prev_char = curr_char;
  1966. X      if ((curr_char = getc(fpin)) == '\n') {
  1967. X        syntax_err("unexpected newline found in string");
  1968. X        line_count++;
  1969. X      } else if (curr_char == '\\') {
  1970. X        prev_char = curr_char;
  1971. X        curr_char = getc(fpin);
  1972. X        continue;
  1973. X      } else if (curr_char == '"') {
  1974. X        break;
  1975. X      }
  1976. X    };
  1977. X
  1978. X      } else if (curr_char == '\'') {
  1979. X
  1980. X    /* nuke character quotes -- must be on same line */
  1981. X    may_flush = TRUE;
  1982. X    while (!feof(fpin)) {
  1983. X      prev_char = curr_char;
  1984. X      if ((curr_char = getc(fpin)) == '\n') {
  1985. X        syntax_err("unexpected newline in character constant");
  1986. X        line_count++;
  1987. X      } else if (curr_char == '\\') {
  1988. X        prev_char = curr_char;
  1989. X        curr_char = getc(fpin);
  1990. X      } else if (curr_char == '\'') {
  1991. X        break;
  1992. X      } 
  1993. X    }
  1994. X
  1995. X      } else if (curr_char == '*' && prev_char == '/') {
  1996. X
  1997. X    /* nuke comments */
  1998. X    num_comment++;
  1999. X    while ((curr_char = getc(fpin)) != EOF) {
  2000. X
  2001. X      /* test for end of comment */
  2002. X      if (curr_char == '\n') line_count++;
  2003. X      if ((curr_char == '/') && (prev_char == '*')) {
  2004. X        break;
  2005. X      }
  2006. X      prev_char = curr_char;
  2007. X
  2008. X    }
  2009. X    curr_char = ' ';
  2010. X
  2011. X      } else if (curr_char == '/' && prev_char == '/') {
  2012. X
  2013. X    /* nuke C++ comments (don't count it) */
  2014. X    while ((curr_char = getc(fpin)) != EOF) {
  2015. X
  2016. X      /* test for end of comment */
  2017. X      if (curr_char == '\n') {
  2018. X        line_count++;
  2019. X        break;
  2020. X      }
  2021. X      prev_char = curr_char;
  2022. X
  2023. X    }
  2024. X    curr_char = ' ';
  2025. X
  2026. X      } else if (curr_char == '{') {
  2027. X
  2028. X    depth++;
  2029. X    code_info[count++] = curr_char;
  2030. X
  2031. X      } else if (curr_char == '}') {
  2032. X
  2033. X    --depth;
  2034. X    if (count > 0) code_info[count++] = curr_char;
  2035. X    if (may_flush) {
  2036. X      if (depth == 0) may_flush = FALSE;
  2037. X      code_info[count = 0] = '\0';
  2038. X    }
  2039. X
  2040. X      } else {
  2041. X    /* just copy on the off chance */
  2042. X    code_info[count++] = curr_char;
  2043. X      }
  2044. X
  2045. X      /* now note what was last encountered */ 
  2046. X      prev_char = curr_char;
  2047. X
  2048. X    }
  2049. X
  2050. X  }
  2051. X}
  2052. X
  2053. END_OF_FILE
  2054. if test 54378 -ne `wc -c <'parse.c'`; then
  2055.     echo shar: \"'parse.c'\" unpacked with wrong size!
  2056. fi
  2057. # end of 'parse.c'
  2058. fi
  2059. echo shar: End of archive 5 \(of 5\).
  2060. cp /dev/null ark5isdone
  2061. MISSING=""
  2062. for I in 1 2 3 4 5 ; do
  2063.     if test ! -f ark${I}isdone ; then
  2064.     MISSING="${MISSING} ${I}"
  2065.     fi
  2066. done
  2067. if test "${MISSING}" = "" ; then
  2068.     echo You have unpacked all 5 archives.
  2069.     rm -f ark[1-9]isdone
  2070. else
  2071.     echo You still need to unpack the following archives:
  2072.     echo "        " ${MISSING}
  2073. fi
  2074. ##  End of shell archive.
  2075. exit 0
  2076.  
  2077. exit 0 # Just in case...
  2078.