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

  1. From: Adam Bryant <adb@cs.bu.edu>
  2. Subject: v02i041: cextract - (Ver. 1.7) C prototyper/header file generator, Part03/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 41
  8. Archive-name: cextract/part03
  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 3 (of 5)."
  18. # Contents:  main.c
  19. # Wrapped by adb@csa on Fri Oct 30 16:20:36 1992
  20. PATH=/bin:/usr/bin:/usr/ucb ; export PATH
  21. if test -f 'main.c' -a "${1}" != "-c" ; then 
  22.   echo shar: Will not clobber existing file \"'main.c'\"
  23. else
  24. echo shar: Extracting \"'main.c'\" \(24410 characters\)
  25. sed "s/^X//" >'main.c' <<'END_OF_FILE'
  26. X/*
  27. X *
  28. X * The purpose of this program is to extract the function descriptions
  29. X * (prototypes) from C source code.  It also provides for the creation
  30. X * of documentation based on those prototypes.
  31. X *
  32. X * The specific reason for the creation of this program was to
  33. X * provide a method for automatically creating header files to
  34. X * describe all of the functions to be used within a multi-file
  35. X * program.
  36. X *
  37. X * This file makes use of code in the companion files parse.c and io.c.
  38. X *
  39. X * Copyright (c) 1990, 1991, 1992 by Adam Bryant
  40. X *
  41. X * See Copyright notice in the file parse.c or in the manual page.
  42. X *
  43. X */
  44. X/*
  45. X * Version history:
  46. X *
  47. X * For Version 0.30:  file parse functions were separated out into a
  48. X *   separate file so that other programs could make use of them.  The
  49. X *   functions descriptions are now stored in dynamic memory and
  50. X *   functions are provided to allow the manipulation of those
  51. X *   descriptions.
  52. X * Version 0.31:  Only a few minor adjustments were made to cextract...
  53. X *   only as much as was needed to build the cextdoc program using the
  54. X *   cproto.[ch] files.
  55. X * Version 0.40:  Totally rewrote the parsing code so that the use of
  56. X *   temporary files is unnecessary.  Instead, two dynamic storage
  57. X *   elements have been created.  Besides being much faster, this
  58. X *   method is also much more elegant than the prior method.
  59. X * Version 0.41:  Switched the NOSETBUFFER to a SETBUFFER flag.
  60. X *   Added in the ability to handle the vararg system to convert it
  61. X *   to the "..." for ANSI C.
  62. X *
  63. X * ... change notes for later versions in parse.c
  64. X *
  65. X * Note on Version 1.0: merged the cextract and cextdoc into one
  66. X *   program, with differential being made based on the command line
  67. X *   or in the program name.  Version sent to comp.sources.reviewed.
  68. X *
  69. X */
  70. X#include "xtract.h"
  71. X#ifndef VMS
  72. X#include <sys/types.h>
  73. X#include <sys/stat.h>
  74. X#else
  75. X#include <types.h>
  76. X#include <stat.h>
  77. X#endif /* VMS */
  78. X
  79. X/* definition strings to be set when the C preprocessor runs */
  80. X#ifndef VAXC
  81. X#define CPP_GIVEN "-D__CEXTRACT__"
  82. X#define CPP_GIVEN2 "-D__CEXTDOC__"
  83. X#else
  84. X#define CPP_GIVEN "/define=__CEXTRACT__"
  85. X#define CPP_GIVEN2 "/define=__CEXTDOC__"
  86. X#endif /* VAXC */
  87. X
  88. X/* output filter from the parsing routines */
  89. Xvoid
  90. Xout_char(type, outch)
  91. X  int type, outch;
  92. X{
  93. X  /* to keep track of where the output list is */
  94. X  int tab_width = get_option(OPT_TABWIDTH);
  95. X  static P_BUFDATA curbuf[2] = { NULL, NULL };
  96. X  static int curpos[2] = { 0, 0 };
  97. X  static int tab_count = 0;
  98. X
  99. X  /* split output properly */
  100. X  switch (type) {
  101. X  case 0:
  102. X    /* documentation mode should never get this */
  103. X    if (doc_extract != DOC_NONE) {
  104. X      fprintf(stderr, "Serious Internal Error: bad out_char() data\n");
  105. X      exit(1);
  106. X    }
  107. X  case 1:
  108. X    /* give it to the first one */
  109. X    if (tempbuf[type] == NULL) {
  110. X
  111. X      /* start the list */
  112. X      if ((tempbuf[type] = (P_BUFDATA) malloc(sizeof(S_BUFDATA))) == NULL) {
  113. X    fprintf(stderr, "Memory Allocation Error\n");
  114. X    exit(1);
  115. X      }
  116. X      tempbuf[type]->next = NULL;
  117. X      curbuf[type] = tempbuf[type];
  118. X    }
  119. X
  120. X    /* have we got enough in this one? */
  121. X    if (curpos[type] == MID_SIZE) {
  122. X
  123. X      /* finish it off */
  124. X    build_memory:
  125. X      curbuf[type]->data[MID_SIZE] = '\0';
  126. X      curpos[type] = 0;
  127. X
  128. X      /* start the next one */
  129. X      if ((curbuf[type]->next =
  130. X       (P_BUFDATA) malloc(sizeof(S_BUFDATA))) == NULL) {
  131. X    fprintf(stderr, "Memory Allocation Error\n");
  132. X    exit(1);
  133. X      }
  134. X      curbuf[type] = curbuf[type]->next;
  135. X      curbuf[type]->next = NULL;
  136. X
  137. X    }
  138. X
  139. X    /* special output filter for the documentation mode */
  140. X    if (doc_extract != DOC_NONE) {
  141. X
  142. X      /* tab expansion? */
  143. X      if (tab_width > 0) {
  144. X    if (outch == '\t') {
  145. X      /* fill out tabs properly */
  146. X      while (tab_count++ < tab_width) {
  147. X
  148. X        /* check that it will fit */
  149. X        if (curpos[type] == MID_SIZE) {
  150. X          tab_count--;
  151. X          goto build_memory;
  152. X        }
  153. X
  154. X        /* put out the space */
  155. X        curbuf[type]->data[(curpos[type])++] = ' ';
  156. X
  157. X      }
  158. X      tab_count = 0;
  159. X      break;
  160. X    } else if (outch == '\\') {
  161. X      /* account for font changes */
  162. X      tab_count -= 2;
  163. X    } else if (outch == '\n') {
  164. X      /* now on a new line */
  165. X      tab_count = 0;
  166. X    } else {
  167. X      /* just count */
  168. X      if (++tab_count == tab_width) {
  169. X        tab_count = 0;
  170. X      }
  171. X    }
  172. X      }
  173. X
  174. X    }
  175. X
  176. X    /* now store it */
  177. X    curbuf[type]->data[(curpos[type])++] = outch;
  178. X    break;
  179. X  case -1:
  180. X    /* close everything up */
  181. X    if (curbuf[0] != NULL) {
  182. X      curbuf[0]->data[curpos[0]] = '\0';
  183. X    }
  184. X    if (curbuf[1] != NULL) {
  185. X      curbuf[1]->data[curpos[1]] = '\0';
  186. X    }
  187. X    break;
  188. X  default:
  189. X    /* ain't one of mine */
  190. X    fprintf(stderr, "Serious Internal Error: bad data to out_char()\n");
  191. X    break;
  192. X  }
  193. X
  194. X}
  195. X
  196. X/* show the version of the program */
  197. Xvoid
  198. Xshow_version ()
  199. X{
  200. X  fprintf(stderr, "%s: version %d.%d, Copyright 1992 by Adam Bryant\n",
  201. X      prog_name, VERSION, PATCHLEVEL);
  202. X}
  203. X
  204. X/* quickly show a sting and indicate if it is on or off */
  205. Xstatic void
  206. Xquick_show (str, mode)
  207. X  char *str;
  208. X  int mode;
  209. X{
  210. X  fprintf(stderr, "\t%s is %s.\n", str, mode ? "on":"off");
  211. X}
  212. X
  213. X/* show all of the settings */
  214. Xvoid
  215. Xshow_settings ()
  216. X{
  217. X  P_MACRO macro_temp;
  218. X  P_SUBST sub_tmp;
  219. X
  220. X  /* give the version info and current settings */
  221. X  show_version();
  222. X  fprintf(stderr, "\n  List of current settings:\n");
  223. X  fprintf(stderr, "\tC preprocessor in use: %s\n", cpp_prog);
  224. X  switch (doc_extract) {
  225. X  case DOC_NONE:
  226. X    fprintf(stderr, "\tfunction prototype extraction mode.\n");
  227. X    if (output_file[0][0] != '\0') {
  228. X      fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[0]);
  229. X    }
  230. X    if (header_string[0] != '\0') {
  231. X      fprintf(stderr, "\tthe header string is \"%s\".\n", header_string);
  232. X    }
  233. X    quick_show("merged ANSI and K&R C output", get_option(OPT_COMPACT));
  234. X    if (!get_option(OPT_COMPACT)) {
  235. X      quick_show("showing both ANSI and K&R C", get_option(OPT_BOTHUSE));
  236. X      if (!get_option(OPT_BOTHUSE)) {
  237. X    quick_show("ANSI C output format", get_option(OPT_STDCUSE));
  238. X      }
  239. X    }
  240. X    quick_show("showing prototypes at all times", get_option(OPT_SHOWANYWAY));
  241. X    break;
  242. X  case DOC_NORMAL:
  243. X    fprintf(stderr, "\ttext documentation mode.\n");
  244. X    if (output_file[1][0] != '\0') {
  245. X      fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[1]);
  246. X    }
  247. X    break;
  248. X  case DOC_ROFF:
  249. X    fprintf(stderr, "\ttroff documentation mode.\n");
  250. X    if (output_file[1][0] != '\0') {
  251. X      fprintf(stderr, "\tthe output file is \"%s\".\n", output_file[1]);
  252. X    }
  253. X    break;
  254. X  default:
  255. X    fprintf(stderr, "\tError, unknown mode.\n\n");
  256. X    exit(1);
  257. X    break;
  258. X  }
  259. X  if (get_option(OPT_SORTMODE) == SORT_ALL) {
  260. X    quick_show("sorting for all functions", TRUE);
  261. X  } else if (get_option(OPT_SORTMODE) == SORT_FILE) {
  262. X    quick_show("sorting for each file", TRUE);
  263. X  } else {
  264. X    quick_show("sorting", FALSE);
  265. X  }
  266. X  if (get_option(OPT_WRAPPOINT) > 0) {
  267. X    fprintf(stderr, "\tlong prototype lists wrap at column %d.\n",
  268. X        get_option(OPT_WRAPPOINT));
  269. X  } else {
  270. X    quick_show("wrapping of long prototypes", FALSE);
  271. X  }
  272. X  quick_show("separating function name and type", get_option(OPT_TYPEWRAP));
  273. X  quick_show("showing first comment in each file",
  274. X         get_option(OPT_FIRSTCOMMENT));
  275. X  quick_show("sending file name with first comment",
  276. X         get_option(OPT_PREPEND));
  277. X  quick_show("comment capturing", get_option(OPT_COMMENTS));
  278. X  if (get_option(OPT_STATICMODE) == ONLY_STATICS) {
  279. X    quick_show("only static functions are searched for", TRUE);
  280. X  } else {
  281. X    quick_show("including static functions in search",
  282. X           get_option(OPT_STATICMODE) == ANY_STATICS);
  283. X  }
  284. X  quick_show("prepending extern to function declarations",
  285. X         get_option(OPT_EXTERNS));
  286. X  quick_show("testing for multi-line comments",
  287. X         !get_option(OPT_SINGLECOMMENTS));
  288. X
  289. X  /* now show all of the macro definitions */
  290. X  if (macro_list != NULL) {
  291. X    fprintf(stderr, "\n  List of preprocessor definitions:\n");
  292. X    for (macro_temp = macro_list;
  293. X     macro_temp != NULL;
  294. X     macro_temp = macro_temp->next) {
  295. X      /* use? */
  296. X      if ((macro_temp->usewhen != 2) &&
  297. X      (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
  298. X      fprintf(stderr, "\t%s\n", macro_temp->m_str);
  299. X    }
  300. X  }
  301. X
  302. X  /* now check the substitutions */
  303. X  if (subst_list != NULL) {
  304. X    fprintf(stderr, "\n  List of prototype substitutions:\n");
  305. X    for (sub_tmp = subst_list;
  306. X     sub_tmp != NULL;
  307. X     sub_tmp = sub_tmp->next) {
  308. X      /* used? */
  309. X      if ((sub_tmp->usewhen != 2) &&
  310. X      (sub_tmp->usewhen != (doc_extract != DOC_NONE))) continue;
  311. X
  312. X      /* check it */
  313. X      switch (sub_tmp->submode) {
  314. X      case SUBST_FULL:
  315. X    /* the full string needs replacing? */
  316. X    fprintf(stderr, "\treplace all \"%s\" with \"%s\"\n",
  317. X        sub_tmp->from_str, sub_tmp->to_str);
  318. X    break;
  319. X      case SUBST_TYPE:
  320. X    /* the type only needs replacing? */
  321. X    fprintf(stderr, "\treplace type \"%s\" with \"%s\"\n",
  322. X        sub_tmp->from_str, sub_tmp->to_str);
  323. X    break;
  324. X      case SUBST_NAME:
  325. X    /* the variable only needs replacing? WHY!? */
  326. X    fprintf(stderr, "\treplace name \"%s\" with \"%s\"\n",
  327. X        sub_tmp->from_str, sub_tmp->to_str);
  328. X    break;
  329. X      }
  330. X    }
  331. X  }
  332. X
  333. X  /* all done */
  334. X  fprintf(stderr, "\n");
  335. X  exit(0);
  336. X}
  337. X
  338. X/* quick function to copy a "string" */
  339. Xint
  340. Xcopy_str (o_str, in_str)
  341. X  char *o_str, *in_str;
  342. X{
  343. X  int ch, count = 0, ch_read = 0;
  344. X
  345. X  /* find the beginning of the string */
  346. X  while ((*in_str != '"') &&
  347. X     (*in_str != '\0')) {
  348. X    ch_read++;
  349. X    in_str++;
  350. X  }
  351. X
  352. X  /* now was a string found? */
  353. X  if (*in_str == '\0') {
  354. X    return(-1);
  355. X  }
  356. X  ch_read++;
  357. X  in_str++;
  358. X
  359. X  /* copy all of the string */
  360. X  while (((ch = *(in_str)) != '\0') &&
  361. X     (ch != '"')) {
  362. X    /* copy it */
  363. X    o_str[count++] = ch;
  364. X    ch_read++;
  365. X    in_str++;
  366. X  }
  367. X  if (ch == '"') ch_read++;
  368. X
  369. X  /* finish up and get out */
  370. X  o_str[count] = '\0';
  371. X  return(ch_read);
  372. X}
  373. X
  374. X/* show the usage for the program */
  375. Xvoid
  376. Xshow_usage()
  377. X{
  378. X#ifndef VMS
  379. X  fprintf(stderr,
  380. X      "Usage: %s [-Q#] [+AaBbPpNnVvxZ -Hstr -Yprg -o ofile] [[-opts] file ... ]\n",
  381. X      prog_name);
  382. X  fprintf(stderr, "\t+A        alphabetically sort all functions [incompatable with +C]\n");
  383. X  fprintf(stderr, "\t+a        alphabetically sort functions within each file [default off]\n");
  384. X  fprintf(stderr, "\t-B        build a system configuration file based on settings\n");
  385. X  fprintf(stderr, "\t-b        build a configuration file in the current directory\n");
  386. X  fprintf(stderr, "\t+C        include first comment from each file\n");
  387. X  fprintf(stderr, "\t+c        include comments immediately preceding functions\n");
  388. X  fprintf(stderr, "\t-Dexpr    send a macro definition to the C preprocessor\n");
  389. X  fprintf(stderr, "\t+E        add a preceding 'extern' to each function definition\n");
  390. X  fprintf(stderr, "\t+F        toggle prepending of file name to first comment [need +C]\n");
  391. X  fprintf(stderr, "\t-f#cc     in troff doc-mode set various font styles\n");
  392. X  fprintf(stderr, "\t-Hstring  build header file with read test on string\n");
  393. X  fprintf(stderr, "\t-Idir     add directory to search list for include files\n");
  394. X  fprintf(stderr, "\t-o file   send output to a file instead of standard output\n");
  395. X  fprintf(stderr, "\t           [take first non-flag as filename for output]\n");
  396. X  fprintf(stderr, "\t+m        allow multi-line comments when parsing comments\n");
  397. X  fprintf(stderr, "\t-N        do documentation output in troff ms format\n");
  398. X  fprintf(stderr, "\t-n        do documentation output in normal text\n");
  399. X  fprintf(stderr, "\t+P        create output in both ANSI and non-ANSI prototypes\n");
  400. X  fprintf(stderr, "\t+p        create output in ANSI C prototype format\n");
  401. X  fprintf(stderr, "\t-Q#       do not read in config files, or only those specified\n");
  402. X  fprintf(stderr, "\t-qfile    read in a specified configuration file\n");
  403. X  fprintf(stderr, "\t+r        remove variable names prior to output\n");
  404. X  fprintf(stderr, "\t+S        show parameters for non-ANSI portion of output\n");
  405. X  fprintf(stderr, "\t+s        include static function definitions\n");
  406. X  fprintf(stderr, "\t-s=only   capture only static function definitions\n");
  407. X  fprintf(stderr, "\t-s=none   exclude static function definitions\n");
  408. X  fprintf(stderr, "\t-s=any    include static function definitions\n");
  409. X  fprintf(stderr, "\t-TN       set tab width in doc-mode to N characters [0 = off]\n");
  410. X  fprintf(stderr, "\t-Uname    undefine the given macro name\n");
  411. X  fprintf(stderr, "\t-V        display the program settings then exit\n");
  412. X  fprintf(stderr, "\t-v        display version information then exit\n");
  413. X  fprintf(stderr, "\t+W        place function type on a separate line.\n");
  414. X  fprintf(stderr, "\t+w#       wrap long parameter output [dflt length 72]\n");
  415. X  fprintf(stderr, "\t-x        run program in extraction mode\n");
  416. X  fprintf(stderr, "\t-Yprog    specify program to use as a C preprocessor\n");
  417. X  fprintf(stderr, "\t+Z        create the output as a compact, merged list\n");
  418. X#else /* VMS */
  419. X  fprintf(stderr, "USAGE: %s [/READ-CONFIG=#] [/OUTPUT=outfile] [[/OPTS] FILE ... ]\n",
  420. X      prog_name);
  421. X#endif /* VMS */
  422. X  exit(1);
  423. X}
  424. X
  425. X/* set the value of a global option */
  426. Xvoid
  427. Xset_option(which, how, value)
  428. X  Optype which;
  429. X  int how, value;
  430. X{
  431. X#ifdef CHECK_INPUTS
  432. X  /* check input values */
  433. X  if ((which < 0) ||
  434. X      (which >= OPT_NUMBER)) {
  435. X    fprintf(stderr, "SERIOUS ERROR: Internal option value out of range %d\n",
  436. X        which);
  437. X    exit(1);
  438. X  }
  439. X  if ((how < 0) ||
  440. X      (how > 2)) {
  441. X    fprintf(stderr, "SERIOUS ERROR: Internal option method out of range %d\n",
  442. X        how);
  443. X    exit(1);
  444. X  }
  445. X#endif /* CHECK_INPUTS */
  446. X
  447. X  /* now set properly */
  448. X  if (how == 2) {
  449. X    global_opts[0][which] = value;
  450. X    global_opts[1][which] = value;
  451. X  } else {
  452. X    global_opts[how][which] = value;
  453. X  }
  454. X}
  455. X
  456. X/* retrieve the value of a global option */
  457. Xint
  458. Xget_option(which)
  459. X  Optype which;
  460. X{
  461. X#ifdef CHECK_INPUTS
  462. X  /* check input values */
  463. X  if ((which < 0) ||
  464. X      (which >= OPT_NUMBER)) {
  465. X    fprintf(stderr, "SERIOUS ERROR: Internal option value out of range %d\n",
  466. X        which);
  467. X    exit(1);
  468. X  }
  469. X#endif /* CHECK_INPUTS */
  470. X
  471. X  /* return whichever setting is needed */
  472. X  if (doc_extract == DOC_NONE) {
  473. X    return(global_opts[0][which]);
  474. X  }
  475. X  return(global_opts[1][which]);
  476. X}
  477. X
  478. X/* set configuration settings based on the initial name */
  479. Xstatic void
  480. Xcext_init()
  481. X{
  482. X  /* enter the proper mode */
  483. X  if (strncmp(CEXTDOC_NAME, prog_name, strlen(prog_name)) == 0) {
  484. X    doc_extract = DOC_NORMAL;
  485. X  } else {
  486. X    doc_extract = DOC_NONE;
  487. X  }
  488. X
  489. X  /* set documentation mode options properly */
  490. X  set_option(OPT_COMMENTS, 1, TRUE);
  491. X  set_option(OPT_STATICMODE, 1, ANY_STATICS);
  492. X  set_option(OPT_EXTERNS, 1, FALSE);
  493. X  set_option(OPT_STDCUSE, 1, TRUE);
  494. X  set_option(OPT_SORTMODE, 1, SORT_FILE);
  495. X
  496. X  /* set extraction mode options now */
  497. X  set_option(OPT_COMMENTS, 0, FALSE);
  498. X  set_option(OPT_STATICMODE, 0, NO_STATICS);
  499. X  set_option(OPT_EXTERNS, 0, TRUE);
  500. X  set_option(OPT_STDCUSE, 0, FALSE);
  501. X  set_option(OPT_SORTMODE, 0, SORT_NONE);
  502. X
  503. X  /* now set common options */
  504. X  set_option(OPT_NONAMES, 2, FALSE);
  505. X  set_option(OPT_COMPACT, 2, FALSE);
  506. X  set_option(OPT_TYPEWRAP, 2, FALSE);
  507. X  set_option(OPT_WRAPPOINT, 2, 0);
  508. X  set_option(OPT_BOTHUSE, 2, TRUE);
  509. X  set_option(OPT_SINGLECOMMENTS, 2, TRUE);
  510. X  set_option(OPT_FIRSTCOMMENT, 2, FALSE);
  511. X  set_option(OPT_SHOWANYWAY, 2, TRUE);
  512. X  set_option(OPT_PREPEND, 2, FALSE);
  513. X  set_option(OPT_TABWIDTH, 2, 8);
  514. X}
  515. X
  516. X/* return FALSE if character is not a normal part of a filename */
  517. Xint
  518. Xfname_char(ch)
  519. X  int ch;
  520. X{
  521. X  switch (ch) {
  522. X#ifdef MS_DOS
  523. X  case '\\':
  524. X#endif /* MS_DOS */
  525. X#ifdef VMS
  526. X  case ']':
  527. X  case ':':
  528. X#endif /* VMS */
  529. X  case '/':
  530. X    /* nope */
  531. X    return(FALSE);
  532. X  }
  533. X  return(TRUE);
  534. X}
  535. X
  536. X/* routine to build the macros onto the prototype line */
  537. Xstatic void
  538. Xappend_macros(str_out)
  539. X  char *str_out;
  540. X{
  541. X  P_MACRO macro_temp;
  542. X
  543. X#ifndef VAXC
  544. X  for (macro_temp = macro_list;
  545. X       macro_temp != NULL;
  546. X       macro_temp = macro_temp->next) {
  547. X
  548. X    /* check for use */
  549. X    if ((macro_temp->usewhen != 2) &&
  550. X    (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
  551. X
  552. X    /* use it */
  553. X    strcat(str_out, macro_temp->m_str);
  554. X    strcat(str_out, " ");
  555. X
  556. X  }
  557. X#else
  558. X  char und_str[MID_SIZE], def_str[MID_SIZE], inc_str[MID_SIZE];
  559. X  int und_uses = 0, def_uses = 0, inc_uses = 0;
  560. X  int und_len = strlen(UNDEF_LEADER);
  561. X  int inc_len = strlen(UNDEF_LEADER);
  562. X  int def_len = strlen(DEF_LEADER);
  563. X
  564. X  /* initialize */
  565. X  und_str[0] = '\0';
  566. X  def_str[0] = '\0';
  567. X  inc_str[0] = '\0';
  568. X
  569. X  /* properly build the command line for the C compiler */
  570. X  for (macro_temp = macro_list;
  571. X       macro_temp != NULL;
  572. X       macro_temp = macro_temp->next) {
  573. X
  574. X    /* check for use */
  575. X    if ((macro_temp->usewhen != 2) &&
  576. X    (macro_temp->usewhen != (doc_extract != DOC_NONE))) continue;
  577. X
  578. X    /* check for the definition statement */
  579. X    if (strncmp(DEF_LEADER, macro_temp->m_str, def_len) == 0) {
  580. X      if (def_uses++ > 0) {
  581. X    strcat(def_str, ",");
  582. X      }
  583. X      if (macro_temp->m_str[def_len] == '(') {
  584. X    strcat(def_str, macro_temp->m_str + def_len + 1);
  585. X    def_str[strlen(def_str) - 1] = '\0';
  586. X    def_uses++;
  587. X      } else {
  588. X    strcat(def_str, macro_temp->m_str + def_len);
  589. X      }
  590. X    } else if (strncmp(UNDEF_LEADER, macro_temp->m_str, und_len) == 0) {
  591. X      if (und_uses++ > 0) {
  592. X    strcat(und_str, ",");
  593. X      }
  594. X      if (macro_temp->m_str[und_len] == '(') {
  595. X    strcat(und_str, macro_temp->m_str + und_len + 1);
  596. X    und_str[strlen(und_str) - 1] = '\0';
  597. X    def_uses++;
  598. X      } else {
  599. X    strcat(und_str, macro_temp->m_str + und_len);
  600. X      }
  601. X    } else if (strncmp(INC_LEADER, macro_temp->m_str, inc_len) == 0) {
  602. X      if (inc_uses++ > 0) {
  603. X    strcat(inc_str, ",");
  604. X      }
  605. X      if (macro_temp->m_str[inc_len] == '(') {
  606. X    strcat(inc_str, macro_temp->m_str + inc_len + 1);
  607. X    und_str[strlen(inc_str) - 1] = '\0';
  608. X    def_uses++;
  609. X      } else {
  610. X    strcat(inc_str, macro_temp->m_str + inc_len);
  611. X      }
  612. X    } else {
  613. X      strcat(str_out, macro_temp->m_str);
  614. X    }
  615. X
  616. X  }
  617. X
  618. X  /* now finish everything off */
  619. X  if (def_uses > 0) {
  620. X    strcat(str_out, DEF_LEADER);
  621. X    if (def_uses > 1) strcat(str_out, "(");
  622. X    strcat(str_out, def_str);
  623. X    if (def_uses > 1) strcat(str_out, ")");
  624. X  }
  625. X  if (und_uses > 0) {
  626. X    strcat(str_out, UNDEF_LEADER);
  627. X    if (und_uses > 1) strcat(str_out, "(");
  628. X    strcat(str_out, und_str);
  629. X    if (und_uses > 1) strcat(str_out, ")");
  630. X  }
  631. X  if (inc_uses > 0) {
  632. X    strcat(str_out, INC_LEADER);
  633. X    if (inc_uses > 1) strcat(str_out, "(");
  634. X    strcat(str_out, inc_str);
  635. X    if (inc_uses > 1) strcat(str_out, ")");
  636. X  }
  637. X  strcat(str_out, " ");
  638. X#endif /* VAXC */
  639. X}
  640. X
  641. X/* control program flow and command line options */
  642. Xint
  643. Xmain (argc, argv)
  644. X  int argc;
  645. X  char **argv;
  646. X{
  647. X  char cur_argstr[MID_SIZE], sysl_out[MID_SIZE];
  648. X  extern int getpid();
  649. X  struct stat fst;
  650. X  int count, j, len;
  651. X
  652. X  /* initialize some things */
  653. X  fpout = stdout;
  654. X  len = strlen(argv[0]);
  655. X  for (j = len - 1; j > 0; j--) {
  656. X    if (fname_char(argv[0][j]) == FALSE) {
  657. X      j++;
  658. X      break;
  659. X    }
  660. X  }
  661. X  strcpy(prog_name, &(argv[0][j]));
  662. X  out_filenum = 0;
  663. X  start_comment[0] = '\0';
  664. X  header_string[0] = '\0';
  665. X  cur_cfg_file[0] = '\0';
  666. X  output_file[0][0] = '\0';
  667. X  output_file[1][0] = '\0';
  668. X  cfg_file[0] = '\0';
  669. X  sprintf(cpp_prog, "%s %s", CPP, CPP_COMMENTS);
  670. X  macro_list = last_macro = NULL;
  671. X  cext_init();
  672. X
  673. X  /* check for config file flags */
  674. X  count = 1;
  675. X  if ((count < argc) &&
  676. X      is_switch(argv[count][0])) {
  677. X
  678. X#ifndef VMS
  679. X    /* are we skipping config files? */
  680. X    if (argv[count][1] == 'Q') {
  681. X
  682. X      /* check the type */
  683. X      if (isdigit(argv[count][2])) {
  684. X    cfg_switch = argv[count][2] - '0';
  685. X    if ((cfg_switch < 0) ||
  686. X        (cfg_switch > 7) ||
  687. X        (argv[count][3] != '\0')) {
  688. X      fprintf(stderr, "Invalid value for -Q flag\n");
  689. X      show_usage();
  690. X    }
  691. X      } else if (argv[count][2] != '\0') {
  692. X    fprintf(stderr, "Invalid data following the -Q flag\n");
  693. X    show_usage();
  694. X      } else {
  695. X    cfg_switch = 0;
  696. X      }
  697. X
  698. X      /* processed this one */
  699. X      count++;
  700. X    } else {
  701. X#endif /* VMS */
  702. X
  703. X      /* now test for full length string */
  704. X      if (minmatch_str(&(argv[count][1]), "read-config", 4)) {
  705. X    len = strlen(argv[count]);
  706. X    for (j = 4; j < len; j++) {
  707. X      if ((argv[count][j] == ':') ||
  708. X          (argv[count][j] == '=')) {
  709. X        j++;
  710. X        break;
  711. X      }
  712. X    }
  713. X    if (j == len) {
  714. X      cfg_switch = 0;
  715. X    } else if (isdigit(argv[count][j])) {
  716. X      cfg_switch = argv[count][j] - '0';
  717. X      if ((cfg_switch < 0) ||
  718. X          (cfg_switch > 7) ||
  719. X          (argv[count][j + 1] != '\0')) {
  720. X        fprintf(stderr, "Invalid value for -read-config flag\n");
  721. X        show_usage();
  722. X      }
  723. X    } else {
  724. X      fprintf(stderr, "Invalid data following the -read-config flag\n");
  725. X      show_usage();
  726. X    }
  727. X    count++;
  728. X      }
  729. X
  730. X#ifndef VMS
  731. X    }
  732. X#endif /* VMS */
  733. X  }
  734. X
  735. X  /* now do the configurations */
  736. X  add_macro(2, CPP_GIVEN);
  737. X  add_macro(1, CPP_GIVEN2);
  738. X  do_config();
  739. X
  740. X  /* go through the entire argument list */
  741. X  while (count     < argc) {
  742. X
  743. X    /* check for any switches */
  744. X    if (is_switch(argv[count][0])) {
  745. X
  746. X      /* call the routine for command line parsing */
  747. X      if (argv[count][0] == '-') {
  748. X    j = FALSE;
  749. X      } else {
  750. X    j = TRUE;
  751. X      }
  752. X      strcpy(cur_argstr, &(argv[count][1]));
  753. X      parse_cmd(cur_argstr, j, TRUE);
  754. X
  755. X    } else {
  756. X
  757. X      /* treat it as a file name */
  758. X      if (out_filenum == 1) {
  759. X
  760. X    /* store the output file name */
  761. X    strcpy(output_file[0], argv[count]);
  762. X    strcpy(output_file[1], argv[count]);
  763. X    out_filenum = 2;
  764. X
  765. X      } else {
  766. X
  767. X    /* check if both C and A are on */
  768. X    if (get_option(OPT_FIRSTCOMMENT) &&
  769. X        (get_option(OPT_SORTMODE) == SORT_ALL)) {
  770. X      fprintf(stderr, "Sorting all functions and displaying file names does not mix\n");
  771. X      show_usage();
  772. X    }
  773. X
  774. X    /* yes, a file has been parsed */
  775. X    out_filenum = 3;
  776. X
  777. X    /* process the file for input */
  778. X    strcpy(file_name, argv[count]);
  779. X    strcpy(errout_filename, file_name);
  780. X    line_count = 1;
  781. X
  782. X    /* check if the file exits */
  783. X    if (stat( file_name, &fst ) != 0) {
  784. X      sprintf(cur_argstr, "error: could not access file <%s>",
  785. X          file_name);
  786. X      err_msg(cur_argstr);
  787. X      exit(1);
  788. X    } else if ((fpin = fopen(file_name, "r")) == NULL) {
  789. X      sprintf(cur_argstr, "error: could not read file <%s>",
  790. X          file_name);
  791. X      err_msg(cur_argstr);
  792. X      exit(1);
  793. X    }
  794. X    fclose(fpin);
  795. X
  796. X    /* build /lib/cpp line */
  797. X    sprintf(sysl_out, "%s ", cpp_prog);
  798. X    append_macros(sysl_out);
  799. X    strcat(sysl_out, file_name);
  800. X    /* open it */
  801. X    if ((fpin = open_input(sysl_out, "r")) == NULL) {
  802. X      sprintf(tmp_str, "unable to open CPP \"pipe\" to file <%s>",
  803. X          file_name);
  804. X      err_msg(tmp_str);
  805. X      exit(1);
  806. X    }
  807. X
  808. X#ifdef SETBUFFER
  809. X    /* now set the buffer */
  810. X    setbuffer(fpin, inbuffer, BUFFER_SIZE);
  811. X#endif /* SETBUFFER */
  812. X
  813. X    /* now do it */
  814. X    parse_file();
  815. X    files_parsed++;
  816. X    if (get_option(OPT_SORTMODE) != SORT_ALL) {
  817. X      send_file();
  818. X    }
  819. X    close_input(fpin);
  820. X
  821. X      }
  822. X
  823. X    }
  824. X
  825. X    /* now go to the next argument */
  826. X    count++;
  827. X  }
  828. X
  829. X  /* check if -o flag is unprocessed */
  830. X  if (out_filenum == 1) {
  831. X    fprintf(stderr, "No output file specified\n");
  832. X    show_usage();
  833. X  }
  834. X  if ((out_filenum == 2) || (out_filenum == 0)) {
  835. X    fprintf(stderr, "No files for parsing specified\n");
  836. X    show_usage();
  837. X  }
  838. X
  839. X  /* send out everything, if it hasn't been done */
  840. X  if (get_option(OPT_SORTMODE) == SORT_ALL) {
  841. X    send_file();
  842. X  }
  843. X
  844. X  /* now close things up and combine if needed */
  845. X  cxt_close();
  846. X  exit(0);
  847. X  return(0);
  848. X}
  849. X
  850. X/* transmit the currently stored comment to the output file */
  851. Xvoid
  852. Xsend_first_comment(begin_str)
  853. X  char *begin_str;
  854. X{
  855. X  int mode;
  856. X
  857. X  /* check for last comment */
  858. X  if (start_comment[0] != '\0') {
  859. X
  860. X    /* check the mode */
  861. X    if (doc_extract == DOC_NONE) {
  862. X      mode = 0;
  863. X    } else {
  864. X      mode = 1;
  865. X    }
  866. X
  867. X    /* give the header for troff output */
  868. X    dont_space = FALSE;
  869. X    if (doc_extract == DOC_ROFF) {
  870. X      start_block = TRUE;
  871. X      init_roff(1);
  872. X      if (total_out > 0) {
  873. X    out_str(1, ".bp\n");
  874. X    out_str(1, ".sp 0.5i\n");
  875. X      }
  876. X      out_str(1, ".KS\n");
  877. X      out_str(1, ".nf\n");
  878. X      out_str(1, ".ft 2\n");
  879. X    } else {
  880. X      out_char(mode, '\n');
  881. X    }
  882. X
  883. X    /* duplicate if needed */
  884. X    if (!get_option(OPT_COMPACT) &&
  885. X    (doc_extract == DOC_NONE) &&
  886. X    (get_option(OPT_SHOWANYWAY) &&
  887. X     get_option(OPT_BOTHUSE))) {
  888. X      out_char(1, '\n');
  889. X      out_str(0, begin_str);
  890. X      out_str(1, begin_str);
  891. X      out_str(0, start_comment);
  892. X      out_str(1, start_comment);
  893. X      out_char(0, '\n');
  894. X      out_char(1, '\n');
  895. X    } else {
  896. X      out_str(mode, begin_str);
  897. X      out_str(mode, start_comment);
  898. X      out_char(mode, '\n');
  899. X    }
  900. X
  901. X  }
  902. X}
  903. X
  904. X#ifdef TEST
  905. X/* dummy function that will never be used but makes a nice test */
  906. Xchar (*(*test_it())[])(same_foo, x, y, fpfoo, z, fpp2)
  907. X  int *x, z;
  908. X  FILE* fpfoo, fpp2;
  909. X  char (*(*same_foo())[])();
  910. X  int *y;
  911. X{
  912. X  /* As scary a bit of code as I could think of.  Is it valid? */
  913. X}
  914. X#endif /*TEST*/
  915. END_OF_FILE
  916. if test 24410 -ne `wc -c <'main.c'`; then
  917.     echo shar: \"'main.c'\" unpacked with wrong size!
  918. fi
  919. # end of 'main.c'
  920. fi
  921. echo shar: End of archive 3 \(of 5\).
  922. cp /dev/null ark3isdone
  923. MISSING=""
  924. for I in 1 2 3 4 5 ; do
  925.     if test ! -f ark${I}isdone ; then
  926.     MISSING="${MISSING} ${I}"
  927.     fi
  928. done
  929. if test "${MISSING}" = "" ; then
  930.     echo You have unpacked all 5 archives.
  931.     rm -f ark[1-9]isdone
  932. else
  933.     echo You still need to unpack the following archives:
  934.     echo "        " ${MISSING}
  935. fi
  936. ##  End of shell archive.
  937. exit 0
  938.  
  939. exit 0 # Just in case...
  940.