xref: /freebsd-11-stable/release/picobsd/tinyware/msh/sh1.c (revision 6d8476df784248b28336b4e5c632810893a4967c)
1 #define Extern extern
2 #include <sys/types.h>
3 #include <signal.h>
4 #define _NSIG NSIG
5 #include <errno.h>
6 #include <setjmp.h>
7 #include "sh.h"
8 /* -------- sh.c -------- */
9 /*
10  * shell
11  */
12 
13 /* #include "sh.h" */
14 
15 int	intr;
16 int	inparse;
17 char	flags['z'-'a'+1];
18 char	*flag = flags-'a';
19 char	*elinep = line+sizeof(line)-5;
20 char	*null	= "";
21 int	heedint =1;
22 struct	env	e ={line, iostack, iostack-1,
23 		    (xint *)NULL, FDBASE, (struct env *)NULL};
24 
25 extern	char	**environ;	/* environment pointer */
26 
27 /*
28  * default shell, search rules
29  */
30 char	shellname[] = "/bin/sh";
31 char	search[] = ":/bin:/usr/bin";
32 
33 _PROTOTYPE(void (*qflag), (int)) = SIG_IGN;
34 
35 _PROTOTYPE(int main, (int argc, char **argv ));
36 _PROTOTYPE(int newfile, (char *s ));
37 _PROTOTYPE(static char *findeq, (char *cp ));
38 _PROTOTYPE(static char *cclass, (char *p, int sub ));
39 _PROTOTYPE(void initarea, (void));
40 
main(argc,argv)41 int main(argc, argv)
42 int argc;
43 register char **argv;
44 {
45 	register int f;
46 	register char *s;
47 	int cflag;
48 	char *name, **ap;
49 	int (*iof)();
50 
51 	initarea();
52 	if ((ap = environ) != NULL) {
53 		while (*ap)
54 			assign(*ap++, !COPYV);
55 		for (ap = environ; *ap;)
56 			export(lookup(*ap++));
57 	}
58 	closeall();
59 	areanum = 1;
60 
61 	shell = lookup("SHELL");
62 	if (shell->value == null)
63 		setval(shell, shellname);
64 	export(shell);
65 
66 	homedir = lookup("HOME");
67 	if (homedir->value == null)
68 		setval(homedir, "/");
69 	export(homedir);
70 
71 	setval(lookup("$"), itoa(getpid(), 5));
72 
73 	path = lookup("PATH");
74 	if (path->value == null)
75 		setval(path, search);
76 	export(path);
77 
78 	ifs = lookup("IFS");
79 	if (ifs->value == null)
80 		setval(ifs, " \t\n");
81 
82 	prompt = lookup("PS1");
83 	if (prompt->value == null)
84 #ifndef UNIXSHELL
85 		setval(prompt, "$ ");
86 #else
87 		setval(prompt, "% ");
88 #endif
89 
90 	if (geteuid() == 0) {
91 		setval(prompt, "# ");
92 		prompt->status &= ~EXPORT;
93 	}
94 	cprompt = lookup("PS2");
95 	if (cprompt->value == null)
96 		setval(cprompt, "> ");
97 
98 	iof = filechar;
99 	cflag = 0;
100 	name = *argv++;
101 	if (--argc >= 1) {
102 		if(argv[0][0] == '-' && argv[0][1] != '\0') {
103 			for (s = argv[0]+1; *s; s++)
104 				switch (*s) {
105 				case 'c':
106 					prompt->status &= ~EXPORT;
107 					cprompt->status &= ~EXPORT;
108 					setval(prompt, "");
109 					setval(cprompt, "");
110 					cflag = 1;
111 					if (--argc > 0)
112 						PUSHIO(aword, *++argv, iof = nlchar);
113 					break;
114 
115 				case 'q':
116 					qflag = SIG_DFL;
117 					break;
118 
119 				case 's':
120 					/* standard input */
121 					break;
122 
123 				case 't':
124 					prompt->status &= ~EXPORT;
125 					setval(prompt, "");
126 					iof = linechar;
127 					break;
128 
129 				case 'i':
130 					talking++;
131 				default:
132 					if (*s>='a' && *s<='z')
133 						flag[*s]++;
134 				}
135 		} else {
136 			argv--;
137 			argc++;
138 		}
139 		if (iof == filechar && --argc > 0) {
140 			setval(prompt, "");
141 			setval(cprompt, "");
142 			prompt->status &= ~EXPORT;
143 			cprompt->status &= ~EXPORT;
144 			if (newfile(name = *++argv))
145 				exit(1);
146 		}
147 	}
148 	setdash();
149 	if (e.iop < iostack) {
150 		PUSHIO(afile, 0, iof);
151 		if (isatty(0) && isatty(1) && !cflag)
152 			talking++;
153 	}
154 	signal(SIGQUIT, qflag);
155 	if (name && name[0] == '-') {
156 		talking++;
157 		if ((f = open(".profile", 0)) >= 0)
158 			next(remap(f));
159 		if ((f = open("/etc/profile", 0)) >= 0)
160 			next(remap(f));
161 	}
162 	if (talking)
163 		signal(SIGTERM, sig);
164 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
165 		signal(SIGINT, onintr);
166 	dolv = argv;
167 	dolc = argc;
168 	dolv[0] = name;
169 	if (dolc > 1)
170 		for (ap = ++argv; --argc > 0;)
171 			if (assign(*ap = *argv++, !COPYV))
172 				dolc--;	/* keyword */
173 			else
174 				ap++;
175 	setval(lookup("#"), putn((--dolc < 0) ? (dolc = 0) : dolc));
176 
177 	for (;;) {
178 		if (talking && e.iop <= iostack)
179 			prs(prompt->value);
180 		onecommand();
181 	}
182 }
183 
184 void
setdash()185 setdash()
186 {
187 	register char *cp, c;
188 	char m['z'-'a'+1];
189 
190 	cp = m;
191 	for (c='a'; c<='z'; c++)
192 		if (flag[c])
193 			*cp++ = c;
194 	*cp = 0;
195 	setval(lookup("-"), m);
196 }
197 
198 int
newfile(s)199 newfile(s)
200 register char *s;
201 {
202 	register f;
203 
204 	if (strcmp(s, "-") != 0) {
205 		f = open(s, 0);
206 		if (f < 0) {
207 			prs(s);
208 			err(": cannot open");
209 			return(1);
210 		}
211 	} else
212 		f = 0;
213 	next(remap(f));
214 	return(0);
215 }
216 
217 void
onecommand()218 onecommand()
219 {
220 	register i;
221 	jmp_buf m1;
222 
223 	while (e.oenv)
224 		quitenv();
225 	areanum = 1;
226 	freehere(areanum);
227 	freearea(areanum);
228 	garbage();
229 	wdlist = 0;
230 	iolist = 0;
231 	e.errpt = 0;
232 	e.linep = line;
233 	yynerrs = 0;
234 	multiline = 0;
235 	inparse = 1;
236 	intr = 0;
237 	execflg = 0;
238 	setjmp(failpt = m1);	/* Bruce Evans' fix */
239 	if (setjmp(failpt = m1) || yyparse() || intr) {
240 		while (e.oenv)
241 			quitenv();
242 		scraphere();
243 		if (!talking && intr)
244 			leave();
245 		inparse = 0;
246 		intr = 0;
247 		return;
248 	}
249 	inparse = 0;
250 	brklist = 0;
251 	intr = 0;
252 	execflg = 0;
253 	if (!flag['n'])
254 		execute(outtree, NOPIPE, NOPIPE, 0);
255 	if (!talking && intr) {
256 		execflg = 0;
257 		leave();
258 	}
259 	if ((i = trapset) != 0) {
260 		trapset = 0;
261 		runtrap(i);
262 	}
263 }
264 
265 void
fail()266 fail()
267 {
268 	longjmp(failpt, 1);
269 	/* NOTREACHED */
270 }
271 
272 void
leave()273 leave()
274 {
275 	if (execflg)
276 		fail();
277 	scraphere();
278 	freehere(1);
279 	runtrap(0);
280 	exit(exstat);
281 	/* NOTREACHED */
282 }
283 
284 void
warn(s)285 warn(s)
286 register char *s;
287 {
288 	if(*s) {
289 		prs(s);
290 		exstat = -1;
291 	}
292 	prs("\n");
293 	if (flag['e'])
294 		leave();
295 }
296 
297 void
err(s)298 err(s)
299 char *s;
300 {
301 	warn(s);
302 	if (flag['n'])
303 		return;
304 	if (!talking)
305 		leave();
306 	if (e.errpt)
307 		longjmp(e.errpt, 1);
308 	closeall();
309 	e.iop = e.iobase = iostack;
310 }
311 
312 int
newenv(f)313 newenv(f)
314 int f;
315 {
316 	register struct env *ep;
317 
318 	if (f) {
319 		quitenv();
320 		return(1);
321 	}
322 	ep = (struct env *) space(sizeof(*ep));
323 	if (ep == NULL) {
324 		while (e.oenv)
325 			quitenv();
326 		fail();
327 	}
328 	*ep = e;
329 	e.oenv = ep;
330 	e.errpt = errpt;
331 	return(0);
332 }
333 
334 void
quitenv()335 quitenv()
336 {
337 	register struct env *ep;
338 	register fd;
339 
340 	if ((ep = e.oenv) != NULL) {
341 		fd = e.iofd;
342 		e = *ep;
343 		/* should close `'d files */
344 		DELETE(ep);
345 		while (--fd >= e.iofd)
346 			close(fd);
347 	}
348 }
349 
350 /*
351  * Is any character from s1 in s2?
352  */
353 int
anys(s1,s2)354 anys(s1, s2)
355 register char *s1, *s2;
356 {
357 	while (*s1)
358 		if (any(*s1++, s2))
359 			return(1);
360 	return(0);
361 }
362 
363 /*
364  * Is character c in s?
365  */
366 int
any(c,s)367 any(c, s)
368 register int c;
369 register char *s;
370 {
371 	while (*s)
372 		if (*s++ == c)
373 			return(1);
374 	return(0);
375 }
376 
377 char *
putn(n)378 putn(n)
379 register int n;
380 {
381 	return(itoa(n, -1));
382 }
383 
384 char *
itoa(u,n)385 itoa(u, n)
386 register unsigned u;
387 int n;
388 {
389 	register char *cp;
390 	static char s[20];
391 	int m;
392 
393 	m = 0;
394 	if (n < 0 && (int) u < 0) {
395 		m++;
396 		u = -u;
397 	}
398 	cp = s+sizeof(s);
399 	*--cp = 0;
400 	do {
401 		*--cp = u%10 + '0';
402 		u /= 10;
403 	} while (--n > 0 || u);
404 	if (m)
405 		*--cp = '-';
406 	return(cp);
407 }
408 
409 void
next(f)410 next(f)
411 int f;
412 {
413 	PUSHIO(afile, f, filechar);
414 }
415 
416 void
onintr(s)417 onintr(s)
418 int s;				/* ANSI C requires a parameter */
419 {
420 	signal(SIGINT, onintr);
421 	intr = 1;
422 	if (talking) {
423 		if (inparse) {
424 			prs("\n");
425 			fail();
426 		}
427 	}
428 	else if (heedint) {
429 		execflg = 0;
430 		leave();
431 	}
432 }
433 
434 int
letter(c)435 letter(c)
436 register c;
437 {
438 	return((c >= 'a' && c <= 'z') || (c >= 'A' && c <= 'Z') || c == '_');
439 }
440 
441 int
digit(c)442 digit(c)
443 register c;
444 {
445 	return(c >= '0' && c <= '9');
446 }
447 
448 int
letnum(c)449 letnum(c)
450 register c;
451 {
452 	return(letter(c) || digit(c));
453 }
454 
455 char *
space(n)456 space(n)
457 int n;
458 {
459 	register char *cp;
460 
461 	if ((cp = getcell(n)) == 0)
462 		err("out of string space");
463 	return(cp);
464 }
465 
466 char *
strsave(s,a)467 strsave(s, a)
468 register char *s;
469 int a;
470 {
471 	register char *cp, *xp;
472 
473 	if ((cp = space(strlen(s)+1)) != NULL) {
474 		setarea((char *)cp, a);
475 		for (xp = cp; (*xp++ = *s++) != '\0';)
476 			;
477 		return(cp);
478 	}
479 	return("");
480 }
481 
482 void
xfree(s)483 xfree(s)
484 register char *s;
485 {
486 	DELETE(s);
487 }
488 
489 /*
490  * trap handling
491  */
492 void
sig(i)493 sig(i)
494 register int i;
495 {
496 	trapset = i;
497 	signal(i, sig);
498 }
499 
runtrap(i)500 void runtrap(i)
501 int i;
502 {
503 	char *trapstr;
504 
505 	if ((trapstr = trap[i]) == NULL)
506 		return;
507 	if (i == 0)
508 		trap[i] = 0;
509 	RUN(aword, trapstr, nlchar);
510 }
511 
512 /* -------- var.c -------- */
513 /* #include "sh.h" */
514 
515 /*
516  * Find the given name in the dictionary
517  * and return its value.  If the name was
518  * not previously there, enter it now and
519  * return a null value.
520  */
521 struct var *
lookup(n)522 lookup(n)
523 register char *n;
524 {
525 	register struct var *vp;
526 	register char *cp;
527 	register int c;
528 	static struct var dummy;
529 
530 	if (digit(*n)) {
531 		dummy.name = n;
532 		for (c = 0; digit(*n) && c < 1000; n++)
533 			c = c*10 + *n-'0';
534 		dummy.status = RONLY;
535 		dummy.value = c <= dolc? dolv[c]: null;
536 		return(&dummy);
537 	}
538 	for (vp = vlist; vp; vp = vp->next)
539 		if (eqname(vp->name, n))
540 			return(vp);
541 	cp = findeq(n);
542 	vp = (struct var *)space(sizeof(*vp));
543 	if (vp == 0 || (vp->name = space((int)(cp-n)+2)) == 0) {
544 		dummy.name = dummy.value = "";
545 		return(&dummy);
546 	}
547 	for (cp = vp->name; (*cp = *n++) && *cp != '='; cp++)
548 		;
549 	if (*cp == 0)
550 		*cp = '=';
551 	*++cp = 0;
552 	setarea((char *)vp, 0);
553 	setarea((char *)vp->name, 0);
554 	vp->value = null;
555 	vp->next = vlist;
556 	vp->status = GETCELL;
557 	vlist = vp;
558 	return(vp);
559 }
560 
561 /*
562  * give variable at `vp' the value `val'.
563  */
564 void
setval(vp,val)565 setval(vp, val)
566 struct var *vp;
567 char *val;
568 {
569 	nameval(vp, val, (char *)NULL);
570 }
571 
572 /*
573  * if name is not NULL, it must be
574  * a prefix of the space `val',
575  * and end with `='.
576  * this is all so that exporting
577  * values is reasonably painless.
578  */
579 void
nameval(vp,val,name)580 nameval(vp, val, name)
581 register struct var *vp;
582 char *val, *name;
583 {
584 	register char *cp, *xp;
585 	char *nv;
586 	int fl;
587 
588 	if (vp->status & RONLY) {
589 		for (xp = vp->name; *xp && *xp != '=';)
590 			putc(*xp++);
591 		err(" is read-only");
592 		return;
593 	}
594 	fl = 0;
595 	if (name == NULL) {
596 		xp = space(strlen(vp->name)+strlen(val)+2);
597 		if (xp == 0)
598 			return;
599 		/* make string:  name=value */
600 		setarea((char *)xp, 0);
601 		name = xp;
602 		for (cp = vp->name; (*xp = *cp++) && *xp!='='; xp++)
603 			;
604 		if (*xp++ == 0)
605 			xp[-1] = '=';
606 		nv = xp;
607 		for (cp = val; (*xp++ = *cp++) != '\0';)
608 			;
609 		val = nv;
610 		fl = GETCELL;
611 	}
612 	if (vp->status & GETCELL)
613 		xfree(vp->name);	/* form new string `name=value' */
614 	vp->name = name;
615 	vp->value = val;
616 	vp->status |= fl;
617 }
618 
619 void
export(vp)620 export(vp)
621 struct var *vp;
622 {
623 	vp->status |= EXPORT;
624 }
625 
626 void
ronly(vp)627 ronly(vp)
628 struct var *vp;
629 {
630 	if (letter(vp->name[0]))	/* not an internal symbol ($# etc) */
631 		vp->status |= RONLY;
632 }
633 
634 int
isassign(s)635 isassign(s)
636 register char *s;
637 {
638 	if (!letter((int)*s))
639 		return(0);
640 	for (; *s != '='; s++)
641 		if (*s == 0 || !letnum(*s))
642 			return(0);
643 	return(1);
644 }
645 
646 int
assign(s,cf)647 assign(s, cf)
648 register char *s;
649 int cf;
650 {
651 	register char *cp;
652 	struct var *vp;
653 
654 	if (!letter(*s))
655 		return(0);
656 	for (cp = s; *cp != '='; cp++)
657 		if (*cp == 0 || !letnum(*cp))
658 			return(0);
659 	vp = lookup(s);
660 	nameval(vp, ++cp, cf == COPYV? (char *)NULL: s);
661 	if (cf != COPYV)
662 		vp->status &= ~GETCELL;
663 	return(1);
664 }
665 
666 int
checkname(cp)667 checkname(cp)
668 register char *cp;
669 {
670 	if (!letter(*cp++))
671 		return(0);
672 	while (*cp)
673 		if (!letnum(*cp++))
674 			return(0);
675 	return(1);
676 }
677 
678 void
putvlist(f,out)679 putvlist(f, out)
680 register int f, out;
681 {
682 	register struct var *vp;
683 
684 	for (vp = vlist; vp; vp = vp->next)
685 		if (vp->status & f && letter(*vp->name)) {
686 			if (vp->status & EXPORT)
687 				write(out, "export ", 7);
688 			if (vp->status & RONLY)
689 				write(out, "readonly ", 9);
690 			write(out, vp->name, (int)(findeq(vp->name) - vp->name));
691 			write(out, "\n", 1);
692 		}
693 }
694 
695 int
eqname(n1,n2)696 eqname(n1, n2)
697 register char *n1, *n2;
698 {
699 	for (; *n1 != '=' && *n1 != 0; n1++)
700 		if (*n2++ != *n1)
701 			return(0);
702 	return(*n2 == 0 || *n2 == '=');
703 }
704 
705 static char *
findeq(cp)706 findeq(cp)
707 register char *cp;
708 {
709 	while (*cp != '\0' && *cp != '=')
710 		cp++;
711 	return(cp);
712 }
713 
714 /* -------- gmatch.c -------- */
715 /*
716  * int gmatch(string, pattern)
717  * char *string, *pattern;
718  *
719  * Match a pattern as in sh(1).
720  */
721 
722 #define	CMASK	0377
723 #define	QUOTE	0200
724 #define	QMASK	(CMASK&~QUOTE)
725 #define	NOT	'!'	/* might use ^ */
726 
727 int
gmatch(s,p)728 gmatch(s, p)
729 register char *s, *p;
730 {
731 	register int sc, pc;
732 
733 	if (s == NULL || p == NULL)
734 		return(0);
735 	while ((pc = *p++ & CMASK) != '\0') {
736 		sc = *s++ & QMASK;
737 		switch (pc) {
738 		case '[':
739 			if ((p = cclass(p, sc)) == NULL)
740 				return(0);
741 			break;
742 
743 		case '?':
744 			if (sc == 0)
745 				return(0);
746 			break;
747 
748 		case '*':
749 			s--;
750 			do {
751 				if (*p == '\0' || gmatch(s, p))
752 					return(1);
753 			} while (*s++ != '\0');
754 			return(0);
755 
756 		default:
757 			if (sc != (pc&~QUOTE))
758 				return(0);
759 		}
760 	}
761 	return(*s == 0);
762 }
763 
764 static char *
cclass(p,sub)765 cclass(p, sub)
766 register char *p;
767 register int sub;
768 {
769 	register int c, d, not, found;
770 
771 	if ((not = *p == NOT) != 0)
772 		p++;
773 	found = not;
774 	do {
775 		if (*p == '\0')
776 			return((char *)NULL);
777 		c = *p & CMASK;
778 		if (p[1] == '-' && p[2] != ']') {
779 			d = p[2] & CMASK;
780 			p++;
781 		} else
782 			d = c;
783 		if (c == sub || (c <= sub && sub <= d))
784 			found = !not;
785 	} while (*++p != ']');
786 	return(found? p+1: (char *)NULL);
787 }
788 
789 /* -------- area.c -------- */
790 #define	REGSIZE		sizeof(struct region)
791 #define GROWBY		256
792 #undef	SHRINKBY	64
793 #define FREE 32767
794 #define BUSY 0
795 #define	ALIGN (sizeof(int)-1)
796 
797 /* #include "area.h" */
798 
799 struct region {
800 	struct	region *next;
801 	int	area;
802 };
803 
804 /*
805  * All memory between (char *)areabot and (char *)(areatop+1) is
806  * exclusively administered by the area management routines.
807  * It is assumed that sbrk() and brk() manipulate the high end.
808  */
809 static	struct region *areabot;		/* bottom of area */
810 static	struct region *areatop;		/* top of area */
811 static	struct region *areanxt;		/* starting point of scan */
812 
813 void
initarea()814 initarea()
815 {
816 	while ((int)sbrk(0) & ALIGN)
817 		sbrk(1);
818 	areabot = (struct region *)sbrk(REGSIZE);
819 	areabot->next = areabot;
820 	areabot->area = BUSY;
821 	areatop = areabot;
822 	areanxt = areabot;
823 }
824 
825 char *
getcell(nbytes)826 getcell(nbytes)
827 unsigned nbytes;
828 {
829 	register int nregio;
830 	register struct region *p, *q;
831 	register i;
832 
833 	if (nbytes == 0)
834 		abort();	/* silly and defeats the algorithm */
835 	/*
836 	 * round upwards and add administration area
837 	 */
838 	nregio = (nbytes+(REGSIZE-1))/REGSIZE + 1;
839 	for (p = areanxt;;) {
840 		if (p->area > areanum) {
841 			/*
842 			 * merge free cells
843 			 */
844 			while ((q = p->next)->area > areanum && q != areanxt)
845 				p->next = q->next;
846 			/*
847 			 * exit loop if cell big enough
848 			 */
849 			if (q >= p + nregio)
850 				goto found;
851 		}
852 		p = p->next;
853 		if (p == areanxt)
854 			break;
855 	}
856 	i = nregio >= GROWBY ? nregio : GROWBY;
857 	p = (struct region *)sbrk(i * REGSIZE);
858 	if (p == (struct region *)-1)
859 		return((char *)NULL);
860 	p--;
861 	if (p != areatop)
862 		abort();	/* allocated areas are contiguous */
863 	q = p + i;
864 	p->next = q;
865 	p->area = FREE;
866 	q->next = areabot;
867 	q->area = BUSY;
868 	areatop = q;
869 found:
870 	/*
871 	 * we found a FREE area big enough, pointed to by 'p', and up to 'q'
872 	 */
873 	areanxt = p + nregio;
874 	if (areanxt < q) {
875 		/*
876 		 * split into requested area and rest
877 		 */
878 		if (areanxt+1 > q)
879 			abort();	/* insufficient space left for admin */
880 		areanxt->next = q;
881 		areanxt->area = FREE;
882 		p->next = areanxt;
883 	}
884 	p->area = areanum;
885 	return((char *)(p+1));
886 }
887 
888 void
freecell(cp)889 freecell(cp)
890 char *cp;
891 {
892 	register struct region *p;
893 
894 	if ((p = (struct region *)cp) != NULL) {
895 		p--;
896 		if (p < areanxt)
897 			areanxt = p;
898 		p->area = FREE;
899 	}
900 }
901 
902 void
freearea(a)903 freearea(a)
904 register int a;
905 {
906 	register struct region *p, *top;
907 
908 	top = areatop;
909 	for (p = areabot; p != top; p = p->next)
910 		if (p->area >= a)
911 			p->area = FREE;
912 }
913 
914 void
setarea(cp,a)915 setarea(cp,a)
916 char *cp;
917 int a;
918 {
919 	register struct region *p;
920 
921 	if ((p = (struct region *)cp) != NULL)
922 		(p-1)->area = a;
923 }
924 
925 int
getarea(cp)926 getarea(cp)
927 char *cp;
928 {
929 	return ((struct region*)cp-1)->area;
930 }
931 
932 void
garbage()933 garbage()
934 {
935 	register struct region *p, *q, *top;
936 
937 	top = areatop;
938 	for (p = areabot; p != top; p = p->next) {
939 		if (p->area > areanum) {
940 			while ((q = p->next)->area > areanum)
941 				p->next = q->next;
942 			areanxt = p;
943 		}
944 	}
945 #ifdef SHRINKBY
946 	if (areatop >= q + SHRINKBY && q->area > areanum) {
947 		brk((char *)(q+1));
948 		q->next = areabot;
949 		q->area = BUSY;
950 		areatop = q;
951 	}
952 #endif
953 }
954