home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume42 / c2man-2.0 / part04 < prev    next >
Internet Message Format  |  1994-05-06  |  51KB

  1. From: greyham@research.canon.oz.au (Graham Stoney)
  2. Newsgroups: comp.sources.misc
  3. Subject: v42i058:  c2man-2.0 - automatic C documentation generator, Part04/09
  4. Date: 25 Apr 1994 22:30:35 -0500
  5. Organization: Canon Information Systems Research Australia
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <2pi1sr$jnl@sparky.sterling.com>
  9. References: <csm-v42i055=c2man-2.0.222803@sparky.sterling.com>
  10. Summary: a complete posting of the latest c2man: version 2.0 patchlevel 27
  11. X-Md4-Signature: bed17be3265b93ee9f3b0fcb3d03a7cd
  12.  
  13. Submitted-by: greyham@research.canon.oz.au (Graham Stoney)
  14. Posting-number: Volume 42, Issue 58
  15. Archive-name: c2man-2.0/part04
  16. Environment: UNIX, DOS, OS/2, lex, yacc
  17.  
  18. #! /bin/sh
  19. #
  20. # This is c2man version 2.0 at patchlevel 27.
  21. # Make a new directory for the c2man sources, cd to it, and run kits 1 up
  22. # to 9 through sh.  When all 9 kits have been run, read README.
  23. #
  24. echo " "
  25. cat <<EOM
  26. This is c2man 2.0 at patchlevel 27, kit 4 (of 9):
  27. If this shell archive is complete, the line "End of kit 4 (of 9)"
  28. will echo at the end.
  29. EOM
  30. export PATH || (echo "Please use sh to unpack this archive." ; kill $$)
  31. mkdir pc 2>/dev/null
  32. echo Extracting pc/getopt.c
  33. sed >pc/getopt.c <<'!STUFFY!FUNK!' -e 's/X//'
  34. X/* Getopt for GNU.
  35. X   NOTE: getopt is now part of the C library, so if you don't know what
  36. X   "Keep this file name-space clean" means, talk to roland@gnu.ai.mit.edu
  37. X   before changing it!
  38. X
  39. X   Copyright (C) 1987, 88, 89, 90, 91, 92, 1993
  40. X       Free Software Foundation, Inc.
  41. X
  42. X   This program is free software; you can redistribute it and/or modify it
  43. X   under the terms of the GNU General Public License as published by the
  44. X   Free Software Foundation; either version 2, or (at your option) any
  45. X   later version.
  46. X
  47. X   This program is distributed in the hope that it will be useful,
  48. X   but WITHOUT ANY WARRANTY; without even the implied warranty of
  49. X   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  50. X   GNU General Public License for more details.
  51. X
  52. X   You should have received a copy of the GNU General Public License
  53. X   along with this program; if not, write to the Free Software
  54. X   Foundation, 675 Mass Ave, Cambridge, MA 02139, USA.  */
  55. X
  56. X/* NOTE!!!  AIX requires this to be the first thing in the file.
  57. X   Do not put ANYTHING before it!  */
  58. X#if !defined (__GNUC__) && defined (_AIX)
  59. X #pragma alloca
  60. X#endif
  61. X
  62. X#ifdef HAVE_CONFIG_H
  63. X#include "config.h"
  64. X#endif
  65. X
  66. X#ifdef __GNUC__
  67. X#define alloca __builtin_alloca
  68. X#else /* not __GNUC__ */
  69. X#if defined (HAVE_ALLOCA_H) || (defined(sparc) && (defined(sun) || (!defined(USG) && !defined(SVR4) && !defined(__svr4__))))
  70. X#include <alloca.h>
  71. X#else
  72. X#ifdef _MSC_VER
  73. X#include <malloc.h>
  74. X#else
  75. X#ifndef _AIX
  76. Xchar *alloca ();
  77. X#endif
  78. X#endif
  79. X#endif /* alloca.h */
  80. X#endif /* not __GNUC__ */
  81. X
  82. X#if !__STDC__ && !defined(const) && IN_GCC
  83. X#define const
  84. X#endif
  85. X
  86. X/* This tells Alpha OSF/1 not to define a getopt prototype in <stdio.h>.  */
  87. X#ifndef _NO_PROTO
  88. X#define _NO_PROTO
  89. X#endif
  90. X
  91. X#include <stdio.h>
  92. X
  93. X/* Comment out all this code if we are using the GNU C Library, and are not
  94. X   actually compiling the library itself.  This code is part of the GNU C
  95. X   Library, but also included in many other GNU distributions.  Compiling
  96. X   and linking in this code is a waste when using the GNU C library
  97. X   (especially if it is a shared library).  Rather than having every GNU
  98. X   program understand `configure --with-gnu-libc' and omit the object files,
  99. X   it is simpler to just do this in the source for each such file.  */
  100. X
  101. X#if defined (_LIBC) || !defined (__GNU_LIBRARY__)
  102. X
  103. X
  104. X/* This needs to come after some library #include
  105. X   to get __GNU_LIBRARY__ defined.  */
  106. X#ifdef    __GNU_LIBRARY__
  107. X#undef    alloca
  108. X/* Don't include stdlib.h for non-GNU C libraries because some of them
  109. X   contain conflicting prototypes for getopt.  */
  110. X#include <stdlib.h>
  111. X#else    /* Not GNU C library.  */
  112. X#define    __alloca    alloca
  113. X#endif    /* GNU C library.  */
  114. X
  115. X/* If GETOPT_COMPAT is defined, `+' as well as `--' can introduce a
  116. X   long-named option.  Because this is not POSIX.2 compliant, it is
  117. X   being phased out.  */
  118. X/* #define GETOPT_COMPAT */
  119. X
  120. X/* This version of `getopt' appears to the caller like standard Unix `getopt'
  121. X   but it behaves differently for the user, since it allows the user
  122. X   to intersperse the options with the other arguments.
  123. X
  124. X   As `getopt' works, it permutes the elements of ARGV so that,
  125. X   when it is done, all the options precede everything else.  Thus
  126. X   all application programs are extended to handle flexible argument order.
  127. X
  128. X   Setting the environment variable POSIXLY_CORRECT disables permutation.
  129. X   Then the behavior is completely standard.
  130. X
  131. X   GNU application programs can use a third alternative mode in which
  132. X   they can distinguish the relative order of options and other arguments.  */
  133. X
  134. X#include "getopt.h"
  135. X
  136. X/* For communication from `getopt' to the caller.
  137. X   When `getopt' finds an option that takes an argument,
  138. X   the argument value is returned here.
  139. X   Also, when `ordering' is RETURN_IN_ORDER,
  140. X   each non-option ARGV-element is returned here.  */
  141. X
  142. Xchar *optarg = 0;
  143. X
  144. X/* Index in ARGV of the next element to be scanned.
  145. X   This is used for communication to and from the caller
  146. X   and for communication between successive calls to `getopt'.
  147. X
  148. X   On entry to `getopt', zero means this is the first call; initialize.
  149. X
  150. X   When `getopt' returns EOF, this is the index of the first of the
  151. X   non-option elements that the caller should itself scan.
  152. X
  153. X   Otherwise, `optind' communicates from one call to the next
  154. X   how much of ARGV has been scanned so far.  */
  155. X
  156. X/* XXX 1003.2 says this must be 1 before any call.  */
  157. Xint optind = 0;
  158. X
  159. X/* The next char to be scanned in the option-element
  160. X   in which the last option character we returned was found.
  161. X   This allows us to pick up the scan where we left off.
  162. X
  163. X   If this is zero, or a null string, it means resume the scan
  164. X   by advancing to the next ARGV-element.  */
  165. X
  166. Xstatic char *nextchar;
  167. X
  168. X/* Callers store zero here to inhibit the error message
  169. X   for unrecognized options.  */
  170. X
  171. Xint opterr = 1;
  172. X
  173. X/* Set to an option character which was unrecognized.
  174. X   This must be initialized on some systems to avoid linking in the
  175. X   system's own getopt implementation.  */
  176. X
  177. Xint optopt = '?';
  178. X
  179. X/* Describe how to deal with options that follow non-option ARGV-elements.
  180. X
  181. X   If the caller did not specify anything,
  182. X   the default is REQUIRE_ORDER if the environment variable
  183. X   POSIXLY_CORRECT is defined, PERMUTE otherwise.
  184. X
  185. X   REQUIRE_ORDER means don't recognize them as options;
  186. X   stop option processing when the first non-option is seen.
  187. X   This is what Unix does.
  188. X   This mode of operation is selected by either setting the environment
  189. X   variable POSIXLY_CORRECT, or using `+' as the first character
  190. X   of the list of option characters.
  191. X
  192. X   PERMUTE is the default.  We permute the contents of ARGV as we scan,
  193. X   so that eventually all the non-options are at the end.  This allows options
  194. X   to be given in any order, even with programs that were not written to
  195. X   expect this.
  196. X
  197. X   RETURN_IN_ORDER is an option available to programs that were written
  198. X   to expect options and other ARGV-elements in any order and that care about
  199. X   the ordering of the two.  We describe each non-option ARGV-element
  200. X   as if it were the argument of an option with character code 1.
  201. X   Using `-' as the first character of the list of option characters
  202. X   selects this mode of operation.
  203. X
  204. X   The special argument `--' forces an end of option-scanning regardless
  205. X   of the value of `ordering'.  In the case of RETURN_IN_ORDER, only
  206. X   `--' can cause `getopt' to return EOF with `optind' != ARGC.  */
  207. X
  208. Xstatic enum
  209. X{
  210. X  REQUIRE_ORDER, PERMUTE, RETURN_IN_ORDER
  211. X} ordering;
  212. X
  213. X#ifdef    __GNU_LIBRARY__
  214. X/* We want to avoid inclusion of string.h with non-GNU libraries
  215. X   because there are many ways it can cause trouble.
  216. X   On some systems, it contains special magic macros that don't work
  217. X   in GCC.  */
  218. X#include <string.h>
  219. X#define    my_index    strchr
  220. X#define    my_bcopy(src, dst, n)    memcpy ((dst), (src), (n))
  221. X#else
  222. X
  223. X/* Avoid depending on library functions or files
  224. X   whose names are inconsistent.  */
  225. X
  226. Xchar *getenv ();
  227. X
  228. Xstatic char *
  229. Xmy_index (str, chr)
  230. X     const char *str;
  231. X     int chr;
  232. X{
  233. X  while (*str)
  234. X    {
  235. X      if (*str == chr)
  236. X    return (char *) str;
  237. X      str++;
  238. X    }
  239. X  return 0;
  240. X}
  241. X
  242. Xstatic void
  243. Xmy_bcopy (from, to, size)
  244. X     const char *from;
  245. X     char *to;
  246. X     int size;
  247. X{
  248. X  int i;
  249. X  for (i = 0; i < size; i++)
  250. X    to[i] = from[i];
  251. X}
  252. X#endif                /* GNU C library.  */
  253. X
  254. X/* Handle permutation of arguments.  */
  255. X
  256. X/* Describe the part of ARGV that contains non-options that have
  257. X   been skipped.  `first_nonopt' is the index in ARGV of the first of them;
  258. X   `last_nonopt' is the index after the last of them.  */
  259. X
  260. Xstatic int first_nonopt;
  261. Xstatic int last_nonopt;
  262. X
  263. X/* Exchange two adjacent subsequences of ARGV.
  264. X   One subsequence is elements [first_nonopt,last_nonopt)
  265. X   which contains all the non-options that have been skipped so far.
  266. X   The other is elements [last_nonopt,optind), which contains all
  267. X   the options processed since those non-options were skipped.
  268. X
  269. X   `first_nonopt' and `last_nonopt' are relocated so that they describe
  270. X   the new indices of the non-options in ARGV after they are moved.  */
  271. X
  272. Xstatic void
  273. Xexchange (argv)
  274. X     char **argv;
  275. X{
  276. X  int nonopts_size = (last_nonopt - first_nonopt) * sizeof (char *);
  277. X  char **temp = (char **) __alloca (nonopts_size);
  278. X
  279. X  /* Interchange the two blocks of data in ARGV.  */
  280. X
  281. X  my_bcopy ((char *) &argv[first_nonopt], (char *) temp, nonopts_size);
  282. X  my_bcopy ((char *) &argv[last_nonopt], (char *) &argv[first_nonopt],
  283. X        (optind - last_nonopt) * sizeof (char *));
  284. X  my_bcopy ((char *) temp,
  285. X        (char *) &argv[first_nonopt + optind - last_nonopt],
  286. X        nonopts_size);
  287. X
  288. X  /* Update records for the slots the non-options now occupy.  */
  289. X
  290. X  first_nonopt += (optind - last_nonopt);
  291. X  last_nonopt = optind;
  292. X}
  293. X
  294. X/* Scan elements of ARGV (whose length is ARGC) for option characters
  295. X   given in OPTSTRING.
  296. X
  297. X   If an element of ARGV starts with '-', and is not exactly "-" or "--",
  298. X   then it is an option element.  The characters of this element
  299. X   (aside from the initial '-') are option characters.  If `getopt'
  300. X   is called repeatedly, it returns successively each of the option characters
  301. X   from each of the option elements.
  302. X
  303. X   If `getopt' finds another option character, it returns that character,
  304. X   updating `optind' and `nextchar' so that the next call to `getopt' can
  305. X   resume the scan with the following option character or ARGV-element.
  306. X
  307. X   If there are no more option characters, `getopt' returns `EOF'.
  308. X   Then `optind' is the index in ARGV of the first ARGV-element
  309. X   that is not an option.  (The ARGV-elements have been permuted
  310. X   so that those that are not options now come last.)
  311. X
  312. X   OPTSTRING is a string containing the legitimate option characters.
  313. X   If an option character is seen that is not listed in OPTSTRING,
  314. X   return '?' after printing an error message.  If you set `opterr' to
  315. X   zero, the error message is suppressed but we still return '?'.
  316. X
  317. X   If a char in OPTSTRING is followed by a colon, that means it wants an arg,
  318. X   so the following text in the same ARGV-element, or the text of the following
  319. X   ARGV-element, is returned in `optarg'.  Two colons mean an option that
  320. X   wants an optional arg; if there is text in the current ARGV-element,
  321. X   it is returned in `optarg', otherwise `optarg' is set to zero.
  322. X
  323. X   If OPTSTRING starts with `-' or `+', it requests different methods of
  324. X   handling the non-option ARGV-elements.
  325. X   See the comments about RETURN_IN_ORDER and REQUIRE_ORDER, above.
  326. X
  327. X   Long-named options begin with `--' instead of `-'.
  328. X   Their names may be abbreviated as long as the abbreviation is unique
  329. X   or is an exact match for some defined option.  If they have an
  330. X   argument, it follows the option name in the same ARGV-element, separated
  331. X   from the option name by a `=', or else the in next ARGV-element.
  332. X   When `getopt' finds a long-named option, it returns 0 if that option's
  333. X   `flag' field is nonzero, the value of the option's `val' field
  334. X   if the `flag' field is zero.
  335. X
  336. X   The elements of ARGV aren't really const, because we permute them.
  337. X   But we pretend they're const in the prototype to be compatible
  338. X   with other systems.
  339. X
  340. X   LONGOPTS is a vector of `struct option' terminated by an
  341. X   element containing a name which is zero.
  342. X
  343. X   LONGIND returns the index in LONGOPT of the long-named option found.
  344. X   It is only valid when a long-named option has been found by the most
  345. X   recent call.
  346. X
  347. X   If LONG_ONLY is nonzero, '-' as well as '--' can introduce
  348. X   long-named options.  */
  349. X
  350. Xint
  351. X_getopt_internal (argc, argv, optstring, longopts, longind, long_only)
  352. X     int argc;
  353. X     char *const *argv;
  354. X     const char *optstring;
  355. X     const struct option *longopts;
  356. X     int *longind;
  357. X     int long_only;
  358. X{
  359. X  int option_index;
  360. X
  361. X  optarg = 0;
  362. X
  363. X  /* Initialize the internal data when the first call is made.
  364. X     Start processing options with ARGV-element 1 (since ARGV-element 0
  365. X     is the program name); the sequence of previously skipped
  366. X     non-option ARGV-elements is empty.  */
  367. X
  368. X  if (optind == 0)
  369. X    {
  370. X      first_nonopt = last_nonopt = optind = 1;
  371. X
  372. X      nextchar = NULL;
  373. X
  374. X      /* Determine how to handle the ordering of options and nonoptions.  */
  375. X
  376. X      if (optstring[0] == '-')
  377. X    {
  378. X      ordering = RETURN_IN_ORDER;
  379. X      ++optstring;
  380. X    }
  381. X      else if (optstring[0] == '+')
  382. X    {
  383. X      ordering = REQUIRE_ORDER;
  384. X      ++optstring;
  385. X    }
  386. X      else if (getenv ("POSIXLY_CORRECT") != NULL)
  387. X    ordering = REQUIRE_ORDER;
  388. X      else
  389. X    ordering = PERMUTE;
  390. X    }
  391. X
  392. X  if (nextchar == NULL || *nextchar == '\0')
  393. X    {
  394. X      if (ordering == PERMUTE)
  395. X    {
  396. X      /* If we have just processed some options following some non-options,
  397. X         exchange them so that the options come first.  */
  398. X
  399. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  400. X        exchange ((char **) argv);
  401. X      else if (last_nonopt != optind)
  402. X        first_nonopt = optind;
  403. X
  404. X      /* Now skip any additional non-options
  405. X         and extend the range of non-options previously skipped.  */
  406. X
  407. X      while (optind < argc
  408. X         && (argv[optind][0] != '-' || argv[optind][1] == '\0')
  409. X#ifdef GETOPT_COMPAT
  410. X         && (longopts == NULL
  411. X             || argv[optind][0] != '+' || argv[optind][1] == '\0')
  412. X#endif                /* GETOPT_COMPAT */
  413. X         )
  414. X        optind++;
  415. X      last_nonopt = optind;
  416. X    }
  417. X
  418. X      /* Special ARGV-element `--' means premature end of options.
  419. X     Skip it like a null option,
  420. X     then exchange with previous non-options as if it were an option,
  421. X     then skip everything else like a non-option.  */
  422. X
  423. X      if (optind != argc && !strcmp (argv[optind], "--"))
  424. X    {
  425. X      optind++;
  426. X
  427. X      if (first_nonopt != last_nonopt && last_nonopt != optind)
  428. X        exchange ((char **) argv);
  429. X      else if (first_nonopt == last_nonopt)
  430. X        first_nonopt = optind;
  431. X      last_nonopt = argc;
  432. X
  433. X      optind = argc;
  434. X    }
  435. X
  436. X      /* If we have done all the ARGV-elements, stop the scan
  437. X     and back over any non-options that we skipped and permuted.  */
  438. X
  439. X      if (optind == argc)
  440. X    {
  441. X      /* Set the next-arg-index to point at the non-options
  442. X         that we previously skipped, so the caller will digest them.  */
  443. X      if (first_nonopt != last_nonopt)
  444. X        optind = first_nonopt;
  445. X      return EOF;
  446. X    }
  447. X
  448. X      /* If we have come to a non-option and did not permute it,
  449. X     either stop the scan or describe it to the caller and pass it by.  */
  450. X
  451. X      if ((argv[optind][0] != '-' || argv[optind][1] == '\0')
  452. X#ifdef GETOPT_COMPAT
  453. X      && (longopts == NULL
  454. X          || argv[optind][0] != '+' || argv[optind][1] == '\0')
  455. X#endif                /* GETOPT_COMPAT */
  456. X      )
  457. X    {
  458. X      if (ordering == REQUIRE_ORDER)
  459. X        return EOF;
  460. X      optarg = argv[optind++];
  461. X      return 1;
  462. X    }
  463. X
  464. X      /* We have found another option-ARGV-element.
  465. X     Start decoding its characters.  */
  466. X
  467. X      nextchar = (argv[optind] + 1
  468. X          + (longopts != NULL && argv[optind][1] == '-'));
  469. X    }
  470. X
  471. X  if (longopts != NULL
  472. X      && ((argv[optind][0] == '-'
  473. X       && (argv[optind][1] == '-' || long_only))
  474. X#ifdef GETOPT_COMPAT
  475. X      || argv[optind][0] == '+'
  476. X#endif                /* GETOPT_COMPAT */
  477. X      ))
  478. X    {
  479. X      const struct option *p;
  480. X      char *s = nextchar;
  481. X      int exact = 0;
  482. X      int ambig = 0;
  483. X      const struct option *pfound = NULL;
  484. X      int indfound;
  485. X
  486. X      while (*s && *s != '=')
  487. X    s++;
  488. X
  489. X      /* Test all options for either exact match or abbreviated matches.  */
  490. X      for (p = longopts, option_index = 0; p->name;
  491. X       p++, option_index++)
  492. X    if (!strncmp (p->name, nextchar, s - nextchar))
  493. X      {
  494. X        if (s - nextchar == strlen (p->name))
  495. X          {
  496. X        /* Exact match found.  */
  497. X        pfound = p;
  498. X        indfound = option_index;
  499. X        exact = 1;
  500. X        break;
  501. X          }
  502. X        else if (pfound == NULL)
  503. X          {
  504. X        /* First nonexact match found.  */
  505. X        pfound = p;
  506. X        indfound = option_index;
  507. X          }
  508. X        else
  509. X          /* Second nonexact match found.  */
  510. X          ambig = 1;
  511. X      }
  512. X
  513. X      if (ambig && !exact)
  514. X    {
  515. X      if (opterr)
  516. X        fprintf (stderr, "%s: option `%s' is ambiguous\n",
  517. X             argv[0], argv[optind]);
  518. X      nextchar += strlen (nextchar);
  519. X      optind++;
  520. X      return '?';
  521. X    }
  522. X
  523. X      if (pfound != NULL)
  524. X    {
  525. X      option_index = indfound;
  526. X      optind++;
  527. X      if (*s)
  528. X        {
  529. X          /* Don't test has_arg with >, because some C compilers don't
  530. X         allow it to be used on enums.  */
  531. X          if (pfound->has_arg)
  532. X        optarg = s + 1;
  533. X          else
  534. X        {
  535. X          if (opterr)
  536. X            {
  537. X              if (argv[optind - 1][1] == '-')
  538. X            /* --option */
  539. X            fprintf (stderr,
  540. X                 "%s: option `--%s' doesn't allow an argument\n",
  541. X                 argv[0], pfound->name);
  542. X              else
  543. X            /* +option or -option */
  544. X            fprintf (stderr,
  545. X                 "%s: option `%c%s' doesn't allow an argument\n",
  546. X                 argv[0], argv[optind - 1][0], pfound->name);
  547. X            }
  548. X          nextchar += strlen (nextchar);
  549. X          return '?';
  550. X        }
  551. X        }
  552. X      else if (pfound->has_arg == 1)
  553. X        {
  554. X          if (optind < argc)
  555. X        optarg = argv[optind++];
  556. X          else
  557. X        {
  558. X          if (opterr)
  559. X            fprintf (stderr, "%s: option `%s' requires an argument\n",
  560. X                 argv[0], argv[optind - 1]);
  561. X          nextchar += strlen (nextchar);
  562. X          return optstring[0] == ':' ? ':' : '?';
  563. X        }
  564. X        }
  565. X      nextchar += strlen (nextchar);
  566. X      if (longind != NULL)
  567. X        *longind = option_index;
  568. X      if (pfound->flag)
  569. X        {
  570. X          *(pfound->flag) = pfound->val;
  571. X          return 0;
  572. X        }
  573. X      return pfound->val;
  574. X    }
  575. X      /* Can't find it as a long option.  If this is not getopt_long_only,
  576. X     or the option starts with '--' or is not a valid short
  577. X     option, then it's an error.
  578. X     Otherwise interpret it as a short option.  */
  579. X      if (!long_only || argv[optind][1] == '-'
  580. X#ifdef GETOPT_COMPAT
  581. X      || argv[optind][0] == '+'
  582. X#endif                /* GETOPT_COMPAT */
  583. X      || my_index (optstring, *nextchar) == NULL)
  584. X    {
  585. X      if (opterr)
  586. X        {
  587. X          if (argv[optind][1] == '-')
  588. X        /* --option */
  589. X        fprintf (stderr, "%s: unrecognized option `--%s'\n",
  590. X             argv[0], nextchar);
  591. X          else
  592. X        /* +option or -option */
  593. X        fprintf (stderr, "%s: unrecognized option `%c%s'\n",
  594. X             argv[0], argv[optind][0], nextchar);
  595. X        }
  596. X      nextchar = (char *) "";
  597. X      optind++;
  598. X      return '?';
  599. X    }
  600. X    }
  601. X
  602. X  /* Look at and handle the next option-character.  */
  603. X
  604. X  {
  605. X    char c = *nextchar++;
  606. X    char *temp = my_index (optstring, c);
  607. X
  608. X    /* Increment `optind' when we start to process its last character.  */
  609. X    if (*nextchar == '\0')
  610. X      ++optind;
  611. X
  612. X    if (temp == NULL || c == ':')
  613. X      {
  614. X    if (opterr)
  615. X      {
  616. X#if 0
  617. X        if (c < 040 || c >= 0177)
  618. X          fprintf (stderr, "%s: unrecognized option, character code 0%o\n",
  619. X               argv[0], c);
  620. X        else
  621. X          fprintf (stderr, "%s: unrecognized option `-%c'\n", argv[0], c);
  622. X#else
  623. X        /* 1003.2 specifies the format of this message.  */
  624. X        fprintf (stderr, "%s: illegal option -- %c\n", argv[0], c);
  625. X#endif
  626. X      }
  627. X    optopt = c;
  628. X    return '?';
  629. X      }
  630. X    if (temp[1] == ':')
  631. X      {
  632. X    if (temp[2] == ':')
  633. X      {
  634. X        /* This is an option that accepts an argument optionally.  */
  635. X        if (*nextchar != '\0')
  636. X          {
  637. X        optarg = nextchar;
  638. X        optind++;
  639. X          }
  640. X        else
  641. X          optarg = 0;
  642. X        nextchar = NULL;
  643. X      }
  644. X    else
  645. X      {
  646. X        /* This is an option that requires an argument.  */
  647. X        if (*nextchar != '\0')
  648. X          {
  649. X        optarg = nextchar;
  650. X        /* If we end this ARGV-element by taking the rest as an arg,
  651. X           we must advance to the next element now.  */
  652. X        optind++;
  653. X          }
  654. X        else if (optind == argc)
  655. X          {
  656. X        if (opterr)
  657. X          {
  658. X#if 0
  659. X            fprintf (stderr, "%s: option `-%c' requires an argument\n",
  660. X                 argv[0], c);
  661. X#else
  662. X            /* 1003.2 specifies the format of this message.  */
  663. X            fprintf (stderr, "%s: option requires an argument -- %c\n",
  664. X                 argv[0], c);
  665. X#endif
  666. X          }
  667. X        optopt = c;
  668. X        if (optstring[0] == ':')
  669. X          c = ':';
  670. X        else
  671. X          c = '?';
  672. X          }
  673. X        else
  674. X          /* We already incremented `optind' once;
  675. X         increment it again when taking next ARGV-elt as argument.  */
  676. X          optarg = argv[optind++];
  677. X        nextchar = NULL;
  678. X      }
  679. X      }
  680. X    return c;
  681. X  }
  682. X}
  683. X
  684. Xint
  685. Xgetopt (argc, argv, optstring)
  686. X     int argc;
  687. X     char *const *argv;
  688. X     const char *optstring;
  689. X{
  690. X  return _getopt_internal (argc, argv, optstring,
  691. X               (const struct option *) 0,
  692. X               (int *) 0,
  693. X               0);
  694. X}
  695. X
  696. X#endif    /* _LIBC or not __GNU_LIBRARY__.  */
  697. X
  698. X#ifdef TEST
  699. X
  700. X/* Compile with -DTEST to make an executable for use in testing
  701. X   the above definition of `getopt'.  */
  702. X
  703. Xint
  704. Xmain (argc, argv)
  705. X     int argc;
  706. X     char **argv;
  707. X{
  708. X  int c;
  709. X  int digit_optind = 0;
  710. X
  711. X  while (1)
  712. X    {
  713. X      int this_option_optind = optind ? optind : 1;
  714. X
  715. X      c = getopt (argc, argv, "abc:d:0123456789");
  716. X      if (c == EOF)
  717. X    break;
  718. X
  719. X      switch (c)
  720. X    {
  721. X    case '0':
  722. X    case '1':
  723. X    case '2':
  724. X    case '3':
  725. X    case '4':
  726. X    case '5':
  727. X    case '6':
  728. X    case '7':
  729. X    case '8':
  730. X    case '9':
  731. X      if (digit_optind != 0 && digit_optind != this_option_optind)
  732. X        printf ("digits occur in two different argv-elements.\n");
  733. X      digit_optind = this_option_optind;
  734. X      printf ("option %c\n", c);
  735. X      break;
  736. X
  737. X    case 'a':
  738. X      printf ("option a\n");
  739. X      break;
  740. X
  741. X    case 'b':
  742. X      printf ("option b\n");
  743. X      break;
  744. X
  745. X    case 'c':
  746. X      printf ("option c with value `%s'\n", optarg);
  747. X      break;
  748. X
  749. X    case '?':
  750. X      break;
  751. X
  752. X    default:
  753. X      printf ("?? getopt returned character code 0%o ??\n", c);
  754. X    }
  755. X    }
  756. X
  757. X  if (optind < argc)
  758. X    {
  759. X      printf ("non-option ARGV-elements: ");
  760. X      while (optind < argc)
  761. X    printf ("%s ", argv[optind++]);
  762. X      printf ("\n");
  763. X    }
  764. X
  765. X  exit (0);
  766. X}
  767. X
  768. X#endif /* TEST */
  769. !STUFFY!FUNK!
  770. echo Extracting c2man.c
  771. sed >c2man.c <<'!STUFFY!FUNK!' -e 's/X//'
  772. X/* $Id: c2man.c,v 2.0.1.29 1994/01/07 07:04:56 greyham Exp $
  773. X *
  774. X * C Manual page generator.
  775. X * Reads C source code and outputs manual pages.
  776. X */
  777. X#include <ctype.h>
  778. X#include <errno.h>
  779. X
  780. X#include "c2man.h"
  781. X#include "enum.h"
  782. X#include "strconcat.h"
  783. X#include "strappend.h"
  784. X#include "manpage.h"
  785. X#include "output.h"
  786. X#include "patchlevel.h"
  787. X
  788. X#ifdef I_FCNTL
  789. X#include <fcntl.h>
  790. X#endif
  791. X
  792. X#ifdef I_SYS_FILE
  793. X#include <sys/file.h>
  794. X#endif
  795. X
  796. X#include <sys/stat.h>
  797. X#include <signal.h>
  798. X
  799. X/* getopt declarations */
  800. Xextern int getopt();
  801. Xextern char *optarg;
  802. Xextern int optind;
  803. X
  804. X/* lex declarations */
  805. Xextern FILE *yyin;    /* lex input stream */
  806. X
  807. X/* Name of the program */
  808. Xconst char *progname = "c2man";
  809. X
  810. X/* Program options */
  811. X
  812. X/* TRUE if static declarations are also output. */
  813. Xboolean static_out = FALSE;
  814. X
  815. X/* TRUE if variable declarations are output. */
  816. Xboolean variables_out = FALSE;
  817. X
  818. X/* TRUE if formal parameter promotion is enabled. */
  819. Xboolean promote_param = TRUE;
  820. X
  821. X/* String output before prototype declaration specifiers */
  822. Xconst char *decl_spec_prefix = "";
  823. X
  824. X/* String output before prototype declarator */
  825. Xconst char *declarator_prefix = " ";
  826. X
  827. X/* String output after prototype declarator */
  828. Xconst char *declarator_suffix = "\n";
  829. X
  830. X/* String output before the first parameter in a function prototype */
  831. Xconst char *first_param_prefix = "\n\t";
  832. X
  833. X/* String output before each subsequent parameter in a function prototype */
  834. Xconst char *middle_param_prefix = "\n\t";
  835. X
  836. X/* String output after the last parameter in a function prototype */
  837. Xconst char *last_param_suffix = "\n";
  838. X
  839. X/* Directory to write output files in */
  840. Xchar *output_dir = NULL;
  841. X
  842. X/* Name of the manual */
  843. Xchar *manual_name = NULL;
  844. X
  845. X/* Section for manual page */
  846. Xconst char *manual_section = NULL;
  847. X
  848. X/* prefix for generated #include lines */
  849. Xchar *header_prefix = NULL;
  850. X
  851. X/* list of include file specified by user */
  852. XIncludeFile *first_include;
  853. Xstatic IncludeFile **last_next_include = &first_include;
  854. X
  855. X/* do we group related stuff into one file? */
  856. Xboolean group_together;
  857. X
  858. X/* was terse description read from file or command line option? */
  859. Xboolean terse_specified;
  860. X
  861. X/* terse description when grouped together */
  862. Xchar *group_terse = NULL;
  863. X
  864. X/* should we always document parameters, even if it's only "Not Documented" */
  865. Xboolean always_document_params = TRUE;
  866. X
  867. X/* default output info for each object type */
  868. Xstruct Output_Object_Info output_object[_OBJECT_NUM] =
  869. X{
  870. X#if 0
  871. X    {'c', "class"},
  872. X    {'s', "struct"},
  873. X    {'e', "enum"},
  874. X    {'t', "typedef"},
  875. X#endif
  876. X    {'f', "function"},
  877. X    {'v', "variable"},
  878. X    {'F', "static function"},
  879. X    {'V', "static variable"}
  880. X};
  881. X
  882. X/* Include file directories */
  883. X#ifdef MSDOS
  884. Xint num_inc_dir = 1;
  885. Xconst char *inc_dir[MAX_INC_DIR] = { ".\\" };
  886. X#else
  887. Xint num_inc_dir = 2;
  888. Xconst char *inc_dir[MAX_INC_DIR] = { "./", "/usr/include/" };
  889. X#endif
  890. X
  891. X/* total number of errors encountered */
  892. Xint errors;
  893. X
  894. X/* name of the base file being processed; NULL = stdin */
  895. Xconst char *basefile;
  896. XTime_t basetime;    /* modification time of base file */
  897. Xboolean inbasefile;    /* are we parsing in that base file? */
  898. X
  899. X/* is the base file a header file? */
  900. Xboolean header_file;
  901. X
  902. X/* use nroff output by default */
  903. Xstruct Output *output = &nroff_output;
  904. X
  905. X/* should we generate the output file named after the input file? */
  906. Xboolean use_input_name = FALSE;
  907. X
  908. X/* should we generate embeddable files? */
  909. Xboolean make_embeddable = FALSE;
  910. X
  911. X#define USE_CPP
  912. X#ifdef USE_CPP
  913. Xconst char *cpp_cmd = CPP_FILE_COM;
  914. X#if defined(MSDOS)
  915. X#include "popen.h"
  916. X#define popen(c,m)    os_popen(c,m)
  917. X#define pclose(f)    os_pclose(f)
  918. X#else
  919. X#if defined (_MSC_VER)
  920. X#define popen(c,m)    _popen(c,m)
  921. X#define pclose(f)    _pclose(f)
  922. X#endif
  923. X#endif
  924. X#endif
  925. X
  926. Xboolean verbose = FALSE;
  927. X
  928. X/* can cpp read standard input? */
  929. Xstatic boolean cppcanstdin
  930. X#ifdef CPP_CAN_STDIN
  931. X                = 1
  932. X#endif
  933. X;
  934. X/* does cpp ignore header files */
  935. Xstatic boolean cppignhdrs
  936. X#ifdef CPP_IGN_HDRS
  937. X                = 1
  938. X#endif
  939. X;
  940. X
  941. X/* nifty little function for handling I/O errors */
  942. Xvoid my_perror(action, filename)
  943. Xconst char *action, *filename;
  944. X{
  945. X    int err = errno;
  946. X    fprintf(stderr,"%s: %s ", progname, action);
  947. X    errno = err;
  948. X    perror(filename);
  949. X}
  950. X
  951. X/* write the #include lines as specified by the user */
  952. Xvoid print_includes(f)
  953. XFILE *f;
  954. X{
  955. X    IncludeFile *incfile;
  956. X    
  957. X    for (incfile = first_include; incfile; incfile=incfile->next)
  958. X    {
  959. X    char *name = incfile->name;
  960. X    boolean surrounded = *name == '"' || *name == '<';
  961. X    
  962. X    fputs("#include ", f);
  963. X    if (!surrounded)    fputc('<',f);
  964. X    fputs(name, f);
  965. X    if (!surrounded)    fputc('>',f);
  966. X    fputc('\n',f);
  967. X    }
  968. X}
  969. X
  970. Xvoid outmem()
  971. X{
  972. X    fprintf(stderr,"%s: Out of memory!\n", progname);
  973. X    exit(1);
  974. X}
  975. X
  976. X#ifndef DBMALLOC
  977. Xvoid *safe_malloc(size)
  978. Xsize_t size;
  979. X{
  980. X    void *mem;
  981. X
  982. X    if ((mem = (void *)malloc(size)) == NULL)
  983. X    outmem();
  984. X
  985. X    return mem;
  986. X}
  987. X#endif
  988. X
  989. X/* Replace any character escape sequences in a string with the actual
  990. X * characters.  Return a pointer to malloc'ed memory containing the result.
  991. X * This function knows only a few escape sequences.
  992. X */
  993. Xstatic char *
  994. Xescape_string (src)
  995. Xchar *src;
  996. X{
  997. X    char *result, *get, *put;
  998. X
  999. X    result = strduplicate(src);
  1000. X    put = result;
  1001. X    get = src;
  1002. X    while (*get != '\0') {
  1003. X    if (*get == '\\') {
  1004. X        switch (*(++get)) {
  1005. X        case 'n':
  1006. X        *put++ = '\n';
  1007. X        ++get;
  1008. X        break;
  1009. X        case 't':
  1010. X        *put++ = '\t';
  1011. X        ++get;
  1012. X        break;
  1013. X        default:
  1014. X        if (*get != '\0')
  1015. X            *put++ = *get++;
  1016. X        }
  1017. X    } else {
  1018. X        *put++ = *get++;
  1019. X    }
  1020. X    }
  1021. X    *put = *get;
  1022. X    return result;
  1023. X}
  1024. X
  1025. X/* Output usage message and exit.
  1026. X */
  1027. Xstatic void
  1028. Xusage ()
  1029. X{
  1030. X    int i;
  1031. X
  1032. X    fprintf(stderr, "usage: %s [ option ... ] [ file ... ]\n", progname);
  1033. X    fputs(" -o directory\twrite output files in directory\n",stderr);
  1034. X    fputs(" -p\t\tdisable prototype promotion\n", stderr);
  1035. X    fputs(" -s\t\toutput static declarations\n", stderr);
  1036. X    fputs(" -v\t\toutput variable declarations\n", stderr);
  1037. X    fputc('\n', stderr);
  1038. X    fputs(" -i incfile\n", stderr);
  1039. X    fputs(" -i \"incfile\"\n", stderr);
  1040. X    fputs(" -i <incfile>\tadd #include for incfile to SYNOPSIS\n",
  1041. X                                    stderr);
  1042. X    fputc('\n', stderr);
  1043. X    fputs(" -H prefix\tspecify prefix for #include in SYNOPSIS\n", stderr);
  1044. X    fputc('\n', stderr);
  1045. X    fputs(" -g\n", stderr);
  1046. X    fputs(" -G terse\tgroup info from each file into a single page\n",
  1047. X                                    stderr);
  1048. X    fputs(" -e\t\tmake embeddable files\n", stderr);
  1049. X    fputc('\n', stderr);
  1050. X    fputs(" -l ", stderr);
  1051. X#ifdef HAS_LINK
  1052. X    fputs("h|", stderr);
  1053. X#endif
  1054. X#ifdef HAS_SYMLINK
  1055. X    fputs("s|", stderr);
  1056. X#endif
  1057. X    fputs("f|n|r\t", stderr);
  1058. X    fputs("linking for grouped pages: ", stderr);
  1059. X#ifdef HAS_LINK
  1060. X                  fputs("hard, ", stderr);
  1061. X#endif
  1062. X#ifdef HAS_SYMLINK
  1063. X                    fputs("soft, ", stderr);
  1064. X#endif
  1065. X                    fputs("file, none or remove\n", stderr);
  1066. X    fputs(" -n\t\tName output file after input source file\n", stderr);
  1067. X    fputs(" -L\t\tLazy: Be silent about undocumented parameters\n",
  1068. X                                    stderr);
  1069. X    fputs(" -T n|l|t\tselect typesetting output format: nroff, LaTeX or TeXinfo\n",
  1070. X                                    stderr);
  1071. X    fputs(" -M name\tset name of the manual in which the page goes\n",
  1072. X                                    stderr);
  1073. X    fputc('\n', stderr);
  1074. X    fputs(" -D name[=value]\n", stderr);
  1075. X    fputs(" -U name\n", stderr);
  1076. X    fputs(" -I directory\tC preprocessor options\n", stderr);
  1077. X    fputc('\n', stderr);
  1078. X    fputs(" -F template\tset prototype template in the form ", stderr);
  1079. X                    fputs("\"int f (a, b)\"\n",stderr);
  1080. X    fputs(" -P preprocessor\tAlternate C preprocessor ", stderr);
  1081. X                    fputs("(e.g., \"gcc -E -C\")\n", stderr);
  1082. X    fputs(" -V\t\tbe verbose and print version information\n", stderr);
  1083. X    fputs(" -S section\tset the section for the manual page (default = 3)\n",
  1084. X                                    stderr);
  1085. X    fputs(" -O ", stderr);
  1086. X    for (i = 0; i < _OBJECT_NUM; i++)
  1087. X    fputc(output_object[i].flag, stderr);
  1088. X    fputs("[subdir][.ext]", stderr);
  1089. X    fputs("\tOutput control over different object types:\n\t\t", stderr);
  1090. X    for (i = 0; i < _OBJECT_NUM; i++)
  1091. X    {
  1092. X    fputs(output_object[i].name, stderr);
  1093. X    if (i <= _OBJECT_NUM - 2)
  1094. X        fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  1095. X    }
  1096. X    fputs(".\n", stderr);
  1097. X    exit(1);
  1098. X}
  1099. X
  1100. X/* name of the temporary file; kept here so we can blast it if hit with ctrl-C
  1101. X */
  1102. Xstatic char temp_name[20];
  1103. XSignal_t (*old_interrupt_handler)();
  1104. X
  1105. X/* ctrl-C signal handler for use when we have a temporary file */
  1106. Xstatic Signal_t interrupt_handler(sig)
  1107. Xint sig;
  1108. X{
  1109. X    unlink(temp_name);
  1110. X    exit(128 + sig);
  1111. X}
  1112. X
  1113. X/* open a unique temporary file.
  1114. X * To be universally accepted by cpp's, the file's name must end in .c; so we
  1115. X * can't use mktemp, tmpnam or tmpfile.
  1116. X * returns an open stream & sets ret_name to the name.
  1117. X */
  1118. XFILE *open_temp_file()
  1119. X{
  1120. X    int fd;
  1121. X    long n = getpid();
  1122. X    FILE *tempf;
  1123. X    boolean remove_temp_file();
  1124. X
  1125. X    /* keep generating new names until we hit one that does not exist */
  1126. X    do
  1127. X    {
  1128. X    /* ideally we'd like to put the temporary file in /tmp, but it must go
  1129. X     * in the current directory because when cpp processes a #include, it
  1130. X     * looks in the same directory as the file doing the include; so if we
  1131. X     * use /tmp/blah.c to fake reading fred.h via `#include "fred.h"', cpp
  1132. X     * will look for /tmp/fred.h, and fail.
  1133. X     */
  1134. X    sprintf(temp_name,"c2man%ld.c",n++ % 1000000);
  1135. X    }
  1136. X    while((fd =
  1137. X#ifdef HAS_OPEN3
  1138. X    open(temp_name,O_WRONLY|O_CREAT|O_EXCL,0666)
  1139. X#else
  1140. X    creat(temp_name,O_EXCL|0666)        /* do it the old way */
  1141. X#endif
  1142. X                        ) == -1
  1143. X                            && errno == EEXIST);
  1144. X
  1145. X    /* install interrupt handler to remove the temporary file */
  1146. X    old_interrupt_handler = signal(SIGINT, interrupt_handler);
  1147. X
  1148. X    /* convert it to a stream */
  1149. X    if ((fd == -1 && errno != EEXIST) || (tempf = fdopen(fd, "w")) == NULL)
  1150. X    {
  1151. X    my_perror("error fdopening temp file",temp_name);
  1152. X    remove_temp_file();
  1153. X    return NULL;
  1154. X    }
  1155. X
  1156. X    return tempf;
  1157. X}
  1158. X
  1159. X/* remove the temporary file & restore ctrl-C handler.
  1160. X * returns FALSE in the event of failure.
  1161. X */
  1162. Xboolean remove_temp_file()
  1163. X{
  1164. X    int ok = unlink(temp_name) == 0;    /* this should always succeed */
  1165. X    signal(SIGINT, old_interrupt_handler);
  1166. X    return ok;
  1167. X}
  1168. X
  1169. X/* process the specified source file through the pre-processor.
  1170. X * This is a lower level routine called by both process_stdin and process_file
  1171. X * to actually get the work done once any required temporary files have been
  1172. X * generated.
  1173. X */
  1174. Xint process_file_directly(base_cpp_cmd, name)
  1175. Xconst char *base_cpp_cmd;
  1176. Xconst char *name;
  1177. X{
  1178. X    char *full_cpp_cmd;
  1179. X
  1180. X#ifdef DEBUG
  1181. X    fprintf(stderr,"process_file_directly: %s, %s\n", base_cpp_cmd, name);
  1182. X#endif
  1183. X
  1184. X#ifdef USE_CPP
  1185. X    full_cpp_cmd = strconcat(base_cpp_cmd, " ", name, NULLCP);
  1186. X    if (verbose)
  1187. X    fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  1188. X
  1189. X    if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  1190. X    my_perror("error running", base_cpp_cmd);
  1191. X    free(full_cpp_cmd);
  1192. X    return 0;
  1193. X    }
  1194. X#else
  1195. X    if (verbose)    fprintf(stderr,"%s: reading %s\n", progname, name);
  1196. X    if (name && freopen(name, "r", yyin) == NULL)
  1197. X    {
  1198. X    my_perror("cannot open", name);
  1199. X    return 0;
  1200. X    }
  1201. X#endif
  1202. X
  1203. X    parse_file(name);
  1204. X
  1205. X#ifdef USE_CPP
  1206. X    free(full_cpp_cmd);
  1207. X    if (pclose(yyin) & 0xFF00)
  1208. X    return 0;
  1209. X#else
  1210. X    if (fclose(yyin))
  1211. X    {
  1212. X    my_perror("error closing", name);
  1213. X    return 0;
  1214. X    }
  1215. X#endif
  1216. X
  1217. X    return !errors;
  1218. X}
  1219. X
  1220. X/* process a specified file */
  1221. Xint process_file(base_cpp_cmd, name)
  1222. Xconst char *base_cpp_cmd;
  1223. Xconst char *name;
  1224. X{
  1225. X    char *period;
  1226. X    struct stat statbuf;
  1227. X    
  1228. X#ifdef DEBUG
  1229. X    fprintf(stderr,"process_file: %s, %s\n", base_cpp_cmd, name);
  1230. X#endif
  1231. X    basefile = name;
  1232. X    header_file = (period = strrchr(name,'.')) &&
  1233. X                    (period[1] == 'h' || period[1] == 'H');
  1234. X
  1235. X    /* use the file's date as the date in the manual page */
  1236. X    if (stat(name,&statbuf) != 0)
  1237. X    {
  1238. X    my_perror("can't stat", name);
  1239. X    return 0;
  1240. X    }
  1241. X    basetime = statbuf.st_mtime;
  1242. X
  1243. X    /* should we do this via a temporary file?
  1244. X     * Only if it's a header file and either CPP ignores them, or the user
  1245. X     * has specified files to include.
  1246. X     *
  1247. X     * For HP/Apollo (SR10.3, CC 6.8), we must always use a temporary file,
  1248. X     * because its compiler recognizes the special macro "__attribute(p)",
  1249. X     * which we cannot redefine in the command line because it has parameters.
  1250. X     */
  1251. X#ifndef apollo
  1252. X    if (header_file && (cppignhdrs || first_include))
  1253. X#endif
  1254. X    {
  1255. X    FILE *tempf;
  1256. X    int ret;
  1257. X
  1258. X    if (verbose)
  1259. X        fprintf(stderr, "%s: preprocessing via temporary file\n", progname);
  1260. X
  1261. X    if ((tempf = open_temp_file()) == NULL)
  1262. X        return 0;
  1263. X
  1264. X    print_includes(tempf);
  1265. X    if (verbose)    print_includes(stderr);
  1266. X
  1267. X#ifdef apollo
  1268. X    fprintf(tempf,"#define __attribute(p)\n", basefile);
  1269. X#endif
  1270. X    fprintf(tempf,"#include \"%s\"\n", basefile);
  1271. X    if (verbose)    fprintf(stderr,"#include \"%s\"\n", basefile);
  1272. X
  1273. X    if (fclose(tempf) == EOF)
  1274. X    {
  1275. X        my_perror("error closing temp file", temp_name);
  1276. X        remove_temp_file();
  1277. X        return 0;
  1278. X    }
  1279. X
  1280. X    /* since we're using a temporary file, it's not the base file */
  1281. X    inbasefile = 0;
  1282. X    ret = process_file_directly(base_cpp_cmd, temp_name);
  1283. X    remove_temp_file();
  1284. X    return ret;
  1285. X    }
  1286. X
  1287. X    /* otherwise, process it directly */
  1288. X    inbasefile = 1;
  1289. X
  1290. X    return process_file_directly(base_cpp_cmd,name);
  1291. X}
  1292. X
  1293. X/* process the thing on the standard input */
  1294. Xint process_stdin(base_cpp_cmd)
  1295. Xconst char *base_cpp_cmd;
  1296. X{
  1297. X    if (isatty(fileno(stdin)))
  1298. X    fprintf(stderr,"%s: reading standard input\n", progname);
  1299. X
  1300. X    header_file = 0;    /* assume it's not since it's from stdin */
  1301. X    basefile = NULL;
  1302. X
  1303. X    /* use the current date in the man page */
  1304. X    basetime = time((Time_t *)NULL);
  1305. X
  1306. X    inbasefile = 1;        /* reading stdin, we start in the base file */
  1307. X
  1308. X    /* always use a temp file if the preprocessor can't read stdin, otherwise
  1309. X     * only use one if the user specified files for inclusion.
  1310. X     */
  1311. X    if (!cppcanstdin || first_include)    /* did user specify include files? */
  1312. X    {
  1313. X        FILE *tempf;
  1314. X    int c, ret;
  1315. X
  1316. X    if (verbose)
  1317. X        fprintf(stderr,"%s: reading stdin to a temporary file\n", progname);
  1318. X
  1319. X    if ((tempf = open_temp_file()) == NULL)
  1320. X        return 0;
  1321. X
  1322. X    print_includes(tempf);
  1323. X    if (verbose)    print_includes(stderr);
  1324. X    fprintf(tempf,"#line 1 \"stdin\"\n");
  1325. X
  1326. X    while ((c = getchar()) != EOF)
  1327. X        putc(c,tempf);
  1328. X
  1329. X    if (fclose(tempf) == EOF)
  1330. X    {
  1331. X        my_perror("error closing temp file", temp_name);
  1332. X        remove_temp_file();
  1333. X        return 0;
  1334. X    }
  1335. X    ret = process_file_directly(base_cpp_cmd, temp_name);
  1336. X    remove_temp_file();
  1337. X    return ret;
  1338. X    }
  1339. X    else
  1340. X    {
  1341. X    char *full_cpp_cmd = strconcat(base_cpp_cmd," ", CPP_STDIN_FLAGS,
  1342. X                                   NULLCP);
  1343. X    
  1344. X    if (verbose)
  1345. X        fprintf(stderr,"%s: running `%s'\n", progname, full_cpp_cmd);
  1346. X    
  1347. X    if ((yyin = popen(full_cpp_cmd, "r")) == NULL) {
  1348. X        my_perror("error running", full_cpp_cmd);
  1349. X        return 0;
  1350. X    }
  1351. X    
  1352. X    parse_file(basefile);
  1353. X    
  1354. X    free(full_cpp_cmd);
  1355. X    if (pclose(yyin) & 0xFF00)
  1356. X        return 0;
  1357. X    
  1358. X    return !errors;
  1359. X    }
  1360. X}
  1361. X
  1362. Xint
  1363. Xmain (argc, argv)
  1364. Xint argc;
  1365. Xchar **argv;
  1366. X{
  1367. X    int i, c, ok = 0;
  1368. X    char *s, cbuf[2];
  1369. X    const char *base_cpp_cmd;
  1370. X    IncludeFile *includefile;
  1371. X    char *cpp_opts;
  1372. X    const char *default_section = "3";
  1373. X#ifdef HAS_LINK
  1374. X    enum LinkType link_type = LINK_HARD;    /* for -g/G */
  1375. X#else
  1376. X    enum LinkType link_type = LINK_FILE;
  1377. X#endif
  1378. X
  1379. X#ifdef YYDEBUG
  1380. X    extern int yydebug;
  1381. X#endif
  1382. X
  1383. X    /* initialise CPP options with -D__C2MAN__ */
  1384. X    cbuf[0] = VERSION + '0';
  1385. X    cbuf[1] = '\0';
  1386. X    cpp_opts = strconcat("-D__C2MAN__=", cbuf, NULLCP);
  1387. X#ifdef NeXT
  1388. X    cpp_opts = strappend(cpp_opts, " -D_NEXT_SOURCE", NULLCP);
  1389. X#endif
  1390. X
  1391. X    /* Scan command line options. */
  1392. X    while ((c = getopt(argc, argv, "P:D:F:I:psU:Vvo:eM:H:G:gi:S:l:LT:nO:")) 
  1393. X                                    != EOF)
  1394. X    {
  1395. X    switch (c) {
  1396. X    case 'I':
  1397. X    case 'D':
  1398. X    case 'U':
  1399. X        cbuf[0] = c; cbuf[1] = '\0';
  1400. X        if (cpp_opts)
  1401. X        cpp_opts = strappend(cpp_opts," -",cbuf,optarg,NULLCP);
  1402. X        else
  1403. X        cpp_opts = strconcat("-",cbuf,optarg,NULLCP);
  1404. X        break;
  1405. X    case 'P':
  1406. X        cpp_cmd = optarg;
  1407. X
  1408. X        /* with no better info to go on, we have to assume that this
  1409. X         * preprocessor is minimally capable.
  1410. X         */
  1411. X        cppcanstdin = 0;
  1412. X        cppignhdrs = 1;
  1413. X        break;
  1414. X    case 'G':
  1415. X        group_terse = optarg;
  1416. X        terse_specified = TRUE;
  1417. X        /* FALLTHROUGH */
  1418. X    case 'g':
  1419. X        group_together = TRUE;
  1420. X        break;
  1421. X    case 'F':
  1422. X        s = escape_string(optarg);
  1423. X
  1424. X        decl_spec_prefix = s;
  1425. X        while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  1426. X        if (*s == '\0') usage();
  1427. X        *s++ = '\0';
  1428. X        while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  1429. X        if (*s == '\0') usage();
  1430. X
  1431. X        declarator_prefix = s;
  1432. X        while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  1433. X        if (*s == '\0') usage();
  1434. X        *s++ = '\0';
  1435. X        while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  1436. X        if (*s == '\0') usage();
  1437. X
  1438. X        declarator_suffix = s;
  1439. X        while (*s != '\0' && *s != '(') ++s;
  1440. X        if (*s == '\0') usage();
  1441. X        *s++ = '\0';
  1442. X
  1443. X        first_param_prefix = s;
  1444. X        while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  1445. X        if (*s == '\0') usage();
  1446. X        *s++ = '\0';
  1447. X        while (*s != '\0' && *s != ',') ++s;
  1448. X        if (*s == '\0') usage();
  1449. X
  1450. X        middle_param_prefix = ++s;
  1451. X        while (*s != '\0' && isascii(*s) && !isalnum(*s)) ++s;
  1452. X        if (*s == '\0') usage();
  1453. X        *s++ = '\0';
  1454. X        while (*s != '\0' && isascii(*s) && isalnum(*s)) ++s;
  1455. X        if (*s == '\0') usage();
  1456. X
  1457. X        last_param_suffix = s;
  1458. X        while (*s != '\0' && *s != ')') ++s;
  1459. X        *s = '\0';
  1460. X
  1461. X        break;
  1462. X    case 'p':
  1463. X        promote_param = FALSE;
  1464. X        break;
  1465. X    case 's':
  1466. X        static_out = TRUE;
  1467. X        break;
  1468. X    case 'V':
  1469. X        verbose = TRUE;
  1470. X        fprintf(stderr, "%s: Version %d, Patchlevel %d\n",
  1471. X                    progname, VERSION, PATCHLEVEL);
  1472. X        break;
  1473. X    case 'v':
  1474. X        variables_out = TRUE;
  1475. X        break;
  1476. X    case 'o':
  1477. X        output_dir = optarg;
  1478. X        break;
  1479. X    case 'M':
  1480. X        manual_name = optarg;
  1481. X        break;
  1482. X    case 'H':
  1483. X        header_prefix = optarg;
  1484. X        break;
  1485. X    case 'i':
  1486. X        *last_next_include = includefile =
  1487. X                (IncludeFile *)safe_malloc(sizeof *includefile);
  1488. X        includefile->name = optarg;
  1489. X        includefile->next = NULL;
  1490. X        last_next_include = &includefile->next;
  1491. X        break;
  1492. X    case 'S':
  1493. X        manual_section = optarg;
  1494. X        break;
  1495. X    case 'l':
  1496. X        switch(optarg[0])
  1497. X        {
  1498. X#ifdef HAS_LINK
  1499. X        case 'h':    link_type = LINK_HARD;    break;
  1500. X#endif
  1501. X#ifdef HAS_SYMLINK
  1502. X        case 's':    link_type = LINK_SOFT;    break;
  1503. X#endif
  1504. X        case 'f':    link_type = LINK_FILE;    break;
  1505. X        case 'n':    link_type = LINK_NONE;    break;
  1506. X        case 'r':    link_type = LINK_REMOVE;break;
  1507. X        default:    usage();
  1508. X        }
  1509. X        break;
  1510. X    case 'e':
  1511. X        make_embeddable = TRUE;
  1512. X        break;
  1513. X    case 'n':
  1514. X        use_input_name = TRUE;
  1515. X        break;
  1516. X    case 'L':
  1517. X        always_document_params = FALSE;
  1518. X        break;
  1519. X    case 'T':
  1520. X        switch(optarg[0])
  1521. X        {
  1522. X        case 'n':    output = &nroff_output;    break;
  1523. X        case 'l':    output = &latex_output;    default_section = "tex";
  1524. X            break;
  1525. X        case 't':    output = &texinfo_output; default_section = "texi";
  1526. X            break;
  1527. X        default:    usage();
  1528. X        }
  1529. X        break;
  1530. X    case 'O':
  1531. X        for (i = 0; i < _OBJECT_NUM; i++)
  1532. X        if (output_object[i].flag == optarg[0])
  1533. X            break;
  1534. X
  1535. X        if (i == _OBJECT_NUM)
  1536. X        {
  1537. X        fprintf(stderr,"%s: -O option must specify one of:\n\t",
  1538. X                                progname);
  1539. X        for (i = 0; i < _OBJECT_NUM; i++)
  1540. X        {
  1541. X            fprintf(stderr,"%c (%s)", output_object[i].flag,
  1542. X            output_object[i].name);
  1543. X            if (i <= _OBJECT_NUM - 2)
  1544. X            fprintf(stderr,i == _OBJECT_NUM-2 ? " or " : ", ");
  1545. X        }
  1546. X        fprintf(stderr, ".\n");
  1547. X        exit(1);
  1548. X        }
  1549. X
  1550. X        if ((s = strchr(++optarg,'.')))    /* look for an extension */
  1551. X        {
  1552. X        output_object[i].subdir = alloc_string(optarg, s);
  1553. X        output_object[i].extension = strduplicate(s+1);
  1554. X        }
  1555. X        else
  1556. X        output_object[i].subdir = strduplicate(optarg);
  1557. X
  1558. X        break;
  1559. X    case '?':
  1560. X    default:
  1561. X        usage();
  1562. X    }
  1563. X    }
  1564. X
  1565. X    /* make sure we have a manual section */
  1566. X    if (manual_section == NULL)    manual_section = default_section;
  1567. X
  1568. X#ifdef MALLOC_DEBUG
  1569. X    getchar();    /* wait so we can start up NeXT MallocDebug tool */
  1570. X#endif
  1571. X#ifdef YYDEBUG
  1572. X    yydebug = 1;
  1573. X#endif
  1574. X
  1575. X    if (cpp_opts)
  1576. X    {
  1577. X    base_cpp_cmd = strconcat(cpp_cmd, " ", cpp_opts, NULLCP);
  1578. X    free(cpp_opts);
  1579. X    }
  1580. X    else
  1581. X    base_cpp_cmd = cpp_cmd;
  1582. X
  1583. X    if (optind == argc) {
  1584. X    if (use_input_name)
  1585. X    {
  1586. X        fprintf(stderr,"%s: %s\n", progname,
  1587. X        "cannot name output after input file if there isn't one!");
  1588. X        usage();
  1589. X    }
  1590. X    ok = process_stdin(base_cpp_cmd);
  1591. X    }    
  1592. X    else
  1593. X    for (i = optind; i < argc; ++i)
  1594. X        if (!(ok = process_file(base_cpp_cmd,argv[i])))    break;
  1595. X
  1596. X    if (ok && firstpage)
  1597. X    output_manual_pages(firstpage,argc - optind, link_type);
  1598. X    free_manual_pages(firstpage);
  1599. X    destroy_enum_lists();
  1600. X
  1601. X    if (cpp_opts)    free((char *)base_cpp_cmd);
  1602. X
  1603. X    for (includefile = first_include; includefile;)
  1604. X    {
  1605. X    IncludeFile *next = includefile->next;
  1606. X    free(includefile);
  1607. X    includefile = next;
  1608. X    }
  1609. X
  1610. X    for (i = 0; i < _OBJECT_NUM; i++)
  1611. X    {
  1612. X    safe_free(output_object[i].subdir);
  1613. X    safe_free(output_object[i].extension);
  1614. X    }
  1615. X
  1616. X#ifdef DBMALLOC
  1617. X    malloc_dump(2);
  1618. X    malloc_chain_check(1);
  1619. X#endif
  1620. X#ifdef MALLOC_DEBUG
  1621. X    sleep(1000000);
  1622. X#endif
  1623. X    return !ok;
  1624. X}
  1625. !STUFFY!FUNK!
  1626. echo Extracting pc/Makefile.pc
  1627. sed >pc/Makefile.pc <<'!STUFFY!FUNK!' -e 's/X//'
  1628. X# NOTE: This file is generated automatically by processing the Makefile in the
  1629. X# main directory with a perl script.
  1630. X# Makefile for c2man                                           23 Aug 1993
  1631. X#
  1632. X# - for GNU gcc (emx 0.8g kit) under OS/2 2.x or DOS (32-bit)
  1633. X# - for Microsoft C 6.00 under OS/2 or DOS (16-bit)
  1634. X
  1635. X# To use, enter "{d,n}make -f Makefile.pc" (this makefile depends on its
  1636. X# name being "Makefile.pc").
  1637. X#
  1638. X# tested with dmake 3.8 and GNU make 3.68 under OS/2
  1639. X
  1640. Xdefault:
  1641. X    @echo "Enter $(MAKE) -f Makefile.pc target                     "
  1642. X    @echo " where 'target' is chosen from                          " 
  1643. X    @echo "   msc      OS/2 and DOS exe [Microsoft C 6.00a]        "
  1644. X    @echo "   emx      OS/2 and DOS 32-bit exe [EMX/gcc]           "
  1645. X
  1646. Xemx:  
  1647. X    $(MAKE) -f Makefile.pc all \
  1648. X    CC="gcc -O -s" O=".o" \
  1649. X    CFLAGS="-DOS2 -DMSDOS" \
  1650. X    OBJS2="popen.o" \
  1651. X    LDFLAGS="" \
  1652. X    LIBS="c2man-32.def" \
  1653. X
  1654. Xmsc: 
  1655. X    $(MAKE) -f Makefile.pc all \
  1656. X    CC="cl -nologo -AS" O=".obj" \
  1657. X    CFLAGS="-D__STDC__ -DOS2" \
  1658. X    OBJS2="getopt.obj popen.obj" \
  1659. X    LDFLAGS="-Lp -F 2000" \
  1660. X    LIBS="setargv.obj c2man.def -link /NOE" \
  1661. X    BIND="bind c2man.exe /n DOSMAKEPIPE DOSCWAIT"
  1662. X
  1663. XYACC=bison -y
  1664. XLEX=flex
  1665. XSED=sed
  1666. XRM=rm
  1667. XMV=mv
  1668. XECHO=echo
  1669. XMKDEP=mkdep
  1670. X
  1671. X# where we get installed
  1672. Xbin=/bin
  1673. X
  1674. Xmansrc=/etc/man/manl
  1675. Xmanext=l
  1676. X
  1677. X# As Larry said, "Grrrr"
  1678. XSHELL=/bin/sh
  1679. X
  1680. XOSOURCES =    config.h c2man.h semantic.h symbol.h strconcat.h \
  1681. X        strappend.h manpage.h enum.h output.h lex.l grammar.y
  1682. XDCSOURCES =    c2man.c semantic.c string.c symbol.c strconcat.c \
  1683. X        strappend.c manpage.c enum.c nroff.c texinfo.c
  1684. XSOURCES =    $(OSOURCES) $(DCSOURCES)
  1685. XCSOURCES =    $(DCSOURCES) y.tab.c
  1686. XOBJECTS =    c2man$O semantic$O string$O symbol$O y.tab$O strconcat$O \
  1687. X        strappend$O manpage$O enum$O nroff$O texinfo$O
  1688. XGENERATED =    c2man example.inc ctype_ex.inc y.tab.c lex.yy.c y.output \
  1689. X        fixexample.sed flatten.sed
  1690. X
  1691. Xall: c2man.exe example.inc ctype_ex.inc flatten.sed
  1692. X
  1693. Xinstall:
  1694. X    cp c2man.exe $(bin)
  1695. X    $(SED) -f flatten.sed < c2man.1 > $(mansrc)/c2man.$(manext)
  1696. X    -mkdir $(privlib)
  1697. X    -mkdir $(privlib)/eg
  1698. X    cp eg/*.[chly] $(privlib)/eg
  1699. X
  1700. Xuninstall:
  1701. X    $(RM) -f $(bin)/c2man $(mansrc)/c2man.$(manext)
  1702. X    $(RM) -f $(privlib)/eg/*
  1703. X    rmdir $(privlib)/eg
  1704. X    rmdir $(privlib)
  1705. X
  1706. Xc2man.exe: $(OBJECTS)
  1707. X    $(CC) $(CFLAGS) $(LDFLAGS) -o $@ $(OBJECTS) $(LIBS)
  1708. X    $(BIND)
  1709. X
  1710. X.c$O:
  1711. X    $(CC) $(CFLAGS) $(WARNFLAGS) -c $<
  1712. X
  1713. Xy.tab.c: grammar.y
  1714. X    @$(ECHO) Expect 48 shift/reduce conflicts.
  1715. X    $(YACC) grammar.y
  1716. X
  1717. X# don't compile y.tab.c with all warnings; yacc/bison are not up to it.
  1718. Xy.tab$O: y.tab.c lex.yy.c
  1719. X    $(CC) $(CFLAGS) -c y.tab.c
  1720. X
  1721. Xlex.yy.c: lex.l
  1722. X    $(LEX) -t -n lex.l > $@
  1723. X    cp $@ lex_yy.c
  1724. X
  1725. Xexample.inc: c2man.exe example.h fixexample.sed
  1726. X    ./c2man -o- example.h | $(SED) -f fixexample.sed >example.inc
  1727. X
  1728. Xctype_ex.inc: c2man.exe ctype_ex.h fixexample.sed
  1729. X    ./c2man -o- -g ctype_ex.h | $(SED) -f fixexample.sed >ctype_ex.inc
  1730. X
  1731. Xfixexample.sed: fixexample.in
  1732. X    $(SED) -e '/^#/d' fixexample.in > fixexample.sed
  1733. X
  1734. Xflatten.sed: flatten_sed.SH
  1735. X    sh flatten_sed.SH
  1736. X
  1737. XMakefile: Makefile.SH
  1738. X    sh Makefile.SH
  1739. X
  1740. Xconfig.h: config_h.SH
  1741. X    sh config_h.SH
  1742. X
  1743. XTAGS: $(SOURCES)
  1744. X    etags -t $(SOURCES)
  1745. X
  1746. Xclean:
  1747. X    $(RM) -f *$O *.s *.bak *~ *.log $(GENERATED) core
  1748. X
  1749. Xdistclean realclean: clean
  1750. X    $(RM) -f Makefile config.sh mkdep c2man.kit?
  1751. X
  1752. Xlint:
  1753. X    lint -b $(CFLAGS) $(CSOURCES)
  1754. X
  1755. Xprint:
  1756. X    cpr $(SOURCES) | lpr -J'c2man'
  1757. X
  1758. Xtest: c2man.exe
  1759. X    @echo "Running c2man over the examples..." 1>&2
  1760. X    @for file in eg/*.[chly]; do ./c2man -v -o- $$file; done
  1761. X    @echo "Running c2man over its own source code..." 1>&2
  1762. X    @for file in $(DCSOURCES); do ./c2man -v -o- $$file; done
  1763. X    @echo "Hmmm, test seemed to go OK." 1>&2
  1764. X
  1765. Xdepend:
  1766. X    $(SED) -e '1,/^# DO NOT/!d' < Makefile > Makefile.new
  1767. X    $(MKDEP) $(DCSOURCES) >> Makefile.new
  1768. X    - test ! -f y.tab.c -o ! -f lex.yy.c || $(MKDEP) y.tab.c >> Makefile.new
  1769. X    $(MV) -f Makefile.new Makefile
  1770. X
  1771. X# y.tab.c dependancies updated manually since it won't exist yet when make
  1772. X# depend is first run.
  1773. Xy.tab$O: c2man.h config.h confmagic.h enum.h manpage.h semantic.h strappend.h\
  1774. X    strconcat.h symbol.h
  1775. X
  1776. X
  1777. X# DO NOT DELETE THIS LINE! make depend DEPENDS ON IT!
  1778. Xc2man$O: c2man.c c2man.h config.h confmagic.h enum.h manpage.h output.h\
  1779. X    patchlevel.h strappend.h strconcat.h symbol.h
  1780. X
  1781. Xsemantic$O: c2man.h config.h confmagic.h enum.h manpage.h semantic.c\
  1782. X    semantic.h strconcat.h symbol.h
  1783. X
  1784. Xstring$O: c2man.h config.h confmagic.h string.c symbol.h
  1785. X
  1786. Xsymbol$O: c2man.h config.h confmagic.h symbol.c symbol.h
  1787. X
  1788. Xstrconcat$O: c2man.h config.h confmagic.h strconcat.c strconcat.h symbol.h
  1789. X
  1790. Xstrappend$O: c2man.h config.h confmagic.h strappend.c strappend.h symbol.h
  1791. X
  1792. Xmanpage$O: c2man.h config.h confmagic.h manpage.c manpage.h output.h\
  1793. X    semantic.h strconcat.h symbol.h
  1794. X
  1795. Xenum$O: c2man.h config.h confmagic.h enum.c enum.h manpage.h strconcat.h\
  1796. X    symbol.h
  1797. X
  1798. Xnroff$O: c2man.h config.h confmagic.h manpage.h nroff.c output.h symbol.h
  1799. X
  1800. !STUFFY!FUNK!
  1801. echo Extracting strconcat.h
  1802. sed >strconcat.h <<'!STUFFY!FUNK!' -e 's/X//'
  1803. X/* $Id: strconcat.h,v 2.0.1.1 1993/05/17 02:11:47 greyham Exp $
  1804. X * concatenate a list of strings, storing them in a malloc'ed region
  1805. X */
  1806. X#include "config.h"
  1807. X
  1808. Xchar *strconcat _V((const char *first, ...));
  1809. !STUFFY!FUNK!
  1810. echo "End of kit 4 (of 9)"
  1811. echo " "
  1812. cat /dev/null >kit4isdone
  1813. run=''
  1814. config=''
  1815. for iskit in 1 2 3 4 5 6 7 8 9; do
  1816.     if test -f kit${iskit}isdone; then
  1817.         run="$run $iskit"
  1818.     else
  1819.         todo="$todo $iskit"
  1820.     fi
  1821. done
  1822. case $todo in
  1823.     '')
  1824.         echo "You have run all your kits."
  1825.         if test -f PACKNOTES; then
  1826.             sh PACKNOTES
  1827.         else
  1828.             echo "You have to rebuild split files by hand (see PACKLIST)."
  1829.         fi
  1830.         echo "Please read README and then type Configure."
  1831.         chmod 755 Configure
  1832.         rm -f kit*isdone
  1833.         ;;
  1834.     *)  echo "You have run$run."
  1835.         echo "You still need to run$todo."
  1836.         ;;
  1837. esac
  1838. : Someone might mail this, so exit before signature...
  1839. exit 0
  1840. -- 
  1841. Graham Stoney, Hardware/Software Engineer
  1842. Canon Information Systems Research Australia
  1843. Ph: + 61 2 805 2909    Fax: + 61 2 805 2929
  1844.  
  1845. exit 0 # Just in case...
  1846.