]> git.lizzy.rs Git - plan9front.git/blob - sys/src/cmd/rc/compiling.on.unix
rc: change plan9 envname limit to 128, cleanup
[plan9front.git] / sys / src / cmd / rc / compiling.on.unix
1 From geoff@collyer.net Fri Dec 19 01:21:40 EST 2003
2 Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:21:39 EST 2003
3 Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:21:35 EST 2003
4 Message-ID: <c790d8b1e06b3918ad2c7848a3ae0ec7@collyer.net>
5 subject: rc on unix, part 1
6 From: Geoff Collyer <geoff@collyer.net>
7 Date: Thu, 18 Dec 2003 22:21:33 -0800
8 To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
9 MIME-Version: 1.0
10 Content-Type: text/plain; charset="US-ASCII"
11 Content-Transfer-Encoding: 7bit
12
13 I got /sys/src/cmd/rc to compile under APE (in preparation for moving it
14 to Unixes) with the following changed files.  I cadged some include files
15 from rsc but had to edit lib9.h slightly.  I'll send the include files
16 separately.  I can't tell if it works yet, but it does complain about
17 /usr/lib/rcmain being absent when I start it.  Oh, and I haven't yet
18 simulated the effect of the OCEXEC bit.
19
20
21 # To unbundle, run this file
22 echo mkfile
23 sed 's/^X//' >mkfile <<'!'
24 X</$objtype/mkfile
25
26 TARG=rc
27 COMMONOFILES=\
28 X       code.$O\
29 X       exec.$O\
30 X       getflags.$O\
31 X       glob.$O\
32 X       here.$O\
33 X       io.$O\
34 X       lex.$O\
35 X       pcmd.$O\
36 X       pfnc.$O\
37 X       simple.$O\
38 X       subr.$O\
39 X       trap.$O\
40 X       tree.$O\
41 X       var.$O\
42 X       havefork.$O\
43
44 PLAN9OFILES=plan9.$O\
45
46 UNIXOFILES=unix.$O\
47
48 OFILES=$COMMONOFILES $UNIXOFILES y.tab.$O
49
50 HFILES=rc.h\
51 X       x.tab.h\
52 X       io.h\
53 X       exec.h\
54 X       fns.h\
55
56 YFILES=syn.y
57
58 BIN=/$objtype/bin
59
60 UPDATE=\
61 X       mkfile\
62 X       $HFILES\
63 X       ${COMMONOFILES:%.$O=%.c}\
64 X       ${UNIXOFILES:%.$O=%.c}\
65 X       ${PLAN9OFILES:%.$O=%.c}\
66 X       $YFILES\
67 X       ${TARG:%=/386/bin/%}\
68
69 CC=pcc -c -B -I../include
70 LD=pcc
71
72 X</sys/src/cmd/mkone
73
74 x.tab.h: y.tab.h
75 X       cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
76
77 clean:V:
78 X       rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
79
80 regress: $O.out
81 X       cd test
82 X       mk
83
84 unregress:V:
85 X       for(test in test/*.test) rc $test >$test.out
86
87 listing:
88 X       pr mkfile $HFILES $FILES $FILES9 $FILESUNIX $YFILES|lp -du
89 !
90 echo simple.c
91 sed 's/^X//' >simple.c <<'!'
92 X/*
93 X * Maybe `simple' is a misnomer.
94 X */
95 X#include "rc.h"
96 X#include "getflags.h"
97 X#include "exec.h"
98 X#include "io.h"
99 X#include "fns.h"
100 X/*
101 X * Search through the following code to see if we're just going to exit.
102 X */
103 exitnext(void){
104 X       union code *c=&runq->code[runq->pc];
105 X       while(c->f==Xpopredir) c++;
106 X       return c->f==Xexit;
107 X}
108
109 void
110 XXsimple(void)
111 X{
112 X       word *a;
113 X       thread *p = runq;
114 X       var *v;
115 X       struct builtin *bp;
116 X       int pid;
117 X       globlist();
118 X       a = runq->argv->words;
119 X       if(a==0){
120 X               Xerror1("empty argument list");
121 X               return;
122 X       }
123 X       if(flag['x'])
124 X               pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
125 X       v = gvlook(a->word);
126 X       if(v->fn)
127 X               execfunc(v);
128 X       else{
129 X               if(strcmp(a->word, "builtin")==0){
130 X                       if(count(a)==1){
131 X                               pfmt(err, "builtin: empty argument list\n");
132 X                               setstatus("empty arg list");
133 X                               poplist();
134 X                               return;
135 X                       }
136 X                       a = a->next;
137 X                       popword();
138 X               }
139 X               for(bp = Builtin;bp->name;bp++)
140 X                       if(strcmp(a->word, bp->name)==0){
141 X                               (*bp->fnc)();
142 X                               return;
143 X                       }
144 X               if(exitnext()){
145 X                       /* fork and wait is redundant */
146 X                       pushword("exec");
147 X                       execexec();
148 X                       Xexit();
149 X               }
150 X               else{
151 X                       flush(err);
152 X                       Updenv();       /* necessary so changes don't go out again */
153 X                       if((pid = execforkexec()) < 0){
154 X                               Xerror("try again");
155 X                               return;
156 X                       }
157
158 X                       /* interrupts don't get us out */
159 X                       poplist();
160 X                       while(Waitfor(pid, 1) < 0)
161 X                               ;
162 X               }
163 X       }
164 X}
165 struct word nullpath = { "", 0};
166
167 void
168 doredir(redir *rp)
169 X{
170 X       if(rp){
171 X               doredir(rp->next);
172 X               switch(rp->type){
173 X               case ROPEN:
174 X                       if(rp->from!=rp->to){
175 X                               Dup(rp->from, rp->to);
176 X                               close(rp->from);
177 X                       }
178 X                       break;
179 X               case RDUP:
180 X                       Dup(rp->from, rp->to);
181 X                       break;
182 X               case RCLOSE:
183 X                       close(rp->from);
184 X                       break;
185 X               }
186 X       }
187 X}
188
189 word*
190 searchpath(char *w)
191 X{
192 X       word *path;
193 X       if(strncmp(w, "/", 1)==0
194 X       || strncmp(w, "#", 1)==0
195 X       || strncmp(w, "./", 2)==0
196 X       || strncmp(w, "../", 3)==0
197 X       || (path = vlook("path")->val)==0)
198 X               path=&nullpath;
199 X       return path;
200 X}
201
202 void
203 execexec(void)
204 X{
205 X       popword();      /* "exec" */
206 X       if(runq->argv->words==0){
207 X               Xerror1("empty argument list");
208 X               return;
209 X       }
210 X       doredir(runq->redir);
211 X       Execute(runq->argv->words, searchpath(runq->argv->words->word));
212 X       poplist();
213 X}
214
215 void
216 execfunc(var *func)
217 X{
218 X       word *starval;
219 X       popword();
220 X       starval = runq->argv->words;
221 X       runq->argv->words = 0;
222 X       poplist();
223 X       start(func->fn, func->pc, (struct var *)0);
224 X       runq->local = newvar(strdup("*"), runq->local);
225 X       runq->local->val = starval;
226 X       runq->local->changed = 1;
227 X}
228
229 int
230 dochdir(char *word)
231 X{
232 X       /* report to /dev/wdir if it exists and we're interactive */
233 X       static int wdirfd = -2;
234 X       if(chdir(word)<0) return -1;
235 X       if(flag['i']!=0){
236 X               if(wdirfd==-2)  /* try only once */
237 X                       /* TODO: arrange close-on-exec on Unix */
238 X                       wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
239 X               if(wdirfd>=0)
240 X                       write(wdirfd, word, strlen(word));
241 X       }
242 X       return 1;
243 X}
244
245 void
246 execcd(void)
247 X{
248 X       word *a = runq->argv->words;
249 X       word *cdpath;
250 X       char dir[512];
251 X       setstatus("can't cd");
252 X       cdpath = vlook("cdpath")->val;
253 X       switch(count(a)){
254 X       default:
255 X               pfmt(err, "Usage: cd [directory]\n");
256 X               break;
257 X       case 2:
258 X               if(a->next->word[0]=='/' || cdpath==0)
259 X                       cdpath=&nullpath;
260 X               for(;cdpath;cdpath = cdpath->next){
261 X                       strcpy(dir, cdpath->word);
262 X                       if(dir[0])
263 X                               strcat(dir, "/");
264 X                       strcat(dir, a->next->word);
265 X                       if(dochdir(dir)>=0){
266 X                               if(strlen(cdpath->word)
267 X                               && strcmp(cdpath->word, ".")!=0)
268 X                                       pfmt(err, "%s\n", dir);
269 X                               setstatus("");
270 X                               break;
271 X                       }
272 X               }
273 X               if(cdpath==0)
274 X                       pfmt(err, "Can't cd %s: %r\n", a->next->word);
275 X               break;
276 X       case 1:
277 X               a = vlook("home")->val;
278 X               if(count(a)>=1){
279 X                       if(dochdir(a->word)>=0)
280 X                               setstatus("");
281 X                       else
282 X                               pfmt(err, "Can't cd %s: %r\n", a->word);
283 X               }
284 X               else
285 X                       pfmt(err, "Can't cd -- $home empty\n");
286 X               break;
287 X       }
288 X       poplist();
289 X}
290
291 void
292 execexit(void)
293 X{
294 X       switch(count(runq->argv->words)){
295 X       default:
296 X               pfmt(err, "Usage: exit [status]\nExiting anyway\n");
297 X       case 2:
298 X               setstatus(runq->argv->words->next->word);
299 X       case 1: Xexit();
300 X       }
301 X}
302
303 void
304 execshift(void)
305 X{
306 X       int n;
307 X       word *a;
308 X       var *star;
309 X       switch(count(runq->argv->words)){
310 X       default:
311 X               pfmt(err, "Usage: shift [n]\n");
312 X               setstatus("shift usage");
313 X               poplist();
314 X               return;
315 X       case 2:
316 X               n = atoi(runq->argv->words->next->word);
317 X               break;
318 X       case 1:
319 X               n = 1;
320 X               break;
321 X       }
322 X       star = vlook("*");
323 X       for(;n && star->val;--n){
324 X               a = star->val->next;
325 X               efree(star->val->word);
326 X               efree((char *)star->val);
327 X               star->val = a;
328 X               star->changed = 1;
329 X       }
330 X       setstatus("");
331 X       poplist();
332 X}
333
334 int
335 octal(char *s)
336 X{
337 X       int n = 0;
338 X       while(*s==' ' || *s=='\t' || *s=='\n') s++;
339 X       while('0'<=*s && *s<='7') n = n*8+*s++-'0';
340 X       return n;
341 X}
342
343 int
344 mapfd(int fd)
345 X{
346 X       redir *rp;
347 X       for(rp = runq->redir;rp;rp = rp->next){
348 X               switch(rp->type){
349 X               case RCLOSE:
350 X                       if(rp->from==fd)
351 X                               fd=-1;
352 X                       break;
353 X               case RDUP:
354 X               case ROPEN:
355 X                       if(rp->to==fd)
356 X                               fd = rp->from;
357 X                       break;
358 X               }
359 X       }
360 X       return fd;
361 X}
362 union code rdcmds[4];
363
364 void
365 execcmds(io *f)
366 X{
367 X       static int first = 1;
368 X       if(first){
369 X               rdcmds[0].i = 1;
370 X               rdcmds[1].f = Xrdcmds;
371 X               rdcmds[2].f = Xreturn;
372 X               first = 0;
373 X       }
374 X       start(rdcmds, 1, runq->local);
375 X       runq->cmdfd = f;
376 X       runq->iflast = 0;
377 X}
378
379 void
380 execeval(void)
381 X{
382 X       char *cmdline, *s, *t;
383 X       int len = 0;
384 X       word *ap;
385 X       if(count(runq->argv->words)<=1){
386 X               Xerror1("Usage: eval cmd ...");
387 X               return;
388 X       }
389 X       eflagok = 1;
390 X       for(ap = runq->argv->words->next;ap;ap = ap->next)
391 X               len+=1+strlen(ap->word);
392 X       cmdline = emalloc(len);
393 X       s = cmdline;
394 X       for(ap = runq->argv->words->next;ap;ap = ap->next){
395 X               for(t = ap->word;*t;) *s++=*t++;
396 X               *s++=' ';
397 X       }
398 X       s[-1]='\n';
399 X       poplist();
400 X       execcmds(opencore(cmdline, len));
401 X       efree(cmdline);
402 X}
403 union code dotcmds[14];
404
405 void
406 execdot(void)
407 X{
408 X       int iflag = 0;
409 X       int fd;
410 X       list *av;
411 X       thread *p = runq;
412 X       char *zero;
413 X       static int first = 1;
414 X       char file[512];
415 X       word *path;
416 X       if(first){
417 X               dotcmds[0].i = 1;
418 X               dotcmds[1].f = Xmark;
419 X               dotcmds[2].f = Xword;
420 X               dotcmds[3].s="0";
421 X               dotcmds[4].f = Xlocal;
422 X               dotcmds[5].f = Xmark;
423 X               dotcmds[6].f = Xword;
424 X               dotcmds[7].s="*";
425 X               dotcmds[8].f = Xlocal;
426 X               dotcmds[9].f = Xrdcmds;
427 X               dotcmds[10].f = Xunlocal;
428 X               dotcmds[11].f = Xunlocal;
429 X               dotcmds[12].f = Xreturn;
430 X               first = 0;
431 X       }
432 X       else
433 X               eflagok = 1;
434 X       popword();
435 X       if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
436 X               iflag = 1;
437 X               popword();
438 X       }
439 X       /* get input file */
440 X       if(p->argv->words==0){
441 X               Xerror1("Usage: . [-i] file [arg ...]");
442 X               return;
443 X       }
444 X       zero = strdup(p->argv->words->word);
445 X       popword();
446 X       fd=-1;
447 X       for(path = searchpath(zero);path;path = path->next){
448 X               strcpy(file, path->word);
449 X               if(file[0])
450 X                       strcat(file, "/");
451 X               strcat(file, zero);
452 X               if((fd = open(file, 0))>=0) break;
453 X               if(strcmp(file, "/dev/stdin")==0){      /* for sun & ucb */
454 X                       fd = Dup1(0);
455 X                       if(fd>=0)
456 X                               break;
457 X               }
458 X       }
459 X       if(fd<0){
460 X               pfmt(err, "%s: ", zero);
461 X               setstatus("can't open");
462 X               Xerror(".: can't open");
463 X               return;
464 X       }
465 X       /* set up for a new command loop */
466 X       start(dotcmds, 1, (struct var *)0);
467 X       pushredir(RCLOSE, fd, 0);
468 X       runq->cmdfile = zero;
469 X       runq->cmdfd = openfd(fd);
470 X       runq->iflag = iflag;
471 X       runq->iflast = 0;
472 X       /* push $* value */
473 X       pushlist();
474 X       runq->argv->words = p->argv->words;
475 X       /* free caller's copy of $* */
476 X       av = p->argv;
477 X       p->argv = av->next;
478 X       efree((char *)av);
479 X       /* push $0 value */
480 X       pushlist();
481 X       pushword(zero);
482 X       ndot++;
483 X}
484
485 void
486 execflag(void)
487 X{
488 X       char *letter, *val;
489 X       switch(count(runq->argv->words)){
490 X       case 2:
491 X               setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
492 X               break;
493 X       case 3:
494 X               letter = runq->argv->words->next->word;
495 X               val = runq->argv->words->next->next->word;
496 X               if(strlen(letter)==1){
497 X                       if(strcmp(val, "+")==0){
498 X                               flag[letter[0]] = flagset;
499 X                               break;
500 X                       }
501 X                       if(strcmp(val, "-")==0){
502 X                               flag[letter[0]] = 0;
503 X                               break;
504 X                       }
505 X               }
506 X       default:
507 X               Xerror1("Usage: flag [letter] [+-]");
508 X               return;
509 X       }
510 X       poplist();
511 X}
512
513 void
514 execwhatis(void){       /* mildly wrong -- should fork before writing */
515 X       word *a, *b, *path;
516 X       var *v;
517 X       struct builtin *bp;
518 X       char file[512];
519 X       struct io out[1];
520 X       int found, sep;
521 X       a = runq->argv->words->next;
522 X       if(a==0){
523 X               Xerror1("Usage: whatis name ...");
524 X               return;
525 X       }
526 X       setstatus("");
527 X       out->fd = mapfd(1);
528 X       out->bufp = out->buf;
529 X       out->ebuf = &out->buf[NBUF];
530 X       out->strp = 0;
531 X       for(;a;a = a->next){
532 X               v = vlook(a->word);
533 X               if(v->val){
534 X                       pfmt(out, "%s=", a->word);
535 X                       if(v->val->next==0)
536 X                               pfmt(out, "%q\n", v->val->word);
537 X                       else{
538 X                               sep='(';
539 X                               for(b = v->val;b && b->word;b = b->next){
540 X                                       pfmt(out, "%c%q", sep, b->word);
541 X                                       sep=' ';
542 X                               }
543 X                               pfmt(out, ")\n");
544 X                       }
545 X                       found = 1;
546 X               }
547 X               else
548 X                       found = 0;
549 X               v = gvlook(a->word);
550 X               if(v->fn)
551 X                       pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
552 X               else{
553 X                       for(bp = Builtin;bp->name;bp++)
554 X                               if(strcmp(a->word, bp->name)==0){
555 X                                       pfmt(out, "builtin %s\n", a->word);
556 X                                       break;
557 X                               }
558 X                       if(!bp->name){
559 X                               for(path = searchpath(a->word);path;path = path->next){
560 X                                       strcpy(file, path->word);
561 X                                       if(file[0])
562 X                                               strcat(file, "/");
563 X                                       strcat(file, a->word);
564 X                                       if(Executable(file)){
565 X                                               pfmt(out, "%s\n", file);
566 X                                               break;
567 X                                       }
568 X                               }
569 X                               if(!path && !found){
570 X                                       pfmt(err, "%s: not found\n", a->word);
571 X                                       setstatus("not found");
572 X                               }
573 X                       }
574 X               }
575 X       }
576 X       poplist();
577 X       flush(err);
578 X}
579
580 void
581 execwait(void)
582 X{
583 X       switch(count(runq->argv->words)){
584 X       default:
585 X               Xerror1("Usage: wait [pid]");
586 X               return;
587 X       case 2:
588 X               Waitfor(atoi(runq->argv->words->next->word), 0);
589 X               break;
590 X       case 1:
591 X               Waitfor(-1, 0);
592 X               break;
593 X       }
594 X       poplist();
595 X}
596 !
597 echo havefork.c
598 sed 's/^X//' >havefork.c <<'!'
599 X#include "rc.h"
600 X#include "getflags.h"
601 X#include "exec.h"
602 X#include "io.h"
603 X#include "fns.h"
604
605 int havefork = 1;
606
607 void
608 XXasync(void)
609 X{
610 X       int null = open("/dev/null", 0);
611 X       int pid;
612 X       char npid[10];
613 X       if(null<0){
614 X               Xerror("Can't open /dev/null\n");
615 X               return;
616 X       }
617 X#ifdef Unix
618 X       pid = fork();
619 X#else
620 X       pid = rfork(RFFDG|RFPROC|RFNOTEG);
621 X#endif
622 X       switch(pid){
623 X       case -1:
624 X               close(null);
625 X               Xerror("try again");
626 X               break;
627 X       case 0:
628 X               pushredir(ROPEN, null, 0);
629 X               start(runq->code, runq->pc+1, runq->local);
630 X               runq->ret = 0;
631 X               break;
632 X       default:
633 X               close(null);
634 X               runq->pc = runq->code[runq->pc].i;
635 X               inttoascii(npid, pid);
636 X               setvar("apid", newword(npid, (word *)0));
637 X               break;
638 X       }
639 X}
640
641 void
642 XXpipe(void)
643 X{
644 X       struct thread *p = runq;
645 X       int pc = p->pc, forkid;
646 X       int lfd = p->code[pc++].i;
647 X       int rfd = p->code[pc++].i;
648 X       int pfd[2];
649 X       if(pipe(pfd)<0){
650 X               Xerror("can't get pipe");
651 X               return;
652 X       }
653 X       switch(forkid = fork()){
654 X       case -1:
655 X               Xerror("try again");
656 X               break;
657 X       case 0:
658 X               start(p->code, pc+2, runq->local);
659 X               runq->ret = 0;
660 X               close(pfd[PRD]);
661 X               pushredir(ROPEN, pfd[PWR], lfd);
662 X               break;
663 X       default:
664 X               start(p->code, p->code[pc].i, runq->local);
665 X               close(pfd[PWR]);
666 X               pushredir(ROPEN, pfd[PRD], rfd);
667 X               p->pc = p->code[pc+1].i;
668 X               p->pid = forkid;
669 X               break;
670 X       }
671 X}
672
673 X/*
674 X * Who should wait for the exit from the fork?
675 X */
676 void
677 XXbackq(void)
678 X{
679 X       char wd[8193];
680 X       int c;
681 X       char *s, *ewd=&wd[8192], *stop;
682 X       struct io *f;
683 X       var *ifs = vlook("ifs");
684 X       word *v, *nextv;
685 X       int pfd[2];
686 X       int pid;
687 X       stop = ifs->val?ifs->val->word:"";
688 X       if(pipe(pfd)<0){
689 X               Xerror("can't make pipe");
690 X               return;
691 X       }
692 X       switch(pid = fork()){
693 X       case -1:
694 X               Xerror("try again");
695 X               close(pfd[PRD]);
696 X               close(pfd[PWR]);
697 X               return;
698 X       case 0:
699 X               close(pfd[PRD]);
700 X               start(runq->code, runq->pc+1, runq->local);
701 X               pushredir(ROPEN, pfd[PWR], 1);
702 X               return;
703 X       default:
704 X               close(pfd[PWR]);
705 X               f = openfd(pfd[PRD]);
706 X               s = wd;
707 X               v = 0;
708 X               while((c = rchr(f))!=EOF){
709 X                       if(strchr(stop, c) || s==ewd){
710 X                               if(s!=wd){
711 X                                       *s='\0';
712 X                                       v = newword(wd, v);
713 X                                       s = wd;
714 X                               }
715 X                       }
716 X                       else *s++=c;
717 X               }
718 X               if(s!=wd){
719 X                       *s='\0';
720 X                       v = newword(wd, v);
721 X               }
722 X               closeio(f);
723 X               Waitfor(pid, 0);
724 X               /* v points to reversed arglist -- reverse it onto argv */
725 X               while(v){
726 X                       nextv = v->next;
727 X                       v->next = runq->argv->words;
728 X                       runq->argv->words = v;
729 X                       v = nextv;
730 X               }
731 X               runq->pc = runq->code[runq->pc].i;
732 X               return;
733 X       }
734 X}
735
736 void
737 XXpipefd(void)
738 X{
739 X       struct thread *p = runq;
740 X       int pc = p->pc;
741 X       char name[40];
742 X       int pfd[2];
743 X       int sidefd, mainfd;
744 X       if(pipe(pfd)<0){
745 X               Xerror("can't get pipe");
746 X               return;
747 X       }
748 X       if(p->code[pc].i==READ){
749 X               sidefd = pfd[PWR];
750 X               mainfd = pfd[PRD];
751 X       }
752 X       else{
753 X               sidefd = pfd[PRD];
754 X               mainfd = pfd[PWR];
755 X       }
756 X       switch(fork()){
757 X       case -1:
758 X               Xerror("try again");
759 X               break;
760 X       case 0:
761 X               start(p->code, pc+2, runq->local);
762 X               close(mainfd);
763 X               pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
764 X               runq->ret = 0;
765 X               break;
766 X       default:
767 X               close(sidefd);
768 X               pushredir(ROPEN, mainfd, mainfd);       /* isn't this a noop? */
769 X               strcpy(name, Fdprefix);
770 X               inttoascii(name+strlen(name), mainfd);
771 X               pushword(name);
772 X               p->pc = p->code[pc+1].i;
773 X               break;
774 X       }
775 X}
776
777 void
778 XXsubshell(void)
779 X{
780 X       int pid;
781 X       switch(pid = fork()){
782 X       case -1:
783 X               Xerror("try again");
784 X               break;
785 X       case 0:
786 X               start(runq->code, runq->pc+1, runq->local);
787 X               runq->ret = 0;
788 X               break;
789 X       default:
790 X               Waitfor(pid, 1);
791 X               runq->pc = runq->code[runq->pc].i;
792 X               break;
793 X       }
794 X}
795
796 int
797 execforkexec(void)
798 X{
799 X       int pid;
800 X       int n;
801 X       char buf[ERRMAX];
802
803 X       switch(pid = fork()){
804 X       case -1:
805 X               return -1;
806 X       case 0:
807 X               pushword("exec");
808 X               execexec();
809 X               strcpy(buf, "can't exec: ");
810 X               n = strlen(buf);
811 X               errstr(buf+n, ERRMAX-n);
812 X               Exit(buf);
813 X       }
814 X       return pid;
815 X}
816 !
817 echo rc.h
818 sed 's/^X//' >rc.h <<'!'
819 X/*
820 X * Plan9 is defined for plan 9
821 X * V9 is defined for 9th edition
822 X * Sun is defined for sun-os
823 X * Please don't litter the code with ifdefs.  The three below should be enough.
824 X */
825 X#define Unix
826
827 X#ifdef Plan9
828 X#include <u.h>
829 X#include <libc.h>
830 X#define        NSIG    32
831 X#define        SIGINT  2
832 X#define        SIGQUIT 3
833 X#endif
834
835 X#ifdef Unix
836 X#define _POSIX_SOURCE
837 X#define _BSD_EXTENSION
838
839 X#include <stdlib.h>
840 X#include <stdarg.h>
841 X#include <string.h>
842 X#include <unistd.h>
843 X#include <fcntl.h>
844 X#include <lib9.h>
845 X#include <signal.h>
846 X#endif
847
848 X#ifndef ERRMAX
849 X#define ERRMAX 128
850 X#endif
851
852 X#define        YYMAXDEPTH      500
853 X#ifndef PAREN
854 X#include "x.tab.h"
855 X#endif
856 typedef struct tree tree;
857 typedef struct word word;
858 typedef struct io io;
859 typedef union code code;
860 typedef struct var var;
861 typedef struct list list;
862 typedef struct redir redir;
863 typedef struct thread thread;
864 typedef struct builtin builtin;
865
866 struct tree{
867 X       int type;
868 X       int rtype, fd0, fd1;            /* details of REDIR PIPE DUP tokens */
869 X       char *str;
870 X       int quoted;
871 X       int iskw;
872 X       tree *child[3];
873 X       tree *next;
874 X};
875 tree *newtree(void);
876 tree *token(char*, int), *klook(char*), *tree1(int, tree*);
877 tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
878 tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
879 tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
880 tree *simplemung(tree*), *heredoc(tree*);
881 void freetree(tree*);
882 tree *cmdtree;
883 X/*
884 X * The first word of any code vector is a reference count.
885 X * Always create a new reference to a code vector by calling codecopy(.).
886 X * Always call codefree(.) when deleting a reference.
887 X */
888 union code{
889 X       void (*f)(void);
890 X       int i;
891 X       char *s;
892 X};
893 char *promptstr;
894 int doprompt;
895 X#define        NTOK    8192
896 char tok[NTOK];
897 X#define        APPEND  1
898 X#define        WRITE   2
899 X#define        READ    3
900 X#define        HERE    4
901 X#define        DUPFD   5
902 X#define        CLOSE   6
903 struct var{
904 X       char *name;             /* ascii name */
905 X       word *val;      /* value */
906 X       int changed;
907 X       code *fn;               /* pointer to function's code vector */
908 X       int fnchanged;
909 X       int pc;                 /* pc of start of function */
910 X       var *next;      /* next on hash or local list */
911 X};
912 var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
913 X#define        NVAR    521
914 var *gvar[NVAR];                                /* hash for globals */
915 X#define        new(type)       ((type *)emalloc(sizeof(type)))
916 char *emalloc(long);
917 void *Malloc(ulong);
918 void efree(char*);
919 X#define        NOFILE  128             /* should come from <param.h> */
920 struct here{
921 X       tree *tag;
922 X       char *name;
923 X       struct here *next;
924 X};
925 int mypid;
926 X/*
927 X * Glob character escape in strings:
928 X *     In a string, GLOB must be followed by *?[ or GLOB.
929 X *     GLOB* matches any string
930 X *     GLOB? matches any single character
931 X *     GLOB[...] matches anything in the brackets
932 X *     GLOBGLOB matches GLOB
933 X */
934 X#define        GLOB    ((char)0x01)
935 X/*
936 X * onebyte(c), twobyte(c), threebyte(c)
937 X * Is c the first character of a one- two- or three-byte utf sequence?
938 X */
939 X#define        onebyte(c)      ((c&0x80)==0x00)
940 X#define        twobyte(c)      ((c&0xe0)==0xc0)
941 X#define        threebyte(c)    ((c&0xf0)==0xe0)
942 char **argp;
943 char **args;
944 int nerror;             /* number of errors encountered during compilation */
945 int doprompt;           /* is it time for a prompt? */
946 X/*
947 X * Which fds are the reading/writing end of a pipe?
948 X * Unfortunately, this can vary from system to system.
949 X * 9th edition Unix doesn't care, the following defines
950 X * work on plan 9.
951 X */
952 X#define        PRD     0
953 X#define        PWR     1
954 char Rcmain[], Fdprefix[];
955 X#define        register
956 X/*
957 X * How many dot commands have we executed?
958 X * Used to ensure that -v flag doesn't print rcmain.
959 X */
960 int ndot;
961 char *getstatus(void);
962 int lastc;
963 int lastword;
964 !
965 echo unix.c
966 sed 's/^X//' >unix.c <<'!'
967 X/*
968 X * Unix versions of system-specific functions
969 X *     By convention, exported routines herein have names beginning with an
970 X *     upper case letter.
971 X */
972 X#include "rc.h"
973 X#include "io.h"
974 X#include "exec.h"
975 X#include "getflags.h"
976 X#include <errno.h>
977
978 char Rcmain[]="/usr/lib/rcmain";
979 char Fdprefix[]="/dev/fd/";
980
981 void execfinit(void);
982
983 struct builtin Builtin[] = {
984 X       "cd",           execcd,
985 X       "whatis",       execwhatis,
986 X       "eval",         execeval,
987 X       "exec",         execexec,       /* but with popword first */
988 X       "exit",         execexit,
989 X       "shift",        execshift,
990 X       "wait",         execwait,
991 X       "umask",        execumask,
992 X       ".",            execdot,
993 X       "finit",        execfinit,
994 X       "flag",         execflag,
995 X       0
996 X};
997 X#define        SEP     '\1'
998 char **environp;
999
1000 struct word*
1001 enval(s)
1002 register char *s;
1003 X{
1004 X       char *t, c;
1005 X       struct word *v;
1006 X       for(t = s;*t && *t!=SEP;t++);
1007 X       c=*t;
1008 X       *t='\0';
1009 X       v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
1010 X       *t = c;
1011 X       return v;
1012 X}
1013
1014 void
1015 Vinit(void)
1016 X{
1017 X       extern char **environ;
1018 X       char *s;
1019 X       char **env = environ;
1020 X       environp = env;
1021 X       for(;*env;env++){
1022 X               for(s=*env;*s && *s!='(' && *s!='=';s++);
1023 X               switch(*s){
1024 X               case '\0':
1025 X                       pfmt(err, "environment %q?\n", *env);
1026 X                       break;
1027 X               case '=':
1028 X                       *s='\0';
1029 X                       setvar(*env, enval(s+1));
1030 X                       *s='=';
1031 X                       break;
1032 X               case '(':       /* ignore functions for now */
1033 X                       break;
1034 X               }
1035 X       }
1036 X}
1037
1038 char **envp;
1039
1040 void
1041 XXrdfn(void)
1042 X{
1043 X       char *s;
1044 X       int len;
1045 X       for(;*envp;envp++){
1046 X               for(s=*envp;*s && *s!='(' && *s!='=';s++);
1047 X               switch(*s){
1048 X               case '\0':
1049 X                       pfmt(err, "environment %q?\n", *envp);
1050 X                       break;
1051 X               case '=':       /* ignore variables */
1052 X                       break;
1053 X               case '(':               /* Bourne again */
1054 X                       s=*envp+3;
1055 X                       envp++;
1056 X                       len = strlen(s);
1057 X                       s[len]='\n';
1058 X                       execcmds(opencore(s, len+1));
1059 X                       s[len]='\0';
1060 X                       return;
1061 X               }
1062 X       }
1063 X       Xreturn();
1064 X}
1065
1066 union code rdfns[4];
1067
1068 void
1069 execfinit(void)
1070 X{
1071 X       static int first = 1;
1072 X       if(first){
1073 X               rdfns[0].i = 1;
1074 X               rdfns[1].f = Xrdfn;
1075 X               rdfns[2].f = Xjump;
1076 X               rdfns[3].i = 1;
1077 X               first = 0;
1078 X       }
1079 X       Xpopm();
1080 X       envp = environp;
1081 X       start(rdfns, 1, runq->local);
1082 X}
1083
1084 int
1085 cmpenv(const void *aa, const void *ab)
1086 X{
1087 X       char **a = aa, **b = ab;
1088
1089 X       return strcmp(*a, *b);
1090 X}
1091
1092 char **
1093 mkenv(void)
1094 X{
1095 X       char **env, **ep, *p, *q;
1096 X       struct var **h, *v;
1097 X       struct word *a;
1098 X       int nvar = 0, nchr = 0, sep;
1099
1100 X       /*
1101 X        * Slightly kludgy loops look at locals then globals.
1102 X        * locals no longer exist - geoff
1103 X        */
1104 X       for(h = gvar-1; h != &gvar[NVAR]; h++)
1105 X       for(v = h >= gvar? *h: runq->local; v ;v = v->next){
1106 X               if((v==vlook(v->name)) && v->val){
1107 X                       nvar++;
1108 X                       nchr+=strlen(v->name)+1;
1109 X                       for(a = v->val;a;a = a->next)
1110 X                               nchr+=strlen(a->word)+1;
1111 X               }
1112 X               if(v->fn){
1113 X                       nvar++;
1114 X                       nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
1115 X               }
1116 X       }
1117 X       env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
1118 X       ep = env;
1119 X       p = (char *)&env[nvar+1];
1120 X       for(h = gvar-1; h != &gvar[NVAR]; h++)
1121 X       for(v = h >= gvar? *h: runq->local;v;v = v->next){
1122 X               if((v==vlook(v->name)) && v->val){
1123 X                       *ep++=p;
1124 X                       q = v->name;
1125 X                       while(*q) *p++=*q++;
1126 X                       sep='=';
1127 X                       for(a = v->val;a;a = a->next){
1128 X                               *p++=sep;
1129 X                               sep = SEP;
1130 X                               q = a->word;
1131 X                               while(*q) *p++=*q++;
1132 X                       }
1133 X                       *p++='\0';
1134 X               }
1135 X               if(v->fn){
1136 X                       *ep++=p;
1137 X                       *p++='#'; *p++='('; *p++=')';   /* to fool Bourne */
1138 X                       *p++='f'; *p++='n'; *p++=' ';
1139 X                       q = v->name;
1140 X                       while(*q) *p++=*q++;
1141 X                       *p++=' ';
1142 X                       q = v->fn[v->pc-1].s;
1143 X                       while(*q) *p++=*q++;
1144 X                       *p++='\0';
1145 X               }
1146 X       }
1147 X       *ep = 0;
1148 X       qsort((void *)env, nvar, sizeof ep[0], cmpenv);
1149 X       return env;     
1150 X}
1151 char *sigmsg[] = {
1152 X/*  0 normal  */ 0,
1153 X/*  1 SIGHUP  */ "Hangup",
1154 X/*  2 SIGINT  */ 0,
1155 X/*  3 SIGQUIT */ "Quit",
1156 X/*  4 SIGILL  */ "Illegal instruction",
1157 X/*  5 SIGTRAP */ "Trace/BPT trap",
1158 X/*  6 SIGIOT  */ "abort",
1159 X/*  7 SIGEMT  */ "EMT trap",
1160 X/*  8 SIGFPE  */ "Floating exception",
1161 X/*  9 SIGKILL */ "Killed",
1162 X/* 10 SIGBUS  */ "Bus error",
1163 X/* 11 SIGSEGV */ "Memory fault",
1164 X/* 12 SIGSYS  */ "Bad system call",
1165 X/* 13 SIGPIPE */ 0,
1166 X/* 14 SIGALRM */ "Alarm call",
1167 X/* 15 SIGTERM */ "Terminated",
1168 X/* 16 unused  */ "signal 16",
1169 X/* 17 SIGSTOP */ "Process stopped",
1170 X/* 18 unused  */ "signal 18",
1171 X/* 19 SIGCONT */ "Process continued",
1172 X/* 20 SIGCHLD */ "Child death",
1173 X};
1174
1175 void
1176 Waitfor(int pid, int persist)
1177 X{
1178 X       int wpid, sig;
1179 X       struct thread *p;
1180 X       int wstat;
1181 X       char wstatstr[12];
1182
1183 X       for(;;){
1184 X               errno = 0;
1185 X               wpid = wait(&wstat);
1186 X               if(errno==EINTR && persist)
1187 X                       continue;
1188 X               if(wpid==-1)
1189 X                       break;
1190 X               sig = wstat&0177;
1191 X               if(sig==0177){
1192 X                       pfmt(err, "trace: ");
1193 X                       sig = (wstat>>8)&0177;
1194 X               }
1195 X               if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
1196 X                       if(pid!=wpid)
1197 X                               pfmt(err, "%d: ", wpid);
1198 X                       if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
1199 X                               pfmt(err, "%s", sigmsg[sig]);
1200 X                       else if(sig==0177) pfmt(err, "stopped by ptrace");
1201 X                       else pfmt(err, "signal %d", sig);
1202 X                       if(wstat&0200)pfmt(err, " -- core dumped");
1203 X                       pfmt(err, "\n");
1204 X               }
1205 X               wstat = sig?sig+1000:(wstat>>8)&0xFF;
1206 X               if(wpid==pid){
1207 X                       inttoascii(wstatstr, wstat);
1208 X                       setstatus(wstatstr);
1209 X                       break;
1210 X               }
1211 X               else{
1212 X                       for(p = runq->ret;p;p = p->ret)
1213 X                               if(p->pid==wpid){
1214 X                                       p->pid=-1;
1215 X                                       inttoascii(p->status, wstat);
1216 X                                       break;
1217 X                               }
1218 X               }
1219 X       }
1220 X}
1221
1222 char **
1223 mkargv(a)
1224 register struct word *a;
1225 X{
1226 X       char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
1227 X       char **argp = argv+1;   /* leave one at front for runcoms */
1228
1229 X       for(;a;a = a->next)
1230 X               *argp++=a->word;
1231 X       *argp = 0;
1232 X       return argv;
1233 X}
1234
1235 void
1236 Updenv(void)
1237 X{
1238 X}
1239
1240 void
1241 Execute(struct word *args, struct word *path)
1242 X{
1243 X       char *msg="not found";
1244 X#ifdef ETXTBSY
1245 X       int txtbusy = 0;
1246 X#endif
1247 X       char **env = mkenv();
1248 X       char **argv = mkargv(args);
1249 X       char file[512];
1250
1251 X       for(;path;path = path->next){
1252 X               strcpy(file, path->word);
1253 X               if(file[0])
1254 X                       strcat(file, "/");
1255 X               strcat(file, argv[1]);
1256 X#ifdef ETXTBSY
1257 ReExec:
1258 X#endif
1259 X               execve(file, argv+1, env);
1260 X               switch(errno){
1261 X               case ENOEXEC:
1262 X                       pfmt(err, "%s: Bourne again\n", argv[1]);
1263 X                       argv[0]="sh";
1264 X                       argv[1] = strdup(file);
1265 X                       execve("/bin/sh", argv, env);
1266 X                       goto Bad;
1267 X#ifdef ETXTBSY
1268 X               case ETXTBSY:
1269 X                       if(++txtbusy!=5){
1270 X                               sleep(txtbusy);
1271 X                               goto ReExec;
1272 X                       }
1273 X                       msg="text busy"; goto Bad;
1274 X#endif
1275 X               case EACCES:
1276 X                       msg="no access";
1277 X                       break;
1278 X               case ENOMEM:
1279 X                       msg="not enough memory"; goto Bad;
1280 X               case E2BIG:
1281 X                       msg="too big"; goto Bad;
1282 X               }
1283 X       }
1284 Bad:
1285 X       pfmt(err, "%s: %s\n", argv[1], msg);
1286 X       efree((char *)env);
1287 X       efree((char *)argv);
1288 X}
1289
1290 X#define        NDIR    14              /* should get this from param.h */
1291
1292 Globsize(p)
1293 register char *p;
1294 X{
1295 X       int isglob = 0, globlen = NDIR+1;
1296 X       for(;*p;p++){
1297 X               if(*p==GLOB){
1298 X                       p++;
1299 X                       if(*p!=GLOB)
1300 X                               isglob++;
1301 X                       globlen+=*p=='*'?NDIR:1;
1302 X               }
1303 X               else
1304 X                       globlen++;
1305 X       }
1306 X       return isglob?globlen:0;
1307 X}
1308
1309 X#include <sys/types.h>
1310 X#include <dirent.h>
1311
1312 X#define        NDIRLIST        50
1313
1314 DIR *dirlist[NDIRLIST];
1315
1316 Opendir(name)
1317 char *name;
1318 X{
1319 X       DIR **dp;
1320 X       for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
1321 X               if(*dp==0){
1322 X                       *dp = opendir(name);
1323 X                       return *dp?dp-dirlist:-1;
1324 X               }
1325 X       return -1;
1326 X}
1327
1328 int
1329 Readdir(int f, char *p, int /* onlydirs */ )
1330 X{
1331 X       struct dirent *dp = readdir(dirlist[f]);
1332
1333 X       if(dp==0)
1334 X               return 0;
1335 X       strcpy(p, dp->d_name);
1336 X       return 1;
1337 X}
1338
1339 void
1340 Closedir(int f)
1341 X{
1342 X       closedir(dirlist[f]);
1343 X       dirlist[f] = 0;
1344 X}
1345
1346 char *Signame[] = {
1347 X       "sigexit",      "sighup",       "sigint",       "sigquit",
1348 X       "sigill",       "sigtrap",      "sigiot",       "sigemt",
1349 X       "sigfpe",       "sigkill",      "sigbus",       "sigsegv",
1350 X       "sigsys",       "sigpipe",      "sigalrm",      "sigterm",
1351 X       "sig16",        "sigstop",      "sigtstp",      "sigcont",
1352 X       "sigchld",      "sigttin",      "sigttou",      "sigtint",
1353 X       "sigxcpu",      "sigxfsz",      "sig26",        "sig27",
1354 X       "sig28",        "sig29",        "sig30",        "sig31",
1355 X       0,
1356 X};
1357
1358 void
1359 gettrap(int sig)
1360 X{
1361 X       signal(sig, gettrap);
1362 X       trap[sig]++;
1363 X       ntrap++;
1364 X       if(ntrap>=NSIG){
1365 X               pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
1366 X               signal(SIGABRT, (void (*)())0);
1367 X               kill(getpid(), SIGABRT);
1368 X       }
1369 X}
1370
1371 void
1372 Trapinit(void)
1373 X{
1374 X       int i;
1375 X       void (*sig)();
1376
1377 X       if(1 || flag['d']){     /* wrong!!! */
1378 X               sig = signal(SIGINT, gettrap);
1379 X               if(sig==SIG_IGN)
1380 X                       signal(SIGINT, SIG_IGN);
1381 X       }
1382 X       else{
1383 X               for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
1384 X                       sig = signal(i, gettrap);
1385 X                       if(sig==SIG_IGN)
1386 X                               signal(i, SIG_IGN);
1387 X               }
1388 X       }
1389 X}
1390
1391 Unlink(name)
1392 char *name;
1393 X{
1394 X       return unlink(name);
1395 X}
1396 Write(fd, buf, cnt)
1397 char *buf;
1398 X{
1399 X       return write(fd, buf, cnt);
1400 X}
1401 Read(fd, buf, cnt)
1402 char *buf;
1403 X{
1404 X       return read(fd, buf, cnt);
1405 X}
1406 Seek(fd, cnt, whence)
1407 long cnt;
1408 X{
1409 X       return lseek(fd, cnt, whence);
1410 X}
1411 Executable(file)
1412 char *file;
1413 X{
1414 X       return(access(file, 01)==0);
1415 X}
1416 Creat(file)
1417 char *file;
1418 X{
1419 X       return creat(file, 0666);
1420 X}
1421 Dup(a, b){
1422 X       return dup2(a, b);
1423 X}
1424 Dup1(a){
1425 X       return dup(a);
1426 X}
1427 X/*
1428 X * Wrong:  should go through components of a|b|c and return the maximum.
1429 X */
1430 void
1431 Exit(char *stat)
1432 X{
1433 X       int n = 0;
1434
1435 X       while(*stat){
1436 X               if(*stat!='|'){
1437 X                       if(*stat<'0' || '9'<*stat)
1438 X                               exit(1);
1439 X                       else n = n*10+*stat-'0';
1440 X               }
1441 X               stat++;
1442 X       }
1443 X       exit(n);
1444 X}
1445 Eintr(){
1446 X       return errno==EINTR;
1447 X}
1448
1449 void
1450 Noerror()
1451 X{
1452 X       errno = 0;
1453 X}
1454 Isatty(fd){
1455 X       return isatty(fd);
1456 X}
1457
1458 void
1459 Abort()
1460 X{
1461 X       abort();
1462 X}
1463
1464 void
1465 execumask(void)         /* wrong -- should fork before writing */
1466 X{
1467 X       int m;
1468 X       struct io out[1];
1469 X       switch(count(runq->argv->words)){
1470 X       default:
1471 X               pfmt(err, "Usage: umask [umask]\n");
1472 X               setstatus("umask usage");
1473 X               poplist();
1474 X               return;
1475 X       case 2:
1476 X               umask(octal(runq->argv->words->next->word));
1477 X               break;
1478 X       case 1: 
1479 X               umask(m = umask(0));
1480 X               out->fd = mapfd(1);
1481 X               out->bufp = out->buf;
1482 X               out->ebuf=&out->buf[NBUF];
1483 X               out->strp = 0;
1484 X               pfmt(out, "%o\n", m);
1485 X               break;
1486 X       }
1487 X       setstatus("");
1488 X       poplist();
1489 X}
1490
1491 void
1492 Memcpy(a, b, n)
1493 char *a, *b;
1494 X{
1495 X       memmove(a, b, n);
1496 X}
1497
1498 void*
1499 Malloc(unsigned long n)
1500 X{
1501 X       return (void *)malloc(n);
1502 X}
1503
1504 void
1505 errstr(char *buf, int len)
1506 X{
1507 X       strncpy(buf, strerror(errno), len);
1508 X}
1509 !
1510
1511 From geoff@collyer.net Fri Dec 19 01:23:26 EST 2003
1512 Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:23:25 EST 2003
1513 Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:23:22 EST 2003
1514 Message-ID: <0b5ea130198a21a49139759d00d69939@collyer.net>
1515 subject: rc on unix, part 2
1516 From: Geoff Collyer <geoff@collyer.net>
1517 Date: Thu, 18 Dec 2003 22:23:21 -0800
1518 To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
1519 MIME-Version: 1.0
1520 Content-Type: text/plain; charset="US-ASCII"
1521 Content-Transfer-Encoding: 7bit
1522
1523 These are the include files I used to emulate plan 9's include
1524 files on Unix (APE).
1525
1526
1527 # To unbundle, run this file
1528 mkdir include
1529 echo include/bio.h
1530 sed 's/^X//' >include/bio.h <<'!'
1531 X#ifndef _BIOH_
1532 X#define _BIOH_ 1
1533
1534 X#include <sys/types.h> /* for off_t */
1535 X#include <fcntl.h>     /* for O_RDONLY, O_WRONLY */
1536
1537 typedef struct  Biobuf  Biobuf;
1538
1539 enum
1540 X{
1541 X       Bsize           = 8*1024,
1542 X       Bungetsize      = 4,            /* space for ungetc */
1543 X       Bmagic          = 0x314159,
1544 X       Beof            = -1,
1545 X       Bbad            = -2,
1546
1547 X       Binactive       = 0,            /* states */
1548 X       Bractive,
1549 X       Bwactive,
1550 X       Bracteof,
1551
1552 X       Bend
1553 X};
1554
1555 struct  Biobuf
1556 X{
1557 X       int     icount;         /* neg num of bytes at eob */
1558 X       int     ocount;         /* num of bytes at bob */
1559 X       int     rdline;         /* num of bytes after rdline */
1560 X       int     runesize;               /* num of bytes of last getrune */
1561 X       int     state;          /* r/w/inactive */
1562 X       int     fid;            /* open file */
1563 X       int     flag;           /* magic if malloc'ed */
1564 X       off_t   offset;         /* offset of buffer in file */
1565 X       int     bsize;          /* size of buffer */
1566 X       unsigned char*  bbuf;           /* pointer to beginning of buffer */
1567 X       unsigned char*  ebuf;           /* pointer to end of buffer */
1568 X       unsigned char*  gbuf;           /* pointer to good data in buf */
1569 X       unsigned char   b[Bungetsize+Bsize];
1570 X};
1571
1572 X#define        BGETC(bp)\
1573 X       ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
1574 X#define        BPUTC(bp,c)\
1575 X       ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
1576 X#define        BOFFSET(bp)\
1577 X       (((bp)->state==Bractive)?\
1578 X               (bp)->offset + (bp)->icount:\
1579 X       (((bp)->state==Bwactive)?\
1580 X               (bp)->offset + ((bp)->bsize + (bp)->ocount):\
1581 X               -1))
1582 X#define        BLINELEN(bp)\
1583 X       (bp)->rdline
1584 X#define        BFILDES(bp)\
1585 X       (bp)->fid
1586
1587 int     Bbuffered(Biobuf*);
1588 int     Bfildes(Biobuf*);
1589 int     Bflush(Biobuf*);
1590 int     Bgetc(Biobuf*);
1591 int     Bgetd(Biobuf*, double*);
1592 int     Binit(Biobuf*, int, int);
1593 int     Binits(Biobuf*, int, int, unsigned char*, int);
1594 int     Blinelen(Biobuf*);
1595 off_t   Boffset(Biobuf*);
1596 Biobuf* Bopen(char*, int);
1597 int     Bprint(Biobuf*, char*, ...);
1598 int     Bputc(Biobuf*, int);
1599 void*   Brdline(Biobuf*, int);
1600 long    Bread(Biobuf*, void*, long);
1601 off_t   Bseek(Biobuf*, off_t, int);
1602 int     Bterm(Biobuf*);
1603 int     Bungetc(Biobuf*);
1604 long    Bwrite(Biobuf*, void*, long);
1605
1606 long    Bgetrune(Biobuf*);
1607 int     Bputrune(Biobuf*, long);
1608 int     Bungetrune(Biobuf*);
1609
1610 X#endif
1611 !
1612 echo include/fmt.h
1613 sed 's/^X//' >include/fmt.h <<'!'
1614
1615 X/*
1616 X * The authors of this software are Rob Pike and Ken Thompson.
1617 X *              Copyright (c) 2002 by Lucent Technologies.
1618 X * Permission to use, copy, modify, and distribute this software for any
1619 X * purpose without fee is hereby granted, provided that this entire notice
1620 X * is included in all copies of any software which is or includes a copy
1621 X * or modification of this software and in all copies of the supporting
1622 X * documentation for such software.
1623 X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
1624 X * WARRANTY.  IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
1625 X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
1626 X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
1627 X */
1628
1629 X#ifndef _FMTH_
1630 X#define _FMTH_ 1
1631
1632 X#include <stdarg.h>
1633
1634 X#ifndef _UTFH_
1635 X#include <utf.h>
1636 X#endif
1637
1638 typedef struct Fmt      Fmt;
1639 struct Fmt{
1640 X       unsigned char   runes;          /* output buffer is runes or chars? */
1641 X       void    *start;                 /* of buffer */
1642 X       void    *to;                    /* current place in the buffer */
1643 X       void    *stop;                  /* end of the buffer; overwritten if flush fails */
1644 X       int     (*flush)(Fmt *);        /* called when to == stop */
1645 X       void    *farg;                  /* to make flush a closure */
1646 X       int     nfmt;                   /* num chars formatted so far */
1647 X       va_list args;                   /* args passed to dofmt */
1648 X       int     r;                      /* % format Rune */
1649 X       int     width;
1650 X       int     prec;
1651 X       unsigned long   flags;
1652 X};
1653
1654 enum{
1655 X       FmtWidth        = 1,
1656 X       FmtLeft         = FmtWidth << 1,
1657 X       FmtPrec         = FmtLeft << 1,
1658 X       FmtSharp        = FmtPrec << 1,
1659 X       FmtSpace        = FmtSharp << 1,
1660 X       FmtSign         = FmtSpace << 1,
1661 X       FmtZero         = FmtSign << 1,
1662 X       FmtUnsigned     = FmtZero << 1,
1663 X       FmtShort        = FmtUnsigned << 1,
1664 X       FmtLong         = FmtShort << 1,
1665 X       FmtVLong        = FmtLong << 1,
1666 X       FmtComma        = FmtVLong << 1,
1667 X       FmtByte         = FmtComma << 1,
1668 X       FmtLDouble      = FmtByte << 1,
1669
1670 X       FmtFlag         = FmtLDouble << 1
1671 X};
1672
1673 extern  int     print(char*, ...);
1674 extern  char*   seprint(char*, char*, char*, ...);
1675 extern  char*   vseprint(char*, char*, char*, va_list);
1676 extern  int     snprint(char*, int, char*, ...);
1677 extern  int     vsnprint(char*, int, char*, va_list);
1678 extern  char*   smprint(char*, ...);
1679 extern  char*   vsmprint(char*, va_list);
1680 extern  int     sprint(char*, char*, ...);
1681 extern  int     fprint(int, char*, ...);
1682 extern  int     vfprint(int, char*, va_list);
1683
1684 extern  int     runesprint(Rune*, char*, ...);
1685 extern  int     runesnprint(Rune*, int, char*, ...);
1686 extern  int     runevsnprint(Rune*, int, char*, va_list);
1687 extern  Rune*   runeseprint(Rune*, Rune*, char*, ...);
1688 extern  Rune*   runevseprint(Rune*, Rune*, char*, va_list);
1689 extern  Rune*   runesmprint(char*, ...);
1690 extern  Rune*   runevsmprint(char*, va_list);
1691
1692 extern  int     fmtfdinit(Fmt*, int, char*, int);
1693 extern  int     fmtfdflush(Fmt*);
1694 extern  int     fmtstrinit(Fmt*);
1695 extern  char*   fmtstrflush(Fmt*);
1696
1697 extern  int     quotestrfmt(Fmt *f);
1698 extern  void    quotefmtinstall(void);
1699 extern  int     (*fmtdoquote)(int);
1700
1701
1702 extern  int     fmtinstall(int, int (*)(Fmt*));
1703 extern  int     dofmt(Fmt*, char*);
1704 extern  int     fmtprint(Fmt*, char*, ...);
1705 extern  int     fmtvprint(Fmt*, char*, va_list);
1706 extern  int     fmtrune(Fmt*, int);
1707 extern  int     fmtstrcpy(Fmt*, char*);
1708
1709 extern  double  fmtstrtod(const char *, char **);
1710 extern  double  fmtcharstod(int(*)(void*), void*);
1711
1712 X#endif
1713 !
1714 echo include/lib9.h
1715 sed 's/^X//' >include/lib9.h <<'!'
1716 X#include <string.h>
1717 X#include "utf.h"
1718
1719 X#define nil ((void*)0)
1720
1721 X#define uchar _fmtuchar
1722 X#define ushort _fmtushort
1723 X#define uint _fmtuint
1724 X#define ulong _fmtulong
1725 X#define vlong _fmtvlong
1726 X#define uvlong _fmtuvlong
1727
1728 typedef unsigned char           uchar;
1729 typedef unsigned short          ushort;
1730 typedef unsigned int            uint;
1731 typedef unsigned long           ulong;
1732
1733 X#define OREAD O_RDONLY
1734 X#define OWRITE O_WRONLY
1735 X#define ORDWR O_RDWR
1736 X#define OCEXEC 0
1737 !
1738 echo include/regexp9.h
1739 sed 's/^X//' >include/regexp9.h <<'!'
1740 X#ifndef _REGEXP9H_
1741
1742 X#define _REGEXP9H_ 1
1743 X#include <utf.h>
1744
1745 typedef struct Resub            Resub;
1746 typedef struct Reclass          Reclass;
1747 typedef struct Reinst           Reinst;
1748 typedef struct Reprog           Reprog;
1749
1750 X/*
1751 X *     Sub expression matches
1752 X */
1753 struct Resub{
1754 X       union
1755 X       {
1756 X               char *sp;
1757 X               Rune *rsp;
1758 X       }s;
1759 X       union
1760 X       {
1761 X               char *ep;
1762 X               Rune *rep;
1763 X       }e;
1764 X};
1765
1766 X/*
1767 X *     character class, each pair of rune's defines a range
1768 X */
1769 struct Reclass{
1770 X       Rune    *end;
1771 X       Rune    spans[64];
1772 X};
1773
1774 X/*
1775 X *     Machine instructions
1776 X */
1777 struct Reinst{
1778 X       int     type;
1779 X       union   {
1780 X               Reclass *cp;            /* class pointer */
1781 X               Rune    r;              /* character */
1782 X               int     subid;          /* sub-expression id for RBRA and LBRA */
1783 X               Reinst  *right;         /* right child of OR */
1784 X       }u1;
1785 X       union { /* regexp relies on these two being in the same union */
1786 X               Reinst *left;           /* left child of OR */
1787 X               Reinst *next;           /* next instruction for CAT & LBRA */
1788 X       }u2;
1789 X};
1790
1791 X/*
1792 X *     Reprogram definition
1793 X */
1794 struct Reprog{
1795 X       Reinst  *startinst;     /* start pc */
1796 X       Reclass class[16];      /* .data */
1797 X       Reinst  firstinst[5];   /* .text */
1798 X};
1799
1800 extern Reprog   *regcomp(char*);
1801 extern Reprog   *regcomplit(char*);
1802 extern Reprog   *regcompnl(char*);
1803 extern void     regerror(char*);
1804 extern int      regexec(Reprog*, char*, Resub*, int);
1805 extern void     regsub(char*, char*, int, Resub*, int);
1806
1807 extern int      rregexec(Reprog*, Rune*, Resub*, int);
1808 extern void     rregsub(Rune*, Rune*, Resub*, int);
1809
1810 X#endif
1811 !
1812 echo include/utf.h
1813 sed 's/^X//' >include/utf.h <<'!'
1814 X#ifndef _UTFH_
1815 X#define _UTFH_ 1
1816
1817 typedef unsigned short Rune;    /* 16 bits */
1818
1819 enum
1820 X{
1821 X       UTFmax          = 3,            /* maximum bytes per rune */
1822 X       Runesync        = 0x80,         /* cannot represent part of a UTF sequence (<) */
1823 X       Runeself        = 0x80,         /* rune and UTF sequences are the same (<) */
1824 X       Runeerror       = 0x80,         /* decoding error in UTF */
1825 X};
1826
1827 X/*
1828 X * rune routines
1829 X */
1830 extern  int     runetochar(char*, Rune*);
1831 extern  int     chartorune(Rune*, char*);
1832 extern  int     runelen(long);
1833 extern  int     runenlen(Rune*, int);
1834 extern  int     fullrune(char*, int);
1835 extern  int     utflen(char*);
1836 extern  int     utfnlen(char*, long);
1837 extern  char*   utfrune(char*, long);
1838 extern  char*   utfrrune(char*, long);
1839 extern  char*   utfutf(char*, char*);
1840 extern  char*   utfecpy(char*, char*, char*);
1841
1842 extern  Rune*   runestrcat(Rune*, Rune*);
1843 extern  Rune*   runestrchr(Rune*, Rune);
1844 extern  int     runestrcmp(Rune*, Rune*);
1845 extern  Rune*   runestrcpy(Rune*, Rune*);
1846 extern  Rune*   runestrncpy(Rune*, Rune*, long);
1847 extern  Rune*   runestrecpy(Rune*, Rune*, Rune*);
1848 extern  Rune*   runestrdup(Rune*);
1849 extern  Rune*   runestrncat(Rune*, Rune*, long);
1850 extern  int     runestrncmp(Rune*, Rune*, long);
1851 extern  Rune*   runestrrchr(Rune*, Rune);
1852 extern  long    runestrlen(Rune*);
1853 extern  Rune*   runestrstr(Rune*, Rune*);
1854
1855 extern  Rune    tolowerrune(Rune);
1856 extern  Rune    totitlerune(Rune);
1857 extern  Rune    toupperrune(Rune);
1858 extern  int     isalpharune(Rune);
1859 extern  int     islowerrune(Rune);
1860 extern  int     isspacerune(Rune);
1861 extern  int     istitlerune(Rune);
1862 extern  int     isupperrune(Rune);
1863
1864 X#endif
1865 !
1866