home *** CD-ROM | disk | FTP | other *** search
- From: ersmith@uwovax.bitnet (Eric R. Smith)
- Newsgroups: comp.sources.misc
- Subject: v16i090: mkptypes - Generate prototype declarations for C, Part01/01
- Message-ID: <1991Feb3.204131.28866@sparky.IMD.Sterling.COM>
- Date: 3 Feb 91 20:41:31 GMT
- Approved: kent@sparky.imd.sterling.com
- X-Checksum-Snefru: bf556370 9a2818ed 9f5e677b 1ced0392
-
- Submitted-by: ersmith@uwovax.bitnet (Eric R. Smith)
- Posting-number: Volume 16, Issue 90
- Archive-name: mkptypes/part01
-
- Here is mkptypes, a program for generating prototype declarations for
- all functions appearing in a C source file. The output declarations
- are enclosed in a macro so as to be usable by either an ANSI or an
- older C compiler. Typical usage would be to do 'mkptypes *.c >proto.h'
- and then have a '#include "proto.h"' line in the relevant C source
- code files. See the README file for more details.
-
- An earlier version of this program was released on comp.sources.misc
- under the name "mkproto"; this updated version (with new command line
- options and several bug fixes) was renamed to avoid conflict with a
- file system utility available on some versions of Unix.
-
- The source will probably compile as-is on most systems, providing you
- edit the makefile appropriately (the default is for my configuration,
- an Atari ST with gcc).
-
- Eric R. Smith
- eric.smith@uwo.ca
- ersmith@uwovax.bitnet
-
- # This is a shell archive.
- # Remove everything above and including the cut line.
- # Then run the rest of the file through sh.
- #----cut here-----cut here-----cut here-----cut here----#
- #!/bin/sh
- # shar: Shell Archiver
- # Run the following text with /bin/sh to create:
- # README
- # Manifest
- # Makefile
- # mkptypes.1
- # mkptypes.c
- # mkptypes.h
- # mkptypes.man
- # This archive created: 21 January 1991 12:16:52 PM EST
- # By: eric (at home)
- echo shar: extracting README
- sed 's/^X//' << \SHAR_EOF > README
- XHere is mkptypes, a program for generating prototype declarations for all
- Xfunctions appearing in a C source file. The input C code may be either
- XK&R or ANSI C (i.e. it's OK if the functions are defined using prototypes).
- XUnlike some of the sed-based scripts floating around, it (usually)
- Xhandles prototype promotion (e.g. the prototype for 'int foo() char x;...'
- Xis 'int foo(int x)'). Also, it should work OK on just about any computer,
- Xnot just Unix-based ones (it's been tested under minix, Unix, and TOS).
- X
- XUse: typically, you would type 'mkptypes *.c >proto.h' and then add a
- X'#include "proto.h"' line to all the C source files. An ANSI conformant
- Xcompiler will then be able to do type checking on function calls across
- Xmodule boundaries. As a bonus, proto.h will tell you which source files
- Xfunctions were defined in, and (if you gave the -n function to mkptypes)
- Xtheir line numbers. The resulting include file may also be used by
- Xnon-ANSI compilers; you can disable this feature (for cleaner, strictly
- XANSI-conforming output) with the -A flag. See the mkptypes.man file for
- Xa description of all the flags mkptypes accepts.
- X
- XPlease read the description of bugs in mkptypes.man; definitely mkptypes
- Xwill not handle all programs correctly, but it does work on the majority of
- Xthem. A sample of its output is provided in the file "mkptypes.h"; this
- Xis the result of 'mkptypes mkptypes.c >mkptypes.h'.
- X
- XThere is ABSOLUTELY NO WARRANTY for the program; as I said, it doesn't work
- Xon all programs (complicated function definitions can make it produce bogus
- Xoutput). It does what I need, though, and it can certainly make porting stuff
- Xto ANSI compilers easier.
- X
- XAn earlier version of mkptypes was released on Usenet under the name
- X"mkproto". This version has several new command line options, and some bug
- Xfixes. It has been renamed to avoid conflict with a file system utility
- Xavailable under some versions of Unix.
- X
- XMkptypes is in the public domain. If you find any bugs (other than the ones
- Xdocumented) please let me know.
- X--
- XEric R. Smith email:
- XDept. of Mathematics ersmith@uwovax.uwo.ca
- XUniversity of Western Ontario ersmith@uwovax.bitnet
- XLondon, Ont. Canada N6A 5B7
- Xph: (519) 661-3638
- SHAR_EOF
- if test 2224 -ne "`wc -c README`"
- then
- echo shar: error transmitting README '(should have been 2224 characters)'
- fi
- echo shar: extracting Manifest
- sed 's/^X//' << \SHAR_EOF > Manifest
- XMakefile: makefile for mkptypes. Default configuration is for Atari ST.
- XManifest: this file
- Xmkptypes.1: Unix manual page for mkptypes
- Xmkptypes.c: source code for mkptypes
- Xmkptypes.h: prototypes for mkptypes (generated by mkptypes, too)
- Xmkptypes.man: text version of mkptypes.1
- XREADME: do what it says
- SHAR_EOF
- if test 302 -ne "`wc -c Manifest`"
- then
- echo shar: error transmitting Manifest '(should have been 302 characters)'
- fi
- echo shar: extracting Makefile
- sed 's/^X//' << \SHAR_EOF > Makefile
- X#
- X# Makefile for mkptypes. Edit the lines below to suit your tastes; the default
- X# is for my computer (Atari ST running the gcc 1.37); a Unix configuration is
- X# also provided.
- X
- X#CC = cc
- X#PROG = mkptypes
- X#CFLAGS = -O
- X
- XCC = gcc
- XPROG = mkptypes.ttp
- XCFLAGS = -mshort -O
- X
- X$(PROG) : mkptypes.c mkptypes.h
- X $(CC) $(CFLAGS) -o $(PROG) mkptypes.c
- X
- Xclean:
- X rm -f mkptypes.o
- X
- Xrealclean: clean
- X rm -f $(PROG) report core
- SHAR_EOF
- if test 409 -ne "`wc -c Makefile`"
- then
- echo shar: error transmitting Makefile '(should have been 409 characters)'
- fi
- echo shar: extracting mkptypes.1
- sed 's/^X//' << \SHAR_EOF > mkptypes.1
- X.TH MKPTYPES 1
- X.SH NAME
- Xmkptypes \- make prototypes for functions
- X.SH SYNOPSIS
- X.B mkptypes
- X[
- X.B -e
- X] [
- X.B -n
- X] [
- X.B -p
- X.I symbol
- X] [
- X.B -s
- X] [
- X.B -x
- X] [
- X.B -z
- X] [
- X.B -A
- X] [
- X.I file ...
- X]
- X.SH DESCRIPTION
- X.I Mkptypes
- Xtakes as input one or more C source code files, and
- Xproduces as output (on the standard output stream) a list of function
- Xprototypes (a la ANSI) for the external functions defined in the
- Xgiven source files. This output, redirected to a file, is suitable
- Xfor #include'ing in a C source file.
- X.PP
- XThe function definitions in the original source
- Xmay be either ``old-style'' (in which case appropriate prototypes are
- Xgenerated for the functions) or ``new-style'' (in which the definition
- Xincludes a prototype already).
- X.PP
- XThe -e option causes the ``extern'' keyword to be explicitly printed
- Xfor external functions. Some non-ANSI compilers may need this.
- X.PP
- XThe -n option causes the line number where each function was defined
- Xto be prepended to the prototype declaration as a comment.
- X.PP
- XThe -p option controls the name of the macro used to guard prototype
- Xdefinitions. Normally this is ``_P'', but you can change it to any string
- Xyou like. To eliminate the guard macro entirely, use the -A option.
- X.PP
- XThe -s option causes prototypes to be generated for functions declared
- X``static'' as well as extern functions.
- X.PP
- XThe -x option causes parameter names to be omitted from the output
- Xprototypes. This may be necessary for some brain-damaged pseudo-ANSI
- Xcompilers. You may also prefer this style of output. This option has not
- Xbeen thoroughly tested.
- X.PP
- XThe -z option suppresses the definition of the prototype macro given by
- X-p. Header files generated by
- X.I mkptypes
- Xwith this option will not work unless the prototype macro has been defined
- Xelsewhere in the program by the user. Used with the -p option, the -z
- Xoption allows use of predefined prototype hiding macros that may exist
- Xon some systems.
- X.PP
- XThe -A option causes the prototypes emitted to be only readable by ANSI
- Xcompilers. Normally, the prototypes are "macro-ized" so that compilers
- Xwith __STDC__ not defined don't see them.
- X.PP
- XIf files are specified on the command line, then a comment specifying
- Xthe file of origin is emitted before the prototypes constructed from
- Xthat file. If no files are given, then no comments are emitted and
- Xthe C source code is taken from the standard input stream.
- X.SH BUGS
- XMkptypes is easily confused by complicated declarations, such as
- X.nf
- X int ((*signal)())() { ...
- X.fi
- Xor
- X.nf
- X struct foo { int x, y; } foofunc() { ...
- X.fi
- XThis is because the program doesn't actually understand type definitions.
- X.PP
- XSome programs may need to be run through the preprocessor before
- Xbeing run through
- X.I mkptypes .
- XThe -n option will not work correctly on preprocessor output if function
- Xdefinitions (as opposed to declarations) appear in header files.
- X.PP
- XTypedef'd types aren't correctly promoted, e.g. for
- X.nf
- X typedef schar char; int foo(x) schar x;...
- X.fi
- X.I mkptypes
- Xincorrectly generates the prototype int foo(schar x) rather than the
- X[correct] int foo(int x).
- X.PP
- XFunctions named "inline" with no explicit type qualifiers are not
- Xrecognized.
- X.SH SEE ALSO
- X.I cc
- X(1),
- X.I lint
- X(1).
- X.SH AUTHOR
- XEric R. Smith <ersmith@uwovax.uwo.ca>
- X.SH NOTE
- XThere is no warranty for this program (as noted above, it's guaranteed
- Xto break sometimes anyways!). Mkptypes is in the public domain.
- SHAR_EOF
- if test 3399 -ne "`wc -c mkptypes.1`"
- then
- echo shar: error transmitting mkptypes.1 '(should have been 3399 characters)'
- fi
- echo shar: extracting mkptypes.c
- sed 's/^X//' << \SHAR_EOF > mkptypes.c
- X/* Program to extract function declarations from C source code
- X * Written by Eric R. Smith and placed in the public domain
- X * Thanks to:
- X * Jwahar R. Bammi, for catching several bugs and providing the Unix makefiles
- X * Byron T. Jenings Jr. for cleaning up the space code, providing a Unix
- X * manual page, and some ANSI and C++ improvements.
- X * Skip Gilbrech for code to skip parameter names in prototypes.
- X * ... and many others for helpful comments and suggestions.
- X */
- X
- X/* if your compiler claims to be ANSI but doesn't have stddef.h or stdlib.h,
- X * change the next line.
- X * (and then complain to the supplier of the defective compiler)
- X */
- X
- X#if defined(__STDC__) && !defined(minix)
- X#include <stddef.h>
- X#include <stdlib.h>
- X#else
- Xextern char *malloc();
- Xextern long atol();
- X#endif
- X
- X#ifndef EXIT_SUCCESS
- X#define EXIT_SUCCESS 0
- X#define EXIT_FAILURE 1
- X#endif
- X
- X#include <stdio.h>
- X#include <ctype.h>
- X#include <string.h>
- X
- X/*#define DEBUG(s) (fputs(s, stderr)) /* */
- X#define DEBUG(s) /* */
- X
- X#define ISCSYM(x) ((x) > 0 && (isalnum(x) || (x) == '_'))
- X#define ABORTED ( (Word *) -1 )
- X#define MAXPARAM 20 /* max. number of parameters to a function */
- X#define NEWBUFSIZ (20480*sizeof(char)) /* new buffer size */
- X
- Xint dostatic = 0; /* do static functions? */
- Xint donum = 0; /* print line numbers? */
- Xint define_macro = 1; /* define macro for prototypes? */
- Xint use_macro = 1; /* use a macro for prototypes? */
- Xchar *macro_name = "_P"; /* macro to use for prototypes */
- Xint no_parm_names = 0; /* no parm names - only types */
- Xint print_extern = 0; /* use "extern" before function declarations */
- X#ifdef CPP
- Xint call_cpp = 0; /* preprocess files */
- X#endif
- X
- Xchar *ourname; /* our name, from argv[] array */
- Xint inquote = 0; /* in a quote?? */
- Xint newline_seen = 1; /* are we at the start of a line */
- Xlong linenum = 1L; /* line number in current file */
- Xint glastc = ' '; /* last char. seen by getsym() */
- X
- Xtypedef struct word {
- X struct word *next;
- X char string[1];
- X} Word;
- X
- X#include "mkptypes.h"
- X
- X/*
- X * Routines for manipulating lists of words.
- X */
- X
- XWord *word_alloc(s)
- X char *s;
- X{
- X Word *w;
- X
- X/* note that sizeof(Word) already contains space for a terminating null
- X * however, we add 1 so that typefixhack can promote "float" to "double"
- X * by just doing a strcpy.
- X */
- X w = (Word *) malloc(sizeof(Word) + strlen(s) + 1);
- X strcpy(w->string, s);
- X w->next = NULL;
- X return w;
- X}
- X
- Xvoid word_free(w)
- X Word *w;
- X{
- X Word *oldw;
- X while (w) {
- X oldw = w;
- X w = w->next;
- X free(oldw);
- X }
- X}
- X
- X/* return the length of a list; empty words are not counted */
- Xint
- XList_len(w)
- X Word *w;
- X{
- X int count = 0;
- X
- X while (w) {
- X if (*w->string) count++;
- X w = w->next;
- X }
- X return count;
- X}
- X
- X/* Append two lists, and return the result */
- X
- XWord *word_append(w1, w2)
- X Word *w1, *w2;
- X{
- X Word *r, *w;
- X
- X r = w = word_alloc("");
- X
- X while (w1) {
- X w->next = word_alloc(w1->string);
- X w = w->next;
- X w1 = w1->next;
- X }
- X while (w2) {
- X w->next = word_alloc(w2->string);
- X w = w->next;
- X w2 = w2->next;
- X }
- X
- X return r;
- X}
- X
- X/* see if the last entry in w2 is in w1 */
- X
- Xint
- Xfoundin(w1, w2)
- X Word *w1, *w2;
- X{
- X while (w2->next)
- X w2 = w2->next;
- X
- X while (w1) {
- X if (!strcmp(w1->string, w2->string))
- X return 1;
- X w1 = w1->next;
- X }
- X return 0;
- X}
- X
- X/* add the string s to the given list of words */
- X
- Xvoid addword(w, s)
- X Word *w; char *s;
- X{
- X while (w->next) w = w->next;
- X w->next = word_alloc(s);
- X}
- X
- X/* typefixhack: promote formal parameters of type "char", "unsigned char",
- X "short", or "unsigned short" to "int".
- X*/
- X
- Xvoid typefixhack(w)
- X Word *w;
- X{
- X Word *oldw = 0;
- X
- X while (w) {
- X if (*w->string) {
- X if ( (!strcmp(w->string, "char") ||
- X !strcmp(w->string, "short") )
- X && (List_len(w->next) < 2) )
- X {
- X/* delete any "unsigned" specifier present -- yes, it's supposed to do this */
- X if (oldw && !strcmp(oldw->string, "unsigned")) {
- X oldw->next = w->next;
- X free(w);
- X w = oldw;
- X }
- X strcpy(w->string, "int");
- X }
- X else if ( !strcmp(w->string, "float") &&
- X List_len(w->next) < 2 )
- X {
- X strcpy(w->string, "double");
- X }
- X }
- X w = w->next;
- X }
- X}
- X
- X/* read a character: if it's a newline, increment the line count */
- X
- X#ifdef __GNUC__ /* ++jrb */
- Xinline
- X#endif
- Xint ngetc(f)
- X FILE *f;
- X{
- X int c;
- X
- X c = getc(f);
- X if (c == '\n') linenum++;
- X
- X return c;
- X}
- X
- X/* read the next character from the file. If the character is '\' then
- X * read and skip the next character. Any comment sequence is converted
- X * to a blank.
- X */
- X
- Xint fnextch(f)
- X FILE *f;
- X{
- X int c, lastc, incomment;
- X
- X c = ngetc(f);
- X while (c == '\\') {
- XDEBUG("fnextch: in backslash loop\n");
- X c = ngetc(f); /* skip a character */
- X c = ngetc(f);
- X }
- X if (c == '/' && !inquote) {
- X c = ngetc(f);
- X if (c == '*') {
- X incomment = 1;
- X c = ' ';
- XDEBUG("fnextch: comment seen\n");
- X while (incomment) {
- X lastc = c;
- X c = ngetc(f);
- X if (lastc == '*' && c == '/')
- X incomment = 0;
- X else if (c < 0)
- X return c;
- X }
- X return fnextch(f);
- X }
- X else {
- X/* if we pre-fetched a linefeed, remember to adjust the line number */
- X if (c == '\n') linenum--;
- X ungetc(c, f);
- X return '/';
- X }
- X }
- X return c;
- X}
- X
- X
- X/* Get the next "interesting" character. Comments are skipped, and strings
- X * are converted to "0". Also, if a line starts with "#" it is skipped.
- X */
- X
- Xint nextch(f)
- X FILE *f;
- X{
- X int c, n;
- X char *p, numbuf[10];
- X
- X c = fnextch(f);
- X
- X/* skip preprocessor directives */
- X/* EXCEPTION: #line nnn or #nnn lines are interpreted */
- X
- X if (newline_seen && c == '#') {
- X/* skip blanks */
- X do {
- X c = fnextch(f);
- X } while ( c >= 0 && (c == '\t' || c == ' ') );
- X/* check for #line */
- X if (c == 'l') {
- X c = fnextch(f);
- X if (c != 'i') /* not a #line directive */
- X goto skip_rest_of_line;
- X do {
- X c = fnextch(f);
- X } while (c >= 0 && c != '\n' && !isdigit(c));
- X }
- X
- X/* if we have a digit it's a line number, from the preprocessor */
- X if (c >= 0 && isdigit(c)) {
- X p = numbuf;
- X for (n = 8; n >= 0; --n) {
- X *p++ = c;
- X c = fnextch(f);
- X if (c <= 0 || !isdigit(c))
- X break;
- X }
- X *p = 0;
- X linenum = atol(numbuf) - 1;
- X }
- X
- X/* skip the rest of the line */
- Xskip_rest_of_line:
- X while (c >= 0 && c != '\n')
- X c = fnextch(f);
- X if (c < 0)
- X return c;
- X }
- X newline_seen = (c == '\n');
- X
- X if (c == '\'' || c == '\"') {
- XDEBUG("nextch: in a quote\n");
- X inquote = c;
- X while ( (c = fnextch(f)) >= 0 ) {
- X if (c == inquote) {
- X inquote = 0;
- XDEBUG("nextch: out of quote\n");
- X return '0';
- X }
- X }
- XDEBUG("nextch: EOF in a quote\n");
- X }
- X return c;
- X}
- X
- X/*
- X * Get the next symbol from the file, skipping blanks.
- X * Return 0 if OK, -1 for EOF.
- X * Also collapses everything between { and }
- X */
- X
- Xint
- Xgetsym(buf, f)
- X char *buf; FILE *f;
- X{
- X register int c;
- X int inbrack = 0;
- X
- XDEBUG("in getsym\n");
- X c = glastc;
- X while ((c > 0) && isspace(c)) {
- X c = nextch(f);
- X }
- XDEBUG("getsym: spaces skipped\n");
- X if (c < 0) {
- XDEBUG("EOF read in getsym\n");
- X return -1;
- X }
- X if (c == '{') {
- X inbrack = 1;
- XDEBUG("getsym: in bracket\n");
- X while (inbrack) {
- X c = nextch(f);
- X if (c < 0) {
- XDEBUG("getsym: EOF seen in bracket loop\n");
- X glastc = c;
- X return c;
- X }
- X if (c == '{') inbrack++;
- X else if (c == '}') inbrack--;
- X }
- X strcpy(buf, "{}");
- X glastc = nextch(f);
- XDEBUG("getsym: out of in bracket loop\n");
- X return 0;
- X }
- X if (!ISCSYM(c)) {
- X *buf++ = c;
- X *buf = 0;
- X glastc = nextch(f);
- XDEBUG("getsym: returning special symbol\n");
- X return 0;
- X }
- X while (ISCSYM(c)) {
- X *buf++ = c;
- X c = nextch(f);
- X }
- X *buf = 0;
- X glastc = c;
- XDEBUG("getsym: returning word\n");
- X return 0;
- X}
- X
- X/*
- X * skipit: skip until a ";" or the end of a function declaration is seen
- X */
- Xint skipit(buf, f)
- X char *buf;
- X FILE *f;
- X{
- X int i;
- X
- X do {
- XDEBUG("in skipit loop\n");
- X i = getsym(buf, f);
- X if (i < 0) return i;
- X } while (*buf != ';' && *buf != '{');
- X
- X return 0;
- X}
- X
- X/*
- X * find most common type specifiers for purpose of ruling them out as
- X * parm names
- X */
- X
- Xint is_type_word(s)
- Xchar *s;
- X{
- X static char *typewords[] = {
- X "char", "const", "double", "enum",
- X "float", "int", "long", "short",
- X "signed", "struct", "union", "unsigned",
- X "void", "volatile", (char *)0
- X };
- X
- X register char **ss;
- X
- X for (ss = typewords; *ss; ++ss)
- X if (strcmp(s, *ss) == 0)
- X return 1;
- X
- X return 0;
- X}
- X
- X
- X/* Ad-hoc macro to recognize parameter name for purposes of removal.
- X * Idea is to remove the bulk of easily recognized parm names without
- X * losing too many type specifiers. (sg)
- X */
- X#define IS_PARM_NAME(w) \
- X (ISCSYM(*(w)->string) && !is_type_word((w)->string) && \
- X (!(w)->next || *(w)->next->string == ',' || \
- X *(w)->next->string == '['))
- X
- X
- X/*
- X * given a list representing a type and a variable name, extract just
- X * the base type, e.g. "struct word *x" would yield "struct word"
- X */
- X
- XWord *typelist(p)
- X Word *p;
- X{
- X Word *w, *r;
- X
- X r = w = word_alloc("");
- X while (p && p->next) {
- X/* handle int *x --> int */
- X if (p->string[0] && !ISCSYM(p->string[0]))
- X break;
- X/* handle int x[] --> int */
- X if (p->next->string[0] == '[')
- X break;
- X w->next = word_alloc(p->string);
- X w = w->next;
- X p = p->next;
- X }
- X return r;
- X}
- X
- X/*
- X * Get a parameter list; when this is called the next symbol in line
- X * should be the first thing in the list.
- X */
- X
- XWord *getparamlist(f)
- X FILE *f;
- X{
- X static Word *pname[MAXPARAM]; /* parameter names */
- X Word *tlist, /* type name */
- X *plist; /* temporary */
- X int np = 0; /* number of parameters */
- X int typed[MAXPARAM]; /* parameter has been given a type */
- X int tlistdone; /* finished finding the type name */
- X int sawsomething;
- X int i;
- X int inparen = 0;
- X char buf[80];
- X
- XDEBUG("in getparamlist\n");
- X for (i = 0; i < MAXPARAM; i++)
- X typed[i] = 0;
- X
- X plist = word_alloc("");
- X
- X/* first, get the stuff inside brackets (if anything) */
- X
- X sawsomething = 0; /* gets set nonzero when we see an arg */
- X for (;;) {
- X if (getsym(buf, f) < 0) return NULL;
- X if (*buf == ')' && (--inparen < 0)) {
- X if (sawsomething) { /* if we've seen an arg */
- X pname[np] = plist;
- X plist = word_alloc("");
- X np++;
- X }
- X break;
- X }
- X if (*buf == ';') { /* something weird */
- X return ABORTED;
- X }
- X sawsomething = 1; /* there's something in the arg. list */
- X if (*buf == ',' && inparen == 0) {
- X pname[np] = plist;
- X plist = word_alloc("");
- X np++;
- X }
- X else {
- X addword(plist, buf);
- X if (*buf == '(') inparen++;
- X }
- X }
- X
- X/* next, get the declarations after the function header */
- X
- X inparen = 0;
- X
- X tlist = word_alloc("");
- X plist = word_alloc("");
- X tlistdone = 0;
- X sawsomething = 0;
- X for(;;) {
- X if (getsym(buf, f) < 0) return NULL;
- X
- X/* handle a list like "int x,y,z" */
- X if (*buf == ',' && !inparen) {
- X if (!sawsomething)
- X return NULL;
- X for (i = 0; i < np; i++) {
- X if (!typed[i] && foundin(plist, pname[i])) {
- X typed[i] = 1;
- X word_free(pname[i]);
- X pname[i] = word_append(tlist, plist);
- X /* promote types */
- X typefixhack(pname[i]);
- X break;
- X }
- X }
- X if (!tlistdone) {
- X tlist = typelist(plist);
- X tlistdone = 1;
- X }
- X word_free(plist);
- X plist = word_alloc("");
- X }
- X/* handle the end of a list */
- X else if (*buf == ';') {
- X if (!sawsomething)
- X return ABORTED;
- X for (i = 0; i < np; i++) {
- X if (!typed[i] && foundin(plist, pname[i])) {
- X typed[i] = 1;
- X word_free(pname[i]);
- X pname[i] = word_append(tlist, plist);
- X typefixhack(pname[i]);
- X break;
- X }
- X }
- X tlistdone = 0;
- X word_free(tlist); word_free(plist);
- X tlist = word_alloc("");
- X plist = word_alloc("");
- X }
- X/* handle the beginning of the function */
- X else if (!strcmp(buf, "{}")) break;
- X/* otherwise, throw the word into the list (except for "register") */
- X else if (strcmp(buf, "register")) {
- X sawsomething = 1;
- X addword(plist, buf);
- X if (*buf == '(') inparen++;
- X if (*buf == ')') inparen--;
- X }
- X }
- X
- X/* Now take the info we have and build a prototype list */
- X
- X/* empty parameter list means "void" */
- X if (np == 0)
- X return word_alloc("void");
- X
- X plist = tlist = word_alloc("");
- X for (i = 0; i < np; i++) {
- X
- X/* If no type provided, make it an "int" */
- X if ( !(pname[i]->next) ||
- X (!(pname[i]->next->next)&&strcmp(pname[i]->next->string, "void"))) {
- X addword(tlist, "int");
- X }
- X while (tlist->next) tlist = tlist->next;
- X tlist->next = pname[i];
- X if (i < np - 1)
- X addword(tlist, ",");
- X }
- X return plist;
- X}
- X
- X/*
- X * emit a function declaration. The attributes and name of the function
- X * are in wlist; the parameters are in plist.
- X */
- X
- Xvoid emit(wlist, plist, startline)
- X Word *wlist, *plist;
- X long startline;
- X{
- X Word *w;
- X int count = 0;
- X int needspace = 0;
- X int isstatic = 0;
- X
- XDEBUG("emit called\n");
- X if (donum)
- X printf("/*%8ld */ ", startline);
- X
- X for (w = wlist; w; w = w->next) {
- X if (w->string[0]) {
- X count ++;
- X if (!strcmp(w->string, "static"))
- X isstatic = 1;
- X }
- X }
- X
- X/* if the -e flag was given, and it's not a static function, print "extern" */
- X
- X if (print_extern && !isstatic) {
- X printf("extern ");
- X }
- X
- X if (count < 2) {
- X printf("int");
- X needspace = 1;
- X }
- X
- X for (w = wlist; w; w = w->next) {
- X if (needspace)
- X putchar(' ');
- X printf("%s", w->string);
- X needspace = ISCSYM(w->string[0]);
- X }
- X if (use_macro)
- X printf(" %s((", macro_name);
- X else
- X putchar('(');
- X needspace = 0;
- X for (w = plist; w; w = w->next) {
- X if (no_parm_names && IS_PARM_NAME(w))
- X continue;
- X if (w->string[0] == ',')
- X needspace = 1;
- X else if (w->string[0] == '[')
- X needspace = 0;
- X else
- X {
- X if (needspace)
- X putchar(' ');
- X needspace = ISCSYM(w->string[0]);
- X }
- X printf("%s", w->string);
- X }
- X if (use_macro)
- X printf("));\n");
- X else
- X printf(");\n");
- X}
- X
- X/*
- X * get all the function declarations
- X */
- X
- Xvoid getdecl(f)
- X FILE *f;
- X{
- X Word *plist, *wlist = NULL;
- X char buf[80];
- X int sawsomething;
- X long startline; /* line where declaration started */
- X int oktoprint;
- Xagain:
- X word_free(wlist);
- X wlist = word_alloc("");
- X sawsomething = 0;
- X oktoprint = 1;
- X
- X for(;;) {
- XDEBUG("main getdecl loop\n");
- X if (getsym(buf,f) < 0) {
- XDEBUG("EOF in getdecl loop\n");
- X return;
- X }
- X/* try to guess when a declaration is not an external function definition */
- X if (!strcmp(buf, ",") || !strcmp(buf, "{}") ||
- X !strcmp(buf, "=") || !strcmp(buf, "typedef") ||
- X !strcmp(buf, "extern")) {
- X skipit(buf, f);
- X goto again;
- X }
- X if (!dostatic && !strcmp(buf, "static")) {
- X oktoprint = 0;
- X }
- X/* for the benefit of compilers that allow "inline" declarations */
- X if (!strcmp(buf, "inline") && !sawsomething)
- X continue;
- X if (!strcmp(buf, ";")) goto again;
- X
- X/* A left parenthesis *might* indicate a function definition */
- X if (!strcmp(buf, "(")) {
- X startline = linenum;
- X if (!sawsomething || !(plist = getparamlist(f))) {
- X skipit(buf, f);
- X goto again;
- X }
- X if (plist == ABORTED)
- X goto again;
- X
- X/* It seems to have been what we wanted */
- X if (oktoprint)
- X emit(wlist, plist, startline);
- X word_free(plist);
- X goto again;
- X }
- X addword(wlist, buf);
- X sawsomething = 1;
- X }
- X}
- X
- Xvoid
- Xmain(argc, argv)
- Xint argc; char **argv;
- X{
- X FILE *f;
- X char *t, *iobuf;
- X extern void Usage();
- X
- X if (argv[0] && argv[0][0])
- X ourname = argv[0];
- X else
- X ourname = "mkptypes";
- X
- X argv++; argc--;
- X
- X if (argc < 0) /* strange -- no args at all */
- X Usage();
- X
- X iobuf = malloc(NEWBUFSIZ);
- X while (*argv && **argv == '-') {
- X t = *argv++; --argc; t++;
- X while (*t) {
- X if (*t == 'e')
- X print_extern = 1;
- X else if (*t == 'n')
- X donum = 1;
- X else if (*t == 'p') {
- X t = *argv++; --argc;
- X if (!t)
- X Usage();
- X use_macro = 1;
- X macro_name = t;
- X break;
- X }
- X else if (*t == 's')
- X dostatic = 1;
- X else if (*t == 'x')
- X /* no parm names, only types (sg) */
- X no_parm_names = 1;
- X else if (*t == 'z')
- X define_macro = 0;
- X else if (*t == 'A')
- X use_macro = 0;
- X else
- X Usage();
- X t++;
- X }
- X }
- X
- X if (use_macro && define_macro) {
- X printf("#if defined(__STDC__) || defined(__cplusplus)\n");
- X printf("# define %s(s) s\n", macro_name);
- X printf("#else\n");
- X printf("# define %s(s) ()\n", macro_name);
- X printf("#endif\n\n");
- X }
- X if (argc == 0)
- X getdecl(stdin);
- X else
- X while (argc > 0 && *argv) {
- XDEBUG("trying a new file\n");
- X if (!(f = fopen(*argv, "r"))) {
- X perror(*argv);
- X exit(EXIT_FAILURE);
- X }
- X if (iobuf)
- X setvbuf(f, iobuf, _IOFBF, NEWBUFSIZ);
- X
- X printf("\n/* %s */\n", *argv);
- X linenum = 1;
- X newline_seen = 1;
- X glastc = ' ';
- XDEBUG("calling getdecl\n");
- X getdecl(f);
- XDEBUG("back from getdecl\n");
- X argc--; argv++;
- X fclose(f);
- XDEBUG("back from fclose\n");
- X }
- X if (use_macro && define_macro) {
- X printf("\n#undef %s\n", macro_name); /* clean up namespace */
- X }
- X exit(EXIT_SUCCESS);
- X}
- X
- X
- Xvoid Usage()
- X{
- X fprintf(stderr,
- X "Usage: %s [-e][-n][-p sym][-s][-x][-z][-A][files ...]\n", ourname);
- X fputs(" -e: put an explicit \"extern\" keyword in declarations\n",
- X stderr);
- X fputs(" -n: put line numbers of declarations as comments\n",stderr);
- X fputs(" -p nm: use \"nm\" as the prototype macro (default \"_P\")\n",
- X stderr);
- X fputs(" -s: include declarations for static functions\n", stderr);
- X fputs(" -x: omit parameter names in prototypes\n", stderr);
- X fputs(" -z: omit prototype macro definition\n", stderr);
- X fputs(" -A: omit prototype macro; header files are strict ANSI\n",
- X stderr);
- X exit(EXIT_FAILURE);
- X}
- SHAR_EOF
- if test 17019 -ne "`wc -c mkptypes.c`"
- then
- echo shar: error transmitting mkptypes.c '(should have been 17019 characters)'
- fi
- echo shar: extracting mkptypes.h
- sed 's/^X//' << \SHAR_EOF > mkptypes.h
- X#if defined(__STDC__) || defined(__cplusplus)
- X# define _P(s) s
- X#else
- X# define _P(s) ()
- X#endif
- X
- X
- X/* mkptypes.c */
- XWord *word_alloc _P((char *s));
- Xvoid word_free _P((Word *w));
- Xint List_len _P((Word *w));
- XWord *word_append _P((Word *w1, Word *w2));
- Xint foundin _P((Word *w1, Word *w2));
- Xvoid addword _P((Word *w, char *s));
- Xvoid typefixhack _P((Word *w));
- Xint ngetc _P((FILE *f));
- Xint fnextch _P((FILE *f));
- Xint nextch _P((FILE *f));
- Xint getsym _P((char *buf, FILE *f));
- Xint skipit _P((char *buf, FILE *f));
- Xint is_type_word _P((char *s));
- XWord *typelist _P((Word *p));
- XWord *getparamlist _P((FILE *f));
- Xvoid emit _P((Word *wlist, Word *plist, long startline));
- Xvoid getdecl _P((FILE *f));
- Xvoid main _P((int argc, char **argv));
- Xvoid Usage _P((void));
- X
- X#undef _P
- SHAR_EOF
- if test 761 -ne "`wc -c mkptypes.h`"
- then
- echo shar: error transmitting mkptypes.h '(should have been 761 characters)'
- fi
- echo shar: extracting mkptypes.man
- sed 's/^X//' << \SHAR_EOF > mkptypes.man
- XNAME
- X mkptypes - make prototypes for functions
- X
- X
- XSYNOPSIS
- X mkptypes [ -e ][ -n ][ -p symbol ][ -s ][ -x ][ -z ][ -A ] [ file ... ]
- X
- X
- XDESCRIPTION
- X Mkptypes takes as input one or more C source code files, and produces as
- X output (on the standard output stream) a list of function prototypes (a
- X la ANSI) for the external functions defined in the given source files. This
- X output, redirected to a file, is suitable for #include'ing in a C source
- X file. The function definitions in the original source may be either "old-
- X style" (in which case appropriate prototypes are generated for the funct-
- X ions) or "new-style" (in which the definition includes a prototype already).
- X
- X The -e option causes the "extern" keyword to be explicitly printed for
- X external functions. Some non-ANSI compilers may need this.
- X
- X The -n option causes the line number where each function was defined to
- X be prepended to the prototype declaration as a comment.
- X
- X The -p option controls the name of the macro used to guard prototype
- X definitions. Normally this is "_P", but you can change it to any string you
- X like. To eliminate the guard macro entirely, use the -A option.
- X
- X The -s option causes prototypes to be generated for functions declared
- X "static" as well as extern functions.
- X
- X The -x option causes parameter names to be omitted from the output proto-
- X types. This may be necessary for some brain-damaged pseudo-ANSI com-
- X pilers. You may also prefer this style of output. This option has not been
- X thoroughly tested.
- X
- X The -z option suppresses the definition of the prototype macro given by -p.
- X Header files generated by mkptypes with this option will not work unless
- X the prototype macro has been defined elsewhere in the program by the user.
- X Used with the -p option, the -z option allows use of predefined prototype
- X hiding macros that may exist on some systems.
- X
- X The -A option causes the prototypes emitted to be only readable by ANSI
- X compilers. Normally, the prototypes are "macro-ized" so that compilers
- X with __STDC__not defined don't see them.
- X
- X If files are specified on the command line, then a comment specifying the
- X file of origin is emitted before the prototypes constructed from that file.
- X If no files are given, then no comments are emitted and the C source code
- X is taken from the standard input stream.
- X
- XBUGS
- X Mkptypes is easily confused by complicated declarations, such as
- X
- X int ((*signal)())() f ...
- X or
- X
- X struct foo f int x, y; g foofunc() f ...
- X
- X This is because the program doesn't actually understand type definitions.
- X Some programs may need to be run through the preprocessor before being
- X run through mkptypes . The -n option will not work correctly on prepro-
- X cessor output if function definitions (as opposed to declarations) appear
- X in header files.
- X
- X Typedef'd types aren't correctly promoted, e.g. for
- X
- X typedef schar char; int foo(x) schar x;...
- X mkptypes incorrectly generates the prototype int foo(schar x) rather than
- X the [correct] int foo(int x).
- X
- X Functions named "inline" with no explicit type qualifiers are not recog-
- X nized.
- X
- X
- XSEE ALSO
- X cc (1), lint (1).
- X
- X
- XAUTHOR
- X Eric R. Smith <ersmith@uwovax.uwo.ca>
- X
- X
- XNOTE
- X There is no warranty for this program (as noted above, it's guaranteed to
- X break sometimes anyways!). Mkptypes is in the public domain.
- SHAR_EOF
- if test 3462 -ne "`wc -c mkptypes.man`"
- then
- echo shar: error transmitting mkptypes.man '(should have been 3462 characters)'
- fi
- # End of shell archive
- exit 0
-
- exit 0 # Just in case...
- --
- Kent Landfield INTERNET: kent@sparky.IMD.Sterling.COM
- Sterling Software, IMD UUCP: uunet!sparky!kent
- Phone: (402) 291-8300 FAX: (402) 291-4362
- Please send comp.sources.misc-related mail to kent@uunet.uu.net.
-