Home | History | Annotate | Download | only in common
      1 /***********************************************************************
      2 *                                                                      *
      3 *               This software is part of the ast package               *
      4 *          Copyright (c) 1986-2009 AT&T Intellectual Property          *
      5 *                      and is licensed under the                       *
      6 *                  Common Public License, Version 1.0                  *
      7 *                    by AT&T Intellectual Property                     *
      8 *                                                                      *
      9 *                A copy of the License is available at                 *
     10 *            http://www.opensource.org/licenses/cpl1.0.txt             *
     11 *         (with md5 checksum 059e8cd6165cb4c31e351f2b69388fd9)         *
     12 *                                                                      *
     13 *              Information and Software Systems Research               *
     14 *                            AT&T Research                             *
     15 *                           Florham Park NJ                            *
     16 *                                                                      *
     17 *                 Glenn Fowler <gsf (at) research.att.com>                  *
     18 *                                                                      *
     19 ***********************************************************************/
     20 #pragma prototyped
     21 /*
     22  * Glenn Fowler
     23  * AT&T Research
     24  *
     25  * convert C prototypes to ANSI, K&R and C++ styles or K&R to ANSI
     26  * slips into the pp block read
     27  *
     28  * define PROTOMAIN for standalone proto
     29  * PROTOMAIN is coded for minimal library support
     30  */
     31 
     32 static const char id[] = "\n@(#)$Id: proto (AT&T Research) 2008-05-11 $\0\n";
     33 
     34 #if PROTOMAIN
     35 
     36 #include "ppfsm.c"
     37 
     38 #include <hashkey.h>
     39 
     40 #if PROTO_STANDALONE
     41 #undef	O_RDONLY
     42 #endif
     43 
     44 #else
     45 
     46 #include "pplib.h"
     47 #include "ppfsm.h"
     48 
     49 #endif
     50 
     51 #define MAGICGEN	"/* : : generated by proto : : */\n"
     52 
     53 #define MAGICDIR	"pragma"	/* proto magic directive	*/
     54 #define MAGICARG	"prototyped"	/* proto magic directive arg	*/
     55 #define MAGICOFF	"noticed"	/* no notice if found in pragma	*/
     56 #define MAGICTOP	64		/* must be in these top lines	*/
     57 #define NOTICED		"Copyright"	/* no notice if found in magic	*/
     58 #define PUBLICDOMAIN	"Public Domain"	/* no notice if found in magic	*/
     59 
     60 struct proto				/* proto buffer state		*/
     61 {
     62 	int		brace;		/* {..} level			*/
     63 	int		call;		/* call level			*/
     64 	int		fd;		/* input file descriptor	*/
     65 	char*		file;		/* input file name		*/
     66 	long		flags;		/* coupled flags		*/
     67 	long		options;	/* uncoupled flags		*/
     68 	char*		package;	/* header package		*/
     69 	int		line;		/* input line count		*/
     70 	int		test;		/* testing			*/
     71 
     72 	char*		tp;		/* input token base		*/
     73 
     74 	int		iz;		/* input buffer size		*/
     75 	char*		ib;		/* input buffer base		*/
     76 	char*		ip;		/* input buffer pointer		*/
     77 
     78 	int		oz;		/* output buffer size		*/
     79 	char*		ob;		/* output buffer base		*/
     80 	char*		op;		/* output buffer pointer	*/
     81 	char*		ox;		/* output buffer externalize	*/
     82 
     83 	char		cc[3];		/* beg mid end comment char	*/
     84 	char		pushback[4];	/* pushback area for caller	*/
     85 
     86 	char		variadic[256];	/* variadic args buffer		*/
     87 
     88 	/* output buffer */
     89 	/* slide buffer */
     90 	/* input buffer */
     91 };
     92 
     93 /*
     94  * proto is separate from pp so these undef's are ok
     95  */
     96 
     97 #undef	CLASSIC
     98 #define CLASSIC		(1L<<0)
     99 #undef	DECLARE
    100 #define DECLARE		(1L<<1)
    101 #undef	DEFINE
    102 #define DEFINE		(1L<<2)
    103 #undef	DIRECTIVE
    104 #define DIRECTIVE	(1L<<3)
    105 #undef	ERROR
    106 #define ERROR		(1L<<4)
    107 #undef	EXTERN
    108 #define EXTERN		(1L<<5)
    109 #undef	EXTERNALIZE
    110 #define EXTERNALIZE	(1L<<6)
    111 #undef	IDID
    112 #define IDID		(1L<<7)
    113 #undef	INDIRECT
    114 #define INDIRECT	(1L<<8)
    115 #undef	INIT
    116 #define INIT		(1L<<9)
    117 #undef	INIT_DEFINE
    118 #define INIT_DEFINE	(1L<<10)
    119 #undef	INIT_INCLUDE
    120 #define INIT_INCLUDE	(1L<<11)
    121 #undef	JUNK
    122 #define JUNK		(1L<<12)
    123 #undef	LINESYNC
    124 #define LINESYNC	(1L<<13)
    125 #undef	MANGLE
    126 #define MANGLE		(1L<<14)
    127 #undef	MATCH
    128 #define MATCH		(1L<<15)
    129 #undef	MORE
    130 #define MORE		(1L<<16)
    131 #undef	OTHER
    132 #define OTHER		(1L<<17)
    133 #undef	PASS
    134 #define PASS		(1L<<18)
    135 #undef	PLUSONLY
    136 #define PLUSONLY	(1L<<19)
    137 #undef	PLUSPLUS
    138 #define PLUSPLUS	(1L<<20)
    139 #undef	RECURSIVE
    140 #define RECURSIVE	(1L<<21)
    141 #undef	SHARP
    142 #define SHARP		(1L<<22)
    143 #undef	SKIP
    144 #define SKIP		(1L<<23)
    145 #undef	SLIDE
    146 #define SLIDE		(1L<<24)
    147 #undef	TOKENS
    148 #define TOKENS		(1L<<25)
    149 #undef	TYPEDEF
    150 #define TYPEDEF		(1L<<26)
    151 #undef	VARIADIC
    152 #define VARIADIC	(1L<<27)
    153 #undef	VARIADIC2
    154 #define VARIADIC2	(1L<<28)
    155 #undef	YACC
    156 #define YACC		(1L<<29)
    157 #undef	YACCSPLIT
    158 #define YACCSPLIT	(1L<<30)
    159 #undef	YACC2
    160 #define YACC2		(1L<<31)
    161 
    162 #undef	GLOBAL
    163 #define GLOBAL		(MORE)
    164 
    165 #undef	REGULAR
    166 #define REGULAR		(1L<<0)
    167 
    168 #ifndef CHUNK
    169 #define CHUNK		1024
    170 #endif
    171 #define BLOCK		(8*CHUNK)
    172 
    173 #define T_VA_START	(N_TOKEN+1)
    174 
    175 #define RESERVED(b,e,n)	((((long)(b))<<16)|(((long)(e))<<8)|((long)(n)))
    176 
    177 /*
    178  * generate integer
    179  * pointer to end returned
    180  */
    181 
    182 static char*
    183 number(register char* p, register long n)
    184 {
    185 	register long	d;
    186 
    187 	for (d = 1000000; d > 1; d /= 10)
    188 		if (n >= d) *p++ = '0' + (n / d) % 10;
    189 	*p++ = '0' + n % 10;
    190 	return p;
    191 }
    192 
    193 #if PROTOMAIN
    194 
    195 static int		errors;
    196 
    197 #if PROTO_STANDALONE
    198 
    199 /*
    200  * namespace pollution forces us to claim parts of libc
    201  */
    202 
    203 #undef	memcpy
    204 #define memcpy(t,f,n)	memcopy(t,f,n)
    205 #undef	strcpy
    206 #define strcpy(t,f)	strcopy(t,f)
    207 #undef	strlen
    208 #define strlen(s)	sstrlen(s)
    209 #undef	strncmp
    210 #define strncmp(s,t,n)	sstrncmp(s,t,n)
    211 
    212 /*
    213  * environmentally safe strlen()
    214  */
    215 
    216 static int
    217 sstrlen(register const char* s)
    218 {
    219 	register const char*	b;
    220 
    221 	for (b = s; *s; s++);
    222 	return s - b;
    223 }
    224 
    225 /*
    226  * environmentally safe strncmp()
    227  */
    228 
    229 static int
    230 sstrncmp(register const char* s, register char* t, register int n)
    231 {
    232 	register const char*	e = s + n;
    233 
    234 	while (s < e)
    235 	{
    236 		if (*s != *t || !*s)
    237 			return *s - *t;
    238 		s++;
    239 		t++;
    240 	}
    241 	return 0;
    242 }
    243 
    244 /*
    245  * strcpy() except pointer to end returned
    246  */
    247 
    248 static char*
    249 strcopy(register char* s, register const char* t)
    250 {
    251 	while (*s++ = *t++);
    252 	return s - 1;
    253 }
    254 
    255 #endif
    256 
    257 static void
    258 proto_error(char* iob, int level, char* msg, char* arg)
    259 {
    260 	register char*	p;
    261 	char		buf[1024];
    262 
    263 	p = strcopy(buf, "proto: ");
    264 	if (iob)
    265 	{
    266 		register struct proto*	proto = (struct proto*)(iob - sizeof(struct proto));
    267 
    268 		if (proto->line)
    269 		{
    270 			if (proto->file)
    271 			{
    272 				*p++ = '"';
    273 				p = strcopy(p, proto->file);
    274 				*p++ = '"';
    275 				*p++ = ',';
    276 				*p++ = ' ';
    277 			}
    278 			p = strcopy(p, "line ");
    279 			p = number(p, proto->line);
    280 		}
    281 		else if (proto->file)
    282 			p = strcopy(p, proto->file);
    283 	}
    284 	else
    285 	{
    286 		p = strcopy(p, msg);
    287 		msg = arg;
    288 		arg = 0;
    289 	}
    290 	if (*(p - 1) != ' ')
    291 	{
    292 		*p++ = ':';
    293 		*p++ = ' ';
    294 	}
    295 	if (level == 1)
    296 		p = strcopy(p, "warning: ");
    297 	p = strcopy(p, msg);
    298 	if (arg)
    299 	{
    300 		*p++ = ' ';
    301 		p = strcopy(p, arg);
    302 	}
    303 	*p++ = '\n';
    304 	write(2, buf, p - buf);
    305 	if (level >= 3)
    306 		exit(level - 2);
    307 	if (level >= 2)
    308 		errors++;
    309 }
    310 
    311 /*
    312  * memcpy() but pointer to end returned
    313  */
    314 
    315 static char*
    316 memcopy(register char* s, register char* t, int n)
    317 {
    318 	register char*	e = t + n;
    319 
    320 	while (t < e) *s++ = *t++;
    321 	return s;
    322 }
    323 
    324 #include "../libast/port/astlicense.c"
    325 
    326 #else
    327 
    328 #define memcopy(s,t,n)	(((char*)memcpy(s,t,n))+(n))
    329 
    330 #endif
    331 
    332 /*
    333  * generate line sync
    334  * pointer to end returned
    335  */
    336 
    337 static char*
    338 linesync(register struct proto* proto, register char* p, register long n)
    339 {
    340 #if PROTOMAIN
    341 	if (proto->flags & LINESYNC)
    342 #endif
    343 	{
    344 #if PROTOMAIN
    345 		p = strcopy(p, "\n#line ");
    346 #else
    347 		p = strcopy(p, "\n# ");
    348 #endif
    349 		p = number(p, n);
    350 		*p++ = '\n';
    351 	}
    352 	return p;
    353 }
    354 
    355 /*
    356  * output init header
    357  * pointer to end returned
    358  */
    359 
    360 static char*
    361 init(struct proto* proto, char* op, int flags)
    362 {
    363 	register char*	s;
    364 
    365 	if (flags & INIT_DEFINE)
    366 	{
    367 		op = strcopy(op, "\
    368 \n\
    369 #if !defined(__PROTO__)\n\
    370 #  if defined(__STDC__) || defined(__cplusplus) || defined(_proto) || defined(c_plusplus)\n\
    371 #    if defined(__cplusplus)\n\
    372 #      define __LINKAGE__	\"C\"\n\
    373 #    else\n\
    374 #      define __LINKAGE__\n\
    375 #    endif\n\
    376 #    define __STDARG__\n\
    377 #    define __PROTO__(x)	x\n\
    378 #    define __OTORP__(x)\n\
    379 #    define __PARAM__(n,o)	n\n\
    380 #    if !defined(__STDC__) && !defined(__cplusplus)\n\
    381 #      if !defined(c_plusplus)\n\
    382 #      	define const\n\
    383 #      endif\n\
    384 #      define signed\n\
    385 #      define void		int\n\
    386 #      define volatile\n\
    387 #      define __V_		char\n\
    388 #    else\n\
    389 #      define __V_		void\n\
    390 #    endif\n\
    391 #  else\n\
    392 #    define __PROTO__(x)	()\n\
    393 #    define __OTORP__(x)	x\n\
    394 #    define __PARAM__(n,o)	o\n\
    395 #    define __LINKAGE__\n\
    396 #    define __V_		char\n\
    397 #    define const\n\
    398 #    define signed\n\
    399 #    define void		int\n\
    400 #    define volatile\n\
    401 #  endif\n\
    402 #  define __MANGLE__	__LINKAGE__\n\
    403 #  if defined(__cplusplus) || defined(c_plusplus)\n\
    404 #    define __VARARG__	...\n\
    405 #  else\n\
    406 #    define __VARARG__\n\
    407 #  endif\n\
    408 #  if defined(__STDARG__)\n\
    409 #    define __VA_START__(p,a)	va_start(p,a)\n\
    410 #  else\n\
    411 #    define __VA_START__(p,a)	va_start(p)\n\
    412 #  endif\n\
    413 #  if !defined(__INLINE__)\n\
    414 #    if defined(__cplusplus)\n\
    415 #      define __INLINE__	extern __MANGLE__ inline\n\
    416 #    else\n\
    417 #      if defined(_WIN32) && !defined(__GNUC__)\n\
    418 #      	define __INLINE__	__inline\n\
    419 #      endif\n\
    420 #    endif\n\
    421 #  endif\n\
    422 #endif\n\
    423 #if !defined(__LINKAGE__)\n\
    424 #define __LINKAGE__		/* 2004-08-11 transition */\n\
    425 #endif\n\
    426 ");
    427 	}
    428 	else
    429 		op = strcopy(op, "\
    430 \n\
    431 #if !defined(__PROTO__)\n\
    432 #include <prototyped.h>\n\
    433 #endif\n\
    434 #if !defined(__LINKAGE__)\n\
    435 #define __LINKAGE__		/* 2004-08-11 transition */\n\
    436 #endif\n\
    437 ");
    438 	if (proto->package)
    439 	{
    440 		s = "\
    441 #ifndef	__MANGLE_%_DATA__\n\
    442 #  ifdef _BLD_%\n\
    443 #    ifdef __EXPORT__\n\
    444 #      define	__MANGLE_%_DATA__	__MANGLE__ __EXPORT__\n\
    445 #    else\n\
    446 #      define	__MANGLE_%_DATA__	__MANGLE__\n\
    447 #    endif\n\
    448 #    define	__MANGLE_%_FUNC__	__MANGLE__\n\
    449 #  else\n\
    450 #    ifdef __IMPORT__\n\
    451 #      define	__MANGLE_%_DATA__	__MANGLE__ __IMPORT__\n\
    452 #    else\n\
    453 #      define	__MANGLE_%_DATA__	__MANGLE__\n\
    454 #    endif\n\
    455 #    define	__MANGLE_%_FUNC__	__MANGLE__\n\
    456 #  endif\n\
    457 #endif\n\
    458 ";
    459 		for (;;)
    460 		{
    461 			switch (*op++ = *s++)
    462 			{
    463 			case 0:
    464 				op--;
    465 				break;
    466 			case '%':
    467 				op = strcopy(op - 1, proto->package);
    468 				continue;
    469 			default:
    470 				continue;
    471 			}
    472 			break;
    473 		}
    474 	}
    475 	return op;
    476 }
    477 
    478 #define BACKOUT()	(op=ko)
    479 #define CACHE()		do{CACHEIN();CACHEOUT();call=proto->call;}while(0)
    480 #define CACHEIN()	(ip=proto->ip)
    481 #define CACHEOUT()	(op=proto->op)
    482 #define GETCHR()	(*(unsigned char*)ip++)
    483 #define KEEPOUT()	(ko=op)
    484 #define LASTOUT()	(*(op-1))
    485 #define PUTCHR(c)	(*op++=(c))
    486 #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)
    487 #define SYNCIN()	(proto->ip=ip)
    488 #define SYNCOUT()	(proto->op=op)
    489 #define UNGETCHR()	(ip--)
    490 #define UNPUTCHR()	(op--)
    491 
    492 /*
    493  * advance to the next non-space character
    494  */
    495 
    496 static char*
    497 nns(register char* s)
    498 {
    499 	while (*s == ' ' || *s == '\t' || *s == '\n')
    500 		s++;
    501 	return s;
    502 }
    503 
    504 #define DIR_if	01
    505 #define DIR_el	02
    506 #define DIR_en	03
    507 #define DIR	03
    508 
    509 /*
    510  * update directive mask
    511  */
    512 
    513 static int
    514 directive(register char* s, int dir)
    515 {
    516 	switch (*(s = nns(s)))
    517 	{
    518 	case 'e':
    519 	case 'i':
    520 		dir <<= 2;
    521 		switch (*++s)
    522 		{
    523 		case 'f':
    524 			dir |= DIR_if;
    525 			break;
    526 		case 'l':
    527 			dir |= DIR_el;
    528 			break;
    529 		case 'n':
    530 			dir |= DIR_en;
    531 			break;
    532 		}
    533 		break;
    534 	}
    535 	return dir;
    536 }
    537 
    538 /*
    539  * the tokenizer
    540  * top level calls loop until EOB
    541  * recursive calls just return the next token
    542  */
    543 
    544 static int
    545 lex(register struct proto* proto, register long flags)
    546 {
    547 	register char*		ip;
    548 	register char*		op;
    549 	register int		c;
    550 	register int		state;
    551 	register short*		rp;
    552 	char*			m;
    553 	char*			e;
    554 	char*			t;
    555 	char*			bp;
    556 	char*			v;
    557 	char*			im;
    558 	char*			ko;
    559 	char*			aom;
    560 	int			n;
    561 	int			line;
    562 	int			quot;
    563 	int			brack;
    564 	int			sub;
    565 	int			x;
    566 	int			vc;
    567 
    568 	char*			ie = 0;
    569 	char*			om = 0;
    570 	char*			aim = 0;
    571 	char*			aie = 0;
    572 	char*			func = 0;
    573 	int			call = 0;
    574 	int			dir = 0;
    575 	int			group = 0;
    576 	int			last = 0;
    577 	int			paren = 0;
    578 #if PROTOMAIN
    579 	char*			qe = 0;
    580 	int			qn = 0;
    581 	int			args = 0;
    582 #endif
    583 
    584 	CACHE();
    585 #if PROTOMAIN
    586 	if (flags & EXTERN) KEEPOUT();
    587 #endif
    588  fsm_start:
    589 	proto->tp = ip;
    590 	state = PROTO;
    591 	bp = ip;
    592 	do
    593 	{
    594 		rp = fsm[state];
    595  fsm_get:
    596 		while (!(state = rp[c = GETCHR()]));
    597  fsm_next:
    598 		;
    599 	} while (state > 0);
    600 	if ((n = ip - bp - 1) > 0)
    601 	{
    602 		ip = bp;
    603 		MEMCPY(op, ip, n);
    604 		ip++;
    605 	}
    606 	state = ~state;
    607  fsm_terminal:
    608 	switch (TERM(state))
    609 	{
    610 	case S_CHR:
    611 		if (op > proto->ob && *(op - 1) == '=' && (op == proto->ob + 1 || *(op - 2) != '=')) switch (c)
    612 		{
    613 		case '+':
    614 		case '-':
    615 		case '*':
    616 		case '&':
    617 			PUTCHR(' ');
    618 			break;
    619 		}
    620 		PUTCHR(c);
    621 		break;
    622 
    623 	case S_CHRB:
    624 		UNGETCHR();
    625 		c = LASTOUT();
    626 		break;
    627 
    628 	case S_COMMENT:
    629 		switch (c)
    630 		{
    631 		case '\n':
    632 			if (INCOMMENTXX(rp)) goto fsm_newline;
    633 			PUTCHR(c);
    634 			proto->line++;
    635 			rp = fsm[COM2];
    636 			break;
    637 		case '/':
    638 #if PROTOMAIN
    639 			if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT();
    640 			else
    641 #endif
    642 			PUTCHR(c);
    643 			if (INCOMMENTXX(rp))
    644 			{
    645 				rp = fsm[COM5];
    646 				break;
    647 			}
    648 			goto fsm_start;
    649 		case EOF:
    650 			break;
    651 		default:
    652 #if PROTOMAIN
    653 			if ((flags & (EXTERN|MATCH)) == EXTERN) BACKOUT();
    654 			else
    655 #endif
    656 			PUTCHR(c);
    657 			rp = fsm[INCOMMENTXX(rp) ? COM5 : COM3];
    658 			break;
    659 		}
    660 		bp = ip;
    661 		goto fsm_get;
    662 
    663 	case S_EOB:
    664 		if (c)
    665 		{
    666 			if (state = fsm[TERMINAL][INDEX(rp)+1])
    667 				goto fsm_terminal;
    668 			SYNC();
    669 			return 0;
    670 		}
    671 		UNGETCHR();
    672  fsm_eob:
    673 		if ((flags & (DECLARE|GLOBAL|RECURSIVE)) == GLOBAL && (proto->flags & MORE))
    674 		{
    675 #if PROTOMAIN
    676 			if (!(flags & EXTERN)) /* XXX */
    677 #endif
    678 			flags |= SLIDE;
    679 			c = ip - proto->ib;
    680 			if (!(flags & MATCH))
    681 				im = proto->tp;
    682 			if (ip > proto->ib)
    683 			{
    684 				n = ip - im;
    685 				if (ip - n < proto->ib)
    686 					proto->flags |= ERROR;
    687 				memcopy(proto->ib - n, ip - n, n);
    688 				ip = proto->ib;
    689 			}
    690 			proto->tp -= c;
    691 			if (flags & MATCH)
    692 			{
    693 				im -= c;
    694 				ie -= c;
    695 			}
    696 			if (aim)
    697 				aim -= c;
    698 			if (aie)
    699 				aie -= c;
    700 			if ((n = read(proto->fd, ip, proto->iz)) > 0)
    701 			{
    702 				if ((proto->options & REGULAR) && n < proto->iz)
    703 				{
    704 					proto->flags &= ~MORE;
    705 					close(proto->fd);
    706 				}
    707 				*(ip + n) = 0;
    708 				if (state & SPLICE)
    709 					goto fsm_splice;
    710 				bp = ip;
    711 				goto fsm_get;
    712 			}
    713 			*ip = 0;
    714 			proto->flags &= ~MORE;
    715 			close(proto->fd);
    716 		}
    717 		if (state & SPLICE)
    718 			goto fsm_splice;
    719 		/* NOTE: RECURSIVE lex() should really SLIDE too */
    720 		if (!(flags & RECURSIVE) && (state = rp[c = EOF]))
    721 		{
    722 			bp = ip;
    723 			goto fsm_next;
    724 		}
    725 		SYNC();
    726 		return 0;
    727 
    728 	case S_LITBEG:
    729 		quot = c;
    730 #if PROTOMAIN
    731 		if (c == '"' && qe)
    732 		{
    733 			for (n = 0, t = qe + 1; t < op && (*t == ' ' || *t == '\t' || *t == '\n' && ++n || *t >= 'A' && *t <= 'Z' || *t == '_'); t++);
    734 			if (t == op)
    735 			{
    736 				op = qe;
    737 				qe = 0;
    738 				qn = n;
    739 			}
    740 			else PUTCHR(c);
    741 		}
    742 		else
    743 #endif
    744 		PUTCHR(c);
    745 		rp = fsm[LIT1];
    746 		bp = ip;
    747 		goto fsm_get;
    748 
    749 	case S_LITEND:
    750 		if (c == quot)
    751 		{
    752 #if PROTOMAIN
    753 			if (!(flags & DIRECTIVE))
    754 				qe = (c == '"') ? op : (char*)0;
    755 #endif
    756 			PUTCHR(c);
    757 #if PROTOMAIN
    758 			while (qn > 0)
    759 			{
    760 				qn--;
    761 				PUTCHR('\n');
    762 			}
    763 #endif
    764 		}
    765 		else if (c != '\n' && c != EOF)
    766 		{
    767 			PUTCHR(c);
    768 			bp = ip;
    769 			goto fsm_get;
    770 		}
    771 		else
    772 		{
    773 #if PROTOMAIN
    774 			while (qn > 0)
    775 			{
    776 				qn--;
    777 				PUTCHR('\n');
    778 			}
    779 #endif
    780 			UNGETCHR();
    781 		}
    782 		c = T_INVALID;
    783 		break;
    784 
    785 	case S_LITESC:
    786 #if PROTOMAIN
    787 		if (flags & CLASSIC) PUTCHR(c);
    788 		else
    789 #endif
    790 		switch (c)
    791 		{
    792 		case 'a':
    793 			n = CC_bel;
    794 			goto fsm_oct;
    795 		case 'E':
    796 			n = CC_esc;
    797 			goto fsm_oct;
    798 		case 'v':
    799 			n = CC_vt;
    800 			goto fsm_oct;
    801 		case 'x':
    802 			SYNC();
    803 			lex(proto, (flags & GLOBAL) | RECURSIVE);
    804 			for (n = x = 0; (c = GETCHR()), x < 3; x++) switch (c)
    805 			{
    806 			case '0': case '1': case '2': case '3':
    807 			case '4': case '5': case '6': case '7':
    808 			case '8': case '9':
    809 				n = (n << 4) + c - '0';
    810 				break;
    811 			case 'a': case 'b': case 'c': case 'd':
    812 			case 'e': case 'f':
    813 				n = (n << 4) + c - 'a' + 10;
    814 				break;
    815 			case 'A': case 'B': case 'C': case 'D':
    816 			case 'E': case 'F':
    817 				n = (n << 4) + c - 'A' + 10;
    818 				break;
    819 			default:
    820 				goto fsm_hex;
    821 			}
    822  fsm_hex:
    823 			UNGETCHR();
    824  fsm_oct:
    825 			PUTCHR(((n >> 6) & 07) + '0');
    826 			PUTCHR(((n >> 3) & 07) + '0');
    827 			PUTCHR((n & 07) + '0');
    828 			break;
    829 		default:
    830 			PUTCHR(c);
    831 			break;
    832 		}
    833 		rp = fsm[LIT1];
    834 		bp = ip;
    835 		goto fsm_get;
    836 
    837 	case S_MACRO:
    838 		UNGETCHR();
    839 #if PROTOMAIN
    840 		if ((flags & EXTERN) && *proto->tp == 's' && !strncmp(proto->tp, "static", 6))
    841 		{
    842 			c = T_EXTERN;
    843 			break;
    844 		}
    845 #endif
    846 		if (*proto->tp == '_' && !strncmp(proto->tp, "__STDPP__directive", 6)) c = '#';
    847 		else c = T_ID;
    848 
    849 		break;
    850 
    851 	case S_NL:
    852  fsm_newline:
    853 		proto->line++;
    854 #if PROTOMAIN
    855 		if (flags & EXTERN)
    856 		{
    857 			if (op != proto->ob && LASTOUT() != ' ' && LASTOUT() != '\n')
    858 				PUTCHR(' ');
    859 		}
    860 		else
    861 #endif
    862 		PUTCHR(c);
    863 		if (flags & DIRECTIVE)
    864 		{
    865 #if PROTOMAIN
    866 			if (flags & CLASSIC)
    867 			{
    868 				if (flags & EXTERN) BACKOUT();
    869 				if (flags & JUNK)
    870 				{
    871 					*(ip - 1) = 0;
    872 					op = strcopy(om, "/* ");
    873 					op = strcopy(op, im);
    874 					op = strcopy(op, " */\n");
    875 				}
    876 				flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|JUNK|MATCH|SHARP|TYPEDEF);
    877 			}
    878 			else
    879 #endif
    880 			{
    881 				if ((flags & (DEFINE|SHARP)) == (DEFINE|SHARP))
    882 				{
    883 					*(ip - 1) = 0;
    884 					op = strcopy(om, "#if defined(__STDC__) || defined(__STDPP__)\n");
    885 					op = strcopy(op, im);
    886 					op = strcopy(op, "\n#else\n");
    887 					bp = ip;
    888 					ip = im;
    889 					*op++ = *ip++;
    890 					while (*op = *ip++)
    891 						if (*op++ == '#' && *ip != '(')
    892 						{
    893 							op--;
    894 							while (*--op == ' ' || *op == '\t');
    895 							if (*ip == '#')
    896 							{
    897 								op = strcopy(op + 1, "/**/");
    898 								while (*++ip == ' ' || *ip == '\t');
    899 							}
    900 							else
    901 							{
    902 								if (*op != '"') *++op = '"';
    903 								op++;
    904 								while (*ip == ' ' || *ip == '\t') ip++;
    905 								while ((c = *ip) >= 'A' && c <= 'Z' || c >= 'a' && c <= 'z' || c >= '0' && c <= '9' || c == '_') *op++ = *ip++;
    906 								while (*ip == ' ' || *ip == '\t') ip++;
    907 								if (*ip == '"') ip++;
    908 								else *op++ = '"';
    909 							}
    910 						}
    911 					ip = bp;
    912 					op = strcopy(op, "\n#endif\n");
    913 					op = linesync(proto, op, proto->line);
    914 				}
    915 				flags &= ~(DEFINE|DIRECTIVE|IDID|INDIRECT|MATCH|OTHER|SHARP|SKIP|TOKENS|TYPEDEF);
    916 			}
    917 			call = 0;
    918 			group = 0;
    919 			paren = 0;
    920 			last = '\n';
    921 		}
    922 		if (paren == 0 && (flags & (MATCH|RECURSIVE|SKIP|SLIDE)) == SLIDE)
    923 		{
    924 #if PROTOMAIN
    925 			if (flags & EXTERN) BACKOUT();
    926 #endif
    927 			SYNC();
    928 			return 0;
    929 		}
    930 		goto fsm_start;
    931 
    932 	case S_QUAL:
    933 		PUTCHR(c);
    934 		rp = fsm[NEXT(state)];
    935 		bp = ip;
    936 		goto fsm_get;
    937 
    938 	case S_TOK:
    939 		PUTCHR(c);
    940 		c = TYPE(state);
    941 		break;
    942 
    943 	case S_TOKB:
    944 		UNGETCHR();
    945 		c = TYPE(state);
    946 		break;
    947 
    948 	case S_RESERVED:
    949 		UNGETCHR();
    950 		c = T_ID;
    951 		if (!(flags & DECLARE)) switch (RESERVED(*proto->tp, *(ip - 1), ip - proto->tp))
    952 		{
    953 		case RESERVED('N', 'N', 3):
    954 			if (proto->tp[1] == 'o')
    955 				c = T_DO;
    956 			break;
    957 		case RESERVED('d', 'o', 2):
    958 			c = T_DO;
    959 			break;
    960 		case RESERVED('e', 'e', 4):
    961 			if (!(flags & RECURSIVE) && (flags & (DIRECTIVE|TOKENS)) != DIRECTIVE && !strncmp(proto->tp, "else", 4))
    962 			{
    963 				c = T_ELSE;
    964 				goto fsm_id;
    965 			}
    966 			break;
    967 		case RESERVED('e', 'n', 6):
    968 			if (!strncmp(proto->tp, "extern", 6))
    969 				c = T_EXTERN;
    970 			break;
    971 		case RESERVED('f', 'r', 3):
    972 			if (!(flags & RECURSIVE) && !strncmp(proto->tp, "for", 3))
    973 			{
    974 				c = T_FOR;
    975 				goto fsm_id;
    976 			}
    977 			break;
    978 		case RESERVED('i', 'f', 2):
    979 			c = T_IF;
    980 			break;
    981 		case RESERVED('i', 'e', 6):
    982 			if (!strncmp(proto->tp, "inline", 6) && !(flags & (MATCH|SKIP|TOKENS|TYPEDEF)) && proto->brace == 0 && paren == 0 && group == 0 && (last == ';' || last == '}' || last == '\n' || last == 0))
    983 			{
    984 				flags |= SKIP;
    985 				SYNC();
    986 				line = proto->line;
    987 				op = strcopy(op - 6, "__INLINE__");
    988 				SYNC();
    989 			}
    990 			break;
    991 		case RESERVED('r', 'n', 6):
    992 			if (!(flags & RECURSIVE) && !strncmp(proto->tp, "return", 6))
    993 			{
    994 				c = T_RETURN;
    995 				goto fsm_id;
    996 			}
    997 			break;
    998 		case RESERVED('s', 'c', 6):
    999 			if ((proto->options & EXTERNALIZE) && !strncmp(proto->tp, "static", 6))
   1000 			{
   1001 				proto->ox = op - 6;
   1002 				flags |= EXTERNALIZE;
   1003 			}
   1004 			break;
   1005 		case RESERVED('t', 'f', 7):
   1006 			if (!(flags & RECURSIVE) && !strncmp(proto->tp, "typedef", 7))
   1007 			{
   1008 				flags |= TYPEDEF;
   1009 				c = T_EXTERN;
   1010 			}
   1011 			break;
   1012 		case RESERVED('v', 't', 8):
   1013 			if (*ip == '(' && !strncmp(proto->tp, "va_start", 8)) c = T_VA_START;
   1014 			break;
   1015 		case RESERVED('v', 'd', 4):
   1016 			if (!strncmp(proto->tp, "void", 4))
   1017 			{
   1018 				if (flags & (CLASSIC|PLUSONLY|INIT_DEFINE|INIT_INCLUDE)) c = T_VOID;
   1019 				else
   1020 				{
   1021 					SYNC();
   1022 					line = proto->line;
   1023 					if (lex(proto, (flags & GLOBAL) | RECURSIVE) == '*')
   1024 					{
   1025 						memcopy(op - 4, "__V_", 4);
   1026 						memcopy(ip - 4, "__V_", 4);
   1027 					}
   1028 					else c = T_VOID;
   1029 					proto->line = line;
   1030 					SYNC();
   1031 					bp = ip;
   1032 				}
   1033 			}
   1034 			break;
   1035 		case RESERVED('w', 'e', 5):
   1036 			if (!(flags & RECURSIVE) && !strncmp(proto->tp, "while", 5))
   1037 			{
   1038 				c = T_WHILE;
   1039 				goto fsm_id;
   1040 			}
   1041 			break;
   1042 		}
   1043 #if PROTOMAIN
   1044 		if ((flags & CLASSIC) && c != T_EXTERN)
   1045 			c = T_ID;
   1046 #endif
   1047 		break;
   1048 
   1049 	case S_VS:
   1050 		goto fsm_start;
   1051 
   1052 	case S_WS:
   1053 		UNGETCHR();
   1054 #if PROTOMAIN
   1055 		if ((flags & (EXTERN|MATCH)) == EXTERN)
   1056 		{
   1057 			while (op > proto->ob && (*(op - 1) == ' ' || *(op - 1) == '\t'))
   1058 				op--;
   1059 			if (op > proto->ob && *(op - 1) != '\n') *op++ = ' ';
   1060 		}
   1061 #endif
   1062 		goto fsm_start;
   1063 
   1064 	default:
   1065 		if (state & SPLICE)
   1066 		{
   1067 			if (c == '\\')
   1068 			{
   1069 				if (!(n = GETCHR()))
   1070 				{
   1071 					goto fsm_eob;
   1072  fsm_splice:
   1073 					c = '\\';
   1074 					n = GETCHR();
   1075 				}
   1076 				if (n == '\n')
   1077 				{
   1078 					proto->line++;
   1079 					PUTCHR('\\');
   1080 					PUTCHR('\n');
   1081 					bp = ip;
   1082 					goto fsm_get;
   1083 				}
   1084 				UNGETCHR();
   1085 			}
   1086 			state &= ~SPLICE;
   1087 			if (state >= TERMINAL)
   1088 				goto fsm_terminal;
   1089 			rp = fsm[state];
   1090 		}
   1091 		PUTCHR(c);
   1092 		bp = ip;
   1093 		goto fsm_get;
   1094 	}
   1095 	if (!(flags & (INIT_DEFINE|INIT_INCLUDE|RECURSIVE)))
   1096 	{
   1097 		if (!(flags & DIRECTIVE)) switch (c)
   1098 		{
   1099 		case '(':
   1100 #if PROTOMAIN
   1101 			if (!(flags & CLASSIC) || proto->brace == 0)
   1102 #endif
   1103 			{
   1104 				if (paren++ == 0)
   1105 				{
   1106 #if PROTOMAIN
   1107 					if (!(flags & CLASSIC) || group <= 1)
   1108 #endif
   1109 					{
   1110 #if PROTOMAIN
   1111 						args = 0;
   1112 #endif
   1113 						if (group++ == 0) group++;
   1114 						else if (flags & INDIRECT) call++;
   1115 						flags |= MATCH;
   1116 						im = ip - 1;
   1117 						om = op - 1;
   1118 					}
   1119 					sub = 0;
   1120 				}
   1121 				else if (paren == 2 && !aim)
   1122 				{
   1123 					sub++;
   1124 					if (last == '(')
   1125 					{
   1126 						flags &= ~MATCH;
   1127 						om = 0;
   1128 					}
   1129 					else if (flags & INDIRECT)
   1130 					{
   1131 						aim = ip - 1;
   1132 						aom = op - 1;
   1133 					}
   1134 					else if ((flags & (MATCH|TOKENS)) == MATCH)
   1135 					{
   1136 						for (m = ip - 2; m > im && (*m == ' ' || *m == '\t'); m--);
   1137 						if (m != im && sub == 1)
   1138 						{
   1139 							m = im + (*nns(ip) == '*');
   1140 						}
   1141 						if (m == im)
   1142 						{
   1143 							flags &= ~MATCH;
   1144 							om = 0;
   1145 						}
   1146 					}
   1147 					else if ((flags & MATCH) && sub == 1 && *nns(ip) != '*')
   1148 					{
   1149 						flags &= ~MATCH;
   1150 						om = 0;
   1151 					}
   1152 				}
   1153 				flags &= ~TOKENS;
   1154 			}
   1155 			break;
   1156 		case ')':
   1157 #if PROTOMAIN
   1158 			if (!(flags & CLASSIC) || proto->brace == 0)
   1159 #endif
   1160 			if (--paren == 0)
   1161 			{
   1162 #if PROTOMAIN
   1163 				if (flags & CLASSIC)
   1164 				{
   1165 					if (group != 2)
   1166 					{
   1167 						c = T_ID;
   1168 						break;
   1169 					}
   1170 					group++;
   1171 				}
   1172 #endif
   1173 				ie = ip;
   1174 			}
   1175 			else if (paren == 1 && (flags & INDIRECT) && !aie)
   1176 				aie = ip;
   1177 			break;
   1178 		case '*':
   1179 			if (last == '(' && group == 2)
   1180 			{
   1181 				group--;
   1182 				if (paren == 1)
   1183 				{
   1184 					flags |= INDIRECT;
   1185 					aim = aie = 0;
   1186 				}
   1187 			}
   1188 			break;
   1189 		case '#':
   1190 			dir = directive(ip, dir);
   1191 			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))
   1192 				flags |= DIRECTIVE;
   1193 			else if (!(flags & (DECLARE|DIRECTIVE)))
   1194 			{
   1195 				flags |= DIRECTIVE;
   1196 				if (!(flags & PLUSONLY))
   1197 				{
   1198 					bp = ip;
   1199 					while (*ip == ' ' || *ip == '\t') ip++;
   1200 					if (*ip == 'l' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e')
   1201 					{
   1202 						if (*++ip == ' ' || *ip == '\t')
   1203 						{
   1204 							proto->line = 0;
   1205 							while (*++ip >= '0' && *ip <= '9')
   1206 								proto->line = proto->line * 10 + *ip - '0';
   1207 							proto->line--;
   1208 						}
   1209 					}
   1210 #if PROTOMAIN
   1211 					else if ((flags & (CLASSIC|EXTERN)) == CLASSIC)
   1212 					{
   1213 						n = 0;
   1214 						t = ip + 6;
   1215 						while (ip < t && *ip >= 'a' && *ip <= 'z')
   1216 							n = HASHKEYPART(n, *ip++);
   1217 						switch (n)
   1218 						{
   1219 						case HASHKEY4('e','l','s','e'):
   1220 						case HASHKEY5('e','n','d','i','f'):
   1221 							while (*ip == ' ' || *ip == '\t') ip++;
   1222 							if (*ip != '\n' && *ip != '/' && *(ip + 1) != '*')
   1223 							{
   1224 								flags |= JUNK|MATCH;
   1225 								im = ip;
   1226 								om = op + (ip - bp);
   1227 							}
   1228 							break;
   1229 						case HASHKEY4('e','l','i','f'):
   1230 						case HASHKEY5('e','r','r','o','r'):
   1231 						case HASHKEY2('i','f'):
   1232 						case HASHKEY5('i','f','d','e','f'):
   1233 						case HASHKEY6('i','f','n','d','e','f'):
   1234 						case HASHKEY5('u','n','d','e','f'):
   1235 							break;
   1236 						case HASHKEY6('i','n','c','l','u','d'):
   1237 							if (*ip == 'e') ip++;
   1238 							/*FALLTHROUGH*/
   1239 						case HASHKEY6('d','e','f','i','n','e'):
   1240 						case HASHKEY6('p','r','a','g','m','a'):
   1241 							if (*ip < 'a' || *ip > 'z') break;
   1242 							/*FALLTHROUGH*/
   1243 						default:
   1244 							flags |= JUNK|MATCH;
   1245 							im = bp - 1;
   1246 							om = op - 1;
   1247 							break;
   1248 						}
   1249 					}
   1250 					else
   1251 #endif
   1252 					{
   1253 						if (*ip == 'i' && *++ip == 'n' && *++ip == 'c' && *++ip == 'l' && *++ip == 'u' && *++ip == 'd' && *++ip == 'e')
   1254 						{
   1255 							while (*++ip == ' ' || *ip == '\t');
   1256 							if (*ip++ == '<' && *ip++ == 's' && *ip++ == 't' && *ip++ == 'd' && *ip++ == 'a' && *ip++ == 'r' && *ip++ == 'g' && *ip++ == '.' && *ip++ == 'h' && *ip++ == '>')
   1257 							{
   1258 								op = strcopy(op, "\
   1259 if !defined(va_start)\n\
   1260 #if defined(__STDARG__)\n\
   1261 #include <stdarg.h>\n\
   1262 #else\n\
   1263 #include <varargs.h>\n\
   1264 #endif\n\
   1265 #endif\n\
   1266 ");
   1267 								op = linesync(proto, op, proto->line);
   1268 								break;
   1269 							}
   1270 						}
   1271 						else if (*ip == 'd' && *++ip == 'e' && *++ ip == 'f' && *++ip == 'i' && *++ip == 'n' && *++ip == 'e' && (*++ip == ' ' || *ip == '\t'))
   1272 						{
   1273 							while (*++ip == ' ' || *ip == '\t');
   1274 							if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t'))
   1275 							{
   1276 								t = ip;
   1277 								while (*++t == ' ' || *t == '\t');
   1278 								if (*t == 'e' && *++t == 'x' && *++ t == 't' && *++t == 'e' && *++t == 'r' && *++t == 'n' && (*++t == ' ' || *t == '\t' || *t == '\n' || *t == '\r'))
   1279 									ip = t;
   1280 								t = ip;
   1281 								while (*++t == ' ' || *t == '\t');
   1282 								if (*t == '_' && *(t + 1) == '_')
   1283 								{
   1284 									op = strcopy(op, "undef __MANGLE__\n");
   1285 									op = linesync(proto, op, proto->line);
   1286 									op = strcopy(op, "#define __MANGLE__ __LINKAGE__");
   1287 									break;
   1288 								}
   1289 							}
   1290 							flags |= DEFINE|MATCH;
   1291 							im = bp - 1;
   1292 							om = op - 1;
   1293 						}
   1294 						else if (*ip == 'u' && *++ip == 'n' && *++ ip == 'd' && *++ip == 'e' && *++ip == 'f' && (*++ip == ' ' || *ip == '\t'))
   1295 						{
   1296 							while (*++ip == ' ' || *ip == '\t');
   1297 							if (*ip == 'e' && *++ip == 'x' && *++ ip == 't' && *++ip == 'e' && *++ip == 'r' && *++ip == 'n' && (*++ip == ' ' || *ip == '\t' || *ip == '\n' || *ip == '\r'))
   1298 							{
   1299 								op = strcopy(op, "undef __MANGLE__\n");
   1300 								op = linesync(proto, op, proto->line);
   1301 								op = strcopy(op, "#define __MANGLE__ __LINKAGE__");
   1302 								break;
   1303 							}
   1304 							flags |= DEFINE|MATCH;
   1305 							im = bp - 1;
   1306 							om = op - 1;
   1307 						}
   1308 					}
   1309 					ip = bp;
   1310 				}
   1311 				break;
   1312 			}
   1313 			else
   1314 				break;
   1315 			/*FALLTHROUGH*/
   1316 		case '{':
   1317 			if (proto->brace++ == 0 && paren == 0)
   1318 			{
   1319 				if (last == '=') flags |= INIT;
   1320 #if PROTOMAIN
   1321 				else if (flags & CLASSIC)
   1322 				{
   1323 					if ((flags & (MATCH|OTHER|SKIP)) == MATCH)
   1324 					{
   1325 						if (args)
   1326 						{
   1327 							v = number(op, args < 0 ? -args : args);
   1328 							v = strcopy(v, " argument actual/formal mismatch");
   1329 							*v++ = ' ';
   1330 							v = memcopy(v, im, ie - im);
   1331 							*v = 0;
   1332 							proto_error((char*)proto + sizeof(struct proto), 2, op, NiL);
   1333 						}
   1334 						ip--;
   1335 						/*UNDENT...*/
   1336 	v = ie;
   1337 	while (ie < ip)
   1338 		if (*ie++ == '/' && *ie == '*')
   1339 		{
   1340 			e = ie - 1;
   1341 			while (++ie < ip)
   1342 			{
   1343 				if (*ie == '*')
   1344 				{
   1345 					while (ie < ip && *ie == '*') ie++;
   1346 					if (ie < ip && *ie == '/')
   1347 					{
   1348 						while (++ie < ip && (*ie == ' ' || *ie == '\t'));
   1349 						while (e > v && (*(e - 1) == ' ' || *(e - 1) == '\t')) e--;
   1350 						if (e > v && *e != '\n') *e++ = ' ';
   1351 						t = ie;
   1352 						while (--e >= v)
   1353 							*--t = *e;
   1354 						v = t;
   1355 						break;
   1356 					}
   1357 				}
   1358 			}
   1359 		}
   1360 	ie = v;
   1361 						/*...INDENT*/
   1362 						op = om++;
   1363 						if (flags & EXTERN)
   1364 						{
   1365 							v = op;
   1366 							while (v > ko && *--v != ' ');
   1367 							if (*v != ' ')
   1368 							{
   1369 								om = (v = (op += 4)) + 1;
   1370 								while (v >= ko + 4)
   1371 								{
   1372 									*v = *(v - 4);
   1373 									v--;
   1374 								}
   1375 								memcopy(ko, "int ", 4);
   1376 							}
   1377 							if (*v == ' ')
   1378 							{
   1379 								while (*(v + 1) == '*')
   1380 									*v++ = '*';
   1381 								*v = '\t';
   1382 								if ((v - ko) <= 8)
   1383 								{
   1384 									om = (e = ++op) + 1;
   1385 									while (e > v)
   1386 									{
   1387 										*e = *(e - 1);
   1388 										e--;
   1389 									}
   1390 								}
   1391 							}
   1392 							om = (v = (op += 7)) + 1;
   1393 							while (v >= ko + 7)
   1394 							{
   1395 								*v = *(v - 7);
   1396 								v--;
   1397 							}
   1398 							memcopy(ko, "extern ", 7);
   1399 						}
   1400 						PUTCHR('(');
   1401 						t = op;
   1402 						e = 0;
   1403 						/*UNDENT...*/
   1404 	while (ie < ip)
   1405 	{
   1406 		if ((c = *ie) == ' ' || c == '\t' || c == '\n')
   1407 		{
   1408 			while ((c = *++ie) == ' ' || c == '\t' || c == '\n');
   1409 			if (ie >= ip) break;
   1410 			if (c != '*' && op > om) PUTCHR(' ');
   1411 		}
   1412 		if ((n = ((c = *ie) == ',')) || c == ';')
   1413 		{
   1414 			if (flags & EXTERN)
   1415 			{
   1416 				m = op;
   1417 				while (op > om && ((c = *(op - 1)) == '(' || c == ')' || c == '[' || c == ']'))
   1418 					op--;
   1419 				v = op;
   1420 				while (op > om && (c = *(op - 1)) != ' ' && c != '*')
   1421 					op--;
   1422 				while (*(op - 1) == ' ')
   1423 					op--;
   1424 				if (!e)
   1425 				{
   1426 					e = op;
   1427 					while (e > om && *(e - 1) == '*')
   1428 						e--;
   1429 				}
   1430 #if _s5r4_386_compiler_bug_fixed_
   1431 				if (op <= om || *(op - 1) == ',' && (*op++ = ' '))
   1432 					op = strcopy(op, "int");
   1433 #else
   1434 				if (op <= om)
   1435 					op = strcopy(op, "int");
   1436 				else if (*(op - 1) == ',')
   1437 					op = strcopy(op, " int");
   1438 #endif
   1439 				while (v < m)
   1440 					PUTCHR(*v++);
   1441 			}
   1442 			PUTCHR(',');
   1443 			if (n)
   1444 			{
   1445 				if (x = !e) e = op - 1;
   1446 				PUTCHR(' ');
   1447 				m = t;
   1448 				while (m < e)
   1449 					PUTCHR(*m++);
   1450 				if (x)
   1451 				{
   1452 					m = e;
   1453 					while (*--e != ' ');
   1454 					while (*(e - 1) == '*') e--;
   1455 					op -= m - e;
   1456 				}
   1457 			}
   1458 			while ((c = *++ie) == ' ' || c == '\t' || c == '\n');
   1459 			if (ie >= ip) UNPUTCHR();
   1460 			else PUTCHR(' ');
   1461 			if (!n)
   1462 			{
   1463 				t = op;
   1464 				e = 0;
   1465 			}
   1466 		}
   1467 		else if (*ie == '*')
   1468 		{
   1469 			if (op > om && (c = *(op - 1)) == ' ') op--;
   1470 			while (*ie == '*') PUTCHR(*ie++);
   1471 			while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
   1472 			if (c != '(') PUTCHR(' ');
   1473 		}
   1474 		else if (*ie == '(')
   1475 		{
   1476 			if (op > om && *(op - 1) == ' ') op--;
   1477 			PUTCHR(*ie++);
   1478 			while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
   1479 		}
   1480 		else if (*ie == ')')
   1481 		{
   1482 			if (op > om && *(op - 1) == '(')
   1483 				proto_error((char*)proto + sizeof(struct proto), 1, "function pointer argument prototype omitted", NiL);
   1484 			PUTCHR(*ie++);
   1485 			while (*ie == ' ' || *ie == '\t' || *ie == '\n') ie++;
   1486 		}
   1487 		else if ((flags & EXTERN) && (op == om || *(op - 1) == ' ') && *ie == 'r' && !strncmp(ie, "register", 8) && (*(ie + 8) == ' ' || *(ie + 8) == '\t' || *(ie + 8) == '\n'))
   1488 		{
   1489 			ie += 8;
   1490 			if (op > om) UNPUTCHR();
   1491 		}
   1492 		else PUTCHR(*ie++);
   1493 	}
   1494 						/*...INDENT*/
   1495 						if (op <= om) op = strcopy(op, "void");
   1496 						PUTCHR(')');
   1497 						if (flags & EXTERN)
   1498 						{
   1499 							PUTCHR(';');
   1500 							PUTCHR('\n');
   1501 							SYNCOUT();
   1502 							KEEPOUT();
   1503 						}
   1504 						else
   1505 						{
   1506 							PUTCHR('\n');
   1507 							PUTCHR(*ip);
   1508 						}
   1509 						ip++;
   1510 						flags &= ~(MATCH|SKIP);
   1511 					}
   1512 				}
   1513 #endif
   1514 				else if ((flags & (MATCH|PLUSONLY|SKIP|TOKENS)) == (MATCH|TOKENS))
   1515 				{
   1516 					line = proto->line;
   1517 					op = strcopy(om, " __PARAM__(");
   1518 					op = memcopy(op, im, ie - im);
   1519 					PUTCHR(',');
   1520 					PUTCHR(' ');
   1521 					PUTCHR('(');
   1522 					flags &= ~(MATCH|SKIP);
   1523 					if (flags & VARIADIC)
   1524 					{
   1525 						if ((vc = ie - im + 1) > sizeof(proto->variadic)) vc = sizeof(proto->variadic);
   1526 						memcopy(proto->variadic, im, vc);
   1527 						op = strcopy(op, "va_alist)) __OTORP__(va_dcl)\n{");
   1528 					}
   1529 					else
   1530 					{
   1531 						flags |= SKIP;
   1532 						proto->ip = im;
   1533 						proto->op = op;
   1534 						group = 0;
   1535 						brack = 0;
   1536 						for (;;)
   1537 						{
   1538 							switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
   1539 							{
   1540 							case '[':
   1541 								brack++;
   1542 								continue;
   1543 							case ']':
   1544 								brack--;
   1545 								continue;
   1546 							case '(':
   1547 								if (paren++) group++;
   1548 								continue;
   1549 							case ')':
   1550 								if (--paren == 0)
   1551 								{
   1552 									group = 0;
   1553 									if (flags & MATCH)
   1554 									{
   1555 										flags &= ~(MATCH|SKIP);
   1556 										op = memcopy(op, m, e - m);
   1557 									}
   1558 									break;
   1559 								}
   1560 								continue;
   1561 							case ',':
   1562 								if (paren == 1)
   1563 								{
   1564 									group = 0;
   1565 									if (flags & MATCH)
   1566 									{
   1567 										flags &= ~(MATCH|SKIP);
   1568 										op = memcopy(op, m, e - m);
   1569 									}
   1570 									PUTCHR(',');
   1571 									PUTCHR(' ');
   1572 									proto->op = op;
   1573 								}
   1574 								continue;
   1575 							case T_ID:
   1576 								if (group <= 1 && !brack)
   1577 								{
   1578 									flags |= MATCH;
   1579 									m = proto->tp;
   1580 									e = proto->ip;
   1581 								}
   1582 								continue;
   1583 							default:
   1584 								continue;
   1585 							}
   1586 							break;
   1587 						}
   1588 						PUTCHR(')');
   1589 						PUTCHR(')');
   1590 					}
   1591 					if (!(flags & SKIP))
   1592 					{
   1593 						flags |= SKIP;
   1594 						proto->op = strcopy(op, " __OTORP__(");
   1595 						proto->ip = im + 1;
   1596 						n = *(ie - 1);
   1597 						*(ie - 1) = ';';
   1598 						c = *ie;
   1599 						*ie = 0;
   1600 						lex(proto, (flags & GLOBAL) | DECLARE);
   1601 						*(ie - 1) = n;
   1602 						*ie = c;
   1603 						proto->ip = ie;
   1604 						op = proto->op;
   1605 						PUTCHR(')');
   1606 					}
   1607 					if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6);
   1608 					op = linesync(proto, op, proto->line = line);
   1609 					if (flags & DIRECTIVE)
   1610 					{
   1611 						proto->brace = 0;
   1612 						PUTCHR('\n');
   1613 						PUTCHR('#');
   1614 					}
   1615 					else if (!(flags & VARIADIC)) PUTCHR('{');
   1616 				}
   1617 			}
   1618 			flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP);
   1619 			call = 0;
   1620 			group = 0;
   1621 			break;
   1622 		case '}':
   1623 			flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP|TOKENS);
   1624 			if (--proto->brace == 0)
   1625 			{
   1626 				flags &= ~(INIT|VARIADIC|VARIADIC2);
   1627 #if PROTOMAIN
   1628 				if (flags & EXTERN) BACKOUT();
   1629 #endif
   1630 			}
   1631 			call = 0;
   1632 			group = 0;
   1633 			paren = 0;
   1634 			break;
   1635 		case '=':
   1636 			if (last == '?') flags |= DIRECTIVE;
   1637 			else if (paren == 0 && (flags & (INIT|MATCH|SKIP)) == MATCH)
   1638 			{
   1639 				if (last == ')' && proto->brace && (group != 2 || call != 2)) flags |= SKIP;
   1640 				else goto fsm_statement;
   1641 			}
   1642 			goto fsm_other;
   1643 		case ',':
   1644 #if PROTOMAIN
   1645 			if (flags & CLASSIC)
   1646 			{
   1647 				if (paren == 1) args++;
   1648 				else
   1649 				{
   1650 					args--;
   1651 					flags &= ~MATCH;
   1652 				}
   1653 				break;
   1654 			}
   1655 #endif
   1656 			if (paren == 0 && (flags & DECLARE)) *(op - 1) = c = ';';
   1657 			/*FALLTHROUGH*/
   1658 		case ';':
   1659  fsm_statement:
   1660 			if (flags & INIT) /* ignore */;
   1661 #if PROTOMAIN
   1662 			else if (flags & CLASSIC)
   1663 			{
   1664 				if (paren == 0)
   1665 				{
   1666 					if ((flags & MATCH) && last == ')')
   1667 						flags &= ~MATCH;
   1668 					if (!(flags & MATCH))
   1669 					{
   1670 						call = 0;
   1671 						group = 0;
   1672 						flags &= ~SKIP;
   1673 						if (flags & EXTERN) BACKOUT();
   1674 						if (flags & SLIDE)
   1675 						{
   1676 							SYNC();
   1677 							return 0;
   1678 						}
   1679 					}
   1680 					else
   1681 					{
   1682 						args--;
   1683 						if ((flags & (EXTERN|SKIP)) == (EXTERN|SKIP))
   1684 							BACKOUT();
   1685 					}
   1686 				}
   1687 			}
   1688 #endif
   1689 			else if (paren == 0)
   1690 			{
   1691 				if ((flags & (MATCH|OTHER|SKIP)) == MATCH && call > 1)
   1692 				{
   1693 					if ((flags & MANGLE) && func)
   1694 					{
   1695 						func[0] = 'F';
   1696 						func[1] = 'U';
   1697 						func[2] = 'N';
   1698 						func[3] = 'C';
   1699 						func = 0;
   1700 					}
   1701 					if ((flags & (DECLARE|INDIRECT)) == INDIRECT && aim && aie < im)
   1702 					{
   1703 						while (aie < ip && (*aie == ' ' || *aie == '\t' || *aie == '\n')) aie++;
   1704 						v = aim;
   1705 						while (v < aie)
   1706 							if (*v++ == ')') break;
   1707 						while (v < aie && (*v == ' ' || *v == '\t' || *v == '\n')) v++;
   1708 						if (v == aie || !(flags & PLUSPLUS))
   1709 						{
   1710 							if (flags & PLUSPLUS) n = 3;
   1711 							else if (v == aie && *v == '(') n = 10;
   1712 							else n = 11;
   1713 							ko = op;
   1714 							om += n;
   1715 							v = op += n;
   1716 							while (v >= ko + n)
   1717 							{
   1718 								*v = *(v - n);
   1719 								v--;
   1720 							}
   1721 							if (flags & PLUSPLUS) memcopy(aom, "(...))", 6);
   1722 							else if (n == 10) memcopy(aom, "(__VARARG__))", 13);
   1723 							else
   1724 							{
   1725 								ko = strcopy(aom, " __PROTO__(");
   1726 								ko = memcopy(ko, aim, aie - aim);
   1727 								*ko = ')';
   1728 								if (++ko >= om)
   1729 								{
   1730 									*ko++ = ')';
   1731 									om = ko;
   1732 								}
   1733 							}
   1734 						}
   1735 					}
   1736 					else if (flags & TYPEDEF)
   1737 					{
   1738 						op = om;
   1739 						while (*--op == ' ' || *op == '\t' || *op == '\n');
   1740 						if (*op != ')')
   1741 						{
   1742 							op = om += 14;
   1743 							*--op = ')';
   1744 							while ((x = *(op - 14)) >= 'A' && x <= 'Z' || x >= 'a' && x <= 'z' || x >= '0' && x <= '9' || x == '_')
   1745 								*--op = x;
   1746 							memcopy(op - 13, "(__OTORP__(*)", 13);
   1747 						}
   1748 					}
   1749 					if (flags & OTHER)
   1750 						;
   1751 					else if (flags & PLUSPLUS)
   1752 					{
   1753 						op = om;
   1754 						if (!(flags & TOKENS)) op = strcopy(op, "(...)");
   1755 						else op = memcopy(op, im, ie - im);
   1756 						PUTCHR(c);
   1757 					}
   1758 					else
   1759 					{
   1760 						if (flags & DECLARE) op = strcopy(om, "()");
   1761 						else if (!(flags & TOKENS)) op = strcopy(om, "(__VARARG__)");
   1762 						else
   1763 						{
   1764 							op = strcopy(om, " __PROTO__(");
   1765 							op = memcopy(op, im, ie - im);
   1766 							PUTCHR(')');
   1767 						}
   1768 						if (flags & EXTERNALIZE) memcpy(proto->ox, "extern", 6);
   1769 						PUTCHR(c);
   1770 					}
   1771 					flags &= ~(MATCH|VARIADIC|VARIADIC2);
   1772 					if (c == ',' && !(flags & INDIRECT))
   1773 					{
   1774 						call = 1;
   1775 						group = 0;
   1776 						break;
   1777 					}
   1778 				}
   1779 				else if (flags & (OTHER|SKIP)) call = 0;
   1780 				if (c == ';')
   1781 				{
   1782 					flags &= ~(EXTERNALIZE|MANGLE|TOKENS|TYPEDEF);
   1783 					call = 0;
   1784 					if (flags & SLIDE)
   1785 					{
   1786 						SYNC();
   1787 						return 0;
   1788 					}
   1789 				}
   1790 				else call = call > 1 && c == ',';
   1791 				group = 0;
   1792 				flags &= ~(IDID|INDIRECT|MATCH|OTHER|SKIP);
   1793 			}
   1794 			else if (paren == 1 && group == 1 && !(flags & (IDID|MANGLE))) flags |= TOKENS|OTHER;
   1795 			break;
   1796 		case T_DO:
   1797 		case T_IF:
   1798 			flags |= TOKENS|SKIP;
   1799 			break;
   1800 		case T_EXTERN:
   1801 #if PROTOMAIN
   1802 			if (flags & CLASSIC)
   1803 			{
   1804 				if (proto->brace == 0)
   1805 					flags |= SKIP;
   1806 			}
   1807 			else
   1808 #endif
   1809 			if (paren == 0 && !(flags & TYPEDEF))
   1810 			{
   1811 				flags |= MANGLE;
   1812 				if (!(flags & PLUSONLY) || proto->package)
   1813 				{
   1814 					op = strcopy(op, " __MANGLE__");
   1815 					if (proto->package)
   1816 					{
   1817 						op = strcopy(op - 1, proto->package);
   1818 						func = op + 1;
   1819 						op = strcopy(op, "_DATA__");
   1820 					}
   1821 				}
   1822 				else
   1823 					func = 0;
   1824 			}
   1825 			break;
   1826 		case T_VARIADIC:
   1827 			if (paren == 0 && (flags & (DECLARE|VARIADIC)) == DECLARE)
   1828 			{
   1829 				op -= 3;
   1830 				SYNC();
   1831 				return c;
   1832 			}
   1833 			if (paren == 1 && !(flags & SKIP))
   1834 				flags |= VARIADIC;
   1835 			flags |= TOKENS;
   1836 			break;
   1837 		case T_VOID:
   1838 			goto fsm_id;
   1839 		case T_VA_START:
   1840 			if ((flags & (PLUSONLY|VARIADIC)) == VARIADIC)
   1841 			{
   1842 				flags &= ~MATCH;
   1843 				line = proto->line;
   1844 				op = strcopy(op - 8, "__VA_START__");
   1845 				SYNC();
   1846 				for (;;)
   1847 				{
   1848 					switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
   1849 					{
   1850 					case 0:
   1851 					case ';':
   1852 						break;
   1853 					case T_ID:
   1854 						if (!(flags & MATCH))
   1855 						{
   1856 							flags |= MATCH;
   1857 							m = proto->tp;
   1858 							e = proto->ip;
   1859 						}
   1860 						continue;
   1861 					default:
   1862 						continue;
   1863 					}
   1864 					break;
   1865 				}
   1866 				CACHE();
   1867 				if (flags & MATCH)
   1868 				{
   1869 					v = m;
   1870 					n = e - m;
   1871 				}
   1872 				else
   1873 				{
   1874 					v = "ap";
   1875 					n = 2;
   1876 				}
   1877 				op = strcopy(op, " __OTORP__(");
   1878 				proto->ip = proto->variadic;
   1879 				proto->op = op;
   1880 				flags &= ~MATCH;
   1881 				group = 0;
   1882 				bp = proto->ip + 1;
   1883 				if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9;
   1884 				for (;;)
   1885 				{
   1886 					switch (lex(proto, (flags & GLOBAL) | RECURSIVE))
   1887 					{
   1888 					case '(':
   1889 						if (paren++) group++;
   1890 						continue;
   1891 					case ')':
   1892 						if (--paren == 0)
   1893 						{
   1894 							if (flags & MATCH)
   1895 							{
   1896 								flags &= ~MATCH;
   1897 								if (!(flags & VARIADIC2))
   1898 								{
   1899 									op = memcopy(op, m, e - m);
   1900 									op = strcopy(op, " = ");
   1901 								}
   1902 								op = strcopy(op, "va_arg(");
   1903 								op = memcopy(op, v, n);
   1904 								PUTCHR(',');
   1905 								PUTCHR(' ');
   1906 								if (m > bp) op = memcopy(op, bp, m - bp);
   1907 								else op = strcopy(op, "int ");
   1908 								if (group > 1) op = strcopy(op, ")()");
   1909 								else op = memcopy(op, e, proto->ip - e - 1);
   1910 								PUTCHR(')');
   1911 								PUTCHR(';');
   1912 							}
   1913 							group = 0;
   1914 							break;
   1915 						}
   1916 						continue;
   1917 					case ',':
   1918 						if (paren == 1)
   1919 						{
   1920 							if (flags & MATCH)
   1921 							{
   1922 								flags &= ~MATCH;
   1923 								if (!(flags & VARIADIC2))
   1924 								{
   1925 									op = memcopy(op, m, e - m);
   1926 									op = strcopy(op, " = ");
   1927 								}
   1928 								op = strcopy(op, "va_arg(");
   1929 								op = memcopy(op, v, n);
   1930 								PUTCHR(',');
   1931 								PUTCHR(' ');
   1932 								if (m > bp) op = memcopy(op, bp, m - bp);
   1933 								else op = strcopy(op, "int ");
   1934 								if (group > 1) op = strcopy(op, ")()");
   1935 								else op = memcopy(op, e, proto->ip - e - 1);
   1936 								PUTCHR(')');
   1937 								PUTCHR(';');
   1938 								bp = proto->ip + 1;
   1939 								if (*bp == 'r' && !strncmp(bp, "register", 8) && (*(bp + 8) == ' ' || *(bp + 8) == '\t')) bp += 9;
   1940 							}
   1941 							group = 0;
   1942 							proto->op = op;
   1943 						}
   1944 						continue;
   1945 					case T_ID:
   1946 						if (group <= 1)
   1947 						{
   1948 							flags |= MATCH;
   1949 							m = proto->tp;
   1950 							e = proto->ip;
   1951 						}
   1952 						continue;
   1953 					default:
   1954 						continue;
   1955 					}
   1956 					break;
   1957 				}
   1958 				op = strcopy(op, ")");
   1959 				flags |= VARIADIC2;
   1960 				proto->line = line;
   1961 				call = 0;
   1962 				break;
   1963 			}
   1964 			/*FALLTHROUGH*/
   1965 		case T_ID:
   1966  fsm_id:
   1967 #if PROTOMAIN
   1968 			if (flags & CLASSIC)
   1969 			{
   1970 				if (!args && paren == 1) args++;
   1971 				break;
   1972 			}
   1973 #endif
   1974 			if (paren == 0)
   1975 			{
   1976 				if (last == ')')
   1977 				{
   1978 					if (proto->brace == 0 && !(flags & DECLARE)) flags |= SKIP;
   1979 					call = !call;
   1980 				}
   1981 				else if ((flags & SKIP) || c == T_ID || c == T_VOID) call++;
   1982 				else flags |= SKIP;
   1983 				if (last == T_ID) flags |= IDID;
   1984 			}
   1985 			c = T_ID;
   1986 			flags |= TOKENS;
   1987 			break;
   1988 		case T_INVALID:
   1989 			if (*proto->tp >= '0' && *proto->tp <= '9')
   1990 			{
   1991 				n = 0;
   1992 				for (;; op--)
   1993 				{
   1994 					switch (*(op - 1))
   1995 					{
   1996 					case 'f':
   1997 					case 'F':
   1998 						t = op;
   1999 						while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
   2000 						if (*t == '.')
   2001 							op--;
   2002 						n = 0;
   2003 						break;
   2004 					case 'l':
   2005 					case 'L':
   2006 						if (!(n & 01))
   2007 						{
   2008 							n |= 01;
   2009 							t = op;
   2010 							while ((c = *--t) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z');
   2011 							if (*t == '.')
   2012 							{
   2013 								n = 0;
   2014 								op--;
   2015 								break;
   2016 							}
   2017 						}
   2018 						continue;
   2019 					case 'u':
   2020 					case 'U':
   2021 						n |= 02;
   2022 						continue;
   2023 					}
   2024 					break;
   2025 				}
   2026 				if (n & 01)
   2027 					*op++ = 'L';
   2028 				if (n & 02)
   2029 				{
   2030 					m = op;
   2031 					t = op = m + 10;
   2032 					while ((c = *--m) >= '0' && c <= '9' || c >= 'a' && c <= 'z' || c >= 'A' && c <= 'Z')
   2033 						*--t = c;
   2034 					c = *t;
   2035 					strcopy(m + 1, "(unsigned)");
   2036 					*t = c;
   2037 					break;
   2038 				}
   2039 			}
   2040 			goto fsm_other;
   2041 #if PROTOMAIN
   2042 		case '[':
   2043 			if ((flags & CLASSIC) && paren == 0 && group <= 2) flags |= SKIP;
   2044 			/*FALLTHROUGH*/
   2045 #endif
   2046 		default:
   2047  fsm_other:
   2048 #if PROTOMAIN
   2049 			if (flags & CLASSIC) break;
   2050 #endif
   2051 			flags |= TOKENS;
   2052 			if (paren == 0) flags |= OTHER;
   2053 			break;
   2054 		}
   2055 		else if (c == '#' && *ip != '(') flags |= SHARP;
   2056 		last = c;
   2057 #if PROTOMAIN
   2058 		if ((flags & (EXTERN|MATCH)) == (EXTERN|MATCH) && ((flags & (DIRECTIVE|SKIP)) || proto->brace || c != '(' && c != ')' && c != '*' && c != T_ID))
   2059 			CACHEOUT();
   2060 		else
   2061 #endif
   2062 		SYNCOUT();
   2063 		goto fsm_start;
   2064 	}
   2065 	else if (flags & (INIT_DEFINE|INIT_INCLUDE))
   2066 	{
   2067 #if PROTOMAIN
   2068 		if ((flags & YACC) && c == '%' && *ip == '{') t = 0;
   2069 		else
   2070 #endif
   2071 		{
   2072 			if (c == '#') for (t = ip; *t == ' ' || *t == '\t'; t++);
   2073 			else t = "";
   2074 			if (*t++ == 'i' && *t++ == 'f' && *t++ == 'n' && *t++ == 'd' && *t++ == 'e' && *t++ == 'f')
   2075 			{
   2076 #if !PROTOMAIN
   2077 				while (*t == ' ' || *t == '\t') t++;
   2078 				if (*t != '_')
   2079 #endif
   2080 					t = 0;
   2081 			}
   2082 		}
   2083 		if (t)
   2084 		{
   2085 			ip = bp;
   2086 			op = proto->op;
   2087 		}
   2088 		else while (*ip != '\n') *op++ = *ip++;
   2089 		op = init(proto, op, flags);
   2090 		op = linesync(proto, op, proto->line);
   2091 		flags &= ~(INIT_DEFINE|INIT_INCLUDE);
   2092 		proto->flags &= ~(INIT_DEFINE|INIT_INCLUDE);
   2093 		goto fsm_start;
   2094 	}
   2095 	SYNC();
   2096 	return c;
   2097 }
   2098 
   2099 /*
   2100  * close a proto buffer stream
   2101  */
   2102 
   2103 void
   2104 pppclose(char* iob)
   2105 {
   2106 	register struct proto*	proto = (struct proto*)(iob - sizeof(struct proto));
   2107 
   2108 	if (proto->flags & MORE) close(proto->fd);
   2109 	free((char*)proto); /* some ANSI cc's botch the free() prototype */
   2110 }
   2111 
   2112 /*
   2113  * open a new proto buffer stream
   2114  * read buffer pointer returned
   2115  * 0 returned on error or if no magic
   2116  *
   2117  *	file	!=0	file path to open, otherwise use fd
   2118  *	fd		open file fd if file==0
   2119  *	notice	!=0	copyright notice info commented at the top
   2120  *	options	!=0	additional notice name=value pairs, space or ; separated
   2121  *	package	!=0	generate header for this package
   2122  */
   2123 
   2124 char*
   2125 pppopen(char* file, int fd, char* notice, char* options, char* package, char* comment, int flags)
   2126 {
   2127 	register struct proto*	proto;
   2128 	register char*		iob;
   2129 	register long		n;
   2130 	register char*		s;
   2131 	int			pragma;
   2132 	char*			b;
   2133 #if PROTOMAIN
   2134 	int			comlen;
   2135 	char			com[80];
   2136 #endif
   2137 	int			m = 0;
   2138 
   2139 	static int		retain;
   2140 
   2141 	/*
   2142 	 * initialize proto
   2143 	 */
   2144 
   2145 #if PROTOMAIN
   2146 	if (flags & PROTO_CLASSIC) flags &= ~PROTO_INCLUDE;
   2147 #endif
   2148 	if (flags & PROTO_RETAIN) flags &= ~retain;
   2149 	else retain &= PROTO_INITIALIZED;
   2150 	if (file && (fd = open(file, O_RDONLY)) < 0) return 0;
   2151 #if !PROTOMAIN
   2152 	if ((n = lseek(fd, 0L, 2)) > 0)
   2153 	{
   2154 		if (lseek(fd, 0L, 0)) return 0;
   2155 		if (n < CHUNK) n = CHUNK;
   2156 		else if (n > 2 * BLOCK) n = 0;
   2157 		m = 1;
   2158 	}
   2159 	if (n > 0)
   2160 	{
   2161 		/*
   2162 		 * file read in one chunk
   2163 		 */
   2164 
   2165 		if (!(proto = newof(0, struct proto, 1, 4 * n + 2)))
   2166 			return 0;
   2167 		proto->iz = n;
   2168 		proto->oz = 3 * n;
   2169 		n = 0;
   2170 	}
   2171 	else
   2172 #endif
   2173 	{
   2174 		/*
   2175 		 * file read in BLOCK chunks
   2176 		 */
   2177 
   2178 		n = BLOCK;
   2179 		if (!(proto = newof(0, struct proto, 1, 5 * n + 2)))
   2180 			return 0;
   2181 		proto->iz = n;
   2182 		proto->oz = 3 * n;
   2183 		proto->flags |= MORE;
   2184 	}
   2185 	proto->fd = fd;
   2186 	proto->package = package;
   2187 	iob = (char*)proto + sizeof(struct proto);
   2188 	proto->op = proto->ob = iob;
   2189 	proto->ip = proto->ib = iob + proto->oz + n;
   2190 	if (m) proto->options |= REGULAR;
   2191 	if (!comment)
   2192 		comment = "/*";
   2193 	if (!(proto->cc[0] = comment[0]))
   2194 		notice = options = 0;
   2195 	else if (comment[1])
   2196 	{
   2197 		proto->cc[1] = comment[1];
   2198 		proto->cc[2] = comment[2] ? comment[2] : comment[0];
   2199 	}
   2200 	else
   2201 		proto->cc[1] = proto->cc[2] = comment[0];
   2202 
   2203 	/*
   2204 	 * read the first chunk
   2205 	 */
   2206 
   2207 	n = read(fd, proto->ip, proto->iz);
   2208 	if (!(proto->flags & MORE))
   2209 		close(fd);
   2210 	if (n < 0)
   2211 	{
   2212 		pppclose(iob);
   2213 		return 0;
   2214 	}
   2215 	*(proto->ip + n) = 0;
   2216 
   2217 	/*
   2218 	 * check for proto pragma in first block of lines
   2219 	 * pragma blanked out if found
   2220 	 *
   2221 	 *	-1	no pragma
   2222 	 *	 0	#pragma noprototyped
   2223 	 *	 1	#pragma prototyped
   2224 	 *
   2225 	 * NOTE: matches may occur inside comments and quotes
   2226 	 */
   2227 
   2228 #if PROTOMAIN
   2229 	if (!notice && !options || (comlen = astlicense(com, sizeof(com), NiL, "type=check", proto->cc[0], proto->cc[1], proto->cc[2])) <= 0)
   2230 		*com = 0;
   2231 #endif
   2232 	pragma = -1;
   2233 	s = proto->ip;
   2234 	m = MAGICTOP;
   2235 	while (m-- > 0 && *s)
   2236 	{
   2237 		while (*s == ' ' || *s == '\t') s++;
   2238 		if (*s == '#')
   2239 		{
   2240 			b = s++;
   2241 			while (*s == ' ' || *s == '\t') s++;
   2242 			if (!strncmp(s, MAGICDIR, sizeof(MAGICDIR) - 1) && (*(s += sizeof(MAGICDIR) - 1) == ' ' || *s == '\t'))
   2243 			{
   2244 				while (*s == ' ' || *s == '\t') s++;
   2245 				if (*s == 'n' && *(s + 1) == 'o')
   2246 				{
   2247 					s += 2;
   2248 					pragma = -2;
   2249 				}
   2250 				if (!strncmp(s, MAGICARG, sizeof(MAGICARG) - 1) && (*(s += sizeof(MAGICARG) - 1) == ' ' || *s == '\t' || *s == '\n' || *s == '\r'))
   2251 					while (*s)
   2252 					{
   2253 						if ((*(s - 1) == ' ' || *(s - 1) == '\t') && *s == *MAGICOFF && !strncmp(s, MAGICOFF, sizeof(MAGICOFF) - 1))
   2254 							notice = options = 0;
   2255 						if (*s++ == '\n')
   2256 						{
   2257 							pragma += 2;
   2258 #if PROTOMAIN
   2259 							if (!(flags & PROTO_DISABLE) || (flags & PROTO_NOPRAGMA))
   2260 #endif
   2261 							for (s--; b < s; *b++ = ' ');
   2262 							goto magic;
   2263 						}
   2264 					}
   2265 				pragma = -1;
   2266 			}
   2267 		}
   2268 		else if (*s == '/' && !strncmp(s, MAGICGEN, sizeof(MAGICGEN) - 1))
   2269 		{
   2270 			pragma = 0;
   2271 			break;
   2272 		}
   2273 #if PROTOMAIN
   2274 		else if (*s == '%' && *(s + 1) == '{')
   2275 			proto->flags |= YACC;
   2276 		if (notice || options)
   2277 		{
   2278 			if (*s == *com && !strncmp(s, com, comlen))
   2279 				notice = options = 0;
   2280 			else
   2281 				while (*s)
   2282 				{
   2283 					if (*s == *NOTICED && !strncmp(s, NOTICED, sizeof(NOTICED) - 1))
   2284 					{
   2285 						s += sizeof(NOTICED) - 1;
   2286 						while (*s == ' ' || *s == '\t')
   2287 							s++;
   2288 						if (*s == '(' && (*(s + 1) == 'c' || *(s + 1) == 'C') && *(s + 2) == ')' || *s >= '0' && *s <= '9' && *(s + 1) >= '0' && *(s + 1) <= '9')
   2289 						{
   2290 							notice = options = 0;
   2291 							break;
   2292 						}
   2293 					}
   2294 					if (*s == *PUBLICDOMAIN && !strncmp(s, PUBLICDOMAIN, sizeof(PUBLICDOMAIN) - 1))
   2295 					{
   2296 						notice = options = 0;
   2297 						break;
   2298 					}
   2299 					else if (*s++ == '\n')
   2300 					{
   2301 						s--;
   2302 						break;
   2303 					}
   2304 				}
   2305 		}
   2306 #endif
   2307 		while (*s && *s++ != '\n');
   2308 	}
   2309  magic:
   2310 	if (flags & PROTO_PLUSPLUS) proto->flags |= PLUSPLUS;
   2311 	if (flags & PROTO_TEST) proto->test = 1;
   2312 	if (flags & PROTO_EXTERNALIZE) proto->options |= EXTERNALIZE;
   2313 #if PROTOMAIN
   2314 	if (flags & PROTO_CLASSIC) pragma = -pragma;
   2315 	if (flags & PROTO_DISABLE) pragma = 0;
   2316 	if (flags & PROTO_LINESYNC) proto->flags |= LINESYNC;
   2317 	if (!(proto->flags & YACC) && file && (m = strlen(file)) > 2 && file[--m] == 'y' && file[--m] == '.')
   2318 		proto->flags |= YACC;
   2319 #endif
   2320 	if (pragma <= 0)
   2321 	{
   2322 		if (flags & PROTO_PLUSPLUS)
   2323 		{
   2324 			flags &= ~(PROTO_HEADER|PROTO_INCLUDE);
   2325 			proto->flags |= PLUSONLY;
   2326 		}
   2327 		else if (!(flags & (PROTO_FORCE|PROTO_PASS)))
   2328 		{
   2329 			pppclose(iob);
   2330 			return 0;
   2331 		}
   2332 		else if ((flags & (PROTO_FORCE|PROTO_PASS)) == PROTO_PASS || !pragma)
   2333 		{
   2334 			proto->flags |= PASS;
   2335 			if (proto->flags & MORE)
   2336 				proto->oz += proto->iz;
   2337 			proto->iz = n;
   2338 			if (notice || options)
   2339 			{
   2340 				if (proto->cc[0] == '#' && proto->ip[0] == '#' && proto->ip[1] == '!')
   2341 				{
   2342 					s = proto->ip;
   2343 					while (*s && *s++ != '\n');
   2344 					m = s - proto->ip;
   2345 					proto->op = memcopy(proto->op, proto->ip, m);
   2346 					proto->ip = s;
   2347 					proto->iz = n -= m;
   2348 				}
   2349 #if PROTOMAIN
   2350 				if (proto->cc[0])
   2351 				{
   2352 					if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0)
   2353 						proto_error((char*)proto + sizeof(struct proto), 1, proto->op, NiL);
   2354 					else
   2355 						proto->op += comlen;
   2356 				}
   2357 				if (!(flags & PROTO_CLASSIC) && !(proto->flags & YACC))
   2358 #endif
   2359 				proto->op = linesync(proto, proto->op, 1);
   2360 				proto->iz += proto->op - proto->ob;
   2361 			}
   2362 			memcopy(proto->op, proto->ip, n);
   2363 			return iob;
   2364 		}
   2365 	}
   2366 #if PROTOMAIN
   2367 	if (!(retain & PROTO_INITIALIZED))
   2368 	{
   2369 		retain |= PROTO_INITIALIZED;
   2370 		ppfsm(FSM_INIT, NiL);
   2371 	}
   2372 #endif
   2373 	proto->line = 1;
   2374 #if CHUNK >= 512
   2375 	if (notice || options || (flags & (PROTO_HEADER|PROTO_INCLUDE)))
   2376 	{
   2377 #if PROTOMAIN
   2378 		if (notice || options)
   2379 		{
   2380 			if ((comlen = astlicense(proto->op, proto->oz, notice, options, proto->cc[0], proto->cc[1], proto->cc[2])) < 0)
   2381 				proto_error((char*)proto + sizeof(struct proto), 1, proto->op, NiL);
   2382 			else
   2383 				proto->op += comlen;
   2384 		}
   2385 #endif
   2386 		if (flags & PROTO_INCLUDE)
   2387 		{
   2388 			proto->flags |= INIT_INCLUDE;
   2389 			if (flags & PROTO_RETAIN)
   2390 				retain |= PROTO_INCLUDE;
   2391 		}
   2392 		else if (flags & PROTO_HEADER)
   2393 		{
   2394 			if (flags & PROTO_RETAIN) retain |= PROTO_HEADER;
   2395 #if PROTOMAIN
   2396 			if (flags & PROTO_CLASSIC)
   2397 			{
   2398 				*proto->op++ = '#';
   2399 				proto->op = strcopy(proto->op, MAGICDIR);
   2400 				*proto->op++ = ' ';
   2401 				proto->op = strcopy(proto->op, MAGICARG);
   2402 				*proto->op++ = '\n';
   2403 			}
   2404 			else
   2405 #endif
   2406 			proto->flags |= INIT_DEFINE;
   2407 		}
   2408 #if PROTOMAIN
   2409 		if (!(flags & PROTO_CLASSIC))
   2410 		{
   2411 			if (proto->flags & YACC)
   2412 			{
   2413 				proto->op = strcopy(proto->op, "\n%{\n" + !notice);
   2414 				proto->op = strcopy(proto->op, MAGICGEN);
   2415 				proto->op = strcopy(proto->op, "%}\n");
   2416 			}
   2417 			else
   2418 			{
   2419 				if (n || notice || options)
   2420 					*proto->op++ = '\n';
   2421 				proto->op = strcopy(proto->op, MAGICGEN);
   2422 				if (n)
   2423 					proto->op = linesync(proto, proto->op, proto->line);
   2424 				else if (proto->flags & (INIT_DEFINE|INIT_INCLUDE))
   2425 					proto->op = init(proto, proto->op, proto->flags);
   2426 			}
   2427 		}
   2428 #endif
   2429 	}
   2430 #endif
   2431 #if PROTOMAIN
   2432 	proto->file = file;
   2433 	if (flags & PROTO_CLASSIC)
   2434 	{
   2435 		proto->flags |= CLASSIC;
   2436 		if (!(flags & PROTO_HEADER)) proto->flags |= EXTERN;
   2437 	}
   2438 #endif
   2439 	return iob;
   2440 }
   2441 
   2442 /*
   2443  * read next proto'd chunk into iob
   2444  * the chunk is 0 terminated and its size is returned
   2445  */
   2446 
   2447 int
   2448 pppread(char* iob)
   2449 {
   2450 	register struct proto*	proto = (struct proto*)(iob - sizeof(struct proto));
   2451 	register int		n;
   2452 
   2453 	if (proto->flags & PASS)
   2454 	{
   2455 		if (proto->iz)
   2456 		{
   2457 			n = proto->iz;
   2458 			proto->iz = 0;
   2459 		}
   2460 		else if (!(proto->flags & MORE)) n = 0;
   2461 		else if ((n = read(proto->fd, proto->ob, proto->oz)) <= 0 || (proto->options & REGULAR) && n < proto->oz)
   2462 		{
   2463 			proto->flags &= ~MORE;
   2464 			close(proto->fd);
   2465 		}
   2466 	}
   2467 	else
   2468 	{
   2469 		if (proto->op == proto->ob)
   2470 		{
   2471 			if (proto->flags & ERROR) return -1;
   2472 #if PROTOMAIN
   2473 			if (proto->flags & YACC)
   2474 			{
   2475 				register char*	ip = proto->ip;
   2476 				register char*	op = proto->ob;
   2477 				register char*	ep = proto->ob + proto->oz - 2;
   2478 
   2479 				if (!*ip)
   2480 				{
   2481 					ip = proto->ip = proto->ib;
   2482 					if (!(proto->flags & MORE)) n = 0;
   2483 					else if ((n = read(proto->fd, ip, proto->iz)) <= 0 || (proto->options & REGULAR) && n < proto->iz)
   2484 					{
   2485 						if (n < 0) n = 0;
   2486 						proto->flags &= ~MORE;
   2487 						close(proto->fd);
   2488 					}
   2489 					ip[n] = 0;
   2490 				}
   2491 				if (proto->flags & YACCSPLIT)
   2492 				{
   2493 					proto->flags &= ~YACCSPLIT;
   2494 					if (*ip == '%')
   2495 					{
   2496 						*op++ = *ip++;
   2497 						if (proto->flags & YACC2) proto->flags &= ~YACC;
   2498 						else proto->flags |= YACC2;
   2499 					}
   2500 				}
   2501 				if (proto->flags & YACC)
   2502 					while (op < ep && (n = *op++ = *ip))
   2503 					{
   2504 						ip++;
   2505 						if (n == '%')
   2506 						{
   2507 							if (*ip == '%' && (ip == proto->ip + 1 || *(ip - 2) == '\n'))
   2508 							{
   2509 								*op++ = *ip++;
   2510 								if (proto->flags & YACC2) proto->flags &= ~YACC;
   2511 								else proto->flags |= YACC2;
   2512 								break;
   2513 							}
   2514 							if (!*ip)
   2515 							{
   2516 								*op++ = '%';
   2517 								proto->flags |= YACCSPLIT;
   2518 								break;
   2519 							}
   2520 						}
   2521 						else if (n == '\n') proto->line++;
   2522 					}
   2523 				proto->op = memcopy(proto->ob, proto->ip, ip - proto->ip);
   2524 				proto->ip = ip;
   2525 			}
   2526 			else
   2527 #endif
   2528 			lex(proto, proto->flags);
   2529 			if ((proto->flags & (ERROR|MORE)) == ERROR)
   2530 				proto->op = strcopy(proto->op, "/* NOTE: some constructs may not have been converted */\n");
   2531 		}
   2532 		n = proto->op - proto->ob;
   2533 		proto->op = proto->ob;
   2534 	}
   2535 	return n;
   2536 }
   2537 
   2538 #if !PROTOMAIN
   2539 
   2540 /*
   2541  * drop control of iob after first pppread()
   2542  * return value is input fd
   2543  * if fd<0 then all data in iob
   2544  */
   2545 
   2546 int
   2547 pppdrop(char* iob)
   2548 {
   2549 	register struct proto*	proto = (struct proto*)(iob - sizeof(struct proto));
   2550 
   2551 	if (proto->flags & MORE)
   2552 	{
   2553 		proto->flags &= ~MORE;
   2554 		return proto->fd;
   2555 	}
   2556 	return -1;
   2557 }
   2558 
   2559 #endif
   2560