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