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

  1. From: greyham@research.canon.oz.au (Graham Stoney)
  2. Newsgroups: comp.sources.misc
  3. Subject: v42i055:  c2man-2.0 - automatic C documentation generator, Part01/09
  4. Date: 25 Apr 1994 22:29:25 -0500
  5. Organization: Canon Information Systems Research Australia
  6. Sender: kent@sparky.sterling.com
  7. Approved: kent@sparky.sterling.com
  8. Message-ID: <csm-v42i055=c2man-2.0.222803@sparky.sterling.com>
  9. Summary: a complete posting of the latest c2man: version 2.0 patchlevel 27
  10. X-Md4-Signature: 12aa964efe2a5224cb5b1dca080d0745
  11.  
  12. Submitted-by: greyham@research.canon.oz.au (Graham Stoney)
  13. Posting-number: Volume 42, Issue 55
  14. Archive-name: c2man-2.0/part01
  15. Environment: UNIX, DOS, OS/2, lex, yacc
  16.  
  17. Note: c2man was previously posted in comp.sources.reviewed, but the patches
  18. were lagging months and months behind and then the moderator recently resigned,
  19. so unfortunately I've been forced to switch to comp.sources.misc.
  20.  
  21.                 c2man, Version 2
  22.                 by Graham Stoney
  23.  
  24.  Copyright (c) 1992, 1993, 1994 by Canon Information Systems Research Australia
  25.                   All rights reserved.
  26.  
  27. This is c2man, a program for generating Unix style manual pages in nroff/troff
  28. -man, TeXinfo or LaTeX format directly from ordinary comments embedded in C
  29. source code. It should run on virtually any Unix-like system, OS/2 or MSDOS.
  30.  
  31. You will need lex or flex, plus yacc or bison, and a C compiler (traditional
  32. K&R 1 or ISO/ANSI will do) to build the program. You'll also need a text
  33. formatter to format its output.
  34.  
  35. This version of c2man is copyright, but may be freely redistributed and modified
  36. so long as:
  37.  
  38. 1. The names of all contributing authors remain on the documentation,
  39. 2. All derivative works are clearly documented as such,
  40. 3. All derivative works remain freely redistributable under the same conditions.
  41.  
  42. As such, there is no warranty.
  43.  
  44.  
  45. #! /bin/sh
  46. #
  47. # This is c2man version 2.0 at patchlevel 27.
  48. # Make a new directory for the c2man sources, cd to it, and run kits 1 up
  49. # to 9 through sh.  When all 9 kits have been run, read README.
  50. #
  51. echo " "
  52. cat <<EOM
  53. This is c2man 2.0 at patchlevel 27, kit 1 (of 9):
  54. If this shell archive is complete, the line "End of kit 1 (of 9)"
  55. will echo at the end.
  56. EOM
  57. export PATH || (echo "Please use sh to unpack this archive." ; kill $$)
  58. mkdir eg pc 2>/dev/null
  59. echo Extracting README
  60. sed >README <<'!STUFFY!FUNK!' -e 's/X//'
  61. X
  62. X                c2man, Version 2
  63. X                by Graham Stoney
  64. X
  65. X Copyright (c) 1992, 1993, 1994 by Canon Information Systems Research Australia
  66. X                  All rights reserved.
  67. X
  68. XThis is c2man, a program for generating Unix style manual pages in nroff/troff
  69. X-man, TeXinfo or LaTeX format directly from ordinary comments embedded in C
  70. Xsource code. It should run on virtually any Unix-like system, OS/2 or MSDOS.
  71. X
  72. XYou will need lex or flex, plus yacc or bison, and a C compiler (traditional
  73. XK&R 1 or ISO/ANSI will do) to build the program. You'll also need a text
  74. Xformatter to format its output.
  75. X
  76. XThis version of c2man is copyright, but may be freely redistributed and modified
  77. Xso long as:
  78. X
  79. X1. The names of all contributing authors remain on the documentation,
  80. X2. All derivative works are clearly documented as such,
  81. X3. All derivative works remain freely redistributable under the same conditions.
  82. X
  83. XAs such, there is no warranty.
  84. X
  85. Xc2man owes a huge debt to the public domain program cproto, by Chin Huang, from
  86. Xwhich much of the code is derived.
  87. X
  88. XThe manual page must be installed with 'make install'; it includes an
  89. Xautomatically generated example and needs to be "flattened" when installed, so
  90. Xyou can't just cp it into place. As a further consequence, the examples will be
  91. Xmissing from the manual page if you try to read it before doing a make.
  92. X
  93. Xc2man does not currently support C++, but if you think this would be worth
  94. Xwhile, look in the file C++autodoc for information on how I envisage C++
  95. Xsupport could be added, and get ready to volunteer.
  96. X
  97. XBy popular demand, there are a few trivial examples of different comment
  98. Xstyles in the eg directory.  I'm open to submissions from users too.
  99. X
  100. X
  101. XThere is a mailing list for c2man users; it is very low volume and has a very
  102. Xlow noise content.  This is the preferred place to ask questions about the
  103. Xprogram and discuss modifications and additions with the author and other
  104. Xusers.  You are encouraged to join by sending mail with no Subject: line to
  105. X<listserv@research.canon.oz.au> containing:
  106. X
  107. X    SUBSCRIBE c2man Your name
  108. X
  109. XWhere `Your name' should be replaced with your real name.
  110. XMessages for distribution to everyone on the list should be sent to:
  111. X<c2man@research.canon.oz.au>.
  112. X
  113. X
  114. XThe time I have available for c2man support is rather limited, but if it lacks
  115. Xany features you require, feel free to Email me (preferably to the mailing list
  116. Xaddress above) asking about it.  Unless you request otherwise, I will probably
  117. Xcc: to the list replies to any questions that I get mailed, to save me
  118. Xanswering them again for other people.  I encourage you to go ahead and make
  119. Xany changes you like and send me the diffs for inclusion in the next patch, but
  120. Xit's a good idea to ask first in case someone already has the feature you want
  121. Xin the works.  Changes need to be reasonably "clean" for me to integrate them.
  122. X
  123. XPlease try to remember to include the c2man version number in any bug reports.
  124. XYou can find it by running: c2man -V /dev/null
  125. X
  126. XIf you'd like to be notified automatically about new releases and patches,
  127. Xanswer yes to the Configure question about sending mail to the author.
  128. X
  129. X
  130. XSpecial thanks for their direct and indirect contributions to c2man go to:
  131. X    Larry Wall, Raphael Manfredi and Harlan Stenn for writing various bits of
  132. X    metaconfig, which generated the Configure script.
  133. X
  134. X    Darrel Hankerson for the OS/2 and MSDOS ports.
  135. X
  136. X    Richard Kooijman for the LaTeX backend, and for fixing the TeXinfo backend.
  137. X
  138. X    Vern Paxson for his suggestions on how to handle comments lexing better.
  139. X
  140. XThanks to the following people for suggestions & bug fixes is long overdue:
  141. X    Peter (P.) Barszczewski, Carlo Tarantola, Dennis Allison,
  142. X    Philip Yzarn de Louraille, Jerry Lieberthal, Mats Ohrman, Stefan Zimmermann,
  143. X    Dolf Grunbauer, Lele Gaifax, Carl R. Crawford, Jhon Honce, Chris Borchert,
  144. X    Jerry E. Dunmire, Marty Leisner, Dan Forrest, Ken Weinert, Ken Poppleton.
  145. X
  146. X(Hmmm.  This is beginning to sound like an Academy Awards night...)
  147. X
  148. X
  149. XSee the file INSTALL for Unix installation instructions.
  150. XOS/2 and MSDOS users should see the README.pc file in the pc directory.
  151. X
  152. X
  153. XGraham Stoney                       greyham@research.canon.oz.au
  154. XMailing List for general c2man Questions & Answers   c2man@research.canon.oz.au
  155. !STUFFY!FUNK!
  156. echo Extracting pc/README.pc
  157. sed >pc/README.pc <<'!STUFFY!FUNK!' -e 's/X//'
  158. XThis directory contains sources for compiling c2man for OS/2 and
  159. XDOS, using EMX/gcc or Microsoft C. The popen.c routines are adapted
  160. Xfrom the versions supplied with GNU awk, and are needed for
  161. Xexecutables which run under DOS. The getopt routines (needed for MSC)
  162. Xare adapted from the GNU versions.
  163. X
  164. XTo install, copy these files to the directory containing the 
  165. Xsources for c2man, and use
  166. X   make -f Makefile.pc
  167. Xto see a list of targets.
  168. X
  169. XThis version is still in beta-test.
  170. X
  171. X--
  172. XDarrel Hankerson hankedr@mail.auburn.edu
  173. X23 August 1993
  174. !STUFFY!FUNK!
  175. echo Extracting manpage.c
  176. sed >manpage.c <<'!STUFFY!FUNK!' -e 's/X//'
  177. X/* $Id: manpage.c,v 2.0.1.41 1994/02/23 04:38:28 greyham Exp $
  178. X * stuff to do with manual page outputing
  179. X */
  180. X
  181. X#include "c2man.h"
  182. X
  183. X#include <errno.h>
  184. X#include <ctype.h>
  185. X
  186. X#include "manpage.h"
  187. X#include "strconcat.h"
  188. X#include "strappend.h"
  189. X#include "semantic.h"
  190. X#include "output.h"
  191. X
  192. X#ifdef I_SYS_FILE
  193. X#include <sys/file.h>
  194. X#endif
  195. X
  196. X/* list of manual pages */
  197. XManualPage *firstpage = NULL;
  198. XManualPage **lastpagenext = &firstpage;
  199. X
  200. Xvoid dummy() {}
  201. X
  202. Xvoid
  203. Xnew_manual_page(comment, decl_spec, declarator)
  204. X     char *comment;
  205. X     DeclSpec *decl_spec;
  206. X     Declarator *declarator;
  207. X{
  208. X    ManualPage *newpage;
  209. X
  210. X    /* check that we really want a man page for this */
  211. X    if ((!comment) ||
  212. X    !inbasefile ||
  213. X    (!variables_out && !is_function_declarator(declarator)) ||
  214. X    (decl_spec->flags & DS_JUNK) ||
  215. X    (!static_out && (decl_spec->flags & DS_STATIC) && !header_file) ||
  216. X
  217. X    /* only document extern stuff if it's in a header file, or includes a
  218. X     * function definition.
  219. X     */
  220. X    ((decl_spec->flags & DS_EXTERN) && !header_file &&
  221. X                    declarator->type != DECL_FUNCDEF))
  222. X    {
  223. X    free_decl_spec(decl_spec);
  224. X    free_declarator(declarator);
  225. X    safe_free(comment);
  226. X    return;
  227. X    }
  228. X    
  229. X    declarator->comment = comment;
  230. X    
  231. X    newpage = (ManualPage *)safe_malloc(sizeof *newpage);
  232. X    newpage->decl_spec = (DeclSpec *)safe_malloc(sizeof *newpage->decl_spec);
  233. X    newpage->declarator = declarator;
  234. X
  235. X    *newpage->decl_spec = *decl_spec;
  236. X    newpage->sourcefile = strduplicate(basefile);
  237. X    newpage->sourcetime = basetime;
  238. X
  239. X    *lastpagenext = newpage;
  240. X    newpage->next = NULL;
  241. X    lastpagenext = &newpage->next;
  242. X}
  243. X
  244. Xvoid free_manual_page(page)
  245. X     ManualPage *page;
  246. X{
  247. X    free_decl_spec(page->decl_spec);
  248. X    free(page->decl_spec);
  249. X    free_declarator(page->declarator);
  250. X    safe_free(page->sourcefile);
  251. X}
  252. X
  253. X/* free the list of manual pages */
  254. Xvoid free_manual_pages(first)
  255. X     ManualPage *first;
  256. X{
  257. X    ManualPage *page, *next;
  258. X
  259. X    /* free any terse description read from the file */
  260. X    if (group_terse && !terse_specified)
  261. X    {
  262. X        free(group_terse);
  263. X    group_terse = NULL;
  264. X    }
  265. X    
  266. X    for (page = first;page;page = next)
  267. X    {
  268. X    next = page->next;
  269. X    free_manual_page(page);
  270. X    free(page);
  271. X    }
  272. X}
  273. X
  274. X/* allocate a substring starting at start, ending at end (NOT including *end) */
  275. Xchar *alloc_string(start, end)
  276. X     const char *start;
  277. X     const char *end;
  278. X{
  279. X    int len = end - start;
  280. X    char *ret;
  281. X    if (len == 0)    return NULL;
  282. X    
  283. X    ret = (char *)safe_malloc((size_t)len+1);
  284. X
  285. X    strncpy(ret,start,len);
  286. X    ret[len] = '\0';
  287. X
  288. X    return ret; 
  289. X}
  290. X
  291. X/* remember the terse description from the first comment in a file */
  292. Xvoid remember_terse(comment)
  293. X     char *comment;
  294. X{
  295. X    char *c, *d;
  296. X    
  297. X    enum { STUFF, LEADSPACE, DASH, TRAILSPACE, FOUND } state = STUFF;
  298. X
  299. X    /* if we've found a terse comment in a previous file, or one was
  300. X     * specified on the command line, forget it.
  301. X     */
  302. X    if (group_terse)    return;
  303. X
  304. X    /* look for a whitespace surrounded sequence of dashes to skip */
  305. X    for (c = comment;*c && state != FOUND;c++)
  306. X    {
  307. X    switch (state)
  308. X    {
  309. X    case STUFF:    if (isspace(*c))    state = LEADSPACE;
  310. X            break;
  311. X    case LEADSPACE:    if (*c == '-')        state = DASH;
  312. X            else if (!isspace(*c))    state = STUFF;
  313. X            break;
  314. X    case DASH:    if (isspace(*c))    state = TRAILSPACE;
  315. X            else if (*c != '-')    state = STUFF;
  316. X            break;
  317. X    case TRAILSPACE:if (!isspace(*c))    { c--; state = FOUND; }
  318. X            break;
  319. X    case FOUND:    break;
  320. X    }
  321. X    }
  322. X
  323. X    /* if no dashes were found, go back to the start */
  324. X    if (state != FOUND)    c = comment;
  325. X
  326. X    d = c + 1;
  327. X    
  328. X    while (*d && *d != '\n')
  329. X    d++;
  330. X
  331. X    group_terse = alloc_string(c,d);
  332. X}
  333. X
  334. X/* output a comment in man page form, followed by a newline */
  335. Xvoid
  336. Xoutput_comment(comment)
  337. Xconst char *comment;
  338. X{
  339. X    enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
  340. X    boolean new_line = TRUE;
  341. X    boolean dot_command = FALSE;
  342. X    
  343. X    if (!comment || !comment[0])
  344. X    {
  345. X    output->text("Not Documented.\n");
  346. X    return;
  347. X    }
  348. X
  349. X    /* correct punctuation a bit as it goes out */
  350. X    for (;*comment;comment++)
  351. X    {
  352. X    int c = *comment;
  353. X
  354. X    if (dot_command)
  355. X    {
  356. X        if (c == '\n')    dot_command = FALSE;
  357. X    }
  358. X    else if (new_line && c == '.')
  359. X        dot_command = TRUE;
  360. X    else if (new_line && !isalpha(c) && c != '"' && c != '\'' && c != '`')
  361. X    {
  362. X        output->break_line();
  363. X        state = CAPITALISE;
  364. X    }
  365. X    else if (c == '.')
  366. X        state = PERIOD;
  367. X    else if (isspace(c) && state == PERIOD)
  368. X        state = CAPITALISE;
  369. X    else if (isalnum(c) && state == CAPITALISE)
  370. X    {   
  371. X        if (islower(c))    c = toupper(c);
  372. X        state = TEXT;
  373. X    }
  374. X           
  375. X    output->character(c);
  376. X    new_line = c == '\n';
  377. X    }
  378. X
  379. X    /* do a full stop if there wasn't one */
  380. X    if (!dot_command && state == TEXT)    output->character('.');
  381. X
  382. X    output->character('\n');
  383. X}
  384. X
  385. X/* output the returns section in man page form, followed by a newline */
  386. Xvoid
  387. Xoutput_returns(comment)
  388. Xchar *comment;
  389. X{
  390. X    enum { TEXT, PERIOD, CAPITALISE } state = CAPITALISE;
  391. X    char lastchar = '\n';
  392. X    boolean tag_list_started = FALSE;
  393. X
  394. X    /* for each line... */
  395. X    while (*comment)
  396. X    {
  397. X    boolean tagged = FALSE;
  398. X
  399. X    /* explicitly reject dot commands */
  400. X    if (*comment && *comment != '.')
  401. X    {
  402. X        char *c = comment;
  403. X
  404. X        /* search along until the end of a word */
  405. X        while (*c && *c != ':' && !isspace(*c))
  406. X        c++;
  407. X
  408. X        /* skip all spaces or tabs after the first word */
  409. X        while (*c && *c != '\n')
  410. X        {
  411. X        if (*c == '\t' || *c == ':')
  412. X        {
  413. X            tagged = TRUE;
  414. X            break;
  415. X        }
  416. X        else if (!isspace(*c))
  417. X            break;
  418. X
  419. X        c++;
  420. X        }
  421. X    }
  422. X
  423. X    /* is it tagged?; explicitly reject dot commands */
  424. X    if (tagged)
  425. X    {
  426. X        /* output lingering newline if necessary */
  427. X        if (lastchar != '\n')
  428. X        {
  429. X        if (state == TEXT && !ispunct(lastchar))    output->character('.');
  430. X        output->character(lastchar = '\n');
  431. X        }
  432. X
  433. X        if (!tag_list_started)
  434. X        {
  435. X        output->tag_list_start();
  436. X        tag_list_started = TRUE;
  437. X        }
  438. X
  439. X        /* output the taggy bit */
  440. X        output->tag_entry_start();
  441. X        while (*comment && *comment != ':' && !isspace(*comment))
  442. X        output->character(*comment++);
  443. X        output->tag_entry_end();
  444. X
  445. X        /* skip any extra tabs or spaces */
  446. X        while (*comment == ':' || (isspace(*comment) && *comment != '\n'))
  447. X        comment++;
  448. X
  449. X        state = CAPITALISE;
  450. X    }
  451. X
  452. X    /* terminate the previous line if necessary */
  453. X    if (lastchar != '\n')    output->character(lastchar = '\n');
  454. X
  455. X    /* dot commands go out unaltered */
  456. X    if (*comment == '.')
  457. X    {
  458. X        for (;*comment && *comment != '\n'; comment++)
  459. X        output->character(*comment);
  460. X        output->character('\n');
  461. X    }
  462. X    else
  463. X    {
  464. X        /* correct punctuation a bit as the line goes out */
  465. X        for (;*comment && *comment != '\n'; comment++)
  466. X        {
  467. X        char c = *comment;
  468. X
  469. X        if (c == '.')
  470. X            state = PERIOD;
  471. X        else if (isspace(c) && state == PERIOD)
  472. X            state = CAPITALISE;
  473. X        else if (isalnum(c) && state == CAPITALISE)
  474. X        {   
  475. X            if (islower(c))    c = toupper(c);
  476. X            state = TEXT;
  477. X        }
  478. X
  479. X        output->character(lastchar = c);
  480. X        }
  481. X
  482. X        /* if it ended in punctuation, just output the nl straight away. */
  483. X        if (ispunct(lastchar))
  484. X        {
  485. X        if (lastchar == '.')    state = CAPITALISE;
  486. X        output->character(lastchar = '\n');
  487. X        }
  488. X    }
  489. X
  490. X    if (*comment)    comment++;
  491. X    }
  492. X
  493. X    /* output lingering newline if necessary */
  494. X    if (lastchar != '\n')
  495. X    {
  496. X    if (state == TEXT && !ispunct(lastchar))    output->character('.');
  497. X    output->character('\n');
  498. X    }
  499. X
  500. X    if (tag_list_started)
  501. X    output->tag_list_end();
  502. X
  503. X}
  504. X
  505. X/* output the description for an identifier; be it return value or param */
  506. Xstatic void output_identifier_description(comment, outfunc,
  507. X                            decl_spec, declarator)
  508. X    const char *comment;        /* comment for this identifier */
  509. X    void (*outfunc) _((const char *));    /* function to output comment */
  510. X    const DeclSpec *decl_spec;
  511. X    const Declarator *declarator;
  512. X{
  513. X    /* one day, this may document the contents of structures too */
  514. X
  515. X    /* output list of possible enum values, if any */
  516. X    if (decl_spec->enum_list)
  517. X    {
  518. X    int maxtaglen = 0;
  519. X    int descriptions = 0;
  520. X    Enumerator *e;
  521. X    int is_first = 1;
  522. X    boolean started = FALSE;
  523. X    
  524. X    /* don't output the "Not Doc." message for enums */
  525. X    if (comment)
  526. X    {
  527. X        (*outfunc)(comment);
  528. X        output->blank_line();
  529. X    }
  530. X    
  531. X    /* see if any have descriptions */
  532. X    for (e = decl_spec->enum_list->first; e; e = e->next)
  533. X        if (e->name[0] != '_')
  534. X        {
  535. X        int taglen = strlen(e->name);
  536. X        if (taglen > maxtaglen)    maxtaglen = taglen;
  537. X        if (e->comment)    descriptions = 1;
  538. X        }
  539. X
  540. X    output->text("Possible values for a");
  541. X    if (strchr("aAeEiIoOuU",decl_spec->text[0]))    output->character('n');
  542. X    output->character(' ');
  543. X    output->code(decl_spec->text);
  544. X    output->text(" are as follows:\n");
  545. X
  546. X    for (e = decl_spec->enum_list->first; e; e = e->next)
  547. X    {
  548. X        /* don't print names with a leading underscore! */
  549. X        if (e->name[0] == '_')    continue;
  550. X        
  551. X        if (e->group_comment)
  552. X        {
  553. X        /* break out of table mode for the group comment */
  554. X        if (started)
  555. X        {
  556. X            if (descriptions)
  557. X            output->table_end();
  558. X            else
  559. X            output->list_end();
  560. X            started = FALSE;
  561. X        }
  562. X        output->indent();
  563. X        output_comment(e->group_comment);
  564. X        }
  565. X
  566. X        if (!started)
  567. X        {
  568. X        if (descriptions)
  569. X            output->table_start();
  570. X        else
  571. X            output->list_start();
  572. X        started = TRUE;
  573. X        }
  574. X
  575. X        if (descriptions)
  576. X        output->table_entry(e->name, maxtaglen, e->comment);
  577. X        else
  578. X        {
  579. X        if (!is_first)
  580. X            output->list_separator();
  581. X        is_first = 0;
  582. X        output->list_entry(e->name);
  583. X        }
  584. X    }
  585. X
  586. X    if (started)
  587. X    {
  588. X        if (descriptions)
  589. X        output->table_end();
  590. X        else
  591. X        output->list_end();
  592. X    }
  593. X    } 
  594. X    else
  595. X    (*outfunc)(comment);
  596. X}
  597. X
  598. X/* is there automatic documentation here? */
  599. Xstatic boolean auto_documented(page)
  600. Xconst ManualPage *page;
  601. X{
  602. X    /* one day we may handle structs too */
  603. X    return
  604. X    page->decl_spec->enum_list != NULL;    /* enums are self-documenting. */
  605. X}
  606. X
  607. X/* decide if a manual page needs a RETURNS section.
  608. X * If this is true, then output_identifier_description must be able to generate
  609. X * sensible output for it.
  610. X */
  611. Xstatic boolean needs_returns_section(page)
  612. Xconst ManualPage *page;
  613. X{
  614. X    return 
  615. X    (page->returns && page->returns[0]) ||
  616. X    (auto_documented(page) && is_function_declarator(page->declarator));
  617. X}
  618. X
  619. X/* does this declarator have documented parameters? */
  620. Xboolean has_documented_parameters(d)
  621. Xconst Declarator *d;
  622. X{
  623. X    if (has_parameters(d))
  624. X    {
  625. X    Parameter *p;
  626. X
  627. X    for (p = d->head->params.first; p != NULL; p = p->next)
  628. X        if (p->declarator->comment || always_document_params)
  629. X        return TRUE;
  630. X    }
  631. X    return FALSE;
  632. X}
  633. X
  634. X/* Output the list of function parameter descriptions.
  635. X */
  636. Xvoid
  637. Xoutput_parameter_descriptions (params, function)
  638. XParameterList *params;
  639. Xchar *function;
  640. X{
  641. X    Parameter *p;
  642. X    boolean tag_list_started = FALSE;
  643. X
  644. X    for (p = params->first; p != NULL; p = p->next)
  645. X    {
  646. X    if (p->suppress ||
  647. X        (!always_document_params && p->declarator->comment == NULL))
  648. X        continue;
  649. X
  650. X    if (!tag_list_started)
  651. X    {
  652. X    output->tag_list_start();
  653. X    tag_list_started = TRUE;
  654. X    }
  655. X
  656. X    if (p->duplicate)
  657. X        output->tag_entry_start_extra();
  658. X    else
  659. X        output->tag_entry_start();
  660. X
  661. X    output_parameter(p);
  662. X
  663. X    /* include function name if it's a duplicate */
  664. X    if (p->duplicate)
  665. X        output->tag_entry_end_extra(function);
  666. X    else
  667. X        output->tag_entry_end();
  668. X
  669. X    output_identifier_description(p->declarator->comment, output_comment,
  670. X                        &p->decl_spec, &p->declarator);
  671. X    }
  672. X
  673. X    if (tag_list_started)
  674. X    output->tag_list_end();
  675. X}
  676. X
  677. X/* split out the 'Returns:' section of a function comment */
  678. Xboolean
  679. Xsplit_returns_comment(comment, description, returns)
  680. X     char *comment;
  681. X     char **description;
  682. X     char **returns;
  683. X{
  684. X    char *retstart;
  685. X
  686. X    for (retstart = comment;
  687. X     retstart;
  688. X     retstart = strchr(retstart,'\n'))
  689. X    {
  690. X    if (*retstart == '\n')    retstart++;    /* skip the newline */
  691. X
  692. X    if (!strncmpi(retstart, "returns",(size_t)7))
  693. X    {        
  694. X        char *descend = retstart - 2;    /* back before newline */
  695. X
  696. X        /* go back to the end of the description in case there were
  697. X         * linefeeds before the returns.
  698. X         */
  699. X        while (descend > comment && isspace(*descend))
  700. X        descend--;
  701. X
  702. X        *description =
  703. X        descend > comment ? alloc_string(comment,descend+1) : NULL;
  704. X
  705. X        retstart += 7;
  706. X        
  707. X        while (*retstart == ':' || isspace(*retstart))
  708. X        retstart++;
  709. X
  710. X        if (*retstart)
  711. X        *returns = strduplicate(retstart);
  712. X        else
  713. X            *returns = NULL;
  714. X        return TRUE;
  715. X    }
  716. X    }
  717. X
  718. X    *description = comment;
  719. X    *returns = NULL;
  720. X    return FALSE;
  721. X}
  722. X
  723. X/* skip to past the dash on the first line, if there is one
  724. X * The dash must be surrounded by whitespace, so hyphens are not skipped.
  725. X */
  726. Xconst char *skipdash(c)
  727. Xconst char *c;
  728. X{
  729. X    const char *d;
  730. X
  731. X    /* ignore anything on the first line, up to a dash (if any) */
  732. X    for (d = c + 1; *d && *d != '\n' && *d != '-'; d++)
  733. X    ;
  734. X
  735. X    if (isspace(d[-1]) && d[0] == '-' && isspace(d[1]))
  736. X    {
  737. X    do
  738. X        d++;
  739. X    while (*d && *d != '\n' && isspace(*d));
  740. X
  741. X    if (*d && *d != '\n')    c = d;
  742. X    }
  743. X    return c;
  744. X}
  745. X
  746. X/* split the function comment into manual page format */
  747. Xvoid
  748. Xsplit_function_comment(comment, identifier_name,
  749. X                    terse, description, returns, extra_sections)
  750. X    const char *comment;
  751. X    const char *identifier_name;
  752. X     char **terse;
  753. X     char **description;
  754. X     char **returns;
  755. X     Section **extra_sections;
  756. X{
  757. X    const char *c, *start_text = NULL, *end_text = NULL;
  758. X    char **put_ptr = NULL;
  759. X    Section *first_section, **lastnextsection = &first_section;
  760. X    boolean explicit_description = FALSE;
  761. X    boolean lastblank = TRUE;
  762. X    boolean skip_dash = FALSE;
  763. X    
  764. X    *description = *returns = NULL;
  765. X    if (terse)    *terse = NULL;
  766. X
  767. X    /* for each line... */
  768. X    for (c = comment; *c;)
  769. X    {
  770. X    const char *start_line = c;
  771. X    boolean section_heading;
  772. X    /* remember if it's a blank line */
  773. X    if (*c == '\n')
  774. X    {
  775. X        lastblank = TRUE;
  776. X        c++;
  777. X        continue;
  778. X    }
  779. X
  780. X    /* if the last one was blank, perhaps this one is a section heading
  781. X     */
  782. X    if (lastblank)
  783. X    {
  784. X        /* see if we've found the start of a SECTION */
  785. X        while (isalpha(*c))
  786. X        c++;
  787. X    
  788. X        section_heading = *c == '\n' || *c == ':' ||
  789. X                    (*c == '\0' && start_line == comment);
  790. X    }
  791. X    else
  792. X        section_heading = FALSE;
  793. X
  794. X    lastblank = FALSE;    /* this one's not blank; for next time */
  795. X
  796. X    if (section_heading)
  797. X    {
  798. X        size_t section_len = c - start_line; /* length of section name */
  799. X
  800. X        /* yes, we've found a SECTION; store the previous one (if any) */
  801. X        if (put_ptr && start_text)
  802. X        {
  803. X        if (skip_dash)    start_text = skipdash(start_text);
  804. X        *put_ptr = alloc_string(start_text,end_text);
  805. X        }
  806. X
  807. X        skip_dash = FALSE;
  808. X
  809. X        /* check for comments that start with the name of the identifier */
  810. X        if (start_line == comment &&
  811. X        !strncmp(start_line, identifier_name, section_len))
  812. X        {
  813. X        put_ptr = description;
  814. X        }
  815. X
  816. X        /* only accept NAME if not grouped */
  817. X        else if (terse && 
  818. X             (!strncmpi(start_line,"NAME", section_len) ||
  819. X              !strncmpi(start_line,"FUNCTION", section_len) ||
  820. X              !strncmpi(start_line,"PROCEDURE", section_len) ||
  821. X              !strncmpi(start_line,"ROUTINE", section_len))
  822. X             )
  823. X
  824. X        {
  825. X        put_ptr = terse;
  826. X        skip_dash = TRUE;
  827. X        }
  828. X        else if (!strncmpi(start_line,"DESCRIPTION", section_len))
  829. X        {
  830. X        explicit_description = TRUE;
  831. X        put_ptr = description;
  832. X        }
  833. X        else if (!strncmpi(start_line,"RETURNS", section_len))
  834. X        {
  835. X        put_ptr = returns;
  836. X        }
  837. X        else
  838. X        {
  839. X        /* allocate a new section */
  840. X        Section *new_section =
  841. X                (Section *)safe_malloc(sizeof *new_section);
  842. X
  843. X        *lastnextsection = new_section;
  844. X        lastnextsection = &new_section->next;
  845. X
  846. X        new_section->name = alloc_string(start_line,c);
  847. X        strtoupper(new_section->name);
  848. X        new_section->text = NULL;
  849. X        new_section->been_output = FALSE; /* not been output yet */
  850. X        put_ptr = &new_section->text;
  851. X        }
  852. X
  853. X        /* defer decision about where text starts till we find some */
  854. X        start_text = NULL;
  855. X
  856. X        if (*c == ':')    /* skip the terminating : */
  857. X        {
  858. X        c++;
  859. X
  860. X        /* skip forward to the start of the text */
  861. X        while (*c && *c != '\n' && isspace(*c))
  862. X            c++;
  863. X
  864. X        /* if we find the text here, then we've got it */
  865. X        if (*c && *c != '\n')
  866. X            start_text = c;
  867. X        }
  868. X    }
  869. X    else
  870. X    {
  871. X        /* are we looking at the top of the function comment? */
  872. X        if (start_line == comment)
  873. X        {
  874. X        /* only look for terse comment if not grouped together */
  875. X        if (terse)
  876. X        {
  877. X            const char *endterse, *afterdash = skipdash(start_line);
  878. X
  879. X            /* find the end of the terse comment */
  880. X            while (*c && *c != '.' && *c != '\n')
  881. X            c++;
  882. X
  883. X            endterse = *c == '.' ? c+1 : c;
  884. X            *terse = alloc_string(
  885. X            afterdash < endterse ? afterdash : start_line,
  886. X            endterse);
  887. X
  888. X            /* skip it if it's a ., and any trailing spaces */
  889. X            if (*c == '.')
  890. X            do c++; while (*c && *c != '\n' && isspace(*c));
  891. X
  892. X            start_text = NULL;    /* look for it */
  893. X
  894. X            if (*c && *c != '\n')
  895. X            /* actually, it's a description, starting here */
  896. X            start_text = c;
  897. X        }
  898. X        /* must be a description starting at the beginning of the line.
  899. X         */
  900. X        else
  901. X            start_text = start_line;
  902. X
  903. X        put_ptr = description;
  904. X        }
  905. X        else
  906. X        /* have we just located the first real text in a section? */
  907. X        if (put_ptr && !start_text)    start_text = start_line;
  908. X    }
  909. X
  910. X    /* skip the line */
  911. X    if (*c && *c != '\n')
  912. X        while (*c && *c != '\n')    c++;
  913. X
  914. X    end_text = c;    /* so far, the text ends at the end of this line */
  915. X    if (*c)    c++;
  916. X    }
  917. X
  918. X    /* store the last one */
  919. X    if (put_ptr && start_text)
  920. X    {
  921. X    if (skip_dash)    start_text = skipdash(start_text);
  922. X    *put_ptr = alloc_string(start_text,end_text);
  923. X    }
  924. X
  925. X    /* terminate (or nuke) section list */
  926. X    *lastnextsection = NULL;
  927. X
  928. X    /* if there wasn't a RETURNS section, and the DESCRIPTION field was not
  929. X     * explicit, see if we can split one out of the description field.
  930. X     */
  931. X    if (*returns == NULL && !explicit_description)
  932. X    {
  933. X    char *olddesc = *description;
  934. X        if (split_returns_comment(olddesc, description, returns))
  935. X        free(olddesc);
  936. X    }
  937. X
  938. X    *extra_sections = first_section;
  939. X}
  940. X
  941. X/* see if two parameters are declared identically */
  942. Xboolean params_identical(first, second)
  943. X     Parameter *first;
  944. X     Parameter *second;
  945. X{
  946. X    return
  947. X    first->decl_spec.flags == second->decl_spec.flags &&
  948. X
  949. X    /* there may be no decl_spec.text if it's an ellipsis arg */
  950. X    ((!first->decl_spec.text && !second->decl_spec.text) ||
  951. X     (first->decl_spec.text && second->decl_spec.text &&
  952. X      !strcmp(first->decl_spec.text, second->decl_spec.text))) &&
  953. X
  954. X    ((!first->declarator->text && !second->declarator->text) ||
  955. X     (first->declarator->text && second->declarator->text &&
  956. X      !strcmp(first->declarator->text, second->declarator->text)));
  957. X}
  958. X
  959. X/* search all the parameters in this grouped manual page for redundancies */
  960. Xboolean mark_duplicate_parameters(firstpage)
  961. X     ManualPage *firstpage;
  962. X{
  963. X    Parameter *param;
  964. X    boolean any = FALSE;
  965. X    ManualPage *page;
  966. X
  967. X    for (page = firstpage; page; page = page->next)
  968. X    {
  969. X    if (has_parameters(page->declarator))
  970. X    for (param = page->declarator->head->params.first; param;
  971. X                            param = param->next)
  972. X    {
  973. X        ManualPage *otherpage;
  974. X        Parameter *otherparam;
  975. X        
  976. X        if (always_document_params || param->declarator->comment)
  977. X        any = TRUE;
  978. X
  979. X        for (otherpage = page->next; otherpage;
  980. X                        otherpage = otherpage->next)
  981. X        {
  982. X        if (has_parameters(otherpage->declarator))
  983. X        for (otherparam = otherpage->declarator->head->params.first;
  984. X             otherparam;
  985. X             otherparam = otherparam->next)
  986. X        {
  987. X            /* do these two look the same? */
  988. X            if (params_identical(param, otherparam))
  989. X            {
  990. X            /* order is important for bit positions */
  991. X            enum { NEITHER, US, THEM, BOTH } has_comm = NEITHER;
  992. X            
  993. X            /* work out who has the comment */
  994. X            if (param->declarator->comment)    has_comm |= US;
  995. X            if (otherparam->declarator->comment) has_comm |= THEM;
  996. X
  997. X            switch(has_comm)
  998. X            {
  999. X            case NEITHER:
  1000. X            case US:
  1001. X                otherparam->suppress = TRUE;
  1002. X                break;
  1003. X            case THEM:
  1004. X                param->suppress = TRUE;
  1005. X                break;
  1006. X            case BOTH:
  1007. X                if (!strcmp(param->declarator->comment,
  1008. X                        otherparam->declarator->comment))
  1009. X                otherparam->suppress = TRUE;
  1010. X                else
  1011. X                {
  1012. X                param->duplicate = TRUE;
  1013. X                otherparam->duplicate = TRUE;
  1014. X                }
  1015. X                break;
  1016. X            }
  1017. X            }
  1018. X        }
  1019. X        }
  1020. X    }
  1021. X    }
  1022. X    return any;
  1023. X}
  1024. X
  1025. X/* output a formatting string so that it works with filling on */
  1026. Xvoid output_format_string(fmt)
  1027. Xconst char *fmt;
  1028. X{
  1029. X    while (*fmt)
  1030. X    {
  1031. X    output->character(*fmt);
  1032. X
  1033. X    if (*fmt++ == '\n')
  1034. X        output->break_line();    /* break the line */
  1035. X    }
  1036. X}
  1037. X
  1038. X/* write the warning for the header */
  1039. Xvoid output_warning()
  1040. X{
  1041. X    output->comment();
  1042. X    output->text("WARNING! THIS FILE WAS GENERATED AUTOMATICALLY BY ");
  1043. X    output->text(progname);
  1044. X    output->text("!\n");
  1045. X    output->comment();
  1046. X    output->text("DO NOT EDIT! CHANGES MADE TO THIS FILE WILL BE LOST!\n");
  1047. X}
  1048. X
  1049. Xvoid output_includes()
  1050. X{
  1051. X    IncludeFile *incfile;
  1052. X    
  1053. X    for (incfile = first_include; incfile; incfile=incfile->next)
  1054. X    {
  1055. X    char *name = incfile->name;
  1056. X    boolean surrounded = *name == '"' || *name == '<';
  1057. X    
  1058. X    output->text("#include ");
  1059. X    if (!surrounded)    output->character('<');
  1060. X    output->text(name);
  1061. X    if (!surrounded)    output->character('>');
  1062. X    output->text("\n");
  1063. X    output->break_line();
  1064. X    }
  1065. X}
  1066. X
  1067. X/* Writes the entire contents of the manual page specified by basepage. */
  1068. Xvoid
  1069. Xoutput_manpage(firstpage, basepage, input_files, title, section)
  1070. X    /* the first page in the list of all manual pages.  This is used to build
  1071. X     * the SEE ALSO section of related pages when group_together is false.
  1072. X     */
  1073. X    ManualPage *firstpage;
  1074. X
  1075. X    /* the base page from which the output manual page will be generated.  if
  1076. X     * group_together indicates that the user wanted grouped pages, basepage
  1077. X     * will always be the same as firstpage, and all the ManualPage's in the
  1078. X     * list will be grouped together into the one output page.
  1079. X     */
  1080. X    ManualPage *basepage;
  1081. X
  1082. X    int input_files;
  1083. X    const char *title;
  1084. X    const char *section;
  1085. X{
  1086. X    ManualPage *page;
  1087. X    boolean need_returns;
  1088. X    char *terseout, *terse = NULL;
  1089. X    
  1090. X    /* check if there's more than one page in the group */
  1091. X    boolean grouped = group_together && firstpage->next;
  1092. X
  1093. X    /* split up all the function comments for this page */
  1094. X    for (page = basepage; page; page = page->next)
  1095. X    {
  1096. X    split_function_comment(page->declarator->comment,
  1097. X        page->declarator->name,
  1098. X        group_together ? (char **)NULL : &terse,
  1099. X        &page->description,&page->returns,&page->first_section);
  1100. X    if (!group_together)    break;
  1101. X    }
  1102. X
  1103. X    /* work out what we'll actually print as a terse description */
  1104. X    terseout = group_terse ? group_terse : (terse ? terse : "Not Described");
  1105. X
  1106. X    if (!make_embeddable)
  1107. X    {
  1108. X    output->header(basepage, input_files, grouped,
  1109. X            title ? title : basepage->declarator->name, section);
  1110. X    }
  1111. X    output->section("NAME");
  1112. X    
  1113. X    /* output the names of all the stuff documented on this page */
  1114. X    for (page = basepage; page; page = page->next)
  1115. X    {
  1116. X    output->text(page->declarator->name);
  1117. X
  1118. X    if (!group_together)    break;
  1119. X
  1120. X    if (page->next)    output->text(",\n");
  1121. X    }
  1122. X
  1123. X    output->character(' ');
  1124. X    output->dash();
  1125. X    output->character(' ');
  1126. X    output->text(terseout);
  1127. X    output->character('\n');
  1128. X    
  1129. X    output->section("SYNOPSIS");
  1130. X
  1131. X    output->code_start();
  1132. X    
  1133. X    /* list the include files the user asked us to */
  1134. X    output_includes();
  1135. X
  1136. X    /* if it's a header file, say to #include it */
  1137. X    if (header_file)
  1138. X    {
  1139. X    output->text("#include <");
  1140. X    if (header_prefix)
  1141. X    {
  1142. X        output->text(header_prefix);
  1143. X        output->character('/');
  1144. X    }
  1145. X    output->text(basefile);
  1146. X    output->text(">\n");
  1147. X    }
  1148. X
  1149. X    /* can't just use .PP; that may reset our font */
  1150. X    if (first_include || header_file)    output->blank_line();
  1151. X
  1152. X    for (page = basepage; page; page = page->next)
  1153. X    {
  1154. X    output_format_string(decl_spec_prefix);
  1155. X
  1156. X    /* make sure variables are prefixed extern */
  1157. X    if (!(page->decl_spec->flags & DS_STATIC) &&
  1158. X        !is_function_declarator(page->declarator) &&
  1159. X        !strstr(page->decl_spec->text, "extern"))
  1160. X        output->text("extern ");
  1161. X
  1162. X    output_decl_spec(page->decl_spec);
  1163. X    output_format_string(declarator_prefix);
  1164. X
  1165. X    /* format it nicely if there's more than one parameter */
  1166. X    output_declarator(page->declarator, 
  1167. X        page->declarator->head->params.first !=
  1168. X        page->declarator->head->params.last);
  1169. X
  1170. X    output->text(";\n");
  1171. X    
  1172. X    if (!grouped)    break;
  1173. X    if (page->next)    output->blank_line();
  1174. X    }
  1175. X
  1176. X    output->code_end();
  1177. X
  1178. X    /* only output paramaters if there actually are some,
  1179. X     * not including merely (void)
  1180. X     */
  1181. X    if ((grouped && mark_duplicate_parameters(basepage)) ||
  1182. X        (!grouped && has_documented_parameters(basepage->declarator)))
  1183. X    {
  1184. X    output->section("PARAMETERS");
  1185. X
  1186. X    for (page = basepage; page; page = page->next)
  1187. X    {
  1188. X        if (has_parameters(page->declarator))
  1189. X        output_parameter_descriptions(&page->declarator->head->params,
  1190. X                            page->declarator->name);
  1191. X        if (!grouped)    break;    /* only do first page */
  1192. X    }
  1193. X    }
  1194. X
  1195. X    output->section("DESCRIPTION");
  1196. X
  1197. X    if (grouped)
  1198. X    {
  1199. X    need_returns = FALSE;
  1200. X    for (page = basepage; page; page = page->next)
  1201. X    {
  1202. X        if (needs_returns_section(page))    need_returns = TRUE;
  1203. X
  1204. X        /* enum variables are documented in DESCRIPTION */
  1205. X        if (auto_documented(page) &&
  1206. X                    !is_function_declarator(page->declarator))
  1207. X        {
  1208. X        output->sub_section(page->declarator->name);
  1209. X        output_identifier_description(page->description,
  1210. X            output_comment, page->decl_spec, page->declarator);
  1211. X        }
  1212. X        else if (page->description)
  1213. X        {
  1214. X        output->sub_section(page->declarator->name);
  1215. X        output_comment(page->description);
  1216. X        }
  1217. X
  1218. X        safe_free(page->description);
  1219. X    }
  1220. X    }
  1221. X    else
  1222. X    {
  1223. X    const char *descr = basepage->description ? basepage->description
  1224. X                           : terseout;
  1225. X
  1226. X    need_returns = needs_returns_section(basepage);
  1227. X
  1228. X    if (auto_documented(page) && !is_function_declarator(page->declarator))
  1229. X        output_identifier_description(descr, output_comment,
  1230. X                        page->decl_spec, page->declarator);
  1231. X    else
  1232. X        output_comment(descr);
  1233. X
  1234. X    safe_free(basepage->description);
  1235. X
  1236. X    }
  1237. X
  1238. X    /* terse can now never be a static string */
  1239. X    safe_free(terse);
  1240. X
  1241. X    if (need_returns)
  1242. X    {
  1243. X    output->section("RETURNS");
  1244. X
  1245. X    for (page = basepage; page; page = page->next)
  1246. X    {
  1247. X        if (needs_returns_section(page))
  1248. X        {
  1249. X        if (grouped) output->sub_section(page->declarator->name);
  1250. X
  1251. X        output_identifier_description(page->returns, output_returns,
  1252. X                        page->decl_spec, page->declarator);
  1253. X        safe_free(page->returns);
  1254. X        }
  1255. X
  1256. X        if (!grouped)    break;
  1257. X    }
  1258. X    }
  1259. X
  1260. X    /* output any other sections */
  1261. X    for (page = basepage; page; page = page->next)
  1262. X    {
  1263. X    Section *section, *next;
  1264. X
  1265. X    for (section = page->first_section; section; section = next)
  1266. X    {
  1267. X        next = section->next;
  1268. X
  1269. X        if (!section->been_output && section->text)
  1270. X        {
  1271. X        output->section(section->name);
  1272. X        if (grouped) output->sub_section(page->declarator->name);
  1273. X        output_comment(section->text);
  1274. X        section->been_output = TRUE;
  1275. X    
  1276. X        if (grouped && page->next)
  1277. X        {
  1278. X            ManualPage *other_page = page->next;
  1279. X    
  1280. X            /* look through all the other pages for matching sections */
  1281. X            for (; other_page; other_page = other_page->next)
  1282. X            {
  1283. X            Section *other_section = other_page->first_section;
  1284. X            for (;other_section; other_section =
  1285. X                                other_section->next)
  1286. X            {
  1287. X                if (other_section->been_output ||
  1288. X                strcmp(other_section->name, section->name))
  1289. X                continue;
  1290. X    
  1291. X                output->sub_section(other_page->declarator->name);
  1292. X                output_comment(other_section->text);
  1293. X                other_section->been_output = TRUE;
  1294. X            }
  1295. X            }
  1296. X        }
  1297. X        }
  1298. X
  1299. X
  1300. X        /* free this section */
  1301. X        free(section->name);
  1302. X        safe_free(section->text);
  1303. X        free(section);
  1304. X    }
  1305. X
  1306. X    if (!grouped)    break;
  1307. X    }
  1308. X
  1309. X    /* only output SEE ALSO if not grouped */
  1310. X    if (!group_together)
  1311. X    {
  1312. X    ManualPage *also;
  1313. X
  1314. X    /* add the SEE ALSO section */
  1315. X    /* look for any other functions to refer to */
  1316. X    for (also = firstpage; also && also == basepage; also = also->next)
  1317. X        ;
  1318. X    
  1319. X    if (also)    /* did we find at least one? */
  1320. X    {
  1321. X        int isfirst = 1;
  1322. X
  1323. X        output->section("SEE ALSO");
  1324. X        
  1325. X        for (also = firstpage; also; also = also->next)
  1326. X        {
  1327. X        if (also == basepage)    continue;
  1328. X        
  1329. X        if (!isfirst)
  1330. X            output->text(",\n");
  1331. X        else
  1332. X            isfirst = 0;
  1333. X            
  1334. X        output->text(also->declarator->name);
  1335. X        output->character('(');
  1336. X        output->text(manual_section);
  1337. X        output->character(')');
  1338. X        }
  1339. X    
  1340. X        output->character('\n');
  1341. X    }
  1342. X    }
  1343. X
  1344. X    if (!make_embeddable)
  1345. X    output->file_end();
  1346. X}
  1347. X
  1348. X
  1349. X/* generate output filename based on a string */
  1350. Xchar *page_file_name(based_on, object_type, extension)
  1351. X    /* string to base the name on; this will be the name of an identifier or
  1352. X     * the base of the input file name.
  1353. X     */
  1354. X    const char *based_on;
  1355. X    enum Output_Object object_type;    /* class of object documented */
  1356. X    const char *extension;        /* file extension to use */
  1357. X{
  1358. X    char *filename;
  1359. X    const char *subdir = output_object[object_type].subdir;
  1360. X
  1361. X#ifndef FLEXFILENAMES
  1362. X    char *basename;
  1363. X    int chopoff = 14 - strlen(extension) - 1;
  1364. X
  1365. X    basename = strduplicate(based_on);
  1366. X    if (strlen(basename) > chopoff)
  1367. X    basename[chopoff] = '\0';
  1368. X#else
  1369. X    const char *basename = based_on;
  1370. X#endif
  1371. X
  1372. X    filename = strduplicate(output_dir);
  1373. X
  1374. X    if (subdir)
  1375. X    {
  1376. X    if (filename)    filename = strappend(filename, "/", NULLCP);
  1377. X    filename = strappend(filename, subdir, NULLCP);
  1378. X    }
  1379. X
  1380. X    if (filename)    filename = strappend(filename, "/", NULLCP);
  1381. X    filename = strappend(filename, basename,".",extension, NULLCP);
  1382. X
  1383. X#ifndef FLEXFILENAMES
  1384. X    free(basename);
  1385. X#endif
  1386. X    return filename;
  1387. X}
  1388. X
  1389. X/* determine the output page type from a declaration */
  1390. Xenum Output_Object page_output_type(decl_spec, declarator)
  1391. Xconst DeclSpec *decl_spec;
  1392. Xconst Declarator *declarator;
  1393. X{
  1394. X    boolean is_static = decl_spec->flags & DS_STATIC;
  1395. X    return is_function_declarator(declarator)
  1396. X    ? (is_static ? OBJECT_STATIC_FUNCTION : OBJECT_FUNCTION)
  1397. X    : (is_static ? OBJECT_STATIC_VARIABLE : OBJECT_VARIABLE);
  1398. X}
  1399. X
  1400. X/* determine the extension/section from an output type */
  1401. Xconst char *page_manual_section(output_type)
  1402. Xenum Output_Object output_type;
  1403. X{
  1404. X    return    output_object[output_type].extension ?
  1405. X        output_object[output_type].extension : manual_section;
  1406. X}
  1407. X
  1408. X/* remove an existing file, if it exists & we have write permission to it */
  1409. Xint remove_old_file(name)
  1410. Xconst char *name;
  1411. X{
  1412. X#ifdef HAS_ACCESS
  1413. X    /* check that we have write premission before blasting it */
  1414. X    if (access(name,W_OK) == -1)
  1415. X    {
  1416. X    if (errno != ENOENT)
  1417. X    {
  1418. X        my_perror("can't access output file", name);
  1419. X        return FALSE;
  1420. X    }
  1421. X     }
  1422. X    else
  1423. X#endif
  1424. X    {
  1425. X    /* if it exists, blast it */
  1426. X    if (unlink(name) == -1 && errno != ENOENT)
  1427. X    {
  1428. X        my_perror("error unlinking old link file", name);
  1429. X        return FALSE;
  1430. X    }
  1431. X    }
  1432. X    return TRUE;
  1433. X}
  1434. X
  1435. X/* output all the manual pages in a list */
  1436. Xvoid output_manual_pages(first, input_files, link_type)
  1437. X    ManualPage *first;
  1438. X    int input_files;    /* number of different input files */
  1439. X    enum LinkType link_type;    /* how grouped pages will be linked */
  1440. X{
  1441. X    ManualPage *page;
  1442. X    int tostdout = output_dir && !strcmp(output_dir,"-");
  1443. X
  1444. X    char *filename = NULL;
  1445. X
  1446. X    /* output each page, in turn */
  1447. X    for (page = first; page; page = page->next)
  1448. X    {
  1449. X    char *input_file_base = NULL;
  1450. X    enum Output_Object output_type =
  1451. X            page_output_type(page->decl_spec, page->declarator);
  1452. X
  1453. X    /* the manual name is used as the output file extension, and also in
  1454. X     * the nroff output header.
  1455. X     */
  1456. X    const char *section = page_manual_section(output_type);
  1457. X
  1458. X    /* work out the base name of the file this was generated from */
  1459. X    if (page->sourcefile)
  1460. X    {
  1461. X        const char *base = strrchr(firstpage->sourcefile, '/');
  1462. X        const char *last;
  1463. X    
  1464. X        /* use the file name as the manual page title */
  1465. X        if (base == NULL)
  1466. X        base = firstpage->sourcefile;
  1467. X        else
  1468. X        base++;
  1469. X        last = strrchr(base, '.');
  1470. X        if (last == NULL)
  1471. X        last = base + strlen(base);
  1472. X    
  1473. X        input_file_base = alloc_string(base, last);
  1474. X    }
  1475. X
  1476. X    if (!tostdout)
  1477. X    {
  1478. X        safe_free(filename);    /* free previous, if any */
  1479. X        filename = page_file_name(
  1480. X        use_input_name && input_file_base
  1481. X                ? input_file_base : page->declarator->name,
  1482. X        output_type, section);
  1483. X        fprintf(stderr,"generating: %s\n",filename);
  1484. X
  1485. X        /* a previous run may have left links, so nuke old file first */
  1486. X        if (!remove_old_file(filename))    exit(1);
  1487. X
  1488. X        if (freopen(filename, "w", stdout) == NULL)
  1489. X        {
  1490. X        my_perror("error opening output file", filename);
  1491. X        free(filename);
  1492. X        exit(1);
  1493. X        }
  1494. X    }
  1495. X
  1496. X    /* do the page itself */
  1497. X    output_manpage(first, page, input_files,
  1498. X        group_together && input_file_base ? input_file_base
  1499. X                          : page->declarator->name,
  1500. X        group_together ? manual_section : section);
  1501. X
  1502. X    safe_free(input_file_base);
  1503. X
  1504. X    /* don't continue if grouped, because all info went into this page */
  1505. X    if (group_together)        break;
  1506. X
  1507. X    if (tostdout &&    page->next)    output->character('\f');
  1508. X    }
  1509. X
  1510. X    /* close the last output file if there was one */
  1511. X    if (!tostdout && fclose(stdout) == EOF)
  1512. X    {
  1513. X    my_perror("error linking closing file", filename);
  1514. X    exit(1);
  1515. X    }
  1516. X
  1517. X    /* if pages are grouped, just link the rest to the first */
  1518. X    if (group_together && !tostdout && link_type != LINK_NONE)
  1519. X    {
  1520. X    for (page=use_input_name && first->sourcefile ? first : first->next;
  1521. X                            page; page = page->next)
  1522. X    {
  1523. X        enum Output_Object output_type =
  1524. X            page_output_type(page->decl_spec, page->declarator);
  1525. X        const char *extension = page_manual_section(output_type);
  1526. X        char *linkname = page_file_name(page->declarator->name,
  1527. X                            output_type, extension);
  1528. X        int result = 0;
  1529. X
  1530. X        /* we may have a function with the same name as the sourcefile */
  1531. X        if (!strcmp(filename, linkname))
  1532. X        {
  1533. X        free(linkname);
  1534. X        continue;
  1535. X        }
  1536. X            
  1537. X        fprintf(stderr,"%s: %s\n",
  1538. X        link_type == LINK_REMOVE ? "removing" : "linking", linkname);
  1539. X
  1540. X        /* always nuke old output file, since it may be linked to the one
  1541. X         * we've just generated, so LINK_FILE may trash it.
  1542. X         */
  1543. X        if (!remove_old_file(linkname))    exit(1);
  1544. X
  1545. X        switch(link_type)
  1546. X        {
  1547. X#ifdef HAS_LINK
  1548. X        case LINK_HARD:
  1549. X        result = link(filename, linkname);
  1550. X        break;
  1551. X#endif
  1552. X#ifdef HAS_SYMLINK
  1553. X        case LINK_SOFT:
  1554. X        result = symlink(filename, linkname);
  1555. X        break;
  1556. X#endif
  1557. X        case LINK_FILE:
  1558. X        if (freopen(linkname, "w", stdout) == NULL)
  1559. X        {
  1560. X            result = -1;
  1561. X            break;
  1562. X        }
  1563. X        output_warning();
  1564. X        output->include(filename);
  1565. X        if (fclose(stdout) == EOF)
  1566. X            result = -1;
  1567. X        break;
  1568. X        case LINK_NONE:
  1569. X        case LINK_REMOVE:
  1570. X        break;
  1571. X        }
  1572. X
  1573. X        /* check it went OK */
  1574. X        if (result == -1)
  1575. X        {
  1576. X        my_perror("error linking output file", linkname);
  1577. X        exit(1);
  1578. X        }
  1579. X        free(linkname);
  1580. X    }
  1581. X    }
  1582. X
  1583. X    safe_free(filename);
  1584. X}
  1585. !STUFFY!FUNK!
  1586. echo Extracting c2man.h
  1587. sed >c2man.h <<'!STUFFY!FUNK!' -e 's/X//'
  1588. X/* $Id: c2man.h,v 2.0.1.15 1994/01/07 07:04:30 greyham Exp $
  1589. X *
  1590. X * Definitions for C language manual page generator
  1591. X */
  1592. X#ifndef _C2MAN_H
  1593. X#define _C2MAN_H
  1594. X
  1595. X#include "config.h"
  1596. X#include "symbol.h"
  1597. X
  1598. X#ifdef I_SYS_TYPES
  1599. X#include <sys/types.h>
  1600. X#endif
  1601. X
  1602. X#ifdef I_STDLIB
  1603. X#include <stdlib.h>
  1604. X#endif
  1605. X
  1606. X#ifdef I_STRING
  1607. X#include <string.h>
  1608. X#else
  1609. X#include <strings.h>
  1610. X#endif
  1611. X
  1612. X#include <stdio.h>
  1613. X
  1614. X#ifdef I_UNISTD
  1615. X#include <unistd.h>
  1616. X#endif
  1617. X
  1618. X#ifdef I_STDDEF
  1619. X#include <stddef.h>
  1620. X#endif
  1621. X
  1622. X#ifdef I_TIME
  1623. X#include <time.h>
  1624. X#endif
  1625. X#ifdef I_SYS_TIME
  1626. X#include <sys/time.h>
  1627. X#endif
  1628. X
  1629. X#ifdef NeXT
  1630. X#include <libc.h>
  1631. X#undef ECHO    /* lex generates ECHO */
  1632. X#endif
  1633. X
  1634. X#ifdef DBMALLOC
  1635. X#include </usr/local/debug_include/malloc.h>
  1636. X#endif
  1637. X
  1638. X#include "confmagic.h"
  1639. X
  1640. X/* number of spaces in a tab */
  1641. X#define NUM_TAB_SPACES 4
  1642. X
  1643. X/* maximum include file nesting */
  1644. X#define MAX_INC_DEPTH 15
  1645. X
  1646. X/* maximum number of include directories */
  1647. X#define MAX_INC_DIR 15
  1648. X
  1649. X/* maximum number of characters in a text buffer */
  1650. X#define MAX_TEXT_LENGTH    256
  1651. X
  1652. X/* Boolean type */
  1653. Xtypedef int boolean;
  1654. X#ifndef TRUE
  1655. X#define FALSE    0
  1656. X#define TRUE    1
  1657. X#endif
  1658. X
  1659. X/* NULL char *, useful for passing NULL to functions wanting a char * */
  1660. X#define NULLCP    ((char *)0)
  1661. X
  1662. X/* This is a list of function parameters. */
  1663. Xtypedef struct _parameter_list {
  1664. X    struct _parameter    *first;    /* pointer to first parameter in list */
  1665. X    struct _parameter    *last;  /* pointer to last parameter in list */  
  1666. X} ParameterList;
  1667. X
  1668. X/* Declaration specifier flags */
  1669. X#define DS_NONE     0    /* default */
  1670. X#define DS_EXTERN    1    /* contains "extern" specifier */
  1671. X#define DS_STATIC    2    /* contains "static" specifier */
  1672. X#define DS_CHAR     4    /* contains "char" type specifier */
  1673. X#define DS_SHORT    8    /* contains "short" type specifier */
  1674. X#define DS_FLOAT    16    /* contains "float" type specifier */
  1675. X#define DS_JUNK     32    /* we're not interested in this declaration */
  1676. X#define DS_INLINE    64    /* makes static look interesting */
  1677. X
  1678. X/* This structure stores information about a declaration specifier. */
  1679. Xtypedef struct _decl_spec {
  1680. X    unsigned short    flags;    /* flags defined above */
  1681. X    char        *text;    /* source text */
  1682. X    struct _enumerator_list *enum_list;    /* associated enum (if any) */
  1683. X} DeclSpec;
  1684. X
  1685. X/* Styles of declaration/definition */
  1686. Xtypedef enum {
  1687. X    DECL_SIMPLE,    /* simple declaration */
  1688. X    DECL_COMPOUND,    /* compound declaration */
  1689. X    DECL_FUNCTION,    /* function declaration (prototype) */
  1690. X    DECL_FUNCDEF    /* an actual function definition */
  1691. X} DeclType;
  1692. X
  1693. X/* This structure stores information about a declarator. */
  1694. Xtypedef struct _declarator {
  1695. X    char        *name;        /* name of variable or function */
  1696. X    char        *text;        /* source text */
  1697. X    DeclType        type;        /* style of function declaration */
  1698. X    ParameterList    params;        /* function parameters */
  1699. X    char         *comment;    /* description of param or variable */
  1700. X    struct _declarator     *head;        /* head function declarator */
  1701. X    struct _declarator     *func_stack;    /* stack of function declarators */
  1702. X    struct _declarator    *next;        /* next declarator in list */
  1703. X} Declarator;
  1704. X
  1705. X/* This is a list of declarators. */
  1706. Xtypedef struct _declarator_list {
  1707. X    Declarator        *first;    /* pointer to first declarator in list */
  1708. X    Declarator        *last;  /* pointer to last declarator in list */  
  1709. X} DeclaratorList;
  1710. X
  1711. X/* This structure stores information about a declaration. */
  1712. Xtypedef struct _declaration {
  1713. X    DeclSpec        decl_spec;
  1714. X    DeclaratorList    decl_list;
  1715. X} Declaration;
  1716. X
  1717. X/* this structure store information about an enumerator */
  1718. Xtypedef struct _enumerator {
  1719. X    char *name;            /* name of enum entry */
  1720. X    char *comment;        /* description of entry */
  1721. X    char *group_comment;    /* general descr. for next few enums in list */
  1722. X    struct _enumerator *next;    /* next enumerator in list */
  1723. X} Enumerator;
  1724. X
  1725. X/* This is a list of enumerators. */
  1726. Xtypedef struct _enumerator_list {
  1727. X    Enumerator        *first;    /* pointer to first enumerator in list */
  1728. X    Enumerator        *last;  /* pointer to last enumerator in list */
  1729. X    struct _enumerator_list *next;    /* next list in a list-of-lists */
  1730. X} EnumeratorList;
  1731. X
  1732. X
  1733. X/* This structure stores information about a function parameter. */
  1734. Xtypedef struct _parameter {
  1735. X    DeclSpec        decl_spec;
  1736. X    Declarator        *declarator;
  1737. X    boolean        suppress;    /* don't print in grouped page */
  1738. X    boolean        duplicate;    /* mention fn in grouped page */
  1739. X    struct _parameter    *next;        /* next parameter in list */
  1740. X} Parameter;
  1741. X
  1742. X/* this is an identifier, with surrounding comments (if any) */
  1743. Xtypedef struct _identifier {
  1744. X    char *name;
  1745. X    char *comment_before, *comment_after;
  1746. X} Identifier;
  1747. X
  1748. X/* parser stack entry type */
  1749. Xtypedef union {
  1750. X    char        *text;
  1751. X    DeclSpec        decl_spec;
  1752. X    Parameter        parameter;
  1753. X    ParameterList    param_list;
  1754. X    Declarator        *declarator;
  1755. X    DeclaratorList    decl_list;
  1756. X    Declaration        declaration;
  1757. X    Enumerator        enumerator;
  1758. X    EnumeratorList    *enum_list;
  1759. X    Identifier        identifier;
  1760. X    boolean        boolean;
  1761. X} yystype;
  1762. X
  1763. X/* include files specified by user */
  1764. Xtypedef struct _includefile
  1765. X{
  1766. X    char *name;
  1767. X    struct _includefile *next;
  1768. X} IncludeFile;
  1769. X
  1770. X/* output object types */
  1771. Xenum Output_Object
  1772. X{
  1773. X#if 0    /* C++ stuff */
  1774. X    OBJECT_CLASS,
  1775. X    OBJECT_STRUCT,
  1776. X    OBJECT_ENUM,
  1777. X    OBJECT_TYPEDEF,
  1778. X#endif
  1779. X    OBJECT_FUNCTION,
  1780. X    OBJECT_VARIABLE,
  1781. X    OBJECT_STATIC_FUNCTION,
  1782. X    OBJECT_STATIC_VARIABLE,
  1783. X    _OBJECT_NUM
  1784. X};
  1785. X
  1786. Xstruct Output_Object_Info
  1787. X{
  1788. X    char flag;        /* -O flag used to set it */
  1789. X    char *name;        /* descriptive name for usage() */
  1790. X    char *extension;    /* file extension */
  1791. X    char *subdir;    /* subdirectory */
  1792. X};
  1793. X
  1794. X#define YYSTYPE yystype
  1795. X
  1796. X/* Program options */
  1797. Xextern boolean static_out;
  1798. Xextern boolean variables_out;
  1799. Xextern boolean promote_param;
  1800. Xextern const char *decl_spec_prefix, *declarator_prefix, *declarator_suffix;
  1801. Xextern const char *first_param_prefix, *middle_param_prefix, *last_param_suffix;
  1802. Xextern int num_inc_dir;
  1803. Xextern const char *inc_dir[];
  1804. Xextern char *manual_name;
  1805. Xextern const char *progname;
  1806. Xextern char *header_prefix;
  1807. Xextern IncludeFile *first_include;
  1808. X
  1809. Xextern char *group_terse;
  1810. Xextern boolean group_together;
  1811. Xextern boolean terse_specified;
  1812. Xextern boolean always_document_params;
  1813. X
  1814. Xextern char *output_dir;
  1815. X
  1816. X/* Global declarations */
  1817. Xextern int line_num;
  1818. Xextern const char *basefile;
  1819. Xextern Time_t basetime;
  1820. Xextern boolean inbasefile;
  1821. Xextern boolean header_file;
  1822. Xextern SymbolTable *typedef_names;
  1823. Xextern void output_error();
  1824. Xextern void parse_file _((const char *start_file));
  1825. Xextern int errors;
  1826. Xextern const char *manual_section;
  1827. Xextern boolean use_input_name;
  1828. Xextern boolean make_embeddable;
  1829. Xextern struct Output_Object_Info output_object[_OBJECT_NUM];
  1830. X
  1831. X/* Output a string to standard output. */
  1832. X#define put_string(s)    fputs(s, stdout)
  1833. X
  1834. X/* a malloc that handles errors, and a free that handles NULL */
  1835. X#ifndef DBMALLOC
  1836. Xvoid *safe_malloc _((size_t size));
  1837. X#else
  1838. X/* use macro so dbmalloc tells us where safe_malloc is called from */
  1839. X#define safe_malloc(s)    malloc(s)
  1840. X#endif
  1841. X#define safe_free(p)    do { if (p) free(p); } while(0)
  1842. X
  1843. Xvoid outmem();
  1844. Xvoid print_includes _((FILE *f));/* write #include lines */
  1845. X
  1846. Xvoid yyerror _V((const char *fmt, ...));
  1847. X
  1848. Xchar *strduplicate _((const char *s));
  1849. Xint strncmpi _((const char *s1, const char *s2, size_t n));
  1850. Xchar *strtoupper _((char *s));
  1851. X
  1852. Xvoid my_perror _((const char *action, const char *filename));
  1853. X
  1854. Xchar *alloc_string _((const char *start, const char *end));
  1855. X
  1856. X#endif
  1857. !STUFFY!FUNK!
  1858. echo Extracting eg/namedash.h
  1859. sed >eg/namedash.h <<'!STUFFY!FUNK!' -e 's/X//'
  1860. X/*
  1861. X * NAME
  1862. X *    namedash - name section with dash.
  1863. X *
  1864. X * DESCRIPTION
  1865. X *    This function goes way over the top and includes a NAME section that
  1866. X *    has a dash in it.
  1867. X */
  1868. Xint namedash();
  1869. !STUFFY!FUNK!
  1870. echo "End of kit 1 (of 9)"
  1871. echo " "
  1872. cat /dev/null >kit1isdone
  1873. run=''
  1874. config=''
  1875. for iskit in 1 2 3 4 5 6 7 8 9; do
  1876.     if test -f kit${iskit}isdone; then
  1877.         run="$run $iskit"
  1878.     else
  1879.         todo="$todo $iskit"
  1880.     fi
  1881. done
  1882. case $todo in
  1883.     '')
  1884.         echo "You have run all your kits."
  1885.         if test -f PACKNOTES; then
  1886.             sh PACKNOTES
  1887.         else
  1888.             echo "You have to rebuild split files by hand (see PACKLIST)."
  1889.         fi
  1890.         echo "Please read README and then type Configure."
  1891.         chmod 755 Configure
  1892.         rm -f kit*isdone
  1893.         ;;
  1894.     *)  echo "You have run$run."
  1895.         echo "You still need to run$todo."
  1896.         ;;
  1897. esac
  1898. : Someone might mail this, so exit before signature...
  1899. exit 0
  1900. -- 
  1901. Graham Stoney, Hardware/Software Engineer
  1902. Canon Information Systems Research Australia
  1903. Ph: + 61 2 805 2909    Fax: + 61 2 805 2929
  1904.  
  1905. exit 0 # Just in case...
  1906.