home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / reviewed / volume01 / cextract / part03 < prev    next >
Internet Message Format  |  1991-07-08  |  56KB

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