home *** CD-ROM | disk | FTP | other *** search
/ Usenet 1994 October / usenetsourcesnewsgroupsinfomagicoctober1994disk2.iso / misc / volume16 / mkptypes / part01 next >
Internet Message Format  |  1991-02-06  |  32KB

  1. From: ersmith@uwovax.bitnet (Eric R. Smith)
  2. Newsgroups: comp.sources.misc
  3. Subject: v16i090:  mkptypes - Generate prototype declarations for C, Part01/01
  4. Message-ID: <1991Feb3.204131.28866@sparky.IMD.Sterling.COM>
  5. Date: 3 Feb 91 20:41:31 GMT
  6. Approved: kent@sparky.imd.sterling.com
  7. X-Checksum-Snefru: bf556370 9a2818ed 9f5e677b 1ced0392
  8.  
  9. Submitted-by: ersmith@uwovax.bitnet (Eric R. Smith)
  10. Posting-number: Volume 16, Issue 90
  11. Archive-name: mkptypes/part01
  12.  
  13. Here is mkptypes, a program for generating prototype declarations for
  14. all functions appearing in a C source file. The output declarations
  15. are enclosed in a macro so as to be usable by either an ANSI or an
  16. older C compiler. Typical usage would be to do 'mkptypes *.c >proto.h'
  17. and then have a '#include "proto.h"' line in the relevant C source
  18. code files. See the README file for more details.
  19.  
  20. An earlier version of this program was released on comp.sources.misc
  21. under the name "mkproto"; this updated version (with new command line
  22. options and several bug fixes) was renamed to avoid conflict with a
  23. file system utility available on some versions of Unix.
  24.  
  25. The source will probably compile as-is on most systems, providing you
  26. edit the makefile appropriately (the default is for my configuration,
  27. an Atari ST with gcc).
  28.  
  29. Eric R. Smith
  30. eric.smith@uwo.ca
  31. ersmith@uwovax.bitnet
  32.  
  33. #    This is a shell archive.
  34. #    Remove everything above and including the cut line.
  35. #    Then run the rest of the file through sh.
  36. #----cut here-----cut here-----cut here-----cut here----#
  37. #!/bin/sh
  38. # shar:    Shell Archiver
  39. #    Run the following text with /bin/sh to create:
  40. #    README
  41. #    Manifest
  42. #    Makefile
  43. #    mkptypes.1
  44. #    mkptypes.c
  45. #    mkptypes.h
  46. #    mkptypes.man
  47. # This archive created: 21 January 1991 12:16:52 PM EST
  48. # By:    eric (at home)
  49. echo shar: extracting README
  50. sed 's/^X//' << \SHAR_EOF > README
  51. XHere is mkptypes, a program for generating prototype declarations for all
  52. Xfunctions appearing in a C source file. The input C code may be either
  53. XK&R or ANSI C (i.e. it's OK if the functions are defined using prototypes).
  54. XUnlike some of the sed-based scripts floating around, it (usually)
  55. Xhandles prototype promotion (e.g. the prototype for 'int foo() char x;...'
  56. Xis 'int foo(int x)'). Also, it should work OK on just about any computer,
  57. Xnot just Unix-based ones (it's been tested under minix, Unix, and TOS).
  58. X
  59. XUse: typically, you would type 'mkptypes *.c >proto.h' and then add a
  60. X'#include "proto.h"' line to all the C source files. An ANSI conformant
  61. Xcompiler will then be able to do type checking on function calls across
  62. Xmodule boundaries. As a bonus, proto.h will tell you which source files
  63. Xfunctions were defined in, and (if you gave the -n function to mkptypes)
  64. Xtheir line numbers. The resulting include file may also be used by
  65. Xnon-ANSI compilers; you can disable this feature (for cleaner, strictly
  66. XANSI-conforming output) with the -A flag. See the mkptypes.man file for
  67. Xa description of all the flags mkptypes accepts.
  68. X
  69. XPlease read the description of bugs in mkptypes.man; definitely mkptypes
  70. Xwill not handle all programs correctly, but it does work on the majority of
  71. Xthem. A sample of its output is provided in the file "mkptypes.h"; this
  72. Xis the result of 'mkptypes mkptypes.c >mkptypes.h'.
  73. X
  74. XThere is ABSOLUTELY NO WARRANTY for the program; as I said, it doesn't work
  75. Xon all programs (complicated function definitions can make it produce bogus
  76. Xoutput). It does what I need, though, and it can certainly make porting stuff
  77. Xto ANSI compilers easier.
  78. X
  79. XAn earlier version of mkptypes was released on Usenet under the name
  80. X"mkproto". This version has several new command line options, and some bug
  81. Xfixes. It has been renamed to avoid conflict with a file system utility
  82. Xavailable under some versions of Unix.
  83. X
  84. XMkptypes is in the public domain. If you find any bugs (other than the ones
  85. Xdocumented) please let me know.
  86. X--
  87. XEric R. Smith                     email:
  88. XDept. of Mathematics            ersmith@uwovax.uwo.ca
  89. XUniversity of Western Ontario   ersmith@uwovax.bitnet
  90. XLondon, Ont. Canada N6A 5B7
  91. Xph: (519) 661-3638
  92. SHAR_EOF
  93. if test 2224 -ne "`wc -c README`"
  94. then
  95. echo shar: error transmitting README '(should have been 2224 characters)'
  96. fi
  97. echo shar: extracting Manifest
  98. sed 's/^X//' << \SHAR_EOF > Manifest
  99. XMakefile:    makefile for mkptypes. Default configuration is for Atari ST.
  100. XManifest:    this file
  101. Xmkptypes.1:    Unix manual page for mkptypes
  102. Xmkptypes.c:    source code for mkptypes
  103. Xmkptypes.h:    prototypes for mkptypes (generated by mkptypes, too)
  104. Xmkptypes.man:    text version of mkptypes.1
  105. XREADME:        do what it says
  106. SHAR_EOF
  107. if test 302 -ne "`wc -c Manifest`"
  108. then
  109. echo shar: error transmitting Manifest '(should have been 302 characters)'
  110. fi
  111. echo shar: extracting Makefile
  112. sed 's/^X//' << \SHAR_EOF > Makefile
  113. X#
  114. X# Makefile for mkptypes. Edit the lines below to suit your tastes; the default
  115. X# is for my computer (Atari ST running the gcc 1.37); a Unix configuration is
  116. X# also provided.
  117. X
  118. X#CC = cc
  119. X#PROG = mkptypes
  120. X#CFLAGS = -O
  121. X
  122. XCC = gcc
  123. XPROG = mkptypes.ttp
  124. XCFLAGS = -mshort -O
  125. X
  126. X$(PROG) : mkptypes.c mkptypes.h
  127. X    $(CC) $(CFLAGS) -o $(PROG) mkptypes.c
  128. X
  129. Xclean:
  130. X    rm -f mkptypes.o
  131. X
  132. Xrealclean: clean
  133. X    rm -f $(PROG) report core
  134. SHAR_EOF
  135. if test 409 -ne "`wc -c Makefile`"
  136. then
  137. echo shar: error transmitting Makefile '(should have been 409 characters)'
  138. fi
  139. echo shar: extracting mkptypes.1
  140. sed 's/^X//' << \SHAR_EOF > mkptypes.1
  141. X.TH MKPTYPES 1
  142. X.SH NAME
  143. Xmkptypes \- make prototypes for functions
  144. X.SH SYNOPSIS
  145. X.B mkptypes
  146. X[
  147. X.B -e
  148. X] [
  149. X.B -n
  150. X] [
  151. X.B -p
  152. X.I symbol
  153. X] [
  154. X.B -s
  155. X] [
  156. X.B -x
  157. X] [
  158. X.B -z
  159. X] [
  160. X.B -A
  161. X] [
  162. X.I file ...
  163. X]
  164. X.SH DESCRIPTION
  165. X.I Mkptypes
  166. Xtakes as input one or more C source code files, and
  167. Xproduces as output (on the standard output stream) a list of function
  168. Xprototypes (a la ANSI) for the external functions defined in the
  169. Xgiven source files. This output, redirected to a file, is suitable
  170. Xfor #include'ing in a C source file.
  171. X.PP
  172. XThe function definitions in the original source
  173. Xmay be either ``old-style'' (in which case appropriate prototypes are
  174. Xgenerated for the functions) or ``new-style'' (in which the definition
  175. Xincludes a prototype already).
  176. X.PP
  177. XThe -e option causes the ``extern'' keyword to be explicitly printed
  178. Xfor external functions. Some non-ANSI compilers may need this.
  179. X.PP
  180. XThe -n option causes the line number where each function was defined
  181. Xto be prepended to the prototype declaration as a comment.
  182. X.PP
  183. XThe -p option controls the name of the macro used to guard prototype
  184. Xdefinitions. Normally this is ``_P'', but you can change it to any string
  185. Xyou like. To eliminate the guard macro entirely, use the -A option.
  186. X.PP
  187. XThe -s option causes prototypes to be generated for functions declared
  188. X``static'' as well as extern functions.
  189. X.PP
  190. XThe -x option causes parameter names to be omitted from the output
  191. Xprototypes. This may be necessary for some brain-damaged pseudo-ANSI
  192. Xcompilers. You may also prefer this style of output. This option has not
  193. Xbeen thoroughly tested.
  194. X.PP
  195. XThe -z option suppresses the definition of the prototype macro given by
  196. X-p. Header files generated by
  197. X.I mkptypes
  198. Xwith this option will not work unless the prototype macro has been defined
  199. Xelsewhere in the program by the user. Used with the -p option, the -z
  200. Xoption allows use of predefined prototype hiding macros that may exist
  201. Xon some systems.
  202. X.PP
  203. XThe -A option causes the prototypes emitted to be only readable by ANSI
  204. Xcompilers. Normally, the prototypes are "macro-ized" so that compilers
  205. Xwith __STDC__ not defined don't see them.
  206. X.PP
  207. XIf files are specified on the command line, then a comment specifying
  208. Xthe file of origin is emitted before the prototypes constructed from
  209. Xthat file. If no files are given, then no comments are emitted and
  210. Xthe C source code is taken from the standard input stream.
  211. X.SH BUGS
  212. XMkptypes is easily confused by complicated declarations, such as
  213. X.nf
  214. X         int ((*signal)())() { ...
  215. X.fi
  216. Xor
  217. X.nf
  218. X         struct foo { int x, y; } foofunc() { ...
  219. X.fi
  220. XThis is because the program doesn't actually understand type definitions.
  221. X.PP
  222. XSome programs may need to be run through the preprocessor before
  223. Xbeing run through
  224. X.I mkptypes .
  225. XThe -n option will not work correctly on preprocessor output if function
  226. Xdefinitions (as opposed to declarations) appear in header files.
  227. X.PP
  228. XTypedef'd types aren't correctly promoted, e.g. for
  229. X.nf
  230. X        typedef schar char; int foo(x) schar x;...
  231. X.fi
  232. X.I mkptypes
  233. Xincorrectly generates the prototype int foo(schar x) rather than the
  234. X[correct] int foo(int x).
  235. X.PP
  236. XFunctions named "inline" with no explicit type qualifiers are not
  237. Xrecognized.
  238. X.SH SEE ALSO
  239. X.I cc
  240. X(1),
  241. X.I lint
  242. X(1).
  243. X.SH AUTHOR
  244. XEric R. Smith <ersmith@uwovax.uwo.ca>
  245. X.SH NOTE
  246. XThere is no warranty for this program (as noted above, it's guaranteed
  247. Xto break sometimes anyways!). Mkptypes is in the public domain.
  248. SHAR_EOF
  249. if test 3399 -ne "`wc -c mkptypes.1`"
  250. then
  251. echo shar: error transmitting mkptypes.1 '(should have been 3399 characters)'
  252. fi
  253. echo shar: extracting mkptypes.c
  254. sed 's/^X//' << \SHAR_EOF > mkptypes.c
  255. X/* Program to extract function declarations from C source code
  256. X * Written by Eric R. Smith and placed in the public domain
  257. X * Thanks to:
  258. X * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles
  259. X * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix
  260. X *   manual page, and some ANSI and C++ improvements.
  261. X * Skip Gilbrech for code to skip parameter names in prototypes.
  262. X * ... and many others for helpful comments and suggestions.
  263. X */
  264. X
  265. X/* if your compiler claims to be ANSI but doesn't have stddef.h or stdlib.h,
  266. X * change the next line.
  267. X * (and then complain to the supplier of the defective compiler)
  268. X */
  269. X
  270. X#if defined(__STDC__) && !defined(minix)
  271. X#include <stddef.h>
  272. X#include <stdlib.h>
  273. X#else
  274. Xextern char *malloc();
  275. Xextern long atol();
  276. X#endif
  277. X
  278. X#ifndef EXIT_SUCCESS
  279. X#define EXIT_SUCCESS  0
  280. X#define EXIT_FAILURE  1
  281. X#endif
  282. X
  283. X#include <stdio.h>
  284. X#include <ctype.h>
  285. X#include <string.h>
  286. X
  287. X/*#define DEBUG(s) (fputs(s, stderr)) /* */
  288. X#define DEBUG(s) /* */
  289. X
  290. X#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
  291. X#define ABORTED ( (Word *) -1 )
  292. X#define MAXPARAM 20         /* max. number of parameters to a function */
  293. X#define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
  294. X
  295. Xint dostatic = 0;        /* do static functions? */
  296. Xint donum    = 0;        /* print line numbers? */
  297. Xint define_macro   = 1;        /* define macro for prototypes? */
  298. Xint use_macro   = 1;        /* use a macro for prototypes? */
  299. Xchar *macro_name = "_P";    /*   macro to use for prototypes */
  300. Xint no_parm_names = 0;        /* no parm names - only types */
  301. Xint print_extern = 0;        /* use "extern" before function declarations */
  302. X#ifdef CPP
  303. Xint call_cpp = 0;        /* preprocess files */
  304. X#endif
  305. X
  306. Xchar *ourname;            /* our name, from argv[] array */
  307. Xint inquote = 0;        /* in a quote?? */
  308. Xint newline_seen = 1;        /* are we at the start of a line */
  309. Xlong linenum  = 1L;        /* line number in current file */
  310. Xint glastc   = ' ';        /* last char. seen by getsym() */
  311. X
  312. Xtypedef struct word {
  313. X    struct word *next;
  314. X    char   string[1];
  315. X} Word;
  316. X
  317. X#include "mkptypes.h"
  318. X
  319. X/*
  320. X * Routines for manipulating lists of words.
  321. X */
  322. X
  323. XWord *word_alloc(s)
  324. X    char *s;
  325. X{
  326. X    Word *w;
  327. X
  328. X/* note that sizeof(Word) already contains space for a terminating null
  329. X * however, we add 1 so that typefixhack can promote "float" to "double"
  330. X *  by just doing a strcpy.
  331. X */
  332. X    w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
  333. X    strcpy(w->string, s);
  334. X    w->next = NULL;
  335. X    return w;
  336. X}
  337. X
  338. Xvoid word_free(w)
  339. X    Word *w;
  340. X{
  341. X    Word *oldw;
  342. X    while (w) {
  343. X        oldw = w;
  344. X        w = w->next;
  345. X        free(oldw);
  346. X    }
  347. X}
  348. X
  349. X/* return the length of a list; empty words are not counted */
  350. Xint
  351. XList_len(w)
  352. X    Word *w;
  353. X{
  354. X    int count = 0;
  355. X
  356. X    while (w) {
  357. X        if (*w->string) count++;
  358. X        w = w->next;
  359. X    }
  360. X    return count;
  361. X}
  362. X
  363. X/* Append two lists, and return the result */
  364. X
  365. XWord *word_append(w1, w2)
  366. X    Word *w1, *w2;
  367. X{
  368. X    Word *r, *w;
  369. X
  370. X    r = w = word_alloc("");
  371. X
  372. X    while (w1) {
  373. X        w->next = word_alloc(w1->string);
  374. X        w = w->next;
  375. X        w1 = w1->next;
  376. X    }
  377. X    while (w2) {
  378. X        w->next = word_alloc(w2->string);
  379. X        w = w->next;
  380. X        w2 = w2->next;
  381. X    }
  382. X
  383. X    return r;
  384. X}
  385. X    
  386. X/* see if the last entry in w2 is in w1 */
  387. X
  388. Xint
  389. Xfoundin(w1, w2)
  390. X    Word *w1, *w2;
  391. X{
  392. X    while (w2->next)
  393. X        w2 = w2->next;
  394. X
  395. X    while (w1) {
  396. X        if (!strcmp(w1->string, w2->string))
  397. X            return 1;
  398. X        w1 = w1->next;
  399. X    }
  400. X    return 0;
  401. X}
  402. X
  403. X/* add the string s to the given list of words */
  404. X
  405. Xvoid addword(w, s)
  406. X    Word *w; char *s;
  407. X{
  408. X    while (w->next) w = w->next;
  409. X    w->next = word_alloc(s);
  410. X}
  411. X
  412. X/* typefixhack: promote formal parameters of type "char", "unsigned char",
  413. X   "short", or "unsigned short" to "int".
  414. X*/
  415. X
  416. Xvoid typefixhack(w)
  417. X    Word *w;
  418. X{
  419. X    Word *oldw = 0;
  420. X
  421. X    while (w) {
  422. X        if (*w->string) {
  423. X            if ( (!strcmp(w->string, "char") ||
  424. X                  !strcmp(w->string, "short") )
  425. X                && (List_len(w->next) < 2) )
  426. X            {
  427. X/* delete any "unsigned" specifier present -- yes, it's supposed to do this */
  428. X                if (oldw && !strcmp(oldw->string, "unsigned")) {
  429. X                    oldw->next = w->next;
  430. X                    free(w);
  431. X                    w = oldw;
  432. X                }
  433. X                strcpy(w->string, "int");
  434. X            }
  435. X            else if ( !strcmp(w->string, "float") &&
  436. X                  List_len(w->next) < 2 )
  437. X            {
  438. X                strcpy(w->string, "double");
  439. X            }
  440. X        }
  441. X        w = w->next;
  442. X    }
  443. X}
  444. X
  445. X/* read a character: if it's a newline, increment the line count */
  446. X
  447. X#ifdef __GNUC__    /* ++jrb */
  448. Xinline
  449. X#endif
  450. Xint ngetc(f)
  451. X    FILE *f;
  452. X{
  453. X    int c;
  454. X
  455. X    c = getc(f);
  456. X    if (c == '\n') linenum++;
  457. X
  458. X    return c;
  459. X}
  460. X
  461. X/* read the next character from the file. If the character is '\' then
  462. X * read and skip the next character. Any comment sequence is converted
  463. X * to a blank.
  464. X */
  465. X
  466. Xint fnextch(f)
  467. X    FILE *f;
  468. X{
  469. X    int c, lastc, incomment;
  470. X
  471. X    c = ngetc(f);
  472. X    while (c == '\\') {
  473. XDEBUG("fnextch: in backslash loop\n");
  474. X        c = ngetc(f);    /* skip a character */
  475. X        c = ngetc(f);
  476. X    }
  477. X    if (c == '/' && !inquote) {
  478. X        c = ngetc(f);
  479. X        if (c == '*') {
  480. X            incomment = 1;
  481. X            c = ' ';
  482. XDEBUG("fnextch: comment seen\n");
  483. X            while (incomment) {
  484. X                lastc = c;
  485. X                c = ngetc(f);
  486. X                if (lastc == '*' && c == '/')
  487. X                    incomment = 0;
  488. X                else if (c < 0)
  489. X                    return c;
  490. X            }
  491. X            return fnextch(f);
  492. X        }
  493. X        else {
  494. X/* if we pre-fetched a linefeed, remember to adjust the line number */
  495. X            if (c == '\n') linenum--;
  496. X            ungetc(c, f);
  497. X            return '/';
  498. X        }
  499. X    }
  500. X    return c;
  501. X}
  502. X
  503. X
  504. X/* Get the next "interesting" character. Comments are skipped, and strings
  505. X * are converted to "0". Also, if a line starts with "#" it is skipped.
  506. X */
  507. X
  508. Xint nextch(f)
  509. X    FILE *f;
  510. X{
  511. X    int c, n;
  512. X    char *p, numbuf[10];
  513. X
  514. X    c = fnextch(f);
  515. X
  516. X/* skip preprocessor directives */
  517. X/* EXCEPTION: #line nnn or #nnn lines are interpreted */
  518. X
  519. X    if (newline_seen && c == '#') {
  520. X/* skip blanks */
  521. X        do {
  522. X            c = fnextch(f);
  523. X        } while ( c >= 0 && (c == '\t' || c == ' ') );
  524. X/* check for #line */
  525. X        if (c == 'l') {
  526. X            c = fnextch(f);
  527. X            if (c != 'i')    /* not a #line directive */
  528. X                goto skip_rest_of_line;
  529. X            do {
  530. X                c = fnextch(f);
  531. X            } while (c >= 0 && c != '\n' && !isdigit(c));
  532. X        }
  533. X
  534. X/* if we have a digit it's a line number, from the preprocessor */
  535. X        if (c >= 0 && isdigit(c)) {
  536. X            p = numbuf;
  537. X            for (n = 8; n >= 0; --n) {
  538. X                *p++ = c;
  539. X                c = fnextch(f);
  540. X                if (c <= 0 || !isdigit(c))
  541. X                    break;
  542. X            }
  543. X            *p = 0;
  544. X            linenum = atol(numbuf) - 1;
  545. X        }
  546. X
  547. X/* skip the rest of the line */
  548. Xskip_rest_of_line:
  549. X        while (c >= 0 && c != '\n')
  550. X            c = fnextch(f);
  551. X        if (c < 0)
  552. X            return c;
  553. X    }
  554. X    newline_seen = (c == '\n');
  555. X
  556. X    if (c == '\'' || c == '\"') {
  557. XDEBUG("nextch: in a quote\n");
  558. X        inquote = c;
  559. X        while ( (c = fnextch(f)) >= 0 ) {
  560. X            if (c == inquote) {
  561. X                inquote = 0;
  562. XDEBUG("nextch: out of quote\n");
  563. X                return '0';
  564. X            }
  565. X        }
  566. XDEBUG("nextch: EOF in a quote\n");
  567. X    }
  568. X    return c;
  569. X}
  570. X
  571. X/*
  572. X * Get the next symbol from the file, skipping blanks.
  573. X * Return 0 if OK, -1 for EOF.
  574. X * Also collapses everything between { and }
  575. X */
  576. X
  577. Xint
  578. Xgetsym(buf, f)
  579. X    char *buf; FILE *f;
  580. X{
  581. X    register int c;
  582. X    int inbrack = 0;
  583. X
  584. XDEBUG("in getsym\n");
  585. X    c = glastc;
  586. X    while ((c > 0) && isspace(c)) {
  587. X        c = nextch(f);
  588. X    }
  589. XDEBUG("getsym: spaces skipped\n");
  590. X    if (c < 0) {
  591. XDEBUG("EOF read in getsym\n");
  592. X        return -1;
  593. X    }
  594. X    if (c == '{') {
  595. X        inbrack = 1;
  596. XDEBUG("getsym: in bracket\n");
  597. X        while (inbrack) {
  598. X            c = nextch(f);
  599. X            if (c < 0) {
  600. XDEBUG("getsym: EOF seen in bracket loop\n");
  601. X                glastc = c;
  602. X                return c;
  603. X            }
  604. X            if (c == '{') inbrack++;
  605. X            else if (c == '}') inbrack--;
  606. X        }
  607. X        strcpy(buf, "{}");
  608. X        glastc = nextch(f);
  609. XDEBUG("getsym: out of in bracket loop\n");
  610. X        return 0;
  611. X    }
  612. X    if (!ISCSYM(c)) {
  613. X        *buf++ = c;
  614. X        *buf = 0;
  615. X        glastc = nextch(f);
  616. XDEBUG("getsym: returning special symbol\n");
  617. X        return 0;
  618. X    }
  619. X    while (ISCSYM(c)) {
  620. X        *buf++ = c;
  621. X        c = nextch(f);
  622. X    }
  623. X    *buf = 0;
  624. X    glastc = c;
  625. XDEBUG("getsym: returning word\n");
  626. X    return 0;
  627. X}
  628. X
  629. X/*
  630. X * skipit: skip until a ";" or the end of a function declaration is seen
  631. X */
  632. Xint skipit(buf, f)
  633. X    char *buf;
  634. X    FILE *f;
  635. X{
  636. X    int i;
  637. X
  638. X    do {
  639. XDEBUG("in skipit loop\n");
  640. X        i = getsym(buf, f);
  641. X        if (i < 0) return i;
  642. X    } while (*buf != ';' && *buf != '{');
  643. X
  644. X    return 0;
  645. X}
  646. X
  647. X/*
  648. X * find most common type specifiers for purpose of ruling them out as
  649. X * parm names
  650. X */
  651. X
  652. Xint is_type_word(s)
  653. Xchar *s;
  654. X{
  655. X    static char *typewords[] = {
  656. X    "char",        "const",    "double",    "enum",
  657. X    "float",    "int",        "long",        "short",
  658. X    "signed",    "struct",    "union",    "unsigned",
  659. X    "void",        "volatile",    (char *)0
  660. X    };
  661. X
  662. X    register char **ss;
  663. X
  664. X    for (ss = typewords; *ss; ++ss)
  665. X    if (strcmp(s, *ss) == 0)
  666. X        return 1;
  667. X
  668. X    return 0;
  669. X}
  670. X
  671. X
  672. X/* Ad-hoc macro to recognize parameter name for purposes of removal.
  673. X * Idea is to remove the bulk of easily recognized parm names without
  674. X * losing too many type specifiers. (sg)
  675. X */
  676. X#define IS_PARM_NAME(w) \
  677. X    (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \
  678. X    (!(w)->next || *(w)->next->string == ',' || \
  679. X     *(w)->next->string == '['))
  680. X
  681. X
  682. X/*
  683. X * given a list representing a type and a variable name, extract just
  684. X * the base type, e.g. "struct word *x" would yield "struct word"
  685. X */
  686. X
  687. XWord *typelist(p)
  688. X    Word *p;
  689. X{
  690. X    Word *w, *r;
  691. X
  692. X    r = w = word_alloc("");
  693. X    while (p && p->next) {
  694. X/* handle int *x --> int */
  695. X        if (p->string[0] && !ISCSYM(p->string[0]))
  696. X            break;
  697. X/* handle int x[] --> int */
  698. X        if (p->next->string[0] == '[')
  699. X            break;
  700. X        w->next = word_alloc(p->string);
  701. X        w = w->next;
  702. X        p = p->next;
  703. X    }
  704. X    return r;
  705. X}
  706. X
  707. X/*
  708. X * Get a parameter list; when this is called the next symbol in line
  709. X * should be the first thing in the list.
  710. X */
  711. X
  712. XWord *getparamlist(f)
  713. X    FILE *f;
  714. X{
  715. X    static Word *pname[MAXPARAM]; /* parameter names */
  716. X    Word    *tlist,          /* type name */
  717. X        *plist;          /* temporary */
  718. X    int      np = 0;          /* number of parameters */
  719. X    int      typed[MAXPARAM];  /* parameter has been given a type */
  720. X    int    tlistdone;      /* finished finding the type name */
  721. X    int    sawsomething;
  722. X    int      i;
  723. X    int    inparen = 0;
  724. X    char buf[80];
  725. X
  726. XDEBUG("in getparamlist\n");
  727. X    for (i = 0; i < MAXPARAM; i++)
  728. X        typed[i] = 0;
  729. X
  730. X    plist = word_alloc("");
  731. X
  732. X/* first, get the stuff inside brackets (if anything) */
  733. X
  734. X    sawsomething = 0;    /* gets set nonzero when we see an arg */
  735. X    for (;;) {
  736. X        if (getsym(buf, f) < 0) return NULL;
  737. X        if (*buf == ')' && (--inparen < 0)) {
  738. X            if (sawsomething) {    /* if we've seen an arg */
  739. X                pname[np] = plist;
  740. X                plist = word_alloc("");
  741. X                np++;
  742. X            }
  743. X            break;
  744. X        }
  745. X        if (*buf == ';') {    /* something weird */
  746. X            return ABORTED;
  747. X        }
  748. X        sawsomething = 1;    /* there's something in the arg. list */
  749. X        if (*buf == ',' && inparen == 0) {
  750. X            pname[np] = plist;
  751. X            plist = word_alloc("");
  752. X            np++;
  753. X        }
  754. X        else {
  755. X            addword(plist, buf);
  756. X            if (*buf == '(') inparen++;
  757. X        }
  758. X    }
  759. X
  760. X/* next, get the declarations after the function header */
  761. X
  762. X    inparen = 0;
  763. X
  764. X    tlist = word_alloc("");
  765. X    plist = word_alloc("");
  766. X    tlistdone = 0;
  767. X    sawsomething = 0;
  768. X    for(;;) {
  769. X        if (getsym(buf, f) < 0) return NULL;
  770. X
  771. X/* handle a list like "int x,y,z" */
  772. X        if (*buf == ',' && !inparen) {
  773. X            if (!sawsomething)
  774. X                return NULL;
  775. X            for (i = 0; i < np; i++) {
  776. X                if (!typed[i] && foundin(plist, pname[i])) {
  777. X                    typed[i] = 1;
  778. X                    word_free(pname[i]);
  779. X                    pname[i] = word_append(tlist, plist);
  780. X                /* promote types */
  781. X                    typefixhack(pname[i]);
  782. X                    break;
  783. X                }
  784. X            }
  785. X            if (!tlistdone) {
  786. X                tlist = typelist(plist);
  787. X                tlistdone = 1;
  788. X            }
  789. X            word_free(plist);
  790. X            plist = word_alloc("");
  791. X        }
  792. X/* handle the end of a list */
  793. X        else if (*buf == ';') {
  794. X            if (!sawsomething)
  795. X                return ABORTED;
  796. X            for (i = 0; i < np; i++) {
  797. X                if (!typed[i] && foundin(plist, pname[i])) {
  798. X                    typed[i] = 1;
  799. X                    word_free(pname[i]);
  800. X                    pname[i] = word_append(tlist, plist);
  801. X                    typefixhack(pname[i]);
  802. X                    break;
  803. X                }
  804. X            }
  805. X            tlistdone = 0;
  806. X            word_free(tlist); word_free(plist);
  807. X            tlist = word_alloc("");
  808. X            plist = word_alloc("");
  809. X        }
  810. X/* handle the  beginning of the function */
  811. X        else if (!strcmp(buf, "{}")) break;
  812. X/* otherwise, throw the word into the list (except for "register") */
  813. X        else if (strcmp(buf, "register")) {
  814. X            sawsomething = 1;
  815. X            addword(plist, buf);
  816. X            if (*buf == '(') inparen++;
  817. X            if (*buf == ')') inparen--;
  818. X        }
  819. X    }
  820. X
  821. X/* Now take the info we have and build a prototype list */
  822. X
  823. X/* empty parameter list means "void" */
  824. X    if (np == 0)
  825. X        return word_alloc("void");
  826. X
  827. X    plist = tlist = word_alloc("");
  828. X    for (i = 0; i < np; i++) {
  829. X
  830. X/* If no type provided, make it an "int" */
  831. X        if ( !(pname[i]->next) ||
  832. X       (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
  833. X            addword(tlist, "int");
  834. X        }
  835. X        while (tlist->next) tlist = tlist->next;
  836. X        tlist->next = pname[i];
  837. X        if (i < np - 1)
  838. X            addword(tlist, ",");
  839. X    }
  840. X    return plist;
  841. X}
  842. X
  843. X/*
  844. X * emit a function declaration. The attributes and name of the function
  845. X * are in wlist; the parameters are in plist.
  846. X */
  847. X
  848. Xvoid emit(wlist, plist, startline)
  849. X    Word *wlist, *plist;
  850. X    long  startline;
  851. X{
  852. X    Word *w;
  853. X    int count = 0;
  854. X    int needspace = 0;
  855. X    int isstatic = 0;
  856. X
  857. XDEBUG("emit called\n");
  858. X    if (donum)
  859. X        printf("/*%8ld */ ", startline);
  860. X
  861. X    for (w = wlist; w; w = w->next) {
  862. X        if (w->string[0]) {
  863. X            count ++;
  864. X            if (!strcmp(w->string, "static"))
  865. X                isstatic = 1;
  866. X        }
  867. X    }
  868. X
  869. X/* if the -e flag was given, and it's not a static function, print "extern" */
  870. X
  871. X    if (print_extern && !isstatic) {
  872. X        printf("extern ");
  873. X    }
  874. X
  875. X    if (count < 2) {
  876. X        printf("int");
  877. X        needspace = 1;
  878. X    }
  879. X
  880. X    for (w = wlist; w; w = w->next) {
  881. X        if (needspace)
  882. X            putchar(' ');
  883. X        printf("%s", w->string);
  884. X        needspace = ISCSYM(w->string[0]);
  885. X    }
  886. X    if (use_macro)
  887. X        printf(" %s((", macro_name);
  888. X    else
  889. X        putchar('(');
  890. X    needspace = 0;
  891. X    for (w = plist; w; w = w->next) {
  892. X        if (no_parm_names && IS_PARM_NAME(w))
  893. X            continue;
  894. X        if (w->string[0] == ',')
  895. X            needspace = 1;
  896. X        else if (w->string[0] == '[')
  897. X            needspace = 0;
  898. X        else
  899. X        {
  900. X            if (needspace)
  901. X                putchar(' ');
  902. X            needspace = ISCSYM(w->string[0]);
  903. X        }
  904. X        printf("%s", w->string);
  905. X    }
  906. X    if (use_macro)
  907. X        printf("));\n");
  908. X    else
  909. X        printf(");\n");
  910. X}
  911. X
  912. X/*
  913. X * get all the function declarations
  914. X */
  915. X
  916. Xvoid getdecl(f)
  917. X    FILE *f;
  918. X{
  919. X    Word *plist, *wlist = NULL;
  920. X    char buf[80];
  921. X    int sawsomething;
  922. X    long startline;        /* line where declaration started */
  923. X    int oktoprint;
  924. Xagain:
  925. X    word_free(wlist);
  926. X    wlist = word_alloc("");
  927. X    sawsomething = 0;
  928. X    oktoprint = 1;
  929. X
  930. X    for(;;) {
  931. XDEBUG("main getdecl loop\n");
  932. X        if (getsym(buf,f) < 0) {
  933. XDEBUG("EOF in getdecl loop\n");
  934. X             return;
  935. X        }
  936. X/* try to guess when a declaration is not an external function definition */
  937. X        if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
  938. X            !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
  939. X            !strcmp(buf, "extern")) {
  940. X            skipit(buf, f);
  941. X            goto again;
  942. X        }
  943. X        if (!dostatic && !strcmp(buf, "static")) {
  944. X            oktoprint = 0;
  945. X        }
  946. X/* for the benefit of compilers that allow "inline" declarations */
  947. X        if (!strcmp(buf, "inline") && !sawsomething)
  948. X            continue;
  949. X        if (!strcmp(buf, ";")) goto again;
  950. X
  951. X/* A left parenthesis *might* indicate a function definition */
  952. X        if (!strcmp(buf, "(")) {
  953. X            startline = linenum;
  954. X            if (!sawsomething || !(plist = getparamlist(f))) {
  955. X                skipit(buf, f);
  956. X                goto again;
  957. X            }
  958. X            if (plist == ABORTED)
  959. X                goto again;
  960. X
  961. X/* It seems to have been what we wanted */
  962. X            if (oktoprint)
  963. X                emit(wlist, plist, startline);
  964. X            word_free(plist);
  965. X            goto again;
  966. X        }
  967. X        addword(wlist, buf);
  968. X        sawsomething = 1;
  969. X    }
  970. X}
  971. X
  972. Xvoid
  973. Xmain(argc, argv)
  974. Xint argc; char **argv;
  975. X{
  976. X    FILE *f;
  977. X    char *t, *iobuf;
  978. X    extern void Usage();
  979. X
  980. X    if (argv[0] && argv[0][0])
  981. X        ourname = argv[0];
  982. X    else
  983. X        ourname = "mkptypes";
  984. X
  985. X    argv++; argc--;
  986. X
  987. X    if (argc < 0)        /* strange -- no args at all */
  988. X        Usage();
  989. X
  990. X    iobuf = malloc(NEWBUFSIZ);
  991. X    while (*argv && **argv == '-') {
  992. X        t = *argv++; --argc; t++;
  993. X        while (*t) {
  994. X            if (*t == 'e')
  995. X                print_extern = 1;
  996. X            else if (*t == 'n')
  997. X                donum = 1;
  998. X            else if (*t == 'p') {
  999. X                t = *argv++; --argc;
  1000. X                if (!t)
  1001. X                    Usage();
  1002. X                use_macro = 1;
  1003. X                macro_name = t;
  1004. X                break;
  1005. X            }
  1006. X            else if (*t == 's')
  1007. X                dostatic = 1;
  1008. X            else if (*t == 'x')
  1009. X                /* no parm names, only types (sg) */
  1010. X                no_parm_names = 1;
  1011. X            else if (*t == 'z')
  1012. X                define_macro = 0;
  1013. X            else if (*t == 'A')
  1014. X                use_macro = 0;
  1015. X            else
  1016. X                Usage();
  1017. X            t++;
  1018. X        }
  1019. X    }
  1020. X
  1021. X    if (use_macro && define_macro) {
  1022. X        printf("#if defined(__STDC__) || defined(__cplusplus)\n");
  1023. X        printf("# define %s(s) s\n", macro_name);
  1024. X        printf("#else\n");
  1025. X        printf("# define %s(s) ()\n", macro_name);
  1026. X        printf("#endif\n\n");
  1027. X    }
  1028. X    if (argc == 0)
  1029. X        getdecl(stdin);
  1030. X    else
  1031. X        while (argc > 0 && *argv) {
  1032. XDEBUG("trying a new file\n");
  1033. X            if (!(f = fopen(*argv, "r"))) {
  1034. X                perror(*argv);
  1035. X                exit(EXIT_FAILURE);
  1036. X            }
  1037. X            if (iobuf)
  1038. X                setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
  1039. X
  1040. X            printf("\n/* %s */\n", *argv);
  1041. X            linenum = 1;
  1042. X            newline_seen = 1;
  1043. X            glastc = ' ';
  1044. XDEBUG("calling getdecl\n");
  1045. X            getdecl(f);
  1046. XDEBUG("back from getdecl\n");
  1047. X            argc--; argv++;
  1048. X            fclose(f);
  1049. XDEBUG("back from fclose\n");
  1050. X        }
  1051. X    if (use_macro && define_macro) {
  1052. X        printf("\n#undef %s\n", macro_name);    /* clean up namespace */
  1053. X    }
  1054. X    exit(EXIT_SUCCESS);
  1055. X}
  1056. X
  1057. X
  1058. Xvoid Usage()
  1059. X{
  1060. X    fprintf(stderr, 
  1061. X       "Usage: %s [-e][-n][-p sym][-s][-x][-z][-A][files ...]\n", ourname);
  1062. X    fputs("   -e: put an explicit \"extern\" keyword in declarations\n",
  1063. X       stderr);
  1064. X    fputs("   -n: put line numbers of declarations as comments\n",stderr);
  1065. X    fputs("   -p nm: use \"nm\" as the prototype macro (default \"_P\")\n",
  1066. X       stderr);
  1067. X    fputs("   -s: include declarations for static functions\n", stderr);
  1068. X    fputs("   -x: omit parameter names in prototypes\n", stderr);
  1069. X    fputs("   -z: omit prototype macro definition\n", stderr);
  1070. X    fputs("   -A: omit prototype macro; header files are strict ANSI\n",
  1071. X       stderr);
  1072. X    exit(EXIT_FAILURE);
  1073. X}
  1074. SHAR_EOF
  1075. if test 17019 -ne "`wc -c mkptypes.c`"
  1076. then
  1077. echo shar: error transmitting mkptypes.c '(should have been 17019 characters)'
  1078. fi
  1079. echo shar: extracting mkptypes.h
  1080. sed 's/^X//' << \SHAR_EOF > mkptypes.h
  1081. X#if defined(__STDC__) || defined(__cplusplus)
  1082. X# define _P(s) s
  1083. X#else
  1084. X# define _P(s) ()
  1085. X#endif
  1086. X
  1087. X
  1088. X/* mkptypes.c */
  1089. XWord *word_alloc _P((char *s));
  1090. Xvoid word_free _P((Word *w));
  1091. Xint List_len _P((Word *w));
  1092. XWord *word_append _P((Word *w1, Word *w2));
  1093. Xint foundin _P((Word *w1, Word *w2));
  1094. Xvoid addword _P((Word *w, char *s));
  1095. Xvoid typefixhack _P((Word *w));
  1096. Xint ngetc _P((FILE *f));
  1097. Xint fnextch _P((FILE *f));
  1098. Xint nextch _P((FILE *f));
  1099. Xint getsym _P((char *buf, FILE *f));
  1100. Xint skipit _P((char *buf, FILE *f));
  1101. Xint is_type_word _P((char *s));
  1102. XWord *typelist _P((Word *p));
  1103. XWord *getparamlist _P((FILE *f));
  1104. Xvoid emit _P((Word *wlist, Word *plist, long startline));
  1105. Xvoid getdecl _P((FILE *f));
  1106. Xvoid main _P((int argc, char **argv));
  1107. Xvoid Usage _P((void));
  1108. X
  1109. X#undef _P
  1110. SHAR_EOF
  1111. if test 761 -ne "`wc -c mkptypes.h`"
  1112. then
  1113. echo shar: error transmitting mkptypes.h '(should have been 761 characters)'
  1114. fi
  1115. echo shar: extracting mkptypes.man
  1116. sed 's/^X//' << \SHAR_EOF > mkptypes.man
  1117. XNAME
  1118. X    mkptypes - make prototypes for functions
  1119. X
  1120. X
  1121. XSYNOPSIS
  1122. X    mkptypes [ -e ][ -n ][ -p symbol ][ -s ][ -x ][ -z ][ -A ] [ file ... ]
  1123. X
  1124. X
  1125. XDESCRIPTION
  1126. X    Mkptypes takes as input one or more C source code files, and produces as
  1127. X    output (on the standard output stream) a list of function prototypes (a
  1128. X    la ANSI) for the external functions defined in the given source files. This
  1129. X    output, redirected to a file, is suitable for #include'ing in a C source
  1130. X    file. The function definitions in the original source may be either "old-
  1131. X    style" (in which case appropriate prototypes are generated for the funct-
  1132. X    ions) or "new-style" (in which the definition includes a prototype already).
  1133. X
  1134. X    The -e option causes the "extern" keyword to be explicitly printed for
  1135. X    external functions. Some non-ANSI compilers may need this.
  1136. X
  1137. X    The -n option causes the line number where each function was defined to
  1138. X    be prepended to the prototype declaration as a comment.
  1139. X
  1140. X    The -p option controls the name of the macro used to guard prototype
  1141. X    definitions. Normally this is "_P", but you can change it to any string you
  1142. X    like. To eliminate the guard macro entirely, use the -A option.
  1143. X
  1144. X    The -s option causes prototypes to be generated for functions declared
  1145. X    "static" as well as extern functions.
  1146. X
  1147. X    The -x option causes parameter names to be omitted from the output proto-
  1148. X    types. This may be necessary for some brain-damaged pseudo-ANSI com-
  1149. X    pilers. You may also prefer this style of output. This option has not been
  1150. X    thoroughly tested.
  1151. X
  1152. X    The -z option suppresses the definition of the prototype macro given by -p.
  1153. X    Header files generated by mkptypes with this option will not work unless
  1154. X    the prototype macro has been defined elsewhere in the program by the user.
  1155. X    Used with the -p option, the -z option allows use of predefined prototype
  1156. X    hiding macros that may exist on some systems.
  1157. X
  1158. X    The -A option causes the prototypes emitted to be only readable by ANSI
  1159. X    compilers.  Normally, the prototypes are "macro-ized" so that compilers
  1160. X    with __STDC__not defined don't see them.
  1161. X
  1162. X    If files are specified on the command line, then a comment specifying the
  1163. X    file of origin is emitted before the prototypes constructed from that file.
  1164. X    If no files are given, then no comments are emitted and the C source code
  1165. X    is taken from the standard input stream.
  1166. X
  1167. XBUGS
  1168. X    Mkptypes is easily confused by complicated declarations, such as
  1169. X
  1170. X           int ((*signal)())() f ...
  1171. X    or
  1172. X
  1173. X           struct foo f int x, y; g foofunc() f ...
  1174. X
  1175. X    This is because the program doesn't actually understand type definitions.
  1176. X    Some programs may need to be run through the preprocessor before being
  1177. X    run through mkptypes . The -n option will not work correctly on prepro-
  1178. X    cessor output if function definitions (as opposed to declarations) appear
  1179. X    in header files.
  1180. X
  1181. X    Typedef'd types aren't correctly promoted, e.g. for
  1182. X
  1183. X           typedef schar char; int foo(x) schar x;...
  1184. X    mkptypes incorrectly generates the prototype int foo(schar x) rather than
  1185. X    the [correct] int foo(int x).
  1186. X
  1187. X    Functions named "inline" with no explicit type qualifiers are not recog-
  1188. X    nized.
  1189. X
  1190. X
  1191. XSEE ALSO
  1192. X    cc (1), lint (1).
  1193. X
  1194. X
  1195. XAUTHOR
  1196. X    Eric R. Smith <ersmith@uwovax.uwo.ca>
  1197. X
  1198. X
  1199. XNOTE
  1200. X    There is no warranty for this program (as noted above, it's guaranteed to
  1201. X    break sometimes anyways!). Mkptypes is in the public domain.
  1202. SHAR_EOF
  1203. if test 3462 -ne "`wc -c mkptypes.man`"
  1204. then
  1205. echo shar: error transmitting mkptypes.man '(should have been 3462 characters)'
  1206. fi
  1207. #    End of shell archive
  1208. exit 0
  1209.  
  1210. exit 0 # Just in case...
  1211. -- 
  1212. Kent Landfield                   INTERNET: kent@sparky.IMD.Sterling.COM
  1213. Sterling Software, IMD           UUCP:     uunet!sparky!kent
  1214. Phone:    (402) 291-8300         FAX:      (402) 291-4362
  1215. Please send comp.sources.misc-related mail to kent@uunet.uu.net.
  1216.