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