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