blob: 416a4988a4e29ed9332bcd2e1b28bcb87ebfbeae [file] [log] [blame]
/*
* cdecl - ANSI C and C++ declaration composer & decoder
*
* originally written
* Graham Ross
* once at tektronix!tekmdp!grahamr
* now at Context, Inc.
*
* modified to provide hints for unsupported types
* added argument lists for functions
* added 'explain cast' grammar
* added #ifdef for 'create program' feature
* ???? (sorry, I lost your name and login)
*
* conversion to ANSI C
* David Wolverton
* ihnp4!houxs!daw
*
* merged D. Wolverton's ANSI C version w/ ????'s version
* added function prototypes
* added C++ declarations
* made type combination checking table driven
* added checks for void variable combinations
* made 'create program' feature a runtime option
* added file parsing as well as just stdin
* added help message at beginning
* added prompts when on a TTY or in interactive mode
* added getopt() usage
* added -a, -r, -p, -c, -d, -D, -V, -i and -+ options
* delinted
* added #defines for those without getopt or void
* added 'set options' command
* added 'quit/exit' command
* added synonyms
* Tony Hansen
* attmail!tony, ihnp4!pegasus!hansen
*
* added extern, register, static
* added links to explain, cast, declare
* separately developed ANSI C support
* Merlyn LeRoy
* merlyn@rose3.rosemount.com
*
* merged versions from LeRoy
* added tmpfile() support
* allow more parts to be missing during explanations
* Tony Hansen
* attmail!tony, ihnp4!pegasus!hansen
*/
char cdeclsccsid[] = "@(#)cdecl.c 2.4 3/31/88";
#include <stdio.h>
#include <ctype.h>
#if __STDC__ || defined(DOS)
# include <stdlib.h>
# include <stddef.h>
# include <string.h>
# include <stdarg.h>
#else
# ifndef NOVARARGS
# include <varargs.h>
# endif /* ndef NOVARARGS */
char *malloc();
void free(), exit(), perror();
# ifdef BSD
# include <strings.h>
extern int errno;
# define strrchr rindex
# define NOTMPFILE
# else
# include <string.h>
# include <errno.h>
# endif /* BSD */
# ifdef NOVOID
# define void int
# endif /* NOVOID */
#endif /* __STDC__ || DOS */
#include <unistd.h>
#include <errno.h>
#define MB_SHORT 0001
#define MB_LONG 0002
#define MB_UNSIGNED 0004
#define MB_INT 0010
#define MB_CHAR 0020
#define MB_FLOAT 0040
#define MB_DOUBLE 0100
#define MB_VOID 0200
#define MB_SIGNED 0400
#define NullCP ((char*)NULL)
#ifdef dodebug
# define Debug(x) do { if (DebugFlag) (void) fprintf x; } while (0)
#else
# define Debug(x) /* nothing */
#endif
#if __STDC__
char *ds(char *), *cat(char *, ...), *visible(int);
#ifndef __sun__
int getopt(int,char *const*, const char *);
#endif
int main(int, char **);
int yywrap_nasko(void);
int dostdin(void);
void mbcheck(void), dohelp(void), usage(void);
void prompt(void), doprompt(void), noprompt(void);
void unsupp(char *, char *);
void notsupported(char *, char *, char *);
void yyerror(char *);
void doset(char *);
void dodeclare(char*, char*, char*, char*, char*);
void docast(char*, char*, char*, char*);
void dodexplain(char*, char*, char*, char*);
void docexplain(char*, char*, char*, char*);
void setprogname(const char *);
int dotmpfile(int, char**), dofileargs(int, char**);
#else
char *ds(), *cat(), *visible();
int getopt();
void mbcheck(), dohelp(), usage();
void prompt(), doprompt(), noprompt();
void unsupp(), notsupported();
void yyerror();
void doset(), dodeclare(), docast(), dodexplain(), docexplain();
void setprogname();
int dotmpfile(), dofileargs();
#endif /* __STDC__ */
FILE *tmpfile();
/* variables used during parsing */
unsigned modbits = 0;
int arbdims = 1;
char *savedname = 0;
char unknown_name[] = "unknown_name";
char prev = 0; /* the current type of the variable being examined */
/* values type */
/* p pointer */
/* r reference */
/* f function */
/* a array (of arbitrary dimensions) */
/* A array with dimensions */
/* n name */
/* v void */
/* s struct | class */
/* t simple type (int, long, etc.) */
/* options */
int RitchieFlag = 0; /* -r, assume Ritchie PDP C language */
int MkProgramFlag = 0; /* -c, output {} and ; after declarations */
int PreANSIFlag = 0; /* -p, assume pre-ANSI C language */
int CplusplusFlag = 0; /* -+, assume C++ language */
int OnATty = 0; /* stdin is coming from a terminal */
int Interactive = 0; /* -i, overrides OnATty */
int KeywordName = 0; /* $0 is a keyword (declare, explain, cast) */
const char *progname = "cdecl"; /* $0 */
#if dodebug
int DebugFlag = 0; /* -d, output debugging trace info */
#endif
#ifdef doyydebug /* compile in yacc trace statements */
#define YYDEBUG 1
#endif /* doyydebug */
#include "cdgram.c.source"
#include "cdlex.c.source"
/* definitions (and abbreviations) for type combinations cross check table */
#define ALWAYS 0 /* combo always okay */
#define _ ALWAYS
#define NEVER 1 /* combo never allowed */
#define X NEVER
#define RITCHIE 2 /* combo not allowed in Ritchie compiler */
#define R RITCHIE
#define PREANSI 3 /* combo not allowed in Pre-ANSI compiler */
#define P PREANSI
#define ANSI 4 /* combo not allowed anymore in ANSI compiler */
#define A ANSI
/* This is an lower left triangular array. If we needed */
/* to save 9 bytes, the "long" row can be removed. */
char crosscheck[9][9] = {
/* L, I, S, C, V, U, S, F, D, */
/* long */ _, _, _, _, _, _, _, _, _,
/* int */ _, _, _, _, _, _, _, _, _,
/* short */ X, _, _, _, _, _, _, _, _,
/* char */ X, X, X, _, _, _, _, _, _,
/* void */ X, X, X, X, _, _, _, _, _,
/* unsigned */ R, _, R, R, X, _, _, _, _,
/* signed */ P, P, P, P, X, X, _, _, _,
/* float */ A, X, X, X, X, X, X, _, _,
/* double */ P, X, X, X, X, X, X, X, _
};
/* the names and bits checked for each row in the above array */
struct
{
char *name;
int bit;
} crosstypes[9] =
{
{ "long", MB_LONG },
{ "int", MB_INT },
{ "short", MB_SHORT },
{ "char", MB_CHAR },
{ "void", MB_VOID },
{ "unsigned", MB_UNSIGNED },
{ "signed", MB_SIGNED },
{ "float", MB_FLOAT },
{ "double", MB_DOUBLE }
};
/* Run through the crosscheck array looking */
/* for unsupported combinations of types. */
void mbcheck()
{
register int i, j, restrict;
char *t1, *t2;
/* Loop through the types */
/* (skip the "long" row) */
for (i = 1; i < 9; i++)
{
/* if this type is in use */
if ((modbits & crosstypes[i].bit) != 0)
{
/* check for other types also in use */
for (j = 0; j < i; j++)
{
/* this type is not in use */
if (!(modbits & crosstypes[j].bit))
continue;
/* check the type of restriction */
restrict = crosscheck[i][j];
if (restrict == ALWAYS)
continue;
t1 = crosstypes[i].name;
t2 = crosstypes[j].name;
if (restrict == NEVER)
{
notsupported("", t1, t2);
}
else if (restrict == RITCHIE)
{
if (RitchieFlag)
notsupported(" (Ritchie Compiler)", t1, t2);
}
else if (restrict == PREANSI)
{
if (PreANSIFlag || RitchieFlag)
notsupported(" (Pre-ANSI Compiler)", t1, t2);
}
else if (restrict == ANSI)
{
if (!RitchieFlag && !PreANSIFlag)
notsupported(" (ANSI Compiler)", t1, t2);
}
else
{
(void) fprintf (stderr,
"%s: Internal error in crosscheck[%d,%d]=%d!\n",
progname, i, j, restrict);
exit(1); /* NOTREACHED */
}
}
}
}
}
/* undefine these as they are no longer needed */
#undef _
#undef ALWAYS
#undef X
#undef NEVER
#undef R
#undef RITCHIE
#undef P
#undef PREANSI
#undef A
#undef ANSI
/* Write out a message about something */
/* being unsupported, possibly with a hint. */
void unsupp(s,hint)
char *s,*hint;
{
notsupported("", s, NullCP);
if (hint)
(void) fprintf(stderr, "\t(maybe you mean \"%s\")\n", hint);
}
/* Write out a message about something */
/* being unsupported on a particular compiler. */
void notsupported(compiler, type1, type2)
char *compiler, *type1, *type2;
{
if (type2)
(void) fprintf(stderr,
"Warning: Unsupported in%s C%s -- '%s' with '%s'\n",
compiler, CplusplusFlag ? "++" : "", type1, type2);
else
(void) fprintf(stdout,
"Warning: Unsupported in%s C%s -- '%s'\n",
compiler, CplusplusFlag ? "++" : "", type1);
}
/* Called by the yacc grammar */
void yyerror(s)
char *s;
{
(void) printf("%s\n",s);
Debug((stdout, "yychar=%d\n", yychar));
}
/* Called by the yacc grammar */
int yywrap_nasko()
{
return 1;
}
/*
* Support for dynamic strings:
* cat() creates a string from the concatenation
* of a null terminated list of input strings.
* The input strings are free()'d by cat()
* (so they better have been malloc()'d).
*
* the different methods of <stdarg.h> and
* <vararg.h> are handled within these macros
*/
#if __STDC__
# define VA_DCL(type,var) (type var,...)
# define VA_START(list,var,type) ((va_start(list,var)) , (var))
#else
#if defined(DOS)
# define VA_DCL(type,var) (var,...) type var;
# define VA_START(list,var,type) ((va_start(list,var)) , (var))
#else
#ifndef NOVARARGS
# define VA_DCL(type,var) (va_alist) va_dcl
# define VA_START(list,var,type) ((va_start(list)) , va_arg(list,type))
#else
/*
* it is assumed here that machines which don't have either
* <varargs.h> or <stdarg.h> will put its arguments on
* the stack in the "usual" way and consequently can grab
* the arguments using the "take the address of the first
* parameter and increment by sizeof" trick.
*/
# define VA_DCL(type,var) (var) type var;
# define VA_START(list,var,type) (list = (va_list)&(var) , (var))
# define va_arg(list,type) ((type *)(list += sizeof(type)))[-1]
# define va_end(p) /* nothing */
typedef char *va_list;
#endif /* NOVARARGS */
#endif /* DOS */
#endif /* __STDC__ */
/* VARARGS */
char *cat
VA_DCL(char*, s1)
{
register char *newstr;
register unsigned len = 1;
char *str;
va_list args;
/* find the length which needs to be allocated */
str = VA_START(args, s1, char*);
for ( ; str; str = va_arg(args, char*))
len += strlen(str);
va_end(args);
/* allocate it */
newstr = malloc(len);
if (newstr == 0)
{
(void) fprintf (stderr, "%s: out of malloc space within cat()!\n",
progname);
exit(1);
}
newstr[0] = '\0';
/* copy in the strings */
str = VA_START(args, s1, char*);
for ( ; str; str = va_arg(args, char*))
{
(void) strcat(newstr,str);
free(str);
}
va_end(args);
Debug((stderr, "\tcat created '%s'\n", newstr));
return newstr;
}
/*
* ds() makes a malloc()'d string from one that's not.
*/
char *ds(s)
char *s;
{
register char *p = malloc((unsigned)(strlen(s)+1));
if (p)
(void) strcpy(p,s);
else
{
(void) fprintf (stderr, "%s: malloc() failed!\n", progname);
exit(1);
}
return p;
}
/* return a visible representation of a character */
char *visible(c)
int c;
{
static char buf[5];
c &= 0377;
if (isprint(c))
{
buf[0] = c;
buf[1] = '\0';
}
else
(void) sprintf(buf,"\\%03o",c);
return buf;
}
#ifdef NOTMPFILE
/* provide a conservative version of tmpfile() */
/* for those systems without it. */
/* tmpfile() returns a FILE* of a file opened */
/* for read&write. It is supposed to be */
/* automatically removed when it gets closed, */
/* but here we provide a separate rmtmpfile() */
/* function to perform that function. */
/* Also provide several possible file names to */
/* try for opening. */
static char *file4tmpfile = 0;
FILE *tmpfile()
{
static char *listtmpfiles[] =
{
"/usr/tmp/cdeclXXXXXX",
"/tmp/cdeclXXXXXX",
"/cdeclXXXXXX",
"cdeclXXXXXX",
0
};
char **listp = listtmpfiles;
for ( ; *listp; listp++)
{
FILE *retfp;
(void) mktemp(*listp);
retfp = fopen(*listp, "w+");
if (!retfp)
continue;
file4tmpfile = *listp;
return retfp;
}
return 0;
}
void rmtmpfile()
{
if (file4tmpfile)
(void) unlink(file4tmpfile);
}
#else
/* provide a mock rmtmpfile() for normal systems */
# define rmtmpfile() /* nothing */
#endif /* NOTMPFILE */
#ifndef NOGETOPT
extern int optind;
#else
/* This is a miniature version of getopt() which will */
/* do just barely enough for us to get by below. */
/* Options are not allowed to be bunched up together. */
/* Option arguments are not supported. */
int optind = 1;
int getopt(argc,argv,optstring)
char **argv;
char *optstring;
{
int ret;
char *p;
if ((argv[optind][0] != '-')
#ifdef DOS
&& (argv[optind][0] != '/')
#endif /* DOS */
)
return EOF;
ret = argv[optind][1];
optind++;
for (p = optstring; *p; p++)
if (*p == ret)
return ret;
(void) fprintf (stderr, "%s: illegal option -- %s\n",
progname, visible(ret));
return '?';
}
#endif
/* the help messages */
struct helpstruct
{
char *text; /* generic text */
char *cpptext; /* C++ specific text */
} helptext[] =
{ /* up-to 23 lines of help text so it fits on (24x80) screens */
/* 1 */{ "[] means optional; {} means 1 or more; <> means defined elsewhere", 0 },
/* 2 */{ " commands are separated by ';' and newlines", 0 },
/* 3 */{ "command:", 0 },
/* 4 */{ " declare <name> as <english>", 0 },
/* 5 */{ " cast <name> into <english>", 0 },
/* 6 */{ " explain <gibberish>", 0 },
/* 7 */{ " set or set options", 0 },
/* 8 */{ " help, ?", 0 },
/* 9 */{ " quit or exit", 0 },
/* 10 */{ "english:", 0 },
/* 11 */{ " function [( <decl-list> )] returning <english>", 0 },
/* 12 */{ " array [<number>] of <english>", 0 },
/* 13 */{ " [{ const | volatile | noalias }] pointer to <english>",
" [{const|volatile}] {pointer|reference} to [member of class <name>] <english>" },
/* 14 */{ " <type>", 0 },
/* 15 */{ "type:", 0 },
/* 16 */{ " {[<storage-class>] [{<modifier>}] [<C-type>]}", 0 },
/* 17 */{ " { struct | union | enum } <name>",
" {struct|class|union|enum} <name>" },
/* 18 */{ "decllist: a comma separated list of <name>, <english> or <name> as <english>", 0 },
/* 19 */{ "name: a C identifier", 0 },
/* 20 */{ "gibberish: a C declaration, like 'int *x', or cast, like '(int *)x'", 0 },
/* 21 */{ "storage-class: extern, static, auto, register", 0 },
/* 22 */{ "C-type: int, char, float, double, or void", 0 },
/* 23 */{ "modifier: short, long, signed, unsigned, const, volatile, or noalias",
"modifier: short, long, signed, unsigned, const, or volatile" },
{ 0, 0 }
};
/* Print out the help text */
void dohelp()
{
register struct helpstruct *p;
register char *fmt = CplusplusFlag ? " %s\n" : "\t%s\n";
for (p = helptext; p->text; p++)
if (CplusplusFlag && p->cpptext)
(void) printf(fmt, p->cpptext);
else
(void) printf(fmt, p->text);
}
/* Tell how to invoke cdecl. */
void usage()
{
(void) fprintf (stderr, "Usage: %s [-r|-p|-a|-+] [-ci%s%s] [files...]\n",
progname,
#ifdef dodebug
"d",
#else
"",
#endif /* dodebug */
#ifdef doyydebug
"D"
#else
""
#endif /* doyydebug */
);
(void) fprintf (stderr, "\t-r Check against Ritchie PDP C Compiler\n");
(void) fprintf (stderr, "\t-p Check against Pre-ANSI C Compiler\n");
(void) fprintf (stderr, "\t-a Check against ANSI C Compiler%s\n",
CplusplusFlag ? "" : " (the default)");
(void) fprintf (stderr, "\t-+ Check against C++ Compiler%s\n",
CplusplusFlag ? " (the default)" : "");
(void) fprintf (stderr, "\t-c Create compilable output (include ; and {})\n");
(void) fprintf (stderr, "\t-i Force interactive mode\n");
#ifdef dodebug
(void) fprintf (stderr, "\t-d Turn on debugging mode\n");
#endif /* dodebug */
#ifdef doyydebug
(void) fprintf (stderr, "\t-D Turn on YACC debugging mode\n");
#endif /* doyydebug */
exit(1);
/* NOTREACHED */
}
/* Manage the prompts. */
static int prompting = 1;
void doprompt() { prompting = 1; }
void noprompt() { prompting = 0; }
void prompt()
{
if ((OnATty || Interactive) && prompting) {
(void) printf("%s> ", progname);
(void) fflush(stdout);
}
}
/* Save away the name of the program from argv[0] */
void setprogname(argv0)
const char *argv0;
{
#ifdef DOS
char *dot;
#endif /* DOS */
progname = strrchr(argv0, '/');
#ifdef DOS
if (!progname)
progname = strrchr(argv0, '\\');
#endif /* DOS */
if (progname)
progname++;
else
progname = argv0;
#ifdef DOS
dot = strchr(progname, '.');
if (dot)
*dot = '\0';
for (dot = progname; *dot; dot++)
*dot = tolower(*dot);
#endif /* DOS */
}
/* Run down the list of keywords to see if the */
/* program is being called named as one of them */
/* or the first argument is one of them. */
int namedkeyword(argn)
char *argn;
{
static char *cmdlist[] =
{
"explain", "declare", "cast", "help", "?", "set", 0
};
/* first check the program name */
char **cmdptr = cmdlist;
for ( ; *cmdptr; cmdptr++)
if (strcmp(*cmdptr, progname) == 0)
{
KeywordName = 1;
return 1;
}
/* now check $1 */
for (cmdptr = cmdlist; *cmdptr; cmdptr++)
if (strcmp(*cmdptr, argn) == 0)
return 1;
/* nope, must be file name arguments */
return 0;
}
/* Read from standard input, turning */
/* on prompting if necessary. */
int dostdin()
{
int ret;
OnATty = isatty(0);
if (OnATty || Interactive)
{
(void) printf("Type `help' or `?' for help\n");
prompt();
}
yyin = stdin;
ret = yyparse();
OnATty = 0;
return ret;
}
/* Write the arguments into a file */
/* and treat that file as the input. */
int dotmpfile(argc, argv)
int argc;
char **argv;
{
int ret = 0;
FILE *tmpfp = tmpfile();
if (!tmpfp)
{
int sverrno = errno;
(void) fprintf (stderr, "%s: cannot open temp file\n",
progname);
errno = sverrno;
perror(progname);
return 1;
}
if (KeywordName)
if (fputs(progname, tmpfp) == EOF)
{
int sverrno;
errwrite:
sverrno = errno;
(void) fprintf (stderr, "%s: error writing to temp file\n",
progname);
errno = sverrno;
perror(progname);
(void) fclose(tmpfp);
rmtmpfile();
return 1;
}
for ( ; optind < argc; optind++)
if (fprintf(tmpfp, " %s", argv[optind]) == EOF)
goto errwrite;
if (putc('\n', tmpfp) == EOF)
goto errwrite;
rewind(tmpfp);
yyin = tmpfp;
ret += yyparse();
(void) fclose(tmpfp);
rmtmpfile();
return ret;
}
/* Read each of the named files for input. */
int dofileargs(argc, argv)
int argc;
char **argv;
{
FILE *ifp;
int ret = 0;
for ( ; optind < argc; optind++)
if (strcmp(argv[optind], "-") == 0)
ret += dostdin();
else if ((ifp = fopen(argv[optind], "r")) == NULL)
{
int sverrno = errno;
(void) fprintf (stderr, "%s: cannot open %s\n",
progname, argv[optind]);
errno = sverrno;
perror(argv[optind]);
ret++;
}
else
{
yyin = ifp;
ret += yyparse();
}
return ret;
}
/* print out a cast */
void docast(name, left, right, type)
char *name, *left, *right, *type;
{
int lenl = strlen(left), lenr = strlen(right);
if (prev == 'f')
unsupp("Cast into function",
"cast into pointer to function");
else if (prev=='A' || prev=='a')
unsupp("Cast into array","cast into pointer");
(void) printf("(%s%*s%s)%s\n",
type, lenl+lenr?lenl+1:0,
left, right, name ? name : "expression");
free(left);
free(right);
free(type);
if (name)
free(name);
}
/* print out a declaration */
void dodeclare(name, storage, left, right, type)
char *name, *storage, *left, *right, *type;
{
if (prev == 'v')
unsupp("Variable of type void",
"variable of type pointer to void");
if (*storage == 'r')
switch (prev)
{
case 'f': unsupp("Register function", NullCP); break;
case 'A':
case 'a': unsupp("Register array", NullCP); break;
case 's': unsupp("Register struct/class", NullCP); break;
}
if (*storage)
(void) printf("%s ", storage);
(void) printf("%s %s%s%s",
type, left,
name ? name : (prev == 'f') ? "f" : "var", right);
if (MkProgramFlag) {
if ((prev == 'f') && (*storage != 'e'))
(void) printf(" { }\n");
else
(void) printf(";\n");
} else {
(void) printf("\n");
}
free(storage);
free(left);
free(right);
free(type);
if (name)
free(name);
}
void dodexplain(storage, constvol, type, decl)
char *storage, *constvol, *type, *decl;
{
if (type && (strcmp(type, "void") == 0))
if (prev == 'n')
unsupp("Variable of type void",
"variable of type pointer to void");
else if (prev == 'a')
unsupp("array of type void",
"array of type pointer to void");
else if (prev == 'r')
unsupp("reference to type void",
"pointer to void");
if (*storage == 'r')
switch (prev)
{
case 'f': unsupp("Register function", NullCP); break;
case 'A':
case 'a': unsupp("Register array", NullCP); break;
case 's': unsupp("Register struct/union/enum/class", NullCP); break;
}
(void) printf("declare %s as ", savedname);
if (*storage)
(void) printf("%s ", storage);
(void) printf("%s", decl);
if (*constvol)
(void) printf("%s ", constvol);
(void) printf("%s\n", type ? type : "int");
}
void docexplain(constvol, type, cast, name)
char *constvol, *type, *cast, *name;
{
if (strcmp(type, "void") == 0)
if (prev == 'a')
unsupp("array of type void",
"array of type pointer to void");
else if (prev == 'r')
unsupp("reference to type void",
"pointer to void");
(void) printf("cast %s into %s", name, cast);
if (strlen(constvol) > 0)
(void) printf("%s ", constvol);
(void) printf("%s\n",type);
}
/* Do the appropriate things for the "set" command. */
void doset(opt)
char *opt;
{
if (strcmp(opt, "create") == 0)
{ MkProgramFlag = 1; }
else if (strcmp(opt, "nocreate") == 0)
{ MkProgramFlag = 0; }
else if (strcmp(opt, "interactive") == 0)
{ Interactive = 1; }
else if (strcmp(opt, "nointeractive") == 0)
{ Interactive = 0; OnATty = 0; }
else if (strcmp(opt, "ritchie") == 0)
{ CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; }
else if (strcmp(opt, "preansi") == 0)
{ CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; }
else if (strcmp(opt, "ansi") == 0)
{ CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; }
else if (strcmp(opt, "cplusplus") == 0)
{ CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; }
#ifdef dodebug
else if (strcmp(opt, "debug") == 0)
{ DebugFlag = 1; }
else if (strcmp(opt, "nodebug") == 0)
{ DebugFlag = 0; }
#endif /* dodebug */
#ifdef doyydebug
else if (strcmp(opt, "yydebug") == 0)
{ yydebug = 1; }
else if (strcmp(opt, "noyydebug") == 0)
{ yydebug = 0; }
#endif /* doyydebug */
else
{
if ((strcmp(opt, unknown_name) != 0) &&
(strcmp(opt, "options") != 0))
(void) printf("Unknown set option: '%s'\n", opt);
(void) printf("Valid set options (and command line equivalents) are:\n");
(void) printf("\toptions\n");
(void) printf("\tcreate (-c), nocreate\n");
(void) printf("\tinteractive (-i), nointeractive\n");
(void) printf("\tritchie (-r), preansi (-p), ansi (-a) or cplusplus (-+)\n");
#ifdef dodebug
(void) printf("\tdebug (-d), nodebug\n");
#endif /* dodebug */
#ifdef doyydebug
(void) printf("\tyydebug (-D), noyydebug\n");
#endif /* doyydebug */
(void) printf("\nCurrent set values are:\n");
(void) printf("\t%screate\n", MkProgramFlag ? " " : " no");
(void) printf("\t%sinteractive\n",
(OnATty || Interactive) ? " " : " no");
if (RitchieFlag)
(void) printf("\t ritchie\n");
else
(void) printf("\t(noritchie)\n");
if (PreANSIFlag)
(void) printf("\t preansi\n");
else
(void) printf("\t(nopreansi)\n");
if (!RitchieFlag && !PreANSIFlag && !CplusplusFlag)
(void) printf("\t ansi\n");
else
(void) printf("\t(noansi)\n");
if (CplusplusFlag)
(void) printf("\t cplusplus\n");
else
(void) printf("\t(nocplusplus)\n");
#ifdef dodebug
(void) printf("\t%sdebug\n", DebugFlag ? " " : " no");
#endif /* dodebug */
#ifdef doyydebug
(void) printf("\t%syydebug\n", yydebug ? " " : " no");
#endif /* doyydebug */
}
}
void versions()
{
(void) printf("Version:\n\t%s\n\t%s\n\t%s\n",
cdeclsccsid, cdgramsccsid, cdlexsccsid);
exit(0);
}
int main(int argc, char **argv)
{
int c, ret = 0;
setprogname(argv[0]);
#ifdef DOS
if (strcmp(progname, "cppdecl") == 0)
#else
if (strcmp(progname, "c++decl") == 0)
#endif /* DOS */
CplusplusFlag = 1;
while ((c = getopt(argc, argv, "cirpa+dDV")) != EOF)
switch (c)
{
case 'c': MkProgramFlag=1; break;
case 'i': Interactive=1; break;
/* The following are mutually exclusive. */
/* Only the last one set prevails. */
case 'r': CplusplusFlag=0; RitchieFlag=1; PreANSIFlag=0; break;
case 'p': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=1; break;
case 'a': CplusplusFlag=0; RitchieFlag=0; PreANSIFlag=0; break;
case '+': CplusplusFlag=1; RitchieFlag=0; PreANSIFlag=0; break;
#ifdef dodebug
case 'd': DebugFlag=1; break;
#endif /* dodebug */
#ifdef doyydebug
case 'D': yydebug=1; break;
#endif /* doyydebug */
case 'V': versions(); break;
case '?': usage(); break;
}
/* Run down the list of arguments, parsing each one. */
/* Use standard input if no file names or "-" is found. */
if (optind == argc)
ret += dostdin();
/* If called as explain, declare or cast, or first */
/* argument is one of those, use the command line */
/* as the input. */
else if (namedkeyword(argv[optind]))
ret += dotmpfile(argc, argv);
else
ret += dofileargs(argc, argv);
return ret;
/* NOTREACHED */
}