123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152115311541155115611571158115911601161116211631164116511661167116811691170117111721173117411751176117711781179118011811182118311841185118611871188118911901191119211931194119511961197119811991200120112021203120412051206120712081209121012111212121312141215121612171218121912201221122212231224122512261227122812291230123112321233123412351236123712381239124012411242124312441245124612471248124912501251125212531254125512561257125812591260126112621263126412651266126712681269127012711272127312741275127612771278127912801281128212831284128512861287128812891290129112921293129412951296129712981299130013011302130313041305130613071308130913101311131213131314131513161317131813191320132113221323132413251326132713281329133013311332133313341335133613371338133913401341134213431344134513461347134813491350135113521353135413551356135713581359136013611362136313641365136613671368136913701371137213731374137513761377137813791380138113821383138413851386138713881389139013911392139313941395139613971398139914001401140214031404140514061407140814091410141114121413141414151416141714181419142014211422142314241425142614271428142914301431143214331434143514361437143814391440144114421443144414451446144714481449145014511452145314541455145614571458145914601461146214631464146514661467146814691470147114721473147414751476147714781479148014811482148314841485148614871488148914901491149214931494149514961497149814991500150115021503150415051506150715081509151015111512151315141515151615171518151915201521152215231524152515261527152815291530153115321533153415351536153715381539154015411542154315441545154615471548154915501551155215531554155515561557155815591560156115621563156415651566156715681569157015711572157315741575157615771578157915801581158215831584158515861587158815891590159115921593159415951596159715981599160016011602160316041605160616071608160916101611161216131614161516161617161816191620162116221623162416251626162716281629163016311632163316341635163616371638163916401641164216431644164516461647164816491650165116521653165416551656165716581659166016611662166316641665166616671668166916701671167216731674167516761677167816791680168116821683168416851686168716881689169016911692169316941695169616971698169917001701170217031704170517061707170817091710171117121713171417151716171717181719172017211722172317241725172617271728172917301731173217331734173517361737173817391740174117421743174417451746174717481749175017511752175317541755175617571758175917601761176217631764176517661767176817691770177117721773177417751776177717781779178017811782178317841785178617871788178917901791179217931794179517961797179817991800180118021803180418051806180718081809181018111812181318141815181618171818181918201821182218231824182518261827182818291830183118321833183418351836183718381839184018411842184318441845184618471848184918501851185218531854185518561857185818591860186118621863186418651866 |
- From geoff@collyer.net Fri Dec 19 01:21:40 EST 2003
- Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:21:39 EST 2003
- Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:21:35 EST 2003
- Message-ID: <c790d8b1e06b3918ad2c7848a3ae0ec7@collyer.net>
- subject: rc on unix, part 1
- From: Geoff Collyer <geoff@collyer.net>
- Date: Thu, 18 Dec 2003 22:21:33 -0800
- To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
- MIME-Version: 1.0
- Content-Type: text/plain; charset="US-ASCII"
- Content-Transfer-Encoding: 7bit
- I got /sys/src/cmd/rc to compile under APE (in preparation for moving it
- to Unixes) with the following changed files. I cadged some include files
- from rsc but had to edit lib9.h slightly. I'll send the include files
- separately. I can't tell if it works yet, but it does complain about
- /usr/lib/rcmain being absent when I start it. Oh, and I haven't yet
- simulated the effect of the OCEXEC bit.
- # To unbundle, run this file
- echo mkfile
- sed 's/^X//' >mkfile <<'!'
- X</$objtype/mkfile
- TARG=rc
- COMMONOFILES=\
- X code.$O\
- X exec.$O\
- X getflags.$O\
- X glob.$O\
- X here.$O\
- X io.$O\
- X lex.$O\
- X pcmd.$O\
- X pfnc.$O\
- X simple.$O\
- X subr.$O\
- X trap.$O\
- X tree.$O\
- X var.$O\
- X havefork.$O\
- PLAN9OFILES=plan9.$O\
- UNIXOFILES=unix.$O\
- OFILES=$COMMONOFILES $UNIXOFILES y.tab.$O
- HFILES=rc.h\
- X x.tab.h\
- X io.h\
- X exec.h\
- X fns.h\
- YFILES=syn.y
- BIN=/$objtype/bin
- UPDATE=\
- X mkfile\
- X $HFILES\
- X ${COMMONOFILES:%.$O=%.c}\
- X ${UNIXOFILES:%.$O=%.c}\
- X ${PLAN9OFILES:%.$O=%.c}\
- X $YFILES\
- X ${TARG:%=/386/bin/%}\
- CC=pcc -c -B -I../include
- LD=pcc
- X</sys/src/cmd/mkone
- x.tab.h: y.tab.h
- X cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
- clean:V:
- X rm -f [$OS].out *.[$OS] [xy].tab.? y.debug $TARG
- regress: $O.out
- X cd test
- X mk
- unregress:V:
- X for(test in test/*.test) rc $test >$test.out
- listing:
- X pr mkfile $HFILES $FILES $FILES9 $FILESUNIX $YFILES|lp -du
- !
- echo simple.c
- sed 's/^X//' >simple.c <<'!'
- X/*
- X * Maybe `simple' is a misnomer.
- X */
- X#include "rc.h"
- X#include "getflags.h"
- X#include "exec.h"
- X#include "io.h"
- X#include "fns.h"
- X/*
- X * Search through the following code to see if we're just going to exit.
- X */
- exitnext(void){
- X union code *c=&runq->code[runq->pc];
- X while(c->f==Xpopredir) c++;
- X return c->f==Xexit;
- X}
- void
- XXsimple(void)
- X{
- X word *a;
- X thread *p = runq;
- X var *v;
- X struct builtin *bp;
- X int pid;
- X globlist();
- X a = runq->argv->words;
- X if(a==0){
- X Xerror1("empty argument list");
- X return;
- X }
- X if(flag['x'])
- X pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
- X v = gvlook(a->word);
- X if(v->fn)
- X execfunc(v);
- X else{
- X if(strcmp(a->word, "builtin")==0){
- X if(count(a)==1){
- X pfmt(err, "builtin: empty argument list\n");
- X setstatus("empty arg list");
- X poplist();
- X return;
- X }
- X a = a->next;
- X popword();
- X }
- X for(bp = Builtin;bp->name;bp++)
- X if(strcmp(a->word, bp->name)==0){
- X (*bp->fnc)();
- X return;
- X }
- X if(exitnext()){
- X /* fork and wait is redundant */
- X pushword("exec");
- X execexec();
- X Xexit();
- X }
- X else{
- X flush(err);
- X Updenv(); /* necessary so changes don't go out again */
- X if((pid = execforkexec()) < 0){
- X Xerror("try again");
- X return;
- X }
- X /* interrupts don't get us out */
- X poplist();
- X while(Waitfor(pid, 1) < 0)
- X ;
- X }
- X }
- X}
- struct word nullpath = { "", 0};
- void
- doredir(redir *rp)
- X{
- X if(rp){
- X doredir(rp->next);
- X switch(rp->type){
- X case ROPEN:
- X if(rp->from!=rp->to){
- X Dup(rp->from, rp->to);
- X close(rp->from);
- X }
- X break;
- X case RDUP:
- X Dup(rp->from, rp->to);
- X break;
- X case RCLOSE:
- X close(rp->from);
- X break;
- X }
- X }
- X}
- word*
- searchpath(char *w)
- X{
- X word *path;
- X if(strncmp(w, "/", 1)==0
- X || strncmp(w, "#", 1)==0
- X || strncmp(w, "./", 2)==0
- X || strncmp(w, "../", 3)==0
- X || (path = vlook("path")->val)==0)
- X path=&nullpath;
- X return path;
- X}
- void
- execexec(void)
- X{
- X popword(); /* "exec" */
- X if(runq->argv->words==0){
- X Xerror1("empty argument list");
- X return;
- X }
- X doredir(runq->redir);
- X Execute(runq->argv->words, searchpath(runq->argv->words->word));
- X poplist();
- X}
- void
- execfunc(var *func)
- X{
- X word *starval;
- X popword();
- X starval = runq->argv->words;
- X runq->argv->words = 0;
- X poplist();
- X start(func->fn, func->pc, (struct var *)0);
- X runq->local = newvar(strdup("*"), runq->local);
- X runq->local->val = starval;
- X runq->local->changed = 1;
- X}
- int
- dochdir(char *word)
- X{
- X /* report to /dev/wdir if it exists and we're interactive */
- X static int wdirfd = -2;
- X if(chdir(word)<0) return -1;
- X if(flag['i']!=0){
- X if(wdirfd==-2) /* try only once */
- X /* TODO: arrange close-on-exec on Unix */
- X wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
- X if(wdirfd>=0)
- X write(wdirfd, word, strlen(word));
- X }
- X return 1;
- X}
- void
- execcd(void)
- X{
- X word *a = runq->argv->words;
- X word *cdpath;
- X char dir[512];
- X setstatus("can't cd");
- X cdpath = vlook("cdpath")->val;
- X switch(count(a)){
- X default:
- X pfmt(err, "Usage: cd [directory]\n");
- X break;
- X case 2:
- X if(a->next->word[0]=='/' || cdpath==0)
- X cdpath=&nullpath;
- X for(;cdpath;cdpath = cdpath->next){
- X strcpy(dir, cdpath->word);
- X if(dir[0])
- X strcat(dir, "/");
- X strcat(dir, a->next->word);
- X if(dochdir(dir)>=0){
- X if(strlen(cdpath->word)
- X && strcmp(cdpath->word, ".")!=0)
- X pfmt(err, "%s\n", dir);
- X setstatus("");
- X break;
- X }
- X }
- X if(cdpath==0)
- X pfmt(err, "Can't cd %s: %r\n", a->next->word);
- X break;
- X case 1:
- X a = vlook("home")->val;
- X if(count(a)>=1){
- X if(dochdir(a->word)>=0)
- X setstatus("");
- X else
- X pfmt(err, "Can't cd %s: %r\n", a->word);
- X }
- X else
- X pfmt(err, "Can't cd -- $home empty\n");
- X break;
- X }
- X poplist();
- X}
- void
- execexit(void)
- X{
- X switch(count(runq->argv->words)){
- X default:
- X pfmt(err, "Usage: exit [status]\nExiting anyway\n");
- X case 2:
- X setstatus(runq->argv->words->next->word);
- X case 1: Xexit();
- X }
- X}
- void
- execshift(void)
- X{
- X int n;
- X word *a;
- X var *star;
- X switch(count(runq->argv->words)){
- X default:
- X pfmt(err, "Usage: shift [n]\n");
- X setstatus("shift usage");
- X poplist();
- X return;
- X case 2:
- X n = atoi(runq->argv->words->next->word);
- X break;
- X case 1:
- X n = 1;
- X break;
- X }
- X star = vlook("*");
- X for(;n && star->val;--n){
- X a = star->val->next;
- X efree(star->val->word);
- X efree((char *)star->val);
- X star->val = a;
- X star->changed = 1;
- X }
- X setstatus("");
- X poplist();
- X}
- int
- octal(char *s)
- X{
- X int n = 0;
- X while(*s==' ' || *s=='\t' || *s=='\n') s++;
- X while('0'<=*s && *s<='7') n = n*8+*s++-'0';
- X return n;
- X}
- int
- mapfd(int fd)
- X{
- X redir *rp;
- X for(rp = runq->redir;rp;rp = rp->next){
- X switch(rp->type){
- X case RCLOSE:
- X if(rp->from==fd)
- X fd=-1;
- X break;
- X case RDUP:
- X case ROPEN:
- X if(rp->to==fd)
- X fd = rp->from;
- X break;
- X }
- X }
- X return fd;
- X}
- union code rdcmds[4];
- void
- execcmds(io *f)
- X{
- X static int first = 1;
- X if(first){
- X rdcmds[0].i = 1;
- X rdcmds[1].f = Xrdcmds;
- X rdcmds[2].f = Xreturn;
- X first = 0;
- X }
- X start(rdcmds, 1, runq->local);
- X runq->cmdfd = f;
- X runq->iflast = 0;
- X}
- void
- execeval(void)
- X{
- X char *cmdline, *s, *t;
- X int len = 0;
- X word *ap;
- X if(count(runq->argv->words)<=1){
- X Xerror1("Usage: eval cmd ...");
- X return;
- X }
- X eflagok = 1;
- X for(ap = runq->argv->words->next;ap;ap = ap->next)
- X len+=1+strlen(ap->word);
- X cmdline = emalloc(len);
- X s = cmdline;
- X for(ap = runq->argv->words->next;ap;ap = ap->next){
- X for(t = ap->word;*t;) *s++=*t++;
- X *s++=' ';
- X }
- X s[-1]='\n';
- X poplist();
- X execcmds(opencore(cmdline, len));
- X efree(cmdline);
- X}
- union code dotcmds[14];
- void
- execdot(void)
- X{
- X int iflag = 0;
- X int fd;
- X list *av;
- X thread *p = runq;
- X char *zero;
- X static int first = 1;
- X char file[512];
- X word *path;
- X if(first){
- X dotcmds[0].i = 1;
- X dotcmds[1].f = Xmark;
- X dotcmds[2].f = Xword;
- X dotcmds[3].s="0";
- X dotcmds[4].f = Xlocal;
- X dotcmds[5].f = Xmark;
- X dotcmds[6].f = Xword;
- X dotcmds[7].s="*";
- X dotcmds[8].f = Xlocal;
- X dotcmds[9].f = Xrdcmds;
- X dotcmds[10].f = Xunlocal;
- X dotcmds[11].f = Xunlocal;
- X dotcmds[12].f = Xreturn;
- X first = 0;
- X }
- X else
- X eflagok = 1;
- X popword();
- X if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
- X iflag = 1;
- X popword();
- X }
- X /* get input file */
- X if(p->argv->words==0){
- X Xerror1("Usage: . [-i] file [arg ...]");
- X return;
- X }
- X zero = strdup(p->argv->words->word);
- X popword();
- X fd=-1;
- X for(path = searchpath(zero);path;path = path->next){
- X strcpy(file, path->word);
- X if(file[0])
- X strcat(file, "/");
- X strcat(file, zero);
- X if((fd = open(file, 0))>=0) break;
- X if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
- X fd = Dup1(0);
- X if(fd>=0)
- X break;
- X }
- X }
- X if(fd<0){
- X pfmt(err, "%s: ", zero);
- X setstatus("can't open");
- X Xerror(".: can't open");
- X return;
- X }
- X /* set up for a new command loop */
- X start(dotcmds, 1, (struct var *)0);
- X pushredir(RCLOSE, fd, 0);
- X runq->cmdfile = zero;
- X runq->cmdfd = openfd(fd);
- X runq->iflag = iflag;
- X runq->iflast = 0;
- X /* push $* value */
- X pushlist();
- X runq->argv->words = p->argv->words;
- X /* free caller's copy of $* */
- X av = p->argv;
- X p->argv = av->next;
- X efree((char *)av);
- X /* push $0 value */
- X pushlist();
- X pushword(zero);
- X ndot++;
- X}
- void
- execflag(void)
- X{
- X char *letter, *val;
- X switch(count(runq->argv->words)){
- X case 2:
- X setstatus(flag[runq->argv->words->next->word[0]]?"":"flag not set");
- X break;
- X case 3:
- X letter = runq->argv->words->next->word;
- X val = runq->argv->words->next->next->word;
- X if(strlen(letter)==1){
- X if(strcmp(val, "+")==0){
- X flag[letter[0]] = flagset;
- X break;
- X }
- X if(strcmp(val, "-")==0){
- X flag[letter[0]] = 0;
- X break;
- X }
- X }
- X default:
- X Xerror1("Usage: flag [letter] [+-]");
- X return;
- X }
- X poplist();
- X}
- void
- execwhatis(void){ /* mildly wrong -- should fork before writing */
- X word *a, *b, *path;
- X var *v;
- X struct builtin *bp;
- X char file[512];
- X struct io out[1];
- X int found, sep;
- X a = runq->argv->words->next;
- X if(a==0){
- X Xerror1("Usage: whatis name ...");
- X return;
- X }
- X setstatus("");
- X out->fd = mapfd(1);
- X out->bufp = out->buf;
- X out->ebuf = &out->buf[NBUF];
- X out->strp = 0;
- X for(;a;a = a->next){
- X v = vlook(a->word);
- X if(v->val){
- X pfmt(out, "%s=", a->word);
- X if(v->val->next==0)
- X pfmt(out, "%q\n", v->val->word);
- X else{
- X sep='(';
- X for(b = v->val;b && b->word;b = b->next){
- X pfmt(out, "%c%q", sep, b->word);
- X sep=' ';
- X }
- X pfmt(out, ")\n");
- X }
- X found = 1;
- X }
- X else
- X found = 0;
- X v = gvlook(a->word);
- X if(v->fn)
- X pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
- X else{
- X for(bp = Builtin;bp->name;bp++)
- X if(strcmp(a->word, bp->name)==0){
- X pfmt(out, "builtin %s\n", a->word);
- X break;
- X }
- X if(!bp->name){
- X for(path = searchpath(a->word);path;path = path->next){
- X strcpy(file, path->word);
- X if(file[0])
- X strcat(file, "/");
- X strcat(file, a->word);
- X if(Executable(file)){
- X pfmt(out, "%s\n", file);
- X break;
- X }
- X }
- X if(!path && !found){
- X pfmt(err, "%s: not found\n", a->word);
- X setstatus("not found");
- X }
- X }
- X }
- X }
- X poplist();
- X flush(err);
- X}
- void
- execwait(void)
- X{
- X switch(count(runq->argv->words)){
- X default:
- X Xerror1("Usage: wait [pid]");
- X return;
- X case 2:
- X Waitfor(atoi(runq->argv->words->next->word), 0);
- X break;
- X case 1:
- X Waitfor(-1, 0);
- X break;
- X }
- X poplist();
- X}
- !
- echo havefork.c
- sed 's/^X//' >havefork.c <<'!'
- X#include "rc.h"
- X#include "getflags.h"
- X#include "exec.h"
- X#include "io.h"
- X#include "fns.h"
- int havefork = 1;
- void
- XXasync(void)
- X{
- X int null = open("/dev/null", 0);
- X int pid;
- X char npid[10];
- X if(null<0){
- X Xerror("Can't open /dev/null\n");
- X return;
- X }
- X#ifdef Unix
- X pid = fork();
- X#else
- X pid = rfork(RFFDG|RFPROC|RFNOTEG);
- X#endif
- X switch(pid){
- X case -1:
- X close(null);
- X Xerror("try again");
- X break;
- X case 0:
- X pushredir(ROPEN, null, 0);
- X start(runq->code, runq->pc+1, runq->local);
- X runq->ret = 0;
- X break;
- X default:
- X close(null);
- X runq->pc = runq->code[runq->pc].i;
- X inttoascii(npid, pid);
- X setvar("apid", newword(npid, (word *)0));
- X break;
- X }
- X}
- void
- XXpipe(void)
- X{
- X struct thread *p = runq;
- X int pc = p->pc, forkid;
- X int lfd = p->code[pc++].i;
- X int rfd = p->code[pc++].i;
- X int pfd[2];
- X if(pipe(pfd)<0){
- X Xerror("can't get pipe");
- X return;
- X }
- X switch(forkid = fork()){
- X case -1:
- X Xerror("try again");
- X break;
- X case 0:
- X start(p->code, pc+2, runq->local);
- X runq->ret = 0;
- X close(pfd[PRD]);
- X pushredir(ROPEN, pfd[PWR], lfd);
- X break;
- X default:
- X start(p->code, p->code[pc].i, runq->local);
- X close(pfd[PWR]);
- X pushredir(ROPEN, pfd[PRD], rfd);
- X p->pc = p->code[pc+1].i;
- X p->pid = forkid;
- X break;
- X }
- X}
- X/*
- X * Who should wait for the exit from the fork?
- X */
- void
- XXbackq(void)
- X{
- X char wd[8193];
- X int c;
- X char *s, *ewd=&wd[8192], *stop;
- X struct io *f;
- X var *ifs = vlook("ifs");
- X word *v, *nextv;
- X int pfd[2];
- X int pid;
- X stop = ifs->val?ifs->val->word:"";
- X if(pipe(pfd)<0){
- X Xerror("can't make pipe");
- X return;
- X }
- X switch(pid = fork()){
- X case -1:
- X Xerror("try again");
- X close(pfd[PRD]);
- X close(pfd[PWR]);
- X return;
- X case 0:
- X close(pfd[PRD]);
- X start(runq->code, runq->pc+1, runq->local);
- X pushredir(ROPEN, pfd[PWR], 1);
- X return;
- X default:
- X close(pfd[PWR]);
- X f = openfd(pfd[PRD]);
- X s = wd;
- X v = 0;
- X while((c = rchr(f))!=EOF){
- X if(strchr(stop, c) || s==ewd){
- X if(s!=wd){
- X *s='\0';
- X v = newword(wd, v);
- X s = wd;
- X }
- X }
- X else *s++=c;
- X }
- X if(s!=wd){
- X *s='\0';
- X v = newword(wd, v);
- X }
- X closeio(f);
- X Waitfor(pid, 0);
- X /* v points to reversed arglist -- reverse it onto argv */
- X while(v){
- X nextv = v->next;
- X v->next = runq->argv->words;
- X runq->argv->words = v;
- X v = nextv;
- X }
- X runq->pc = runq->code[runq->pc].i;
- X return;
- X }
- X}
- void
- XXpipefd(void)
- X{
- X struct thread *p = runq;
- X int pc = p->pc;
- X char name[40];
- X int pfd[2];
- X int sidefd, mainfd;
- X if(pipe(pfd)<0){
- X Xerror("can't get pipe");
- X return;
- X }
- X if(p->code[pc].i==READ){
- X sidefd = pfd[PWR];
- X mainfd = pfd[PRD];
- X }
- X else{
- X sidefd = pfd[PRD];
- X mainfd = pfd[PWR];
- X }
- X switch(fork()){
- X case -1:
- X Xerror("try again");
- X break;
- X case 0:
- X start(p->code, pc+2, runq->local);
- X close(mainfd);
- X pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
- X runq->ret = 0;
- X break;
- X default:
- X close(sidefd);
- X pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
- X strcpy(name, Fdprefix);
- X inttoascii(name+strlen(name), mainfd);
- X pushword(name);
- X p->pc = p->code[pc+1].i;
- X break;
- X }
- X}
- void
- XXsubshell(void)
- X{
- X int pid;
- X switch(pid = fork()){
- X case -1:
- X Xerror("try again");
- X break;
- X case 0:
- X start(runq->code, runq->pc+1, runq->local);
- X runq->ret = 0;
- X break;
- X default:
- X Waitfor(pid, 1);
- X runq->pc = runq->code[runq->pc].i;
- X break;
- X }
- X}
- int
- execforkexec(void)
- X{
- X int pid;
- X int n;
- X char buf[ERRMAX];
- X switch(pid = fork()){
- X case -1:
- X return -1;
- X case 0:
- X pushword("exec");
- X execexec();
- X strcpy(buf, "can't exec: ");
- X n = strlen(buf);
- X errstr(buf+n, ERRMAX-n);
- X Exit(buf);
- X }
- X return pid;
- X}
- !
- echo rc.h
- sed 's/^X//' >rc.h <<'!'
- X/*
- X * Plan9 is defined for plan 9
- X * V9 is defined for 9th edition
- X * Sun is defined for sun-os
- X * Please don't litter the code with ifdefs. The three below should be enough.
- X */
- X#define Unix
- X#ifdef Plan9
- X#include <u.h>
- X#include <libc.h>
- X#define NSIG 32
- X#define SIGINT 2
- X#define SIGQUIT 3
- X#endif
- X#ifdef Unix
- X#define _POSIX_SOURCE
- X#define _BSD_EXTENSION
- X#include <stdlib.h>
- X#include <stdarg.h>
- X#include <string.h>
- X#include <unistd.h>
- X#include <fcntl.h>
- X#include <lib9.h>
- X#include <signal.h>
- X#endif
- X#ifndef ERRMAX
- X#define ERRMAX 128
- X#endif
- X#define YYMAXDEPTH 500
- X#ifndef PAREN
- X#include "x.tab.h"
- X#endif
- typedef struct tree tree;
- typedef struct word word;
- typedef struct io io;
- typedef union code code;
- typedef struct var var;
- typedef struct list list;
- typedef struct redir redir;
- typedef struct thread thread;
- typedef struct builtin builtin;
- struct tree{
- X int type;
- X int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
- X char *str;
- X int quoted;
- X int iskw;
- X tree *child[3];
- X tree *next;
- X};
- tree *newtree(void);
- tree *token(char*, int), *klook(char*), *tree1(int, tree*);
- tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
- tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
- tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
- tree *simplemung(tree*), *heredoc(tree*);
- void freetree(tree*);
- tree *cmdtree;
- X/*
- X * The first word of any code vector is a reference count.
- X * Always create a new reference to a code vector by calling codecopy(.).
- X * Always call codefree(.) when deleting a reference.
- X */
- union code{
- X void (*f)(void);
- X int i;
- X char *s;
- X};
- char *promptstr;
- int doprompt;
- X#define NTOK 8192
- char tok[NTOK];
- X#define APPEND 1
- X#define WRITE 2
- X#define READ 3
- X#define HERE 4
- X#define DUPFD 5
- X#define CLOSE 6
- struct var{
- X char *name; /* ascii name */
- X word *val; /* value */
- X int changed;
- X code *fn; /* pointer to function's code vector */
- X int fnchanged;
- X int pc; /* pc of start of function */
- X var *next; /* next on hash or local list */
- X};
- var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
- X#define NVAR 521
- var *gvar[NVAR]; /* hash for globals */
- X#define new(type) ((type *)emalloc(sizeof(type)))
- char *emalloc(long);
- void *Malloc(ulong);
- void efree(char*);
- X#define NOFILE 128 /* should come from <param.h> */
- struct here{
- X tree *tag;
- X char *name;
- X struct here *next;
- X};
- int mypid;
- X/*
- X * Glob character escape in strings:
- X * In a string, GLOB must be followed by *?[ or GLOB.
- X * GLOB* matches any string
- X * GLOB? matches any single character
- X * GLOB[...] matches anything in the brackets
- X * GLOBGLOB matches GLOB
- X */
- X#define GLOB ((char)0x01)
- X/*
- X * onebyte(c), twobyte(c), threebyte(c)
- X * Is c the first character of a one- two- or three-byte utf sequence?
- X */
- X#define onebyte(c) ((c&0x80)==0x00)
- X#define twobyte(c) ((c&0xe0)==0xc0)
- X#define threebyte(c) ((c&0xf0)==0xe0)
- char **argp;
- char **args;
- int nerror; /* number of errors encountered during compilation */
- int doprompt; /* is it time for a prompt? */
- X/*
- X * Which fds are the reading/writing end of a pipe?
- X * Unfortunately, this can vary from system to system.
- X * 9th edition Unix doesn't care, the following defines
- X * work on plan 9.
- X */
- X#define PRD 0
- X#define PWR 1
- char Rcmain[], Fdprefix[];
- X#define register
- X/*
- X * How many dot commands have we executed?
- X * Used to ensure that -v flag doesn't print rcmain.
- X */
- int ndot;
- char *getstatus(void);
- int lastc;
- int lastword;
- !
- echo unix.c
- sed 's/^X//' >unix.c <<'!'
- X/*
- X * Unix versions of system-specific functions
- X * By convention, exported routines herein have names beginning with an
- X * upper case letter.
- X */
- X#include "rc.h"
- X#include "io.h"
- X#include "exec.h"
- X#include "getflags.h"
- X#include <errno.h>
- char Rcmain[]="/usr/lib/rcmain";
- char Fdprefix[]="/dev/fd/";
- void execfinit(void);
- struct builtin Builtin[] = {
- X "cd", execcd,
- X "whatis", execwhatis,
- X "eval", execeval,
- X "exec", execexec, /* but with popword first */
- X "exit", execexit,
- X "shift", execshift,
- X "wait", execwait,
- X "umask", execumask,
- X ".", execdot,
- X "finit", execfinit,
- X "flag", execflag,
- X 0
- X};
- X#define SEP '\1'
- char **environp;
- struct word*
- enval(s)
- register char *s;
- X{
- X char *t, c;
- X struct word *v;
- X for(t = s;*t && *t!=SEP;t++);
- X c=*t;
- X *t='\0';
- X v = newword(s, c=='\0'?(struct word *)0:enval(t+1));
- X *t = c;
- X return v;
- X}
- void
- Vinit(void)
- X{
- X extern char **environ;
- X char *s;
- X char **env = environ;
- X environp = env;
- X for(;*env;env++){
- X for(s=*env;*s && *s!='(' && *s!='=';s++);
- X switch(*s){
- X case '\0':
- X pfmt(err, "environment %q?\n", *env);
- X break;
- X case '=':
- X *s='\0';
- X setvar(*env, enval(s+1));
- X *s='=';
- X break;
- X case '(': /* ignore functions for now */
- X break;
- X }
- X }
- X}
- char **envp;
- void
- XXrdfn(void)
- X{
- X char *s;
- X int len;
- X for(;*envp;envp++){
- X for(s=*envp;*s && *s!='(' && *s!='=';s++);
- X switch(*s){
- X case '\0':
- X pfmt(err, "environment %q?\n", *envp);
- X break;
- X case '=': /* ignore variables */
- X break;
- X case '(': /* Bourne again */
- X s=*envp+3;
- X envp++;
- X len = strlen(s);
- X s[len]='\n';
- X execcmds(opencore(s, len+1));
- X s[len]='\0';
- X return;
- X }
- X }
- X Xreturn();
- X}
- union code rdfns[4];
- void
- execfinit(void)
- X{
- X static int first = 1;
- X if(first){
- X rdfns[0].i = 1;
- X rdfns[1].f = Xrdfn;
- X rdfns[2].f = Xjump;
- X rdfns[3].i = 1;
- X first = 0;
- X }
- X Xpopm();
- X envp = environp;
- X start(rdfns, 1, runq->local);
- X}
- int
- cmpenv(const void *aa, const void *ab)
- X{
- X char **a = aa, **b = ab;
- X return strcmp(*a, *b);
- X}
- char **
- mkenv(void)
- X{
- X char **env, **ep, *p, *q;
- X struct var **h, *v;
- X struct word *a;
- X int nvar = 0, nchr = 0, sep;
- X /*
- X * Slightly kludgy loops look at locals then globals.
- X * locals no longer exist - geoff
- X */
- X for(h = gvar-1; h != &gvar[NVAR]; h++)
- X for(v = h >= gvar? *h: runq->local; v ;v = v->next){
- X if((v==vlook(v->name)) && v->val){
- X nvar++;
- X nchr+=strlen(v->name)+1;
- X for(a = v->val;a;a = a->next)
- X nchr+=strlen(a->word)+1;
- X }
- X if(v->fn){
- X nvar++;
- X nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
- X }
- X }
- X env = (char **)emalloc((nvar+1)*sizeof(char *)+nchr);
- X ep = env;
- X p = (char *)&env[nvar+1];
- X for(h = gvar-1; h != &gvar[NVAR]; h++)
- X for(v = h >= gvar? *h: runq->local;v;v = v->next){
- X if((v==vlook(v->name)) && v->val){
- X *ep++=p;
- X q = v->name;
- X while(*q) *p++=*q++;
- X sep='=';
- X for(a = v->val;a;a = a->next){
- X *p++=sep;
- X sep = SEP;
- X q = a->word;
- X while(*q) *p++=*q++;
- X }
- X *p++='\0';
- X }
- X if(v->fn){
- X *ep++=p;
- X *p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
- X *p++='f'; *p++='n'; *p++=' ';
- X q = v->name;
- X while(*q) *p++=*q++;
- X *p++=' ';
- X q = v->fn[v->pc-1].s;
- X while(*q) *p++=*q++;
- X *p++='\0';
- X }
- X }
- X *ep = 0;
- X qsort((void *)env, nvar, sizeof ep[0], cmpenv);
- X return env;
- X}
- char *sigmsg[] = {
- X/* 0 normal */ 0,
- X/* 1 SIGHUP */ "Hangup",
- X/* 2 SIGINT */ 0,
- X/* 3 SIGQUIT */ "Quit",
- X/* 4 SIGILL */ "Illegal instruction",
- X/* 5 SIGTRAP */ "Trace/BPT trap",
- X/* 6 SIGIOT */ "abort",
- X/* 7 SIGEMT */ "EMT trap",
- X/* 8 SIGFPE */ "Floating exception",
- X/* 9 SIGKILL */ "Killed",
- X/* 10 SIGBUS */ "Bus error",
- X/* 11 SIGSEGV */ "Memory fault",
- X/* 12 SIGSYS */ "Bad system call",
- X/* 13 SIGPIPE */ 0,
- X/* 14 SIGALRM */ "Alarm call",
- X/* 15 SIGTERM */ "Terminated",
- X/* 16 unused */ "signal 16",
- X/* 17 SIGSTOP */ "Process stopped",
- X/* 18 unused */ "signal 18",
- X/* 19 SIGCONT */ "Process continued",
- X/* 20 SIGCHLD */ "Child death",
- X};
- void
- Waitfor(int pid, int persist)
- X{
- X int wpid, sig;
- X struct thread *p;
- X int wstat;
- X char wstatstr[12];
- X for(;;){
- X errno = 0;
- X wpid = wait(&wstat);
- X if(errno==EINTR && persist)
- X continue;
- X if(wpid==-1)
- X break;
- X sig = wstat&0177;
- X if(sig==0177){
- X pfmt(err, "trace: ");
- X sig = (wstat>>8)&0177;
- X }
- X if(sig>(sizeof sigmsg/sizeof sigmsg[0]) || sigmsg[sig]){
- X if(pid!=wpid)
- X pfmt(err, "%d: ", wpid);
- X if(sig<=(sizeof sigmsg/sizeof sigmsg[0]))
- X pfmt(err, "%s", sigmsg[sig]);
- X else if(sig==0177) pfmt(err, "stopped by ptrace");
- X else pfmt(err, "signal %d", sig);
- X if(wstat&0200)pfmt(err, " -- core dumped");
- X pfmt(err, "\n");
- X }
- X wstat = sig?sig+1000:(wstat>>8)&0xFF;
- X if(wpid==pid){
- X inttoascii(wstatstr, wstat);
- X setstatus(wstatstr);
- X break;
- X }
- X else{
- X for(p = runq->ret;p;p = p->ret)
- X if(p->pid==wpid){
- X p->pid=-1;
- X inttoascii(p->status, wstat);
- X break;
- X }
- X }
- X }
- X}
- char **
- mkargv(a)
- register struct word *a;
- X{
- X char **argv = (char **)emalloc((count(a)+2)*sizeof(char *));
- X char **argp = argv+1; /* leave one at front for runcoms */
- X for(;a;a = a->next)
- X *argp++=a->word;
- X *argp = 0;
- X return argv;
- X}
- void
- Updenv(void)
- X{
- X}
- void
- Execute(struct word *args, struct word *path)
- X{
- X char *msg="not found";
- X#ifdef ETXTBSY
- X int txtbusy = 0;
- X#endif
- X char **env = mkenv();
- X char **argv = mkargv(args);
- X char file[512];
- X for(;path;path = path->next){
- X strcpy(file, path->word);
- X if(file[0])
- X strcat(file, "/");
- X strcat(file, argv[1]);
- X#ifdef ETXTBSY
- ReExec:
- X#endif
- X execve(file, argv+1, env);
- X switch(errno){
- X case ENOEXEC:
- X pfmt(err, "%s: Bourne again\n", argv[1]);
- X argv[0]="sh";
- X argv[1] = strdup(file);
- X execve("/bin/sh", argv, env);
- X goto Bad;
- X#ifdef ETXTBSY
- X case ETXTBSY:
- X if(++txtbusy!=5){
- X sleep(txtbusy);
- X goto ReExec;
- X }
- X msg="text busy"; goto Bad;
- X#endif
- X case EACCES:
- X msg="no access";
- X break;
- X case ENOMEM:
- X msg="not enough memory"; goto Bad;
- X case E2BIG:
- X msg="too big"; goto Bad;
- X }
- X }
- Bad:
- X pfmt(err, "%s: %s\n", argv[1], msg);
- X efree((char *)env);
- X efree((char *)argv);
- X}
- X#define NDIR 14 /* should get this from param.h */
- Globsize(p)
- register char *p;
- X{
- X int isglob = 0, globlen = NDIR+1;
- X for(;*p;p++){
- X if(*p==GLOB){
- X p++;
- X if(*p!=GLOB)
- X isglob++;
- X globlen+=*p=='*'?NDIR:1;
- X }
- X else
- X globlen++;
- X }
- X return isglob?globlen:0;
- X}
- X#include <sys/types.h>
- X#include <dirent.h>
- X#define NDIRLIST 50
- DIR *dirlist[NDIRLIST];
- Opendir(name)
- char *name;
- X{
- X DIR **dp;
- X for(dp = dirlist;dp!=&dirlist[NDIRLIST];dp++)
- X if(*dp==0){
- X *dp = opendir(name);
- X return *dp?dp-dirlist:-1;
- X }
- X return -1;
- X}
- int
- Readdir(int f, char *p, int /* onlydirs */ )
- X{
- X struct dirent *dp = readdir(dirlist[f]);
- X if(dp==0)
- X return 0;
- X strcpy(p, dp->d_name);
- X return 1;
- X}
- void
- Closedir(int f)
- X{
- X closedir(dirlist[f]);
- X dirlist[f] = 0;
- X}
- char *Signame[] = {
- X "sigexit", "sighup", "sigint", "sigquit",
- X "sigill", "sigtrap", "sigiot", "sigemt",
- X "sigfpe", "sigkill", "sigbus", "sigsegv",
- X "sigsys", "sigpipe", "sigalrm", "sigterm",
- X "sig16", "sigstop", "sigtstp", "sigcont",
- X "sigchld", "sigttin", "sigttou", "sigtint",
- X "sigxcpu", "sigxfsz", "sig26", "sig27",
- X "sig28", "sig29", "sig30", "sig31",
- X 0,
- X};
- void
- gettrap(int sig)
- X{
- X signal(sig, gettrap);
- X trap[sig]++;
- X ntrap++;
- X if(ntrap>=NSIG){
- X pfmt(err, "rc: Too many traps (trap %d), dumping core\n", sig);
- X signal(SIGABRT, (void (*)())0);
- X kill(getpid(), SIGABRT);
- X }
- X}
- void
- Trapinit(void)
- X{
- X int i;
- X void (*sig)();
- X if(1 || flag['d']){ /* wrong!!! */
- X sig = signal(SIGINT, gettrap);
- X if(sig==SIG_IGN)
- X signal(SIGINT, SIG_IGN);
- X }
- X else{
- X for(i = 1;i<=NSIG;i++) if(i!=SIGCHLD){
- X sig = signal(i, gettrap);
- X if(sig==SIG_IGN)
- X signal(i, SIG_IGN);
- X }
- X }
- X}
- Unlink(name)
- char *name;
- X{
- X return unlink(name);
- X}
- Write(fd, buf, cnt)
- char *buf;
- X{
- X return write(fd, buf, cnt);
- X}
- Read(fd, buf, cnt)
- char *buf;
- X{
- X return read(fd, buf, cnt);
- X}
- Seek(fd, cnt, whence)
- long cnt;
- X{
- X return lseek(fd, cnt, whence);
- X}
- Executable(file)
- char *file;
- X{
- X return(access(file, 01)==0);
- X}
- Creat(file)
- char *file;
- X{
- X return creat(file, 0666);
- X}
- Dup(a, b){
- X return dup2(a, b);
- X}
- Dup1(a){
- X return dup(a);
- X}
- X/*
- X * Wrong: should go through components of a|b|c and return the maximum.
- X */
- void
- Exit(char *stat)
- X{
- X int n = 0;
- X while(*stat){
- X if(*stat!='|'){
- X if(*stat<'0' || '9'<*stat)
- X exit(1);
- X else n = n*10+*stat-'0';
- X }
- X stat++;
- X }
- X exit(n);
- X}
- Eintr(){
- X return errno==EINTR;
- X}
- void
- Noerror()
- X{
- X errno = 0;
- X}
- Isatty(fd){
- X return isatty(fd);
- X}
- void
- Abort()
- X{
- X abort();
- X}
- void
- execumask(void) /* wrong -- should fork before writing */
- X{
- X int m;
- X struct io out[1];
- X switch(count(runq->argv->words)){
- X default:
- X pfmt(err, "Usage: umask [umask]\n");
- X setstatus("umask usage");
- X poplist();
- X return;
- X case 2:
- X umask(octal(runq->argv->words->next->word));
- X break;
- X case 1:
- X umask(m = umask(0));
- X out->fd = mapfd(1);
- X out->bufp = out->buf;
- X out->ebuf=&out->buf[NBUF];
- X out->strp = 0;
- X pfmt(out, "%o\n", m);
- X break;
- X }
- X setstatus("");
- X poplist();
- X}
- void
- Memcpy(a, b, n)
- char *a, *b;
- X{
- X memmove(a, b, n);
- X}
- void*
- Malloc(unsigned long n)
- X{
- X return (void *)malloc(n);
- X}
- void
- errstr(char *buf, int len)
- X{
- X strncpy(buf, strerror(errno), len);
- X}
- !
- From geoff@collyer.net Fri Dec 19 01:23:26 EST 2003
- Received: from plan9.cs.bell-labs.com ([135.104.9.2]) by plan9; Fri Dec 19 01:23:25 EST 2003
- Received: from collyer.net ([63.192.14.226]) by plan9; Fri Dec 19 01:23:22 EST 2003
- Message-ID: <0b5ea130198a21a49139759d00d69939@collyer.net>
- subject: rc on unix, part 2
- From: Geoff Collyer <geoff@collyer.net>
- Date: Thu, 18 Dec 2003 22:23:21 -0800
- To: presotto@plan9.bell-labs.com, rsc@plan9.bell-labs.com, geoff@collyer.net
- MIME-Version: 1.0
- Content-Type: text/plain; charset="US-ASCII"
- Content-Transfer-Encoding: 7bit
- These are the include files I used to emulate plan 9's include
- files on Unix (APE).
- # To unbundle, run this file
- mkdir include
- echo include/bio.h
- sed 's/^X//' >include/bio.h <<'!'
- X#ifndef _BIOH_
- X#define _BIOH_ 1
- X#include <sys/types.h> /* for off_t */
- X#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
- typedef struct Biobuf Biobuf;
- enum
- X{
- X Bsize = 8*1024,
- X Bungetsize = 4, /* space for ungetc */
- X Bmagic = 0x314159,
- X Beof = -1,
- X Bbad = -2,
- X Binactive = 0, /* states */
- X Bractive,
- X Bwactive,
- X Bracteof,
- X Bend
- X};
- struct Biobuf
- X{
- X int icount; /* neg num of bytes at eob */
- X int ocount; /* num of bytes at bob */
- X int rdline; /* num of bytes after rdline */
- X int runesize; /* num of bytes of last getrune */
- X int state; /* r/w/inactive */
- X int fid; /* open file */
- X int flag; /* magic if malloc'ed */
- X off_t offset; /* offset of buffer in file */
- X int bsize; /* size of buffer */
- X unsigned char* bbuf; /* pointer to beginning of buffer */
- X unsigned char* ebuf; /* pointer to end of buffer */
- X unsigned char* gbuf; /* pointer to good data in buf */
- X unsigned char b[Bungetsize+Bsize];
- X};
- X#define BGETC(bp)\
- X ((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
- X#define BPUTC(bp,c)\
- X ((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
- X#define BOFFSET(bp)\
- X (((bp)->state==Bractive)?\
- X (bp)->offset + (bp)->icount:\
- X (((bp)->state==Bwactive)?\
- X (bp)->offset + ((bp)->bsize + (bp)->ocount):\
- X -1))
- X#define BLINELEN(bp)\
- X (bp)->rdline
- X#define BFILDES(bp)\
- X (bp)->fid
- int Bbuffered(Biobuf*);
- int Bfildes(Biobuf*);
- int Bflush(Biobuf*);
- int Bgetc(Biobuf*);
- int Bgetd(Biobuf*, double*);
- int Binit(Biobuf*, int, int);
- int Binits(Biobuf*, int, int, unsigned char*, int);
- int Blinelen(Biobuf*);
- off_t Boffset(Biobuf*);
- Biobuf* Bopen(char*, int);
- int Bprint(Biobuf*, char*, ...);
- int Bputc(Biobuf*, int);
- void* Brdline(Biobuf*, int);
- long Bread(Biobuf*, void*, long);
- off_t Bseek(Biobuf*, off_t, int);
- int Bterm(Biobuf*);
- int Bungetc(Biobuf*);
- long Bwrite(Biobuf*, void*, long);
- long Bgetrune(Biobuf*);
- int Bputrune(Biobuf*, long);
- int Bungetrune(Biobuf*);
- X#endif
- !
- echo include/fmt.h
- sed 's/^X//' >include/fmt.h <<'!'
- X/*
- X * The authors of this software are Rob Pike and Ken Thompson.
- X * Copyright (c) 2002 by Lucent Technologies.
- X * Permission to use, copy, modify, and distribute this software for any
- X * purpose without fee is hereby granted, provided that this entire notice
- X * is included in all copies of any software which is or includes a copy
- X * or modification of this software and in all copies of the supporting
- X * documentation for such software.
- X * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- X * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- X * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- X * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- X */
- X#ifndef _FMTH_
- X#define _FMTH_ 1
- X#include <stdarg.h>
- X#ifndef _UTFH_
- X#include <utf.h>
- X#endif
- typedef struct Fmt Fmt;
- struct Fmt{
- X unsigned char runes; /* output buffer is runes or chars? */
- X void *start; /* of buffer */
- X void *to; /* current place in the buffer */
- X void *stop; /* end of the buffer; overwritten if flush fails */
- X int (*flush)(Fmt *); /* called when to == stop */
- X void *farg; /* to make flush a closure */
- X int nfmt; /* num chars formatted so far */
- X va_list args; /* args passed to dofmt */
- X int r; /* % format Rune */
- X int width;
- X int prec;
- X unsigned long flags;
- X};
- enum{
- X FmtWidth = 1,
- X FmtLeft = FmtWidth << 1,
- X FmtPrec = FmtLeft << 1,
- X FmtSharp = FmtPrec << 1,
- X FmtSpace = FmtSharp << 1,
- X FmtSign = FmtSpace << 1,
- X FmtZero = FmtSign << 1,
- X FmtUnsigned = FmtZero << 1,
- X FmtShort = FmtUnsigned << 1,
- X FmtLong = FmtShort << 1,
- X FmtVLong = FmtLong << 1,
- X FmtComma = FmtVLong << 1,
- X FmtByte = FmtComma << 1,
- X FmtLDouble = FmtByte << 1,
- X FmtFlag = FmtLDouble << 1
- X};
- extern int print(char*, ...);
- extern char* seprint(char*, char*, char*, ...);
- extern char* vseprint(char*, char*, char*, va_list);
- extern int snprint(char*, int, char*, ...);
- extern int vsnprint(char*, int, char*, va_list);
- extern char* smprint(char*, ...);
- extern char* vsmprint(char*, va_list);
- extern int sprint(char*, char*, ...);
- extern int fprint(int, char*, ...);
- extern int vfprint(int, char*, va_list);
- extern int runesprint(Rune*, char*, ...);
- extern int runesnprint(Rune*, int, char*, ...);
- extern int runevsnprint(Rune*, int, char*, va_list);
- extern Rune* runeseprint(Rune*, Rune*, char*, ...);
- extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
- extern Rune* runesmprint(char*, ...);
- extern Rune* runevsmprint(char*, va_list);
- extern int fmtfdinit(Fmt*, int, char*, int);
- extern int fmtfdflush(Fmt*);
- extern int fmtstrinit(Fmt*);
- extern char* fmtstrflush(Fmt*);
- extern int quotestrfmt(Fmt *f);
- extern void quotefmtinstall(void);
- extern int (*fmtdoquote)(int);
- extern int fmtinstall(int, int (*)(Fmt*));
- extern int dofmt(Fmt*, char*);
- extern int fmtprint(Fmt*, char*, ...);
- extern int fmtvprint(Fmt*, char*, va_list);
- extern int fmtrune(Fmt*, int);
- extern int fmtstrcpy(Fmt*, char*);
- extern double fmtstrtod(const char *, char **);
- extern double fmtcharstod(int(*)(void*), void*);
- X#endif
- !
- echo include/lib9.h
- sed 's/^X//' >include/lib9.h <<'!'
- X#include <string.h>
- X#include "utf.h"
- X#define nil ((void*)0)
- X#define uchar _fmtuchar
- X#define ushort _fmtushort
- X#define uint _fmtuint
- X#define ulong _fmtulong
- X#define vlong _fmtvlong
- X#define uvlong _fmtuvlong
- typedef unsigned char uchar;
- typedef unsigned short ushort;
- typedef unsigned int uint;
- typedef unsigned long ulong;
- X#define OREAD O_RDONLY
- X#define OWRITE O_WRONLY
- X#define ORDWR O_RDWR
- X#define OCEXEC 0
- !
- echo include/regexp9.h
- sed 's/^X//' >include/regexp9.h <<'!'
- X#ifndef _REGEXP9H_
- X#define _REGEXP9H_ 1
- X#include <utf.h>
- typedef struct Resub Resub;
- typedef struct Reclass Reclass;
- typedef struct Reinst Reinst;
- typedef struct Reprog Reprog;
- X/*
- X * Sub expression matches
- X */
- struct Resub{
- X union
- X {
- X char *sp;
- X Rune *rsp;
- X }s;
- X union
- X {
- X char *ep;
- X Rune *rep;
- X }e;
- X};
- X/*
- X * character class, each pair of rune's defines a range
- X */
- struct Reclass{
- X Rune *end;
- X Rune spans[64];
- X};
- X/*
- X * Machine instructions
- X */
- struct Reinst{
- X int type;
- X union {
- X Reclass *cp; /* class pointer */
- X Rune r; /* character */
- X int subid; /* sub-expression id for RBRA and LBRA */
- X Reinst *right; /* right child of OR */
- X }u1;
- X union { /* regexp relies on these two being in the same union */
- X Reinst *left; /* left child of OR */
- X Reinst *next; /* next instruction for CAT & LBRA */
- X }u2;
- X};
- X/*
- X * Reprogram definition
- X */
- struct Reprog{
- X Reinst *startinst; /* start pc */
- X Reclass class[16]; /* .data */
- X Reinst firstinst[5]; /* .text */
- X};
- extern Reprog *regcomp(char*);
- extern Reprog *regcomplit(char*);
- extern Reprog *regcompnl(char*);
- extern void regerror(char*);
- extern int regexec(Reprog*, char*, Resub*, int);
- extern void regsub(char*, char*, int, Resub*, int);
- extern int rregexec(Reprog*, Rune*, Resub*, int);
- extern void rregsub(Rune*, Rune*, Resub*, int);
- X#endif
- !
- echo include/utf.h
- sed 's/^X//' >include/utf.h <<'!'
- X#ifndef _UTFH_
- X#define _UTFH_ 1
- typedef unsigned short Rune; /* 16 bits */
- enum
- X{
- X UTFmax = 3, /* maximum bytes per rune */
- X Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
- X Runeself = 0x80, /* rune and UTF sequences are the same (<) */
- X Runeerror = 0x80, /* decoding error in UTF */
- X};
- X/*
- X * rune routines
- X */
- extern int runetochar(char*, Rune*);
- extern int chartorune(Rune*, char*);
- extern int runelen(long);
- extern int runenlen(Rune*, int);
- extern int fullrune(char*, int);
- extern int utflen(char*);
- extern int utfnlen(char*, long);
- extern char* utfrune(char*, long);
- extern char* utfrrune(char*, long);
- extern char* utfutf(char*, char*);
- extern char* utfecpy(char*, char*, char*);
- extern Rune* runestrcat(Rune*, Rune*);
- extern Rune* runestrchr(Rune*, Rune);
- extern int runestrcmp(Rune*, Rune*);
- extern Rune* runestrcpy(Rune*, Rune*);
- extern Rune* runestrncpy(Rune*, Rune*, long);
- extern Rune* runestrecpy(Rune*, Rune*, Rune*);
- extern Rune* runestrdup(Rune*);
- extern Rune* runestrncat(Rune*, Rune*, long);
- extern int runestrncmp(Rune*, Rune*, long);
- extern Rune* runestrrchr(Rune*, Rune);
- extern long runestrlen(Rune*);
- extern Rune* runestrstr(Rune*, Rune*);
- extern Rune tolowerrune(Rune);
- extern Rune totitlerune(Rune);
- extern Rune toupperrune(Rune);
- extern int isalpharune(Rune);
- extern int islowerrune(Rune);
- extern int isspacerune(Rune);
- extern int istitlerune(Rune);
- extern int isupperrune(Rune);
- X#endif
- !
|