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