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