xref: /plan9/sys/src/cmd/cb/cb.c (revision ec59a3ddbfceee0efe34584c2c9981a5e5ff1ec4)
1 #include <u.h>
2 #include <libc.h>
3 #include <bio.h>
4 #include "cb.h"
5 #include "cbtype.h"
6 
7 void
8 main(int argc, char *argv[])
9 {
10 	Biobuf stdin, stdout;
11 
12 	while (--argc > 0 && (*++argv)[0] == '-'){
13 		switch ((*argv)[1]){
14 		case 's':
15 			strict = 1;
16 			continue;
17 		case 'j':
18 			join = 1;
19 			continue;
20 		case 'l':
21 			if((*argv)[2] != '\0'){
22 				maxleng = atoi( &((*argv)[2]) );
23 			}
24 			else{
25 				maxleng = atoi(*++argv);
26 				argc--;
27 			}
28 			maxtabs = maxleng/TABLENG - 2;
29 			maxleng -= (maxleng + 5)/10;
30 			continue;
31 		default:
32 			fprint(2, "cb: illegal option %c\n", *argv[1]);
33 			exits("boom");
34 		}
35 	}
36 	Binit(&stdout, 1, OWRITE);
37 	output = &stdout;
38 	if (argc <= 0){
39 		Binit(&stdin, 0, OREAD);
40 		input = &stdin;
41 		work();
42 	} else {
43 		while (argc-- > 0){
44 			if ((input = Bopen( *argv, OREAD)) == 0){
45 				fprint(2, "cb: cannot open input file %s\n", *argv);
46 				exits("boom");
47 			}
48 			work();
49 			argv++;
50 		}
51 	}
52 	exits(0);
53 }
54 void
55 work(void)
56 {
57 	int c, cc;
58 	struct keyw *lptr;
59 	char *pt;
60 	int ct;
61 
62 	while ((c = getch()) != Beof){
63 		switch (c){
64 		case '{':
65 			if ((lptr = lookup(lastlook,p)) != 0){
66 				if (lptr->type == ELSE)gotelse();
67 				else if(lptr->type == DO)gotdo();
68 				else if(lptr->type == STRUCT)structlev++;
69 			}
70 			if(++clev >= &ind[CLEVEL-1]){
71 				fprint(2,"too many levels of curly brackets\n");
72 				clev = &ind[CLEVEL-1];
73 			}
74 			clev->pdepth = 0;
75 			clev->tabs = (clev-1)->tabs;
76 			clearif(clev);
77 			if(strict && clev->tabs > 0)
78 				putspace(' ',NO);
79 			putch(c,NO);
80 			getnl();
81 			if(keyflag == DATADEF){
82 				OUT;
83 			}
84 			else {
85 				OUTK;
86 			}
87 			clev->tabs++;
88 			pt = getnext(0);		/* to handle initialized structures */
89 			if(*pt == '{'){		/* hide one level of {} */
90 				while((c=getch()) != '{')
91 					if(c == Beof)error("{");
92 				putch(c,NO);
93 				if(strict){
94 					putch(' ',NO);
95 					eatspace();
96 				}
97 				keyflag = SINIT;
98 			}
99 			continue;
100 		case '}':
101 			pt = getnext(0);		/* to handle initialized structures */
102 			if(*pt == ','){
103 				if(strict){
104 					putspace(' ',NO);
105 					eatspace();
106 				}
107 				putch(c,NO);
108 				putch(*pt,NO);
109 				*pt = '\0';
110 				ct = getnl();
111 				pt = getnext(0);
112 				if(*pt == '{'){
113 					OUT;
114 					while((cc = getch()) != '{')
115 						if(cc == Beof)error("}");
116 					putch(cc,NO);
117 					if(strict){
118 						putch(' ',NO);
119 						eatspace();
120 					}
121 					getnext(0);
122 					continue;
123 				}
124 				else if(strict || ct){
125 					OUT;
126 				}
127 				continue;
128 			}
129 			else if(keyflag == SINIT && *pt == '}'){
130 				if(strict)
131 					putspace(' ',NO);
132 				putch(c,NO);
133 				getnl();
134 				OUT;
135 				keyflag = DATADEF;
136 				*pt = '\0';
137 				pt = getnext(0);
138 			}
139 			outs(clev->tabs);
140 			if(--clev < ind)clev = ind;
141 			ptabs(clev->tabs);
142 			putch(c,NO);
143 			lbegin = 0;
144 			lptr=lookup(pt,lastplace+1);
145 			c = *pt;
146 			if(*pt == ';' || *pt == ','){
147 				putch(*pt,NO);
148 				*pt = '\0';
149 				lastplace=pt;
150 			}
151 			ct = getnl();
152 			if((dolevel && clev->tabs <= dotabs[dolevel]) || (structlev )
153 			    || (lptr != 0 &&lptr->type == ELSE&& clev->pdepth == 0)){
154 				if(c == ';'){
155 					OUTK;
156 				}
157 				else if(strict || (lptr != 0 && lptr->type == ELSE && ct == 0)){
158 					putspace(' ',NO);
159 					eatspace();
160 				}
161 				else if(lptr != 0 && lptr->type == ELSE){
162 					OUTK;
163 				}
164 				if(structlev){
165 					structlev--;
166 					keyflag = DATADEF;
167 				}
168 			}
169 			else {
170 				OUTK;
171 				if(strict && clev->tabs == 0){
172 					if((c=getch()) != '\n'){
173 						Bputc(output, '\n');
174 						Bputc(output, '\n');
175 						unget(c);
176 					}
177 					else {
178 						lineno++;
179 						Bputc(output, '\n');
180 						if((c=getch()) != '\n')unget(c);
181 						else lineno++;
182 						Bputc(output, '\n');
183 					}
184 				}
185 			}
186 			if(lptr != 0 && lptr->type == ELSE && clev->pdepth != 0){
187 				UNBUMP;
188 			}
189 			if(lptr == 0 || lptr->type != ELSE){
190 				clev->iflev = 0;
191 				if(dolevel && docurly[dolevel] == NO && clev->tabs == dotabs[dolevel]+1)
192 					clev->tabs--;
193 				else if(clev->pdepth != 0){
194 					UNBUMP;
195 				}
196 			}
197 			continue;
198 		case '(':
199 			paren++;
200 			if ((lptr = lookup(lastlook,p)) != 0){
201 				if(!(lptr->type == TYPE || lptr->type == STRUCT))keyflag=KEYWORD;
202 				if (strict){
203 					putspace(lptr->punc,NO);
204 					opflag = 1;
205 				}
206 				putch(c,NO);
207 				if (lptr->type == IF)gotif();
208 			}
209 			else {
210 				putch(c,NO);
211 				lastlook = p;
212 				opflag = 1;
213 			}
214 			continue;
215 		case ')':
216 			if(--paren < 0)paren = 0;
217 			putch(c,NO);
218 			if((lptr = lookup(lastlook,p)) != 0){
219 				if(lptr->type == TYPE || lptr->type == STRUCT)
220 					opflag = 1;
221 			}
222 			else if(keyflag == DATADEF)opflag = 1;
223 			else opflag = 0;
224 			outs(clev->tabs);
225 			pt = getnext(1);
226 			if ((ct = getnl()) == 1 && !strict){
227 				if(dolevel && clev->tabs <= dotabs[dolevel])
228 					resetdo();
229 				if(clev->tabs > 0 && (paren != 0 || keyflag == 0)){
230 					if(join){
231 						eatspace();
232 						putch(' ',YES);
233 						continue;
234 					} else {
235 						OUT;
236 						split = 1;
237 						continue;
238 					}
239 				}
240 				else if(clev->tabs > 0 && *pt != '{'){
241 					BUMP;
242 				}
243 				OUTK;
244 			}
245 			else if(strict){
246 				if(clev->tabs == 0){
247 					if(*pt != ';' && *pt != ',' && *pt != '(' && *pt != '['){
248 						OUTK;
249 					}
250 				}
251 				else {
252 					if(keyflag == KEYWORD && paren == 0){
253 						if(dolevel && clev->tabs <= dotabs[dolevel]){
254 							resetdo();
255 							eatspace();
256 							continue;
257 						}
258 						if(*pt != '{'){
259 							BUMP;
260 							OUTK;
261 						}
262 						else {
263 							*pt='\0';
264 							eatspace();
265 							unget('{');
266 						}
267 					}
268 					else if(ct){
269 						if(paren){
270 							if(join){
271 								eatspace();
272 							} else {
273 								split = 1;
274 								OUT;
275 							}
276 						}
277 						else {
278 							OUTK;
279 						}
280 					}
281 				}
282 			}
283 			else if(dolevel && clev->tabs <= dotabs[dolevel])
284 				resetdo();
285 			continue;
286 		case ' ':
287 		case '\t':
288 			if ((lptr = lookup(lastlook,p)) != 0){
289 				if(!(lptr->type==TYPE||lptr->type==STRUCT))
290 					keyflag = KEYWORD;
291 				else if(paren == 0)keyflag = DATADEF;
292 				if(strict){
293 					if(lptr->type != ELSE){
294 						if(lptr->type == TYPE){
295 							if(paren != 0)putch(' ',YES);
296 						}
297 						else
298 							putch(lptr->punc,NO);
299 						eatspace();
300 					}
301 				}
302 				else putch(c,YES);
303 				switch(lptr->type){
304 				case CASE:
305 					outs(clev->tabs-1);
306 					continue;
307 				case ELSE:
308 					pt = getnext(1);
309 					eatspace();
310 					if((cc = getch()) == '\n' && !strict){
311 						unget(cc);
312 					}
313 					else {
314 						unget(cc);
315 						if(checkif(pt))continue;
316 					}
317 					gotelse();
318 					if(strict) unget(c);
319 					if(getnl() == 1 && !strict){
320 						OUTK;
321 						if(*pt != '{'){
322 							BUMP;
323 						}
324 					}
325 					else if(strict){
326 						if(*pt != '{'){
327 							OUTK;
328 							BUMP;
329 						}
330 					}
331 					continue;
332 				case IF:
333 					gotif();
334 					continue;
335 				case DO:
336 					gotdo();
337 					pt = getnext(1);
338 					if(*pt != '{'){
339 						eatallsp();
340 						OUTK;
341 						docurly[dolevel] = NO;
342 						dopdepth[dolevel] = clev->pdepth;
343 						clev->pdepth = 0;
344 						clev->tabs++;
345 					}
346 					continue;
347 				case TYPE:
348 					if(paren)continue;
349 					if(!strict)continue;
350 					gottype(lptr);
351 					continue;
352 				case STRUCT:
353 					gotstruct();
354 					continue;
355 				}
356 			}
357 			else if (lbegin == 0 || p > string)
358 				if(strict)
359 					putch(c,NO);
360 				else putch(c,YES);
361 			continue;
362 		case ';':
363 			putch(c,NO);
364 			if(paren != 0){
365 				if(strict){
366 					putch(' ',YES);
367 					eatspace();
368 				}
369 				opflag = 1;
370 				continue;
371 			}
372 			outs(clev->tabs);
373 			pt = getnext(0);
374 			lptr=lookup(pt,lastplace+1);
375 			if(lptr == 0 || lptr->type != ELSE){
376 				clev->iflev = 0;
377 				if(clev->pdepth != 0){
378 					UNBUMP;
379 				}
380 				if(dolevel && docurly[dolevel] == NO && clev->tabs <= dotabs[dolevel]+1)
381 					clev->tabs--;
382 /*
383 				else if(clev->pdepth != 0){
384 					UNBUMP;
385 				}
386 */
387 			}
388 			getnl();
389 			OUTK;
390 			continue;
391 		case '\n':
392 			if ((lptr = lookup(lastlook,p)) != 0){
393 				pt = getnext(1);
394 				if (lptr->type == ELSE){
395 					if(strict)
396 						if(checkif(pt))continue;
397 					gotelse();
398 					OUTK;
399 					if(*pt != '{'){
400 						BUMP;
401 					}
402 				}
403 				else if(lptr->type == DO){
404 					OUTK;
405 					gotdo();
406 					if(*pt != '{'){
407 						docurly[dolevel] = NO;
408 						dopdepth[dolevel] = clev->pdepth;
409 						clev->pdepth = 0;
410 						clev->tabs++;
411 					}
412 				}
413 				else {
414 					OUTK;
415 					if(lptr->type == STRUCT)gotstruct();
416 				}
417 			}
418 			else if(p == string)Bputc(output, '\n');
419 			else {
420 				if(clev->tabs > 0 &&(paren != 0 || keyflag == 0)){
421 					if(join){
422 						putch(' ',YES);
423 						eatspace();
424 						continue;
425 					} else {
426 						OUT;
427 						split = 1;
428 						continue;
429 					}
430 				}
431 				else if(keyflag == KEYWORD){
432 					OUTK;
433 					continue;
434 				}
435 				OUT;
436 			}
437 			continue;
438 		case '"':
439 		case '\'':
440 			putch(c,NO);
441 			while ((cc = getch()) != c){
442 				if(cc == Beof)
443 					error("\" or '");
444 				putch(cc,NO);
445 				if (cc == '\\'){
446 					putch(getch(),NO);
447 				}
448 				if (cc == '\n'){
449 					outs(clev->tabs);
450 					lbegin = 1;
451 					count = 0;
452 				}
453 			}
454 			putch(cc,NO);
455 			opflag=0;
456 			if (getnl() == 1){
457 				unget('\n');
458 			}
459 			continue;
460 		case '\\':
461 			putch(c,NO);
462 			putch(getch(),NO);
463 			continue;
464 		case '?':
465 			question = 1;
466 			gotop(c);
467 			continue;
468 		case ':':
469 			if ((cc = getch()) == ':') {
470 				putch(c,NO);
471 				putch(cc,NO);
472 				continue;
473 			}
474 			unget(cc);
475 			if (question == 1){
476 				question = 0;
477 				gotop(c);
478 				continue;
479 			}
480 			putch(c,NO);
481 			if(structlev)continue;
482 			if ((lptr = lookup(lastlook,p)) != 0){
483 				if (lptr->type == CASE)outs(clev->tabs - 1);
484 			}
485 			else {
486 				lbegin = 0;
487 				outs(clev->tabs);
488 			}
489 			getnl();
490 			OUTK;
491 			continue;
492 		case '/':
493 			if ((cc = getch()) == '/') {
494 				putch(c,NO);
495 				putch(cc,NO);
496 				cpp_comment(YES);
497 				OUT;
498 				lastlook = 0;
499 				continue;
500 			}
501 			else if (cc != '*') {
502 				unget(cc);
503 				gotop(c);
504 				continue;
505 			}
506 			putch(c,NO);
507 			putch(cc,NO);
508 			cc = comment(YES);
509 			if(getnl() == 1){
510 				if(cc == 0){
511 					OUT;
512 				}
513 				else {
514 					outs(0);
515 					Bputc(output, '\n');
516 					lbegin = 1;
517 					count = 0;
518 				}
519 				lastlook = 0;
520 			}
521 			continue;
522 		case '[':
523 			putch(c,NO);
524 			ct = 0;
525 			while((c = getch()) != ']' || ct > 0){
526 				if(c == Beof)error("]");
527 				putch(c,NO);
528 				if(c == '[')ct++;
529 				if(c == ']')ct--;
530 			}
531 			putch(c,NO);
532 			continue;
533 		case '#':
534 			putch(c,NO);
535 			while ((cc = getch()) != '\n'){
536 				if(cc == Beof)error("newline");
537 				if (cc == '\\'){
538 					putch(cc,NO);
539 					cc = getch();
540 				}
541 				putch(cc,NO);
542 			}
543 			putch(cc,NO);
544 			lbegin = 0;
545 			outs(clev->tabs);
546 			lbegin = 1;
547 			count = 0;
548 			continue;
549 		default:
550 			if (c == ','){
551 				opflag = 1;
552 				putch(c,YES);
553 				if (strict){
554 					if ((cc = getch()) != ' ')unget(cc);
555 					if(cc != '\n')putch(' ',YES);
556 				}
557 			}
558 			else if(isop(c))gotop(c);
559 			else {
560 				if(isalnum(c) && lastlook == 0)lastlook = p;
561 				if(isdigit(c)){
562 					putch(c,NO);
563 					while(isdigit(c=Bgetc(input))||c == '.')putch(c,NO);
564 					if(c == 'e'){
565 						putch(c,NO);
566 						c = Bgetc(input);
567 						putch(c, NO);
568 						while(isdigit(c=Bgetc(input)))putch(c,NO);
569 					}
570 					Bungetc(input);
571 				}
572 				else putch(c,NO);
573 				if(keyflag != DATADEF)opflag = 0;
574 			}
575 		}
576 	}
577 }
578 void
579 gotif(void){
580 	outs(clev->tabs);
581 	if(++clev->iflev >= IFLEVEL-1){
582 		fprint(2,"too many levels of if %d\n",clev->iflev );
583 		clev->iflev = IFLEVEL-1;
584 	}
585 	clev->ifc[clev->iflev] = clev->tabs;
586 	clev->spdepth[clev->iflev] = clev->pdepth;
587 }
588 void
589 gotelse(void){
590 	clev->tabs = clev->ifc[clev->iflev];
591 	clev->pdepth = clev->spdepth[clev->iflev];
592 	if(--(clev->iflev) < 0)clev->iflev = 0;
593 }
594 int
595 checkif(char *pt)
596 {
597 	struct keyw *lptr;
598 	int cc;
599 	if((lptr=lookup(pt,lastplace+1))!= 0){
600 		if(lptr->type == IF){
601 			if(strict)putch(' ',YES);
602 			copy(lptr->name);
603 			*pt='\0';
604 			lastplace = pt;
605 			if(strict){
606 				putch(lptr->punc,NO);
607 				eatallsp();
608 			}
609 			clev->tabs = clev->ifc[clev->iflev];
610 			clev->pdepth = clev->spdepth[clev->iflev];
611 			keyflag = KEYWORD;
612 			return(1);
613 		}
614 	}
615 	return(0);
616 }
617 void
618 gotdo(void){
619 	if(++dolevel >= DOLEVEL-1){
620 		fprint(2,"too many levels of do %d\n",dolevel);
621 		dolevel = DOLEVEL-1;
622 	}
623 	dotabs[dolevel] = clev->tabs;
624 	docurly[dolevel] = YES;
625 }
626 void
627 resetdo(void){
628 	if(docurly[dolevel] == NO)
629 		clev->pdepth = dopdepth[dolevel];
630 	if(--dolevel < 0)dolevel = 0;
631 }
632 void
633 gottype(struct keyw *lptr)
634 {
635 	char *pt;
636 	struct keyw *tlptr;
637 	int c;
638 	while(1){
639 		pt = getnext(1);
640 		if((tlptr=lookup(pt,lastplace+1))!=0){
641 			putch(' ',YES);
642 			copy(tlptr->name);
643 			*pt='\0';
644 			lastplace = pt;
645 			if(tlptr->type == STRUCT){
646 				putch(tlptr->punc,YES);
647 				gotstruct();
648 				break;
649 			}
650 			lptr=tlptr;
651 			continue;
652 		}
653 		else{
654 			putch(lptr->punc,NO);
655 			while((c=getch())== ' ' || c == '\t');
656 			unget(c);
657 			break;
658 		}
659 	}
660 }
661 void
662 gotstruct(void){
663 	int c;
664 	int cc;
665 	char *pt;
666 	while((c=getch()) == ' ' || c == '\t')
667 		if(!strict)putch(c,NO);
668 	if(c == '{'){
669 		structlev++;
670 		unget(c);
671 		return;
672 	}
673 	if(isalpha(c)){
674 		putch(c,NO);
675 		while(isalnum(c=getch()))putch(c,NO);
676 	}
677 	unget(c);
678 	pt = getnext(1);
679 	if(*pt == '{')structlev++;
680 	if(strict){
681 		eatallsp();
682 		putch(' ',NO);
683 	}
684 }
685 void
686 gotop(int c)
687 {
688 	char optmp[OPLENGTH];
689 	char *op_ptr;
690 	struct op *s_op;
691 	char *a, *b;
692 	op_ptr = optmp;
693 	*op_ptr++ = c;
694 	while (isop(( *op_ptr = getch())))op_ptr++;
695 	if(!strict)unget(*op_ptr);
696 	else if (*op_ptr != ' ')unget( *op_ptr);
697 	*op_ptr = '\0';
698 	s_op = op;
699 	b = optmp;
700 	while ((a = s_op->name) != 0){
701 		op_ptr = b;
702 		while ((*op_ptr == *a) && (*op_ptr != '\0')){
703 			a++;
704 			op_ptr++;
705 		}
706 		if (*a == '\0'){
707 			keep(s_op);
708 			opflag = s_op->setop;
709 			if (*op_ptr != '\0'){
710 				b = op_ptr;
711 				s_op = op;
712 				continue;
713 			}
714 			else break;
715 		}
716 		else s_op++;
717 	}
718 }
719 void
720 keep(struct op *o)
721 {
722 	char	*s;
723 	int ok;
724 	if(o->blanks == NEVER)ok = NO;
725 	else ok = YES;
726 	if (strict && ((o->blanks & ALWAYS)
727 	    || ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0)))
728 		putspace(' ',YES);
729 	for(s=o->name; *s != '\0'; s++){
730 		if(*(s+1) == '\0')putch(*s,ok);
731 		else
732 			putch(*s,NO);
733 	}
734 	if (strict && ((o->blanks & ALWAYS)
735 	    || ((opflag == 0 && o->blanks & SOMETIMES) && clev->tabs != 0))) putch(' ',YES);
736 }
737 int
738 getnl(void){
739 	int ch;
740 	char *savp;
741 	int gotcmt;
742 	gotcmt = 0;
743 	savp = p;
744 	while ((ch = getch()) == '\t' || ch == ' ')putch(ch,NO);
745 	if (ch == '/'){
746 		if ((ch = getch()) == '*'){
747 			putch('/',NO);
748 			putch('*',NO);
749 			comment(NO);
750 			ch = getch();
751 			gotcmt=1;
752 		}
753 		else if (ch == '/') {
754 			putch('/',NO);
755 			putch('/',NO);
756 			cpp_comment(NO);
757 			ch = getch();
758 			gotcmt = 1;
759 		}
760 		else {
761 			if(inswitch)*(++lastplace) = ch;
762 			else {
763 				inswitch = 1;
764 				*lastplace = ch;
765 			}
766 			unget('/');
767 			return(0);
768 		}
769 	}
770 	if(ch == '\n'){
771 		if(gotcmt == 0)p=savp;
772 		return(1);
773 	}
774 	unget(ch);
775 	return(0);
776 }
777 void
778 ptabs(int n){
779 	int	i;
780 	int num;
781 	if(n > maxtabs){
782 		if(!folded){
783 			Bprint(output, "/* code folded from here */\n");
784 			folded = 1;
785 		}
786 		num = n-maxtabs;
787 	}
788 	else {
789 		num = n;
790 		if(folded){
791 			folded = 0;
792 			Bprint(output, "/* unfolding */\n");
793 		}
794 	}
795 	for (i = 0; i < num; i++)Bputc(output, '\t');
796 }
797 void
798 outs(int n){
799 	if (p > string){
800 		if (lbegin){
801 			ptabs(n);
802 			lbegin = 0;
803 			if (split == 1){
804 				split = 0;
805 				if (clev->tabs > 0)Bprint(output, "\t");
806 			}
807 		}
808 		*p = '\0';
809 		Bprint(output, "%s", string);
810 		lastlook = p = string;
811 	}
812 	else {
813 		if (lbegin != 0){
814 			lbegin = 0;
815 			split = 0;
816 		}
817 	}
818 }
819 void
820 putch(char c,int ok)
821 {
822 	int cc;
823 	if(p < &string[LINE-1]){
824 		if(count+TABLENG*clev->tabs >= maxleng && ok && !folded){
825 			if(c != ' ')*p++ = c;
826 			OUT;
827 			split = 1;
828 			if((cc=getch()) != '\n')unget(cc);
829 		}
830 		else {
831 			*p++ = c;
832 			count++;
833 		}
834 	}
835 	else {
836 		outs(clev->tabs);
837 		*p++ = c;
838 		count = 0;
839 	}
840 }
841 struct keyw *
842 lookup(char *first, char *last)
843 {
844 	struct keyw *ptr;
845 	char	*cptr, *ckey, *k;
846 
847 	if(first == last || first == 0)return(0);
848 	cptr = first;
849 	while (*cptr == ' ' || *cptr == '\t')cptr++;
850 	if(cptr >= last)return(0);
851 	ptr = key;
852 	while ((ckey = ptr->name) != 0){
853 		for (k = cptr; (*ckey == *k && *ckey != '\0'); k++, ckey++);
854 		if(*ckey=='\0' && (k==last|| (k<last && !isalnum(*k)))){
855 			opflag = 1;
856 			lastlook = 0;
857 			return(ptr);
858 		}
859 		ptr++;
860 	}
861 	return(0);
862 }
863 int
864 comment(int ok)
865 {
866 	int ch;
867 	int hitnl;
868 
869 	hitnl = 0;
870 	while ((ch  = getch()) != Beof){
871 		putch(ch, NO);
872 		if (ch == '*'){
873 gotstar:
874 			if ((ch  = getch()) == '/'){
875 				putch(ch,NO);
876 				return(hitnl);
877 			}
878 			putch(ch,NO);
879 			if (ch == '*')goto gotstar;
880 		}
881 		if (ch == '\n'){
882 			if(ok && !hitnl){
883 				outs(clev->tabs);
884 			}
885 			else {
886 				outs(0);
887 			}
888 			lbegin = 1;
889 			count = 0;
890 			hitnl = 1;
891 		}
892 	}
893 	return(hitnl);
894 }
895 int
896 cpp_comment(int ok)
897 {
898 	int ch;
899 	int hitnl;
900 
901 	hitnl = 0;
902 	while ((ch = getch()) != -1) {
903 		if (ch == '\n') {
904 			if (ok && !hitnl)
905 				outs(clev->tabs);
906 			else
907 				outs(0);
908 			lbegin = 1;
909 			count = 0;
910 			hitnl = 1;
911 			break;
912 		}
913 		putch(ch, NO);
914 	}
915 	return hitnl;
916 }
917 void
918 putspace(char ch, int ok)
919 {
920 	if(p == string)putch(ch,ok);
921 	else if (*(p - 1) != ch) putch(ch,ok);
922 }
923 int
924 getch(void){
925 	char c;
926 	if(inswitch){
927 		if(next != '\0'){
928 			c=next;
929 			next = '\0';
930 			return(c);
931 		}
932 		if(tptr <= lastplace){
933 			if(*tptr != '\0')return(*tptr++);
934 			else if(++tptr <= lastplace)return(*tptr++);
935 		}
936 		inswitch=0;
937 		lastplace = tptr = temp;
938 	}
939 	return(Bgetc(input));
940 }
941 void
942 unget(char c)
943 {
944 	if(inswitch){
945 		if(tptr != temp)
946 			*(--tptr) = c;
947 		else next = c;
948 	}
949 	else Bungetc(input);
950 }
951 char *
952 getnext(int must){
953 	int c;
954 	char *beg;
955 	int prect,nlct;
956 	prect = nlct = 0;
957 	if(tptr > lastplace){
958 		tptr = lastplace = temp;
959 		err = 0;
960 		inswitch = 0;
961 	}
962 	tp = lastplace;
963 	if(inswitch && tptr <= lastplace)
964 		if (isalnum(*lastplace)||ispunct(*lastplace)||isop(*lastplace))return(lastplace);
965 space:
966 	while(isspace(c=Bgetc(input)))puttmp(c,1);
967 	beg = tp;
968 	puttmp(c,1);
969 	if(c == '/'){
970 		if(puttmp(Bgetc(input),1) == '*'){
971 cont:
972 			while((c=Bgetc(input)) != '*'){
973 				puttmp(c,0);
974 				if(must == 0 && c == '\n')
975 					if(nlct++ > 2)goto done;
976 			}
977 			puttmp(c,1);
978 	star:
979 			if(puttmp((c=Bgetc(input)),1) == '/'){
980 				beg = tp;
981 				puttmp((c=Bgetc(input)),1);
982 			}
983 			else if(c == '*')goto star;
984 			else goto cont;
985 		}
986 		else goto done;
987 	}
988 	if(isspace(c))goto space;
989 	if(c == '#' && tp > temp+1 && *(tp-2) == '\n'){
990 		if(prect++ > 2)goto done;
991 		while(puttmp((c=Bgetc(input)),1) != '\n')
992 			if(c == '\\')puttmp(Bgetc(input),1);
993 		goto space;
994 	}
995 	if(isalnum(c)){
996 		while(isalnum(c = Bgetc(input)))puttmp(c,1);
997 		Bungetc(input);
998 	}
999 done:
1000 	puttmp('\0',1);
1001 	lastplace = tp-1;
1002 	inswitch = 1;
1003 	return(beg);
1004 }
1005 void
1006 copy(char *s)
1007 {
1008 	while(*s != '\0')putch(*s++,NO);
1009 }
1010 void
1011 clearif(struct indent *cl)
1012 {
1013 	int i;
1014 	for(i=0;i<IFLEVEL-1;i++)cl->ifc[i] = 0;
1015 }
1016 char
1017 puttmp(char c, int keep)
1018 {
1019 	if(tp < &temp[TEMP-120])
1020 		*tp++ = c;
1021 	else {
1022 		if(keep){
1023 			if(tp >= &temp[TEMP-1]){
1024 				fprint(2,"can't look past huge comment - quiting\n");
1025 				exits("boom");
1026 			}
1027 			*tp++ = c;
1028 		}
1029 		else if(err == 0){
1030 			err++;
1031 			fprint(2,"truncating long comment\n");
1032 		}
1033 	}
1034 	return(c);
1035 }
1036 void
1037 error(char *s)
1038 {
1039 	fprint(2,"saw EOF while looking for %s\n",s);
1040 	exits("boom");
1041 }
1042