/***********************************************************************
* *
* This software is part of the ast package *
* Copyright (c) 1986-2012 AT&T Intellectual Property *
* and is licensed under the *
* Eclipse Public License, Version 1.0 *
* by AT&T Intellectual Property *
* *
* A copy of the License is available at *
* http://www.eclipse.org/org/documents/epl-v10.html *
* (with md5 checksum b35adb5213ca9657e911e9befb180842) *
* *
* Information and Software Systems Research *
* AT&T Research *
* Florham Park NJ *
* *
* Glenn Fowler <gsf@research.att.com> *
* *
***********************************************************************/
#pragma prototyped
/*
* Glenn Fowler
* AT&T Research
*
* convert C prototypes to ANSI, K&R and C++ styles or K&R to ANSI
* slips into the pp block read
*
* define PROTOMAIN for standalone proto
* PROTOMAIN is coded for minimal library support
*/
static const char id[] = "\n@(#)$Id: proto (AT&T Research) 2012-04-14 $\0\n";
#if PROTOMAIN
#include "ppfsm.c"
#include <hashkey.h>
#if PROTO_STANDALONE
#undef O_RDONLY
#endif
#else
#include "pplib.h"
#include "ppfsm.h"
#endif
#define GENERATED "/* : : generated by proto : : */\n"
#define PRAGMADIR "pragma" /* pragma directive */
#define MAGICTOP 80 /* must be in these top lines */
#ifndef elementsof
#define elementsof(x) (sizeof(x)/sizeof(x[0]))
#endif
typedef struct Key_s
{
const char* name;
size_t size;
int hit;
int val;
} Key_t;
typedef struct Proto_s /* proto buffer state */
{
int brace; /* {..} level */
int call; /* call level */
int fd; /* input file descriptor */
char* file; /* input file name */
long flags; /* coupled flags */
long options; /* uncoupled flags */
char* package; /* header package */
int line; /* input line count */
int test; /* testing */
char* tp; /* input token base */
int iz; /* input buffer size */
char* ib; /* input buffer base */
char* ip; /* input buffer pointer */
int oz; /* output buffer size */
char* ob; /* output buffer base */
char* op; /* output buffer pointer */
char* ox; /* output buffer externalize */
char cc[3]; /* beg mid end comment char */
char pushback[4]; /* pushback area for caller */
char variadic[256]; /* variadic args buffer */
/* output buffer */
/* slide buffer */
/* input buffer */
} Proto_t;
/*
* proto is separate from pp so these undef's are ok
*/
#undef CLASSIC
#define CLASSIC (1L<<0)
#undef DECLARE
#define DECLARE (1L<<1)
#undef DEFINE
#define DEFINE (1L<<2)
#undef DIRECTIVE
#define DIRECTIVE (1L<<3)
#undef ERROR
#define ERROR (1L<<4)
#undef EXTERN
#define EXTERN (1L<<5)
#undef EXTERNALIZE
#define EXTERNALIZE (1L<<6)
#undef IDID
#define IDID (1L<<7)
#undef INDIRECT
#define INDIRECT (1L<<8)
#undef INIT
#define INIT (1L<<9)
#undef INIT_DEFINE
#define INIT_DEFINE (1L<<10)
#undef INIT_INCLUDE
#define INIT_INCLUDE (1L<<11)
#undef JUNK
#define JUNK (1L<<12)
#undef LINESYNC
#define LINESYNC (1L<<13)
#undef MANGLE
#define MANGLE (1L<<14)
#undef MATCH
#define MATCH (1L<<15)
#undef MORE
#define MORE (1L<<16)
#undef OTHER
#define OTHER (1L<<17)
#undef PASS
#define PASS (1L<<18)
#undef PLUSONLY
#define PLUSONLY (1L<<19)
#undef PLUSPLUS
#define PLUSPLUS (1L<<20)
#undef RECURSIVE
#define RECURSIVE (1L<<21)
#undef SHARP
#define SHARP (1L<<22)
#undef SKIP
#define SKIP (1L<<23)
#undef SLIDE
#define SLIDE (1L<<24)
#undef TOKENS
#define TOKENS (1L<<25)
#undef TYPEDEF
#define TYPEDEF (1L<<26)
#undef VARIADIC
#define VARIADIC (1L<<27)
#undef VARIADIC2
#define VARIADIC2 (1L<<28)
#undef YACC
#define YACC (1L<<29)
#undef YACCSPLIT
#define YACCSPLIT (1L<<30)
#undef YACC2
#define YACC2 (1L<<31)
#undef GLOBAL
#define GLOBAL (MORE)
#undef REGULAR
#define REGULAR (1L<<0)
#ifndef CHUNK
#define CHUNK 1024
#endif
#define BLOCK (16*CHUNK)
#define T_VA_START (N_TOKEN+1)
#define RESERVED(b,e,n) ((((long)(b))<<16)|(((long)(e))<<8)|((long)(n)))
#define KEYENT(s,m,v) {s,sizeof(s)-1,m,v}
#define HIT_prototyped 0x01
#define HIT_noticed 0x02
static const Key_t pragmas[] =
{
KEYENT("prototyped", HIT_prototyped, 1), /* NOTE: first entry */
KEYENT("noprototyped", HIT_prototyped, 0),
KEYENT("noticed", HIT_noticed, 1),
KEYENT("nonoticed", HIT_noticed, 0),
};
static const Key_t notices[] =
{
KEYENT("Copyright", HIT_noticed, 1),
KEYENT("COPYRIGHT", HIT_noticed, 1),
KEYENT("copyright", HIT_noticed, 1),
KEYENT("Public Domain", HIT_noticed, 0),
KEYENT("PUBLIC DOMAIN", HIT_noticed, 0),
};
/*
* generate integer
* pointer to end returned
*/
static char*
number(register char* p, register long n)
{
register long d;
for (d = 1000000; d > 1; d /= 10)
if (n >= d) *p++ = '0' + (n / d) % 10;
*p++ = '0' + n % 10;
return p;
}
#if PROTOMAIN
static int errors;
#if PROTO_STANDALONE
/*
* namespace pollution forces us to claim parts of libc
*/
#undef memcpy
#define memcpy(t,f,n) memcopy(t,f,n)
#undef strcpy
#define strcpy(t,f) strcopy(t,f)
#undef strlen
#define strlen(s) sstrlen(s)
#undef strncmp
#define strncmp(s,t,n) sstrncmp(s,t,n)
/*
* environmentally safe strlen()
*/
static int
sstrlen(register const char* s)
{
register const char* b;
for (b = s; *s; s++);
return s - b;
}
/*
* environmentally safe strncmp()
*/
static int
sstrncmp(register const char* s, register const char* t, register int n)
{
register const char* e = s + n;
while (s < e)
{
if (*s != *t || !*s)
return *s - *t;
s++;
t++;
}
return 0;
}
/*
* strcpy() except pointer to end returned
*/
static char*
strcopy(register char* s, register const char* t)
{
while (*s++ = *t++);
return s - 1;
}
#endif
static void
proto_error(char* iob, int level, char* msg, char* arg)
{
register char* p;
char buf[1024];
p = strcopy(buf, "proto: ");
if (iob)
{
register Proto_t* proto = (Proto_t*)(iob - sizeof(Proto_t));
if (proto->line)
{
if (proto->file)
{
*p++ = '"';
p = strcopy(p, proto->file);
*p++ = '"';
*p++ = ',';
*p++ = ' ';
}
p = strcopy(p, "line ");
p = number(p, proto->line);
}
else if (proto->file)
p = strcopy(p, proto->file);
}
else
{
p = strcopy(p, msg);
msg = arg;
arg = 0;
}
if (*(p - 1) != ' ')
{
*p++ = ':';
*p++ = ' ';
}
if (level == 1)
p = strcopy(p, "warning: ");
p = strcopy(p, msg);
if (arg)
{
*p++ = ' ';
p = strcopy(p, arg);
}
*p++ = '\n';
write(2, buf, p - buf);
if (level >= 3)
exit(level - 2);
if (level >= 2)
errors++;
}
/*
* memcpy() but pointer to end returned
*/
static char*
memcopy(register char* s, register char* t, int n)
{
register char* e = t + n;
while (t < e) *s++ = *t++;
return s;
}
#include "../libast/port/astlicense.c"
#else
#define memcopy(s,t,n) (((char*)memcpy(s,t,n))+(n))
#endif
/*
* generate line sync
* pointer to end returned
*/
static char*
linesync(register Proto_t* proto, register char* p, register long n)
{
#if PROTOMAIN
if (proto->flags & LINESYNC)
#endif
{
#if PROTOMAIN
p = strcopy(p, "\n#line ");
#else
p = strcopy(p, "\n# ");
#endif
p = number(p, n);
*p++ = '\n';
}
return p;
}
/*
* output init header
* pointer to end returned
*/
static char*
init(Proto_t* proto, char* op, int flags)
{
register char* s;
if (flags & INIT_DEFINE)
{
op = strcopy(op, "\
\n\
#if !defined(__PROTO__)\n\
# if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)\n\
# if defined(__cplusplus)\n\
# define __LINKAGE__ \"C\"\n\
# else\n\
# define __LINKAGE__\n\
# endif\n\
# define __STDARG__\n\
# define __PROTO__(x) x\n\
# define __OTORP__(x)\n\
# define __PARAM__(n,o) n\n\
# if !defined(__STDC__) && !defined(__cplusplus)\n\
# if !defined(c_plusplus)\n\
# define const\n\
# endif\n\
# define signed\n\
# define void int\n\
# define volatile\n\
# define __V_ char\n\
# else\n\
# define __V_ void\n\
# endif\n\
# else\n\
# define __PROTO__(x) ()\n\
# define __OTORP__(x) x\n\
# define __PARAM__(n,o) o\n\
# define __LINKAGE__\n\
# define __V_ char\n\
# define const\n\
# define signed\n\
# define void int\n\
# define volatile\n\
# endif\n\
# define __MANGLE__ __LINKAGE__\n\
# if defined(__cplusplus) || defined(c_plusplus)\n\
# define __VARARG__ ...\n\
# else\n\
# define __VARARG__\n\
# endif\n\
# if defined(__STDARG__)\n\
# define __VA_START__(p,a) va_start(p,a)\n\
# else\n\
# define __VA_START__(p,a) va_start(p)\n\
# endif\n\
# if !defined(__INLINE__)\n\
# if defined(__cplusplus)\n\
# define __INLINE__ extern __MANGLE__ inline\n\
# else\n\
# if defined(_WIN32) && !defined(__GNUC__)\n\
# define __INLINE__ __inline\n\
# endif\n\
# endif\n\
# endif\n\
#endif\n\
#if !defined(__LINKAGE__)\n\
#define __LINKAGE__ /* 2004-08-11 transition */\n\
#endif\n\
");
}
else
op = strcopy(op, "\
\n\
#if !defined(__PROTO__)\n\
#include <prototyped.h>\n\
#endif\n\
#if !defined(__LINKAGE__)\n\
#define __LINKAGE__ /* 2004-08-11 transition */\n\
#endif\n\
");
if (proto->package)
{
s = "\
#ifndef __MANGLE_%_DATA__\n\
# ifdef _BLD_%\n\
# ifdef __EXPORT__\n\
# define __MANGLE_%_DATA__ __MANGLE__ __EXPORT__\n\
# else\n\
# define __MANGLE_%_DATA__ __MANGLE__\n\
# endif\n\
# define __MANGLE_%_FUNC__ __MANGLE__\n\
# else\n\
# ifdef __IMPORT__\n\
# define __MANGLE_%_DATA__ __MANGLE__ __IMPORT__\n\
# else\n\
# define __MANGLE_%_DATA__ __MANGLE__\n\
# endif\n\
# define __MANGLE_%_FUNC__ __MANGLE__\n\
# endif\n\
#endif\n\
";
for (;;)
{
switch (*op++ = *s++)
{
case 0:
op--;
break;
case '%':
op = strcopy(op - 1, proto->package);
continue;
default:
continue;
}
break;
}
}
return op;
}
#define BACKOUT() (op=ko)
#define CACHE() do{CACHEIN();CACHEOUT();call=proto->call;}while(0)
#define CACHEIN() (ip=proto->ip)
#define CACHEOUT() (op=proto->op)
#define GETCHR() (*(unsigned char*)ip++)
#define KEEPOUT() (ko=op)
#define LASTOUT() (*(op-1))
#define PUTCHR(c) (*op++=(c))
#define SYNC() do{SYNCIN();SYNCOUT();proto->flags&=~(EXTERN|INIT|OTHER|VARIADIC|VARIADIC2);proto->flags|=flags&(EXTERN|INIT|OTHER|VARIADIC|VARIADIC2);proto->call=call;}while(0)
#define SYNCIN() (proto->ip=ip)
#define SYNCOUT() (proto->op=op)
#define UNGETCHR() (ip--)
#define UNPUTCHR() (op--)
/*
* advance to the next non-space character
*/
static char*
nns(register char* s)
{
while (*s == ' ' || *s == '\t' || *s == '\n')
s++;
return s;
}
#define DIR_if 01
#define DIR_el 02
#define DIR_en 03
#define DIR 03
/*
* update directive mask
*/
static int
directive(register char* s, int dir)
{
switch (*(s = nns(s)))
{
case 'e':
case 'i':
dir <<= 2;
switch (*++s)
{
case 'f':
dir |= DIR_if;
break;
case 'l':
dir |= DIR_el;
break;
case 'n':
dir |= DIR_en;
break;
}
break;
}
return dir;
}
/*
* the tokenizer
* top level calls loop until EOB
* recursive calls just return the next token
*/
static int
lex(register Proto_t* proto, register long flags)
{
register char* ip;
register char* op;
register int c;
register int state;
register short* rp;
char* m;
char* e;
char* t;
char* bp;
char* v;
char* im;
char* ko;
char* aom;
int n;
int line;
int quot;
int brack;
int sub;
int x;
int vc;
char* ie = 0;
char* om = 0;
char* aim = 0;
char* aie = 0;
char* func = 0;
int call = 0;
int dir = 0;
int group = 0;
int last = 0;
int paren = 0;
#if PROTOMAIN
char* qe = 0;
int qn = 0;
int args = 0;
#endif
CACHE();
#if PROTOMAIN
if (flags & EXTERN) KEEPOUT();
#endif
fsm_start:
proto->tp = ip;
state = PROTO;
bp = ip;
do
{
rp = fsm[state];
fsm_get:
while (!(state = rp[c = GETCHR()]));
fsm_next:
;
} while (state > 0);
if ((n = ip - bp - 1) > 0)
{
ip = bp;
MEMCPY(op, ip, n);
ip++;
}
state = ~state;
fsm_terminal:
switch (TERM(state))
{
case S_CHR:
if (op > proto->ob && *(op - 1) == '=' && (op == proto->ob + 1 || *(op - 2) != '=')) switch (c)
{
case '+':
case '-':
case '*':
case '&':
PUTCHR(' ');
break;
}
PUTCHR(c);
break;
case S_CHRB:
UNGETCHR();
c = LASTOUT();
break;
case S_COMMENT:
switch (c)
{
case '\n':
if (INCOMMENTXX(rp)) goto fsm_newline;
PUTCHR(c);
proto->line++;
rp = fsm[COM2];
break;
case '/':
#if PROTOMAIN
if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT();
else
#endif
PUTCHR(c);
if (INCOMMENTXX(rp))
{
rp = fsm[COM5];
break;
}
goto fsm_start;
case EOF:
break;
default:
#if PROTOMAIN
if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT();
else
#endif
PUTCHR(c);
rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3];
break;
}
bp = ip;
goto fsm_get;
case S_EOB:
if (c)
{
if (state = fsm[TERMINAL][INDEX(rp)+1])
goto fsm_terminal;
SYNC();
return 0;
}
UNGETCHR();
fsm_eob:
if ((flags & (DECLARE|GLOBAL|RECURSIVE)) == GLOBAL && (proto->flags & MORE))
{
#if PROTOMAIN
if (!(flags & EXTERN)) /* XXX */
#endif
flags |= SLIDE;
c = ip - proto->ib;
if (!(flags & MATCH))
im = proto->tp;
if (ip > proto->ib)
{
n = ip - im;
if (ip - n < proto->ib)
proto->flags |= ERROR;
memcopy(proto->ib - n, ip - n, n);
ip = proto->ib;
}
proto->tp -= c;
if (flags & MATCH)
{
im -= c;
ie -= c;
}
if (aim)
aim -= c;
if (aie)
aie -= c;
if ((n = read(proto->fd, ip, proto->iz)) > 0)
{
if ((proto->options & REGULAR) && n < proto->iz)
{
proto->flags &= ~MORE;
close(proto->fd);
}
*(ip + n) = 0;
if (state & SPLICE)
goto fsm_splice;
bp = ip;
goto fsm_get;
}
*ip = 0;
proto->flags &= ~MORE;
close(proto->fd);
}
if (state & SPLICE)
goto fsm_splice;
/* NOTE: RECURSIVE lex() should really SLIDE too */
if (!(flags & RECURSIVE) && (state = rp[c = EOF]))
{
bp = ip;
goto fsm_next;
}
SYNC();
return 0;
case S_LITBEG:
quot = c;
#if PROTOMAIN
if (c == '"' && qe)
{
for (n = 0, t = qe + 1; t < op && (*t == ' ' || *t == '\t' || *t == '\n' && ++n || *t >= 'A' && *t <= 'Z' || *t == '_'); t++);
if (t == op)
{
op = qe;
qe = 0;
qn = n;
}
else PUTCHR(c);
}
else
#endif
PUTCHR(c);
rp = fsm[LIT1];
bp = ip;
goto fsm_get;
case S_LITEND:
if (c == quot)
{
#if PROTOMAIN
if (!(flags & DIRECTIVE))
qe = (c == '"') ? op : (char*)0;
#endif
PUTCHR(c);
#if PROTOMAIN
while (qn > 0)
{
qn--;
PUTCHR('\n');
}
#endif
}
else if (c != '\n' && c != EOF)
{
PUTCHR(c);
bp = ip;
goto fsm_get;
}
else
{
#if PROTOMAIN
while (qn > 0)
{
qn--;
PUTCHR('\n');
}
#endif
UNGETCHR();
}
c = T_INVALID;
break;
case S_LITESC:
#if PROTOMAIN
if (flags & CLASSIC) PUTCHR(c);
else
#endif
switch (c)
{
case 'a':
n = CC_bel;
goto fsm_oct;
case 'E':
n = CC_esc;
goto fsm_oct;
case 'v':
n = CC_vt;
goto fsm_oct;
case 'x':
SYNC();
lex(proto, (flags & GLOBAL) | RECURSIVE);
for (n = x = 0; (c = GETCHR()), x < 3; x++) switch (c)
{
case '0': case '1': case '2': case '3':
case '4': case '5': case '6': case '7':
case '8': case '9':
n = (n << 4) + c - '0';
break;
case 'a': case 'b': case 'c': case 'd':
case 'e': case 'f':
n = (n << 4) + c - 'a' + 10;
break;
case 'A': case 'B': case 'C': case 'D':
case 'E': case 'F':
n = (n << 4) + c - 'A' + 10;
break;
default:
goto fsm_hex;
}
fsm_hex:
UNGETCHR();
fsm_oct:
PUTCHR(((n >> 6) & 07) + '0');
PUTCHR(((n >> 3) & 07) + '0');
PUTCHR((n & 07) + '0');
break;
default:
PUTCHR(c);
break;
}
rp = fsm[LIT1];
bp = ip;
goto fsm_get;
case S_MACRO:
UNGETCHR();
#if PROTOMAIN
if ((flags & EXTERN) && *proto->tp == 's' && !strncmp(proto->tp, "static", 6))
{
c = T_EXTERN;
break;
}
#endif
if (*proto->tp == '_' && !strncmp(proto->tp, "__STDPP__directive", 6)) c = '#';
else c = T_ID;
break;
case S_NL:
fsm_newline:
proto->line++;
#if PROTOMAIN
if (flags & EXTERN)
{
if (op != proto->ob && LASTOUT() != ' ' && LASTOUT() != '\n')
PUTCHR(' ');
}
else
#endif
PUTCHR(c);
if (flags & DIRECTIVE)
{
#if PROTOMAIN
if (flags & CLASSIC)
{
if (flags & EXTERN) BACKOUT();
if (flags & JUNK)
{
*(ip - 1) = 0;
op = strcopy(om, "/* ");
op = strcopy(op, im);
op = strcopy(op, " */\n");
}
flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|JUNK|MATCH|SHARP|TYPEDEF);
}
else
#endif
{
if ((flags & (DEFINE|SHARP)) == (DEFINE|SHARP))
{
*(ip - 1) = 0;
op = strcopy(om, "#if defined(__STDC__) || defined(__STDPP__)\n");
op = strcopy(op, im);
op = strcopy(op, "\n#else\n");
bp = ip;
ip = im;
*op++ = *ip++;
while (*op = *ip++)
if (*op++ == '#' && *ip != '(')
{
op--;
while (*--op == ' ' || *op == '\t');
if (*ip == '#')
{
op = strcopy(op + 1, "/**/");
while (*++ip == ' ' || *ip == '\t');
}
else
{
if (*op != '"') *++op = '"';
op++;
while (*ip == ' ' || *ip == '\t') ip++;
while ((c = *ip) >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '_') *op++ = *ip++;
while (*ip == ' ' || *ip == '\t') ip++;
if (*ip == '"') ip++;
else *op++ = '"';
}
}
ip = bp;
op = strcopy(op, "\n#endif\n");
op = linesync(proto, op, proto->line);
}
flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|MATCH|OTHER|SHARP|SKIP|TOKENS|TYPEDEF);
}
call = 0;
group = 0;
paren = 0;
last = '\n';
}
if (paren == 0 && (flags & (MATCH|RECURSIVE|SKIP|SLIDE)) == SLIDE)
{
#if PROTOMAIN
if (flags & EXTERN) BACKOUT();
#endif
SYNC();
return 0;
}
goto fsm_start;
case S_QUAL:
PUTCHR(c);
rp = fsm[NEXT(state)];
bp = ip;
goto fsm_get;
case S_TOK:
PUTCHR(c);
c = TYPE(state);
break;
case S_TOKB:
UNGETCHR();
c = TYPE(state);
break;
case S_RESERVED:
UNGETCHR();
c = T_ID;
if (!(flags & DECLARE)) switch (RESERVED(*proto->tp, *(ip - 1), ip - proto->tp))
{
case RESERVED('N', 'N', 3):
if (proto->tp[1] == 'o')
c = T_DO;
break;
case RESERVED('d', 'o', 2):
c = T_DO;
break;
case RESERVED('e', 'e', 4):
if (!(flags & RECURSIVE) && (flags & (DIRECTIVE|TOKENS)) != DIRECTIVE && !strncmp(proto->tp, "else", 4))
{
c = T_ELSE;
goto fsm_id;
}
break;
case RESERVED('e', 'n', 6):
if (!strncmp(proto->tp, "extern", 6))
c = T_EXTERN;
break;
case RESERVED('f', 'r', 3):
if (!(flags & RECURSIVE) && !strncmp(proto->tp, "for", 3))
{
c = T_FOR;
goto fsm_id;
}
break;
case RESERVED('i', 'f', 2):
c = T_IF;
break;
case RESERVED('i', 'e', 6):
if (!strncmp(proto->tp, "inline", 6) && !(flags & (MATCH|SKIP|TOKENS|TYPEDEF)) && proto->brace == 0 && paren == 0 && group == 0 && (last == ';' || last == '}' || last == '\n' || last == 0))
{
flags |= SKIP;
SYNC();
line = proto->line;
op = strcopy(op - 6, "__INLINE__");
SYNC();
}
break;
case RESERVED('r', 'n', 6):
if (!(flags & RECURSIVE) && !strncmp(proto->tp, "return", 6))
{
c = T_RETURN;
goto fsm_id;
}
break;
case RESERVED('s', 'c', 6):
if ((proto->options & EXTERNALIZE) && !strncmp(proto->tp, "static", 6))
{
proto->ox = op - 6;
flags |= EXTERNALIZE;
}
break;
case RESERVED('t', 'f', 7):
if (!(flags & RECURSIVE) && !strncmp(proto->tp, "typedef", 7))
{
flags |= TYPEDEF;
c = T_EXTERN;
}
break;
case RESERVED('v', 't', 8):
if (*ip == '(' && !strncmp(proto->tp, "va_start", 8)) c = T_VA_START;
break;
case RESERVED('v', 'd', 4):
if (!strncmp(proto->tp, "void", 4))
{
if (flags & (CLASSIC|PLUSONLY|INIT_DEFINE|INIT_INCLUDE)) c = T_VOID;
else
{
SYNC();
line = proto->line;
if (lex(proto, (flags & GLOBAL) | RECURSIVE) == '*')
{
memcopy(op - 4, "__V_", 4);
memcopy(ip - 4, "__V_", 4);
}
else c = T_VOID;
proto->line = line;
SYNC();
bp = ip;
}
}
break;
case RESERVED('w', 'e', 5):
if (!(flags & RECURSIVE) && !strncmp(proto->tp, "while", 5))
{
c = T_WHILE;
goto fsm_id;
}
break;
}
#if PROTOMAIN
if ((flags & CLASSIC) && c != T_EXTERN)
c = T_ID;
#endif
break;
case S_VS:
goto fsm_start;
case S_WS:
UNGETCHR();
#if PROTOMAIN
if ((flags & (EXTERN|MATCH)) == EXTERN)
{
while (op > proto->ob && (*(op - 1) == ' ' || *(op - 1) == '\t'))
op--;
if (op > proto->ob && *(op - 1) != '\n') *op++ = ' ';
}
#endif
goto fsm_start;
default:
if (state & SPLICE)
{
if (c == '\\')
{
if (!(n = GETCHR()))
{
goto fsm_eob;
fsm_splice:
c = '\\';
n = GETCHR();
}
if (n == '\n')
{
proto->line++;
PUTCHR('\\');
PUTCHR('\n');
bp = ip;
goto fsm_get;
}
UNGETCHR();
}
state &= ~SPLICE;
if (state >= TERMINAL)
goto fsm_terminal;
rp = fsm[state];
}
PUTCHR(c);
bp = ip;
goto fsm_get;
}
if (!(flags & (INIT_DEFINE|INIT_INCLUDE|RECURSIVE)))
{
if (!(flags & DIRECTIVE)) switch (c)
{
case '(':
#if PROTOMAIN
if (!(flags & CLASSIC) || proto->brace == 0)
#endif
{
if (paren++ == 0)
{
#if PROTOMAIN
if (!(flags & CLASSIC) || group <= 1)
#endif
{
#if PROTOMAIN
args = 0;
#endif
if (group++ == 0) group++;
else if (flags & INDIRECT) call++;
flags |= MATCH;
im = ip - 1;
om = op - 1;
}
sub = 0;
}
else if (paren == 2 && !aim)
{
sub++;
if (last == '(')
{
flags &= ~MATCH;
om = 0;
}
else if (flags & INDIRECT)
{
aim = ip - 1;
aom = op - 1;
}
else if ((flags & (MATCH|TOKENS)) == MATCH)
{
for (m = ip - 2; m > im && (*m == ' ' || *m == '\t'); m--);
if (m != im && sub == 1)
{
m = im + (*nns(ip) == '*');
}
if (m == im)
{
flags &= ~MATCH;
om = 0;
}
}
else if ((flags & MATCH) && sub == 1 && *nns(ip) != '*')
{
flags &= ~MATCH;
om = 0;
}
}
flags &= ~TOKENS;
}
break;
case ')':
#if PROTOMAIN
if (!(flags & CLASSIC) || proto->brace == 0)
#endif
if (--paren == 0)
{
#if PROTOMAIN
if (flags & CLASSIC)
{
if (group != 2)
{
c = T_ID;
break;
}
group++;
}
#endif
ie = ip;
}
else if (paren == 1 && (flags & INDIRECT) && !aie)
aie = ip;
break;
case '*':
if (last == '(' && group == 2)
{
group--;
if (paren == 1)
{
flags |= INDIRECT;
aim = aie = 0;
}
}
break;
case '#':
dir = directive(ip, dir);
if (proto->brace == 0 && paren == 0 && last != '=' && (flags & (CLASSIC|DECLARE|DIRECTIVE|MATCH|PLUSONLY|SKIP|TOKENS)) == (MATCH|TOKENS) && ((dir & DIR) != DIR_en || ((dir>>2) & DIR) != DIR_if))
flags |= DIRECTIVE;
else if (!(flags & (DECLARE|DIRECTIVE)))
{
flags |= DIRECTIVE;
if (!(flags & PLUSONLY))
{
bp = ip;
while (*ip == ' ' || *ip == '\t') ip++;
if (*ip == 'l' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e')
{
if (*++ip == ' ' || *ip == '\t')
{
proto->line = 0;
while (*++ip >= '0' && *ip <= '9')
proto->line = proto->line * 10 + *ip - '0';
proto->line--;
}
}
#if PROTOMAIN
else if ((flags & (CLASSIC|EXTERN)) == CLASSIC)
{
n = 0;
t = ip + 6;
while (ip < t && *ip >= 'a' && *ip <= 'z')
n = HASHKEYPART(n, *ip++);
switch (n)
{
case HASHKEY4('e','l','s','e'):
case HASHKEY5('e','n','d','i','f'):
while (*ip == ' ' || *ip == '\t') ip++;
if (*ip != '\n' && *ip != '/' && *(ip + 1) != '*')
{
flags |= JUNK|MATCH;
im = ip;
om = op + (ip - bp);
}
break;
case HASHKEY4('e','l','i','f'):
case HASHKEY5('e','r','r','o','r'):
case HASHKEY2('i','f'):
case HASHKEY5('i','f','d','e','f'):
case HASHKEY6('i','f','n','d','e','f'):
case HASHKEY5('u','n','d','e','f'):
break;
case HASHKEY6('i','n','c','l','u','d'):
if (*ip == 'e') ip++;
/*FALLTHROUGH*/
case HASHKEY6('d','e','f','i','n','e'):
case HASHKEY6('p','r','a','g','m','a'):
if (*ip < 'a' || *ip > 'z') break;
/*FALLTHROUGH*/
default:
flags |= JUNK|MATCH;
im = bp - 1;
om = op - 1;
break;
}
}
else
#endif
{
if (*ip == 'i' && *++ip == 'n' && *++ip == 'c' && *++ip == 'l' && *++ip == 'u' && *++ip == 'd' && *++ip == 'e')
{
while (*++ip == ' ' || *ip == '\t');
if (*ip++ == '<' && *ip++ == 's' && *ip++ == 't' && *ip++ == 'd' && *ip++ == 'a' && *ip++ == 'r' && *ip++ == 'g' && *ip++ == '.' && *ip++ == 'h' && *ip++ == '>')
{
op = strcopy(op, "\
if !defined(va_start)\n\
#if defined(__STDARG__)\n\
#include <stdarg.h>\n\
#else\n\
#include <varargs.h>\n\
#endif\n\
#endif\n\
");
op = linesync(proto, op, proto->line);
break;
}
}
else if (*ip == 'd' && *++ip == 'e' && *++ ip == 'f' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e' && (*++ip == ' ' || *ip == '\t'))
{
while (*++ip == ' ' || *ip == '\t');
if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t'))
{
t = ip;
while (*++t == ' ' || *t == '\t');
if (*t == 'e' && *++t == 'x' && *++ t == 't' && *++t == 'e' && *++t == 'r' && *++t == 'n' && (*++t == ' ' || *t == '\t' || *t == '\n' || *t == '\r'))
ip = t;
t = ip;
while (*++t == ' ' || *t == '\t');
if (*t == '_' && *(t + 1) == '_')
{
op = strcopy(op, "undef __MANGLE__\n");
op = linesync(proto, op, proto->line);
op = strcopy(op, "#define __MANGLE__ __LINKAGE__");
break;
}
}
flags |= DEFINE|MATCH;
im = bp - 1;
om = op - 1;
}
else if (*ip == 'u' && *++ip == 'n' && *++ ip == 'd' && *++ip == 'e' && *++ip == 'f' && (*++ip == ' ' || *ip == '\t'))
{
while (*++ip == ' ' || *ip == '\t');
if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t' || *ip == '\n' || *ip == '\r'))
{
op = strcopy(op, "undef __MANGLE__\n");
op = linesync(proto, op, proto->line);
op = strcopy(op, "#define __MANGLE__ __LINKAGE__");
break;
}
flags |= DEFINE|MATCH;
im = bp - 1;
om = op - 1;
}
}
ip = bp;
}
break;
}
else
break;
/*FALLTHROUGH*/
case '{':
if (proto->brace++ == 0 && paren == 0)
{
if (last == '=') flags |= INIT;
#if PROTOMAIN
else if (flags & CLASSIC)
{
if ((flags & (MATCH|OTHER|SKIP)) == MATCH)
{
if (args)
{
v = number(op, args < 0 ? -args : args);
v = strcopy(v, " argument actual/formal mismatch");
*v++ = ' ';
v = memcopy(v, im, ie - im);
*v = 0;
proto_error((char*)proto + sizeof(Proto_t), 2, op, NiL);
}
ip--;
/*UNDENT...*/
v = ie;
while (ie < ip)
if (*ie++ == '/' && *ie == '*')
{
e = ie - 1;
while (++ie < ip)
{
if (*ie == '*')
{
while (ie < ip && *ie == '*') ie++;
if (ie < ip && *ie == '/')
{
while (++ie < ip && (*ie == ' ' || *ie == '\t'));
while (e > v && (*(e - 1) == ' ' || *(e - 1) == '\t')) e--;
if (e > v && *e != '\n') *e++ = ' ';
t = ie;
while (--e >= v)
*--t = *e;
v = t;
break;
}
}
}
}
ie = v;
/*...INDENT*/
op = om++;
if (flags & EXTERN)
{
v = op;
while (v > ko && *--v != ' ');
if (*v != ' ')
{
om = (v = (op += 4)) + 1;
while (v >= ko + 4)
{
*v = *(v - 4);
v--;
}
memcopy(ko, "int ", 4);
}
if (*v == ' ')
{
while (*(v + 1) == '*')
*v++ = '*';
*v = '\t';
if ((v - ko) <= 8)
{
om = (e = ++op) + 1;
while (e > v)
{
*e = *(e - 1);
e--;
}
}
}
om = (v = (op += 7)) + 1;
while (v >= ko + 7)
{
*v = *(v - 7);
v--;
}
memcopy(ko, "extern ", 7);
}
PUTCHR('(');
t = op;
e = 0;
/*UNDENT...*/
while (ie < ip)
{
if ((c = *ie) == ' ' || c == '\t' || c == '\n')
{
while ((c = *++ie) == ' ' || c == '\t' || c == '\n');
if (ie >= ip) break;
if (c != '*' && op > om) PUTCHR(' ');
}
if ((n = ((c = *ie) == ',')) || c == ';')
{
if (flags & EXTERN)
{
m = op;
while (op > om && ((c = *(op - 1)) == '(' || c == ')' || c == '[' || c == ']'))
op--;
v = op;
while (op > om && (c = *(op - 1)) != ' ' && c != '*')
op--;
while (*(op - 1) == ' ')
op--;
if (!e)
{
e = op;
while (e > om && *(e - 1) == '*')
e--;
}
#if _s5r4_386_compiler_bug_fixed_
if (op <= om || *(op - 1) == ',' && (*op++ = ' '))
op = strcopy(op, "int");
#else
if (op <= om)
op = strcopy(op, "int");
else if (*(op - 1) == ',')
op = strcopy(op, " int");
#endif
while (v < m)
PUTCHR(*v++);
}
PUTCHR(',');
if (n)
{
if (x = !e) e = op - 1;
PUTCHR(' ');
m = t;
while (m < e)
PUTCHR(*m++);
if (x)
{
m = e;
while (*--e != ' ');
while (*(e - 1) == '*') e--;
op -= m - e;
}
}
while ((c = *++ie) == ' ' || c == '\t' || c == '\n');
if (ie >= ip) UNPUTCHR();
else PUTCHR(' ');
if (!n)
{
t = op;
e = 0;
}
}
else if (*ie == '*')
{
if (op > om && (c = *(op - 1)) == ' ') op--;
while (*ie == '*') PUTCHR(*ie++);
while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
if (c != '(') PUTCHR(' ');
}
else if (*ie == '(')
{
if (op > om && *(op - 1) == ' ') op--;
PUTCHR(*ie++);
while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
}
else if (*ie == ')')
{
if (op > om && *(op - 1) == '(')
proto_error((char*)proto + sizeof(Proto_t), 1, "function pointer argument prototype omitted", NiL);
PUTCHR(*ie++);
while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
}
else if ((flags & EXTERN) && (op == om || *(op - 1) == ' ') && *ie == 'r' && !strncmp(ie, "register", 8) && (*(ie + 8) == ' ' || *(ie + 8) == '\t' || *(ie + 8) == '\n'))
{
ie += 8;
if (op > om) UNPUTCHR();
}
else PUTCHR(*ie++);
}
/*...INDENT*/
if (op <= om) op = strcopy(op, "void");
PUTCHR(')');
if (flags & EXTERN)
{
PUTCHR(';');
PUTCHR('\n');
SYNCOUT();
KEEPOUT();
}
else
{
PUTCHR('\n');
PUTCHR(*ip);
}
ip++;
flags &= ~(MATCH|SKIP);
}
}
#endif
else if ((flags & (MATCH|PLUSONLY|SKIP|TOKENS)) == (MATCH|TOKENS))
{
line = proto->line;
op = strcopy(om, " __PARAM__(");
op = memcopy(op, im, ie - im);
PUTCHR(',');
PUTCHR(' ');
PUTCHR('(');
flags &= ~(MATCH|SKIP);
if (flags & VARIADIC)
{
if ((vc = ie - im + 1) > sizeof(proto->variadic)) vc = sizeof(proto->variadic);
memcopy(proto->variadic, im, vc);
op = strcopy(op, "va_alist)) __OTORP__(va_dcl)\n{");
}
else
{
flags |= SKIP;
proto->ip = im;
proto->op = op;
group = 0;
brack = 0;
for (;;)
{
switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
{
case '[':
brack++;
continue;
case ']':
brack--;
continue;
case '(':
if (paren++) group++;
continue;
case ')':
if (--paren == 0)
{
group = 0;
if (flags & MATCH)
{
flags &= ~(MATCH|SKIP);
op = memcopy(op, m, e - m);
}
break;
}
continue;
case ',':
if (paren == 1)
{
group = 0;
if (flags & MATCH)
{
flags &= ~(MATCH|SKIP);
op = memcopy(op, m, e - m);
}
PUTCHR(',');
PUTCHR(' ');
proto->op = op;
}
continue;
case T_ID:
if (group <= 1 && !brack)
{
flags |= MATCH;
m = proto->tp;
e = proto->ip;
}
continue;
default:
continue;
}
break;
}
PUTCHR(')');
PUTCHR(')');
}
if (!(flags & SKIP))
{
flags |= SKIP;
proto->op = strcopy(op, " __OTORP__(");
proto->ip = im + 1;
n = *(ie - 1);
*(ie - 1) = ';';
c = *ie;
*ie = 0;
lex(proto, (flags & GLOBAL) | DECLARE);
*(ie - 1) = n;
*ie = c;
proto->ip = ie;
op = proto->op;
PUTCHR(')');
}
if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6);
op = linesync(proto, op, proto->line = line);
if (flags & DIRECTIVE)
{
proto->brace = 0;
PUTCHR('\n');
PUTCHR('#');
}
else if (!(flags & VARIADIC)) PUTCHR('{');
}
}
flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP);
call = 0;
group = 0;
break;
case '}':
flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP|TOKENS);
if (--proto->brace == 0)
{
flags &= ~(INIT|VARIADIC|VARIADIC2);
#if PROTOMAIN
if (flags & EXTERN) BACKOUT();
#endif
}
call = 0;
group = 0;
paren = 0;
break;
case '=':
if (last == '?') flags |= DIRECTIVE;
else if (paren == 0 && (flags & (INIT|MATCH|SKIP)) == MATCH)
{
if (last == ')' && proto->brace && (group != 2 || call != 2)) flags |= SKIP;
else goto fsm_statement;
}
goto fsm_other;
case ',':
#if PROTOMAIN
if (flags & CLASSIC)
{
if (paren == 1) args++;
else
{
args--;
flags &= ~MATCH;
}
break;
}
#endif
if (paren == 0 && (flags & DECLARE)) *(op - 1) = c = ';';
/*FALLTHROUGH*/
case ';':
fsm_statement:
if (flags & INIT) /* ignore */;
#if PROTOMAIN
else if (flags & CLASSIC)
{
if (paren == 0)
{
if ((flags & MATCH) && last == ')')
flags &= ~MATCH;
if (!(flags & MATCH))
{
call = 0;
group = 0;
flags &= ~SKIP;
if (flags & EXTERN) BACKOUT();
if (flags & SLIDE)
{
SYNC();
return 0;
}
}
else
{
args--;
if ((flags & (EXTERN|SKIP)) == (EXTERN|SKIP))
BACKOUT();
}
}
}
#endif
else if (paren == 0)
{
if ((flags & (MATCH|OTHER|SKIP)) == MATCH && call > 1)
{
if ((flags & MANGLE) && func)
{
func[0] = 'F';
func[1] = 'U';
func[2] = 'N';
func[3] = 'C';
func = 0;
}
if ((flags & (DECLARE|INDIRECT)) == INDIRECT && aim && aie < im)
{
while (aie < ip && (*aie == ' ' || *aie == '\t' || *aie == '\n')) aie++;
v = aim;
while (v < aie)
if (*v++ == ')') break;
while (v < aie && (*v == ' ' || *v == '\t' || *v == '\n')) v++;
if (v == aie || !(flags & PLUSPLUS))
{
if (flags & PLUSPLUS) n = 3;
else if (v == aie && *v == '(') n = 10;
else n = 11;
ko = op;
om += n;
v = op += n;
while (v >= ko + n)
{
*v = *(v - n);
v--;
}
if (flags & PLUSPLUS) memcopy(aom, "(...))", 6);
else if (n == 10) memcopy(aom, "(__VARARG__))", 13);
else
{
ko = strcopy(aom, " __PROTO__(");
ko = memcopy(ko, aim, aie - aim);
*ko = ')';
if (++ko >= om)
{
*ko++ = ')';
om = ko;
}
}
}
}
else if (flags & TYPEDEF)
{
op = om;
while (*--op == ' ' || *op == '\t' || *op == '\n');
if (*op != ')')
{
op = om += 14;
*--op = ')';
while ((x = *(op - 14)) >= 'A' && x <= 'Z' || x >= 'a' && x <= 'z' || x >= '0' && x <= '9' || x == '_')
*--op = x;
memcopy(op - 13, "(__OTORP__(*)", 13);
}
}
if (flags & OTHER)
;
else if (flags & PLUSPLUS)
{
op = om;
if (!(flags & TOKENS)) op = strcopy(op, "(...)");
else op = memcopy(op, im, ie - im);
PUTCHR(c);
}
else
{
if (flags & DECLARE) op = strcopy(om, "()");
else if (!(flags & TOKENS)) op = strcopy(om, "(__VARARG__)");
else
{
op = strcopy(om, " __PROTO__(");
op = memcopy(op, im, ie - im);
PUTCHR(')');
}
if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6);
PUTCHR(c);
}
flags &= ~(MATCH|VARIADIC|VARIADIC2);
if (c == ',' && !(flags & INDIRECT))
{
call = 1;
group = 0;
break;
}
}
else if (flags & (OTHER|SKIP)) call = 0;
if (c == ';')
{
flags &= ~(EXTERNALIZE|MANGLE|TOKENS|TYPEDEF);
call = 0;
if (flags & SLIDE)
{
SYNC();
return 0;
}
}
else call = call > 1 && c == ',';
group = 0;
flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP);
}
else if (paren == 1 && group == 1 && !(flags & (IDID|MANGLE))) flags |= TOKENS|OTHER;
break;
case T_DO:
case T_IF:
flags |= TOKENS|SKIP;
break;
case T_EXTERN:
#if PROTOMAIN
if (flags & CLASSIC)
{
if (proto->brace == 0)
flags |= SKIP;
}
else
#endif
if (paren == 0 && !(flags & TYPEDEF))
{
flags |= MANGLE;
if (!(flags & PLUSONLY) || proto->package)
{
op = strcopy(op, " __MANGLE__");
if (proto->package)
{
op = strcopy(op - 1, proto->package);
func = op + 1;
op = strcopy(op, "_DATA__");
}
}
else
func = 0;
}
break;
case T_VARIADIC:
if (paren == 0 && (flags & (DECLARE|VARIADIC)) == DECLARE)
{
op -= 3;
SYNC();
return c;
}
if (paren == 1 && !(flags & SKIP))
flags |= VARIADIC;
flags |= TOKENS;
break;
case T_VOID:
goto fsm_id;
case T_VA_START:
if ((flags & (PLUSONLY|VARIADIC)) == VARIADIC)
{
flags &= ~MATCH;
line = proto->line;
op = strcopy(op - 8, "__VA_START__");
SYNC();
for (;;)
{
switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
{
case 0:
case ';':
break;
case T_ID:
if (!(flags & MATCH))
{
flags |= MATCH;
m = proto->tp;
e = proto->ip;
}
continue;
default:
continue;
}
break;
}
CACHE();
if (flags & MATCH)
{
v = m;
n = e - m;
}
else
{
v = "ap";
n = 2;
}
op = strcopy(op, " __OTORP__(");
proto->ip = proto->variadic;
proto->op = op;
flags &= ~MATCH;
group = 0;
bp = proto->ip + 1;
if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9;
for (;;)
{
switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
{
case '(':
if (paren++) group++;
continue;
case ')':
if (--paren == 0)
{
if (flags & MATCH)
{
flags &= ~MATCH;
if (!(flags & VARIADIC2))
{
op = memcopy(op, m, e - m);
op = strcopy(op, " = ");
}
op = strcopy(op, "va_arg(");
op = memcopy(op, v, n);
PUTCHR(',');
PUTCHR(' ');
if (m > bp) op = memcopy(op, bp, m - bp);
else op = strcopy(op, "int ");
if (group > 1) op = strcopy(op, ")()");
else op = memcopy(op, e, proto->ip - e - 1);
PUTCHR(')');
PUTCHR(';');
}
group = 0;
break;
}
continue;
case ',':
if (paren == 1)
{
if (flags & MATCH)
{
flags &= ~MATCH;
if (!(flags & VARIADIC2))
{
op = memcopy(op, m, e - m);
op = strcopy(op, " = ");
}
op = strcopy(op, "va_arg(");
op = memcopy(op, v, n);
PUTCHR(',');
PUTCHR(' ');
if (m > bp) op = memcopy(op, bp, m - bp);
else op = strcopy(op, "int ");
if (group > 1) op = strcopy(op, ")()");
else op = memcopy(op, e, proto->ip - e - 1);
PUTCHR(')');
PUTCHR(';');
bp = proto->ip + 1;
if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9;
}
group = 0;
proto->op = op;
}
continue;
case T_ID:
if (group <= 1)
{
flags |= MATCH;
m = proto->tp;
e = proto->ip;
}
continue;
default:
continue;
}
break;
}
op = strcopy(op, ")");
flags |= VARIADIC2;
proto->line = line;
call = 0;
break;
}
/*FALLTHROUGH*/
case T_ID:
fsm_id:
#if PROTOMAIN
if (flags & CLASSIC)
{
if (!args && paren == 1) args++;
break;
}
#endif
if (paren == 0)
{
if (last == ')')
{
if (proto->brace == 0 && !(flags & DECLARE)) flags |= SKIP;
call = !call;
}
else if ((flags & SKIP) || c == T_ID || c == T_VOID) call++;
else flags |= SKIP;
if (last == T_ID) flags |= IDID;
}
c = T_ID;
flags |= TOKENS;
break;
case T_INVALID:
if (*proto->tp >= '0' && *proto->tp <= '9')
{
n = 0;
for (;; op--)
{
switch (*(op - 1))
{
case 'f':
case 'F':
t = op;
while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
if (*t == '.')
op--;
n = 0;
break;
case 'l':
case 'L':
if (!(n & 01))
{
n |= 01;
t = op;
while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
if (*t == '.')
{
n = 0;
op--;
break;
}
}
continue;
case 'u':
case 'U':
n |= 02;
continue;
}
break;
}
if (n & 01)
*op++ = 'L';
if (n & 02)
{
m = op;
t = op = m + 10;
while ((c = *--m) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
*--t = c;
c = *t;
strcopy(m + 1, "(unsigned)");
*t = c;
break;
}
}
goto fsm_other;
#if PROTOMAIN
case '[':
if ((flags & CLASSIC) && paren == 0 && group <= 2) flags |= SKIP;
/*FALLTHROUGH*/
#endif
default:
fsm_other:
#if PROTOMAIN
if (flags & CLASSIC) break;
#endif
flags |= TOKENS;
if (paren == 0) flags |= OTHER;
break;
}
else if (c == '#' && *ip != '(') flags |= SHARP;
last = c;
#if PROTOMAIN
if ((flags & (EXTERN|MATCH)) == (EXTERN|MATCH) && ((flags & (DIRECTIVE|SKIP)) || proto->brace || c != '(' && c != ')' && c != '*' && c != T_ID))
CACHEOUT();
else
#endif
SYNCOUT();
goto fsm_start;
}
else if (flags & (INIT_DEFINE|INIT_INCLUDE))
{
#if PROTOMAIN
if ((flags & YACC) && c == '%' && *ip == '{')
t = 0;
else
#endif
{
if (c == '#')
{
for (t = ip; *t == ' ' || *t == '\t'; t++);
if (*t++ == 'i' && *t++ == 'f' && *t++ == 'n' && *t++ == 'd' && *t++ == 'e' && *t++ == 'f')
{
#if !PROTOMAIN
while (*t == ' ' || *t == '\t') t++;
if (*t != '_')
#endif
t = 0;
}
}
else
t = "";
}
if (t)
{
#if PROTOMAIN
n = ip - proto->tp;
ip -= n;
op -= n;
#else
ip = bp;
op = proto->op;
#endif
}
else
while (*ip != '\n')
*op++ = *ip++;
op = init(proto, op, flags);
op = linesync(proto, op, proto->line);
flags &= ~(INIT_DEFINE|INIT_INCLUDE);
proto->flags &= ~(INIT_DEFINE|INIT_INCLUDE);
goto fsm_start;
}
SYNC();
return c;
}
/*
* close a proto buffer stream
*/
void
pppclose(char* iob)
{
register Proto_t* proto = (Proto_t*)(iob - sizeof(Proto_t));
if (proto->flags & MORE) close(proto->fd);
free((char*)proto); /* some ANSI cc's botch the free() prototype */
}
/*
* open a new proto buffer stream
* read buffer pointer returned
* 0 returned on error or if no magic
*
* file !=0 file path to open, otherwise use fd
* fd open file fd if file==0
* notice !=0 copyright notice info commented at the top
* options !=0 additional notice name=value pairs, space or ; separated
* package !=0 generate header for this package
*/
char*
pppopen(char* file, int fd, char* notice, char* options, char* package, char* comment, int flags)
{
register Proto_t* proto;
register char* iob;
register long n;
register char* s;
char* t;
int pragma;
int clr;
int hit;
int i;
int z;
char* b;
#if PROTOMAIN
int comlen;
char com[80];
#endif
int m = 0;
static int retain;
/*
* initialize proto
*/
#if PROTOMAIN
if (flags & PROTO_CLASSIC) flags &= ~PROTO_INCLUDE;
#endif
if (flags & PROTO_RETAIN) flags &= ~retain;
else retain &= PROTO_INITIALIZED;
if (file && (fd = open(file, O_RDONLY)) < 0) return 0;
#if !PROTOMAIN
if ((n = lseek(fd, 0L, 2)) > 0)
{
if (lseek(fd, 0L, 0)) return 0;
if (n < CHUNK) n = CHUNK;
else if (n > 2 * BLOCK) n = 0;
m = 1;
}
if (n > 0)
{
/*
* file read in one chunk
*/
if (!(proto = newof(0, Proto_t, 1, 4 * n + 2)))
return 0;
proto->iz = n;
proto->oz = 3 * n;
n = 0;
}
else
#endif
{
/*
* file read in BLOCK chunks
*/
n = BLOCK;
if (!(proto = newof(0, Proto_t, 1, 5 * n + 2)))
return 0;
proto->iz = n;
proto->oz = 3 * n;
proto->flags |= MORE;
}
proto->fd = fd;
proto->package = package;
iob = (char*)proto + sizeof(Proto_t);
proto->op = proto->ob = iob;
proto->ip = proto->ib = iob + proto->oz + n;
if (m) proto->options |= REGULAR;
if (!comment)
comment = "/*";
if (!(proto->cc[0] = comment[0]))
notice = options = 0;
else if (comment[1])
{
proto->cc[1] = comment[1];
proto->cc[2] = comment[2] ? comment[2] : comment[0];
}
else
proto->cc[1] = proto->cc[2] = comment[0];
/*
* read the first chunk
*/
n = read(fd, proto->ip, proto->iz);
if (!(proto->flags & MORE))
close(fd);
if (n < 0)
{
pppclose(iob);
return 0;
}
*(proto->ip + n) = 0;
/*
* check for proto pragma in first block of lines
* pragma blanked out if found
*
* -1 no pragma
* 0 #pragma noprototyped
* 1 #pragma prototyped
*
* NOTE: matches may occur inside comments and quotes
*/
#if PROTOMAIN
if (!notice && !options || (comlen = astlicense(com, sizeof(com), NiL, "type=check", proto->cc[0], proto->cc[1], proto->cc[2])) <= 0)
*com = 0;
#endif
hit = (notice || options) ? 0 : HIT_noticed;
pragma = -1;
s = proto->ip;
m = MAGICTOP;
while (m-- > 0 && *s && hit != (HIT_prototyped|HIT_noticed))
{
while (*s == ' ' || *s == '\t')
s++;
if (*s == '#')
{
b = s++;
while (*s == ' ' || *s == '\t')
s++;
if (*s == *PRAGMADIR && !strncmp(s, PRAGMADIR, sizeof(PRAGMADIR) - 1) && (*(s += sizeof(PRAGMADIR) - 1) == ' ' || *s == '\t'))
{
clr = 0;
while (*s && *s != '\r' && *s != '\n')
{
for (; *s == ' ' || *s == '\t'; s++);
for (t = s; *s && *s != ' ' && *s != '\t' && *s != '\r' && *s != '\n'; s++);
z = s - t;
for (i = 0; i < elementsof(pragmas); i++)
if (pragmas[i].size == z && !strncmp(t, pragmas[i].name, z))
{
clr = 1;
hit |= pragmas[i].hit;
switch (pragmas[i].hit)
{
case HIT_noticed:
notice = options = 0;
break;
case HIT_prototyped:
pragma = pragmas[i].val;
break;
}
}
}
if (clr)
{
#if PROTOMAIN
if (!(flags & PROTO_DISABLE) || (flags & PROTO_NOPRAGMA))
#endif
for (; b < s; *b++ = ' ');
}
}
}
else if (*s == *GENERATED && !strncmp(s, GENERATED, sizeof(GENERATED) - 1))
{
pragma = 0;
break;
}
#if PROTOMAIN
else if (*s == '%' && *(s + 1) == '{')
proto->flags |= YACC;
else if (!(hit & HIT_noticed))
{
if (*s == *com && !strncmp(s, com, comlen))
{
hit |= HIT_noticed;
notice = options = 0;
}
else
for (; *s && *s != '\n' && !(hit & HIT_noticed); s++)
for (i = 0; i < elementsof(notices); i++)
if (*s == notices[i].name[0] && !strncmp(s, notices[i].name, notices[i].size))
{
s += notices[i].size;
if (notices[i].val)
{
while (*s == ' ' || *s == '\t')
s++;
if (*s == '(' && (*(s + 1) == 'c' || *(s + 1) == 'C') && *(s + 2) == ')' || *s >= '0' && *s <= '9' && *(s + 1) >= '0' && *(s + 1) <= '9')
{
hit |= notices[i].hit;
notice = options = 0;
}
}
else
{
hit |= notices[i].hit;
notice = options = 0;
}
break;
}
}
#endif
while (*s && *s++ != '\n');
}
if (flags & PROTO_PLUSPLUS) proto->flags |= PLUSPLUS;
if (flags & PROTO_TEST) proto->test = 1;
if (flags & PROTO_EXTERNALIZE) proto->options |= EXTERNALIZE;
#if PROTOMAIN
if (flags & PROTO_CLASSIC) pragma = -pragma;
if (flags & PROTO_DISABLE) pragma = 0;
if (flags & PROTO_LINESYNC) proto->flags |= LINESYNC;
if (!(proto->flags & YACC) && file && (m = strlen(file)) > 2 && file[--m] == 'y' && file[--m] == '.')
proto->flags |= YACC;
#endif
if (pragma <= 0)
{
if (flags & PROTO_PLUSPLUS)
{
flags &= ~(PROTO_HEADER|PROTO_INCLUDE);
proto->flags |= PLUSONLY;
}
else if (!(flags & (PROTO_FORCE|PROTO_PASS)))
{
pppclose(iob);
return 0;
}
else if ((flags & (PROTO_FORCE|PROTO_PASS)) == PROTO_PASS || !pragma)
{
proto->flags |= PASS;
if (proto->flags & MORE)
proto->oz += proto->iz;
proto->iz = n;
if (notice || options)
{
if (proto->cc[0] == '#' && proto->ip[0] == '#' && proto->ip[1] == '!')
{
s = proto->ip;
while (*s && *s++ != '\n');
m = s - proto->ip;
proto->op = memcopy(proto->op, proto->ip, m);
proto->ip = s;
proto->iz = n -= m;
}
#if PROTOMAIN
if (proto->cc[0])
{
if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0)
proto_error((char*)proto + sizeof(Proto_t), 1, proto->op, NiL);
else
proto->op += comlen;
}
if (!(flags & PROTO_CLASSIC) && !(proto->flags & YACC))
#endif
proto->op = linesync(proto, proto->op, 1);
proto->iz += proto->op - proto->ob;
}
memcopy(proto->op, proto->ip, n);
return iob;
}
}
#if PROTOMAIN
if (!(retain & PROTO_INITIALIZED))
{
retain |= PROTO_INITIALIZED;
ppfsm(FSM_INIT, NiL);
}
#endif
proto->line = 1;
#if CHUNK >= 512
if (notice || options || (flags & (PROTO_HEADER|PROTO_INCLUDE)))
{
#if PROTOMAIN
if (notice || options)
{
if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0)
proto_error((char*)proto + sizeof(Proto_t), 1, proto->op, NiL);
else
proto->op += comlen;
}
#endif
if (flags & PROTO_INCLUDE)
{
proto->flags |= INIT_INCLUDE;
if (flags & PROTO_RETAIN)
retain |= PROTO_INCLUDE;
}
else if (flags & PROTO_HEADER)
{
if (flags & PROTO_RETAIN) retain |= PROTO_HEADER;
#if PROTOMAIN
if (flags & PROTO_CLASSIC)
{
*proto->op++ = '#';
proto->op = strcopy(proto->op, PRAGMADIR);
*proto->op++ = ' ';
proto->op = strcopy(proto->op, pragmas[0].name);
*proto->op++ = '\n';
}
else
#endif
proto->flags |= INIT_DEFINE;
}
#if PROTOMAIN
if (!(flags & PROTO_CLASSIC))
{
if (proto->flags & YACC)
{
proto->op = strcopy(proto->op, "\n%{\n" + !notice);
proto->op = strcopy(proto->op, GENERATED);
proto->op = strcopy(proto->op, "%}\n");
}
else
{
if (n || notice || options)
*proto->op++ = '\n';
proto->op = strcopy(proto->op, GENERATED);
if (n)
proto->op = linesync(proto, proto->op, proto->line);
else if (proto->flags & (INIT_DEFINE|INIT_INCLUDE))
proto->op = init(proto, proto->op, proto->flags);
}
}
#endif
}
#endif
#if PROTOMAIN
proto->file = file;
if (flags & PROTO_CLASSIC)
{
proto->flags |= CLASSIC;
if (!(flags & PROTO_HEADER)) proto->flags |= EXTERN;
}
#endif
return iob;
}
/*
* read next proto'd chunk into iob
* the chunk is 0 terminated and its size is returned
*/
int
pppread(char* iob)
{
register Proto_t* proto = (Proto_t*)(iob - sizeof(Proto_t));
register int n;
if (proto->flags & PASS)
{
if (proto->iz)
{
n = proto->iz;
proto->iz = 0;
}
else if (!(proto->flags & MORE)) n = 0;
else if ((n = read(proto->fd, proto->ob, proto->oz)) <= 0 || (proto->options & REGULAR) && n < proto->oz)
{
proto->flags &= ~MORE;
close(proto->fd);
}
}
else
{
if (proto->op == proto->ob)
{
if (proto->flags & ERROR) return -1;
#if PROTOMAIN
if (proto->flags & YACC)
{
register char* ip = proto->ip;
register char* op = proto->ob;
register char* ep = proto->ob + proto->oz - 2;
if (!*ip)
{
ip = proto->ip = proto->ib;
if (!(proto->flags & MORE)) n = 0;
else if ((n = read(proto->fd, ip, proto->iz)) <= 0 || (proto->options & REGULAR) && n < proto->iz)
{
if (n < 0) n = 0;
proto->flags &= ~MORE;
close(proto->fd);
}
ip[n] = 0;
}
if (proto->flags & YACCSPLIT)
{
proto->flags &= ~YACCSPLIT;
if (*ip == '%')
{
*op++ = *ip++;
if (proto->flags & YACC2) proto->flags &= ~YACC;
else proto->flags |= YACC2;
}
}
if (proto->flags & YACC)
while (op < ep && (n = *op++ = *ip))
{
ip++;
if (n == '%')
{
if (*ip == '%' && (ip == proto->ip + 1 || *(ip - 2) == '\n'))
{
*op++ = *ip++;
if (proto->flags & YACC2) proto->flags &= ~YACC;
else proto->flags |= YACC2;
break;
}
if (!*ip)
{
*op++ = '%';
proto->flags |= YACCSPLIT;
break;
}
}
else if (n == '\n') proto->line++;
}
proto->op = memcopy(proto->ob, proto->ip, ip - proto->ip);
proto->ip = ip;
}
else
#endif
lex(proto, proto->flags);
if ((proto->flags & (ERROR|MORE)) == ERROR)
proto->op = strcopy(proto->op, "/* NOTE: some constructs may not have been converted */\n");
}
n = proto->op - proto->ob;
proto->op = proto->ob;
}
return n;
}
#if !PROTOMAIN
/*
* drop control of iob after first pppread()
* return value is input fd
* if fd<0 then all data in iob
*/
int
pppdrop(char* iob)
{
register Proto_t* proto = (Proto_t*)(iob - sizeof(Proto_t));
if (proto->flags & MORE)
{
proto->flags &= ~MORE;
return proto->fd;
}
return -1;
}
#endif