9base

revived minimalist port of Plan 9 userland to Unix
git clone git://git.suckless.org/9base
Log | Files | Refs | README | LICENSE

commit abc072187111c9098f80518e9c8d0b81ae1577d0
parent 89cb321008eab13102fa98bd1b28caadc2c5218e
Author: Anselm R Garbe <anselm@garbe.us>
Date:   Fri, 31 Jul 2009 21:02:58 +0100

upgraded 9base to p9p 20090731
Diffstat:
MMakefile | 2+-
Aawk/README | 13+++++++++++++
Mawk/awk.h | 1+
Mawk/awkgram.y | 1+
Mawk/lex.c | 3++-
Mawk/lib.c | 27+++++++++++++++++++++++++++
Mawk/main.c | 3++-
Mawk/maketab.c | 1+
Mawk/parse.c | 1+
Mawk/proto.h | 3+++
Mawk/re.c | 18+++++++++---------
Mawk/run.c | 25++++++++++++++++---------
Mawk/tran.c | 1+
Mbc/bc.1 | 2+-
Mbc/bc.y | 181++++++++++++++++++++++++++++++++++++++++---------------------------------------
Mconfig.mk | 4+++-
Mdc/dc.c | 31++++++++-----------------------
Mgrep/comp.c | 6+++---
Mgrep/main.c | 14+++++++++-----
Mgrep/sub.c | 2+-
Mlib9/Makefile | 199++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---
Mlib9/_exits.c | 6+++---
Mlib9/_p9dialparse.c | 5++---
Mlib9/_p9dir.c | 144+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mlib9/atexit.c | 4+++-
Mlib9/bio.h | 21+++------------------
Mlib9/bio/bbuffered.c | 1-
Mlib9/bio/bflush.c | 1-
Mlib9/bio/bgetc.c | 1-
Mlib9/bio/bgetd.c | 1-
Mlib9/bio/binit.c | 7++-----
Mlib9/bio/boffset.c | 5++---
Mlib9/bio/brdline.c | 1-
Mlib9/bio/brdstr.c | 2--
Mlib9/bio/bread.c | 1-
Mlib9/bio/bseek.c | 11++++-------
Mlib9/bio/bvprint.c | 7+++----
Mlib9/bio/bwrite.c | 1-
Mlib9/bio/lib9.std.h | 8+++++++-
Mlib9/convD2M.c | 61+++++++++++++++++++++++++++++++++++++++++++++++++------------
Mlib9/convM2D.c | 50+++++++++++++++++++++++++++++++++++++++++++-------
Mlib9/convM2S.c | 17++++++++++++++++-
Mlib9/convS2M.c | 28+++++++++++++++++++++++++---
Alib9/crypt.c | 68++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib9/ctime.c | 157++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++---------
Mlib9/debugmalloc.c | 16++++++++--------
Mlib9/dial.c | 21++++++++++++++-------
Mlib9/dirfwstat.c | 6+++++-
Mlib9/dirread.c | 10++++++++--
Mlib9/dirwstat.c | 24++++++++++++++++++------
Mlib9/encodefmt.c | 11++---------
Mlib9/errstr.c | 2+-
Alib9/exitcode.c | 9+++++++++
Mlib9/fcallfmt.c | 4++--
Mlib9/fmt.h | 17++++++++++++++++-
Mlib9/fmt/LICENSE | 19+++++++++++--------
Clib9/fmt/LICENSE -> lib9/fmt/NOTICE | 0
Clib9/fmt/LICENSE -> lib9/fmt/README | 0
Mlib9/fmt/charstod.c | 14+-------------
Mlib9/fmt/dofmt.c | 128+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------
Mlib9/fmt/dorfmt.c | 25+++++++------------------
Mlib9/fmt/errfmt.c | 14+-------------
Mlib9/fmt/fltfmt.c | 748++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mlib9/fmt/fmt.c | 17+++--------------
Mlib9/fmt/fmtdef.h | 27++++++++-------------------
Mlib9/fmt/fmtfd.c | 18++++--------------
Mlib9/fmt/fmtfdflush.c | 16++--------------
Alib9/fmt/fmtlocale.c | 55+++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib9/fmt/fmtlock.c | 14+-------------
Alib9/fmt/fmtnull.c | 33+++++++++++++++++++++++++++++++++
Mlib9/fmt/fmtprint.c | 14+-------------
Mlib9/fmt/fmtquote.c | 25++++++++++---------------
Mlib9/fmt/fmtrune.c | 14+-------------
Mlib9/fmt/fmtstr.c | 15++-------------
Mlib9/fmt/fmtvprint.c | 14+-------------
Mlib9/fmt/fprint.c | 14+-------------
Alib9/fmt/nan.h | 4++++
Mlib9/fmt/nan64.c | 59++++++++++++++++++++++++++++++++++-------------------------
Mlib9/fmt/plan9.h | 5+++++
Mlib9/fmt/pow10.c | 14+-------------
Mlib9/fmt/print.c | 14+-------------
Mlib9/fmt/runefmtstr.c | 15++-------------
Mlib9/fmt/runeseprint.c | 14+-------------
Mlib9/fmt/runesmprint.c | 14+-------------
Mlib9/fmt/runesnprint.c | 14+-------------
Mlib9/fmt/runesprint.c | 14+-------------
Mlib9/fmt/runevseprint.c | 15++-------------
Mlib9/fmt/runevsmprint.c | 21+++++----------------
Mlib9/fmt/runevsnprint.c | 15++-------------
Mlib9/fmt/seprint.c | 14+-------------
Mlib9/fmt/smprint.c | 14+-------------
Mlib9/fmt/snprint.c | 14+-------------
Mlib9/fmt/sprint.c | 21++++++---------------
Mlib9/fmt/strtod.c | 20++++----------------
Mlib9/fmt/test.c | 35++++++++++++++++++++++-------------
Mlib9/fmt/vfprint.c | 14+-------------
Mlib9/fmt/vseprint.c | 15++-------------
Mlib9/fmt/vsmprint.c | 21+++++----------------
Mlib9/fmt/vsnprint.c | 15++-------------
Alib9/getcallerpc-arm.c | 8++++++++
Mlib9/getnetconn.c | 4++--
Mlib9/getns.c | 25++++++++++++++++++++++++-
Mlib9/lib9.h | 19++-----------------
Mlib9/libc.h | 17++++++++++++-----
Mlib9/malloctag.c | 4----
Mlib9/nan.c | 2+-
Alib9/netcrypt.c | 18++++++++++++++++++
Mlib9/netmkaddr.c | 38++++++++++++++++++++++++--------------
Mlib9/notify.c | 9+++++----
Mlib9/nrand.c | 2--
Mlib9/nulldir.c | 2+-
Mlib9/opentemp.c | 13+++++++++----
Alib9/pin.c | 11+++++++++++
Mlib9/portdate | 85+++++++++++++++++++++++++++++++++++++++++++++++++++----------------------------
Mlib9/post9p.c | 93+++++++++++++++++++++++++++++++++++++++++++++++++++++++------------------------
Mlib9/rand.c | 3---
Mlib9/readn.c | 1-
Mlib9/regex/regcomp.c | 10+++++-----
Mlib9/regex/regexec.c | 2+-
Mlib9/regex/rregexec.c | 19+++++++++----------
Mlib9/rfork.c | 10+++++++---
Mlib9/sendfd.c | 5++++-
Mlib9/sleep.c | 12++++++++++++
Mlib9/sysfatal.c | 5-----
Alib9/test.c | 8++++++++
Alib9/testfltfmt.c | 183+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/testfmt.c | 148+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/testprint.c | 14++++++++++++++
Alib9/tm2sec.c | 110+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Mlib9/truerand.c | 2+-
Mlib9/u.h | 23++++++++++++++++++++---
Mlib9/utf.h | 2+-
Alib9/utf/NOTICE | 13+++++++++++++
Alib9/utf/README | 13+++++++++++++
Clib9/lib9.h -> lib9/utf/lib9.h | 0
Mlib9/utf/rune.c | 2+-
Mlib9/utf/utfecpy.c | 1+
Alib9/write.c | 23+++++++++++++++++++++++
Alib9/zoneinfo.c | 215+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Alib9/zoneinfo.h | 19+++++++++++++++++++
Mls/ls.c | 11+++++------
Dmk/Makefile | 37-------------------------------------
Dmk/NOTICE | 27---------------------------
Dmk/README | 7-------
Dmk/arc.c | 52----------------------------------------------------
Dmk/archive.c | 253-------------------------------------------------------------------------------
Dmk/bufblock.c | 88-------------------------------------------------------------------------------
Dmk/env.c | 149-------------------------------------------------------------------------------
Dmk/file.c | 90-------------------------------------------------------------------------------
Dmk/fns.h | 88-------------------------------------------------------------------------------
Dmk/graph.c | 279-------------------------------------------------------------------------------
Dmk/job.c | 33---------------------------------
Dmk/lex.c | 146-------------------------------------------------------------------------------
Dmk/main.c | 287-------------------------------------------------------------------------------
Dmk/match.c | 49-------------------------------------------------
Dmk/mk.1 | 691-------------------------------------------------------------------------------
Dmk/mk.c | 234-------------------------------------------------------------------------------
Dmk/mk.h | 182-------------------------------------------------------------------------------
Dmk/parse.c | 318-------------------------------------------------------------------------------
Dmk/rc.c | 194-------------------------------------------------------------------------------
Dmk/recipe.c | 117-------------------------------------------------------------------------------
Dmk/rule.c | 110-------------------------------------------------------------------------------
Dmk/run.c | 296-------------------------------------------------------------------------------
Dmk/sh.c | 206-------------------------------------------------------------------------------
Dmk/shell.c | 80-------------------------------------------------------------------------------
Dmk/shprint.c | 125-------------------------------------------------------------------------------
Dmk/symtab.c | 97-------------------------------------------------------------------------------
Dmk/sys.h | 5-----
Dmk/sys.std.h | 22----------------------
Dmk/unix.c | 341-------------------------------------------------------------------------------
Dmk/var.c | 41-----------------------------------------
Dmk/varsub.c | 256-------------------------------------------------------------------------------
Dmk/word.c | 180-------------------------------------------------------------------------------
Mrc/Makefile | 3++-
Mrc/code.c | 226+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mrc/exec.c | 1031+++++++++++++++++++++++++++++++++++++++++--------------------------------------
Mrc/exec.h | 10+++++++---
Mrc/fns.h | 14++++++++++----
Mrc/getflags.c | 171++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mrc/glob.c | 165++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------------
Mrc/havefork.c | 53++++++++++++++++++++++++++++++++++++++++++++---------
Mrc/here.c | 97+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mrc/io.c | 231+++++++++++++++++++++++++++++++++++++++++++++++++++++--------------------------
Mrc/io.h | 6+++---
Mrc/lex.c | 280+++++++++++++++++++++++++++++++++++++++++++++++--------------------------------
Mrc/pcmd.c | 107++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------------
Mrc/pfnc.c | 16++++++++++------
Mrc/plan9ish.c | 71+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++--------
Mrc/rc.1 | 5+++++
Mrc/rc.h | 3++-
Mrc/simple.c | 331++++++++++++++++++++++++++++++++++++++++++++++---------------------------------
Mrc/subr.c | 48+++++++++++++++++++++++++++++++++---------------
Mrc/trap.c | 25++++++++++++++-----------
Mrc/tree.c | 132+++++++++++++++++++++++++++++++++++++++++++++++++------------------------------
Mrc/unixcrap.c | 25+++++++++++++++++++++++++
Mrc/var.c | 98++++++++++++++++++++++++++++++++++++++++++++++++++++++++-----------------------
Msed/sed.1 | 10++++++----
Msed/sed.c | 12+++++++++---
Msort/sort.c | 7+++----
Mtest/test.1 | 4++--
Mtest/test.c | 159+++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++----------
Mtouch/touch.c | 10++++++++--
Myacc/yacc.c | 4++--
203 files changed, 4891 insertions(+), 7638 deletions(-)

diff --git a/Makefile b/Makefile @@ -4,7 +4,7 @@ include config.mk SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \ - mk rc read sed seq sleep sort tee test touch tr uniq + rc read sed seq sleep sort tee test touch tr uniq all: @echo 9base build options: diff --git a/awk/README b/awk/README @@ -0,0 +1,13 @@ +This 'awk' source is directly downloaded from the Plan 9 source + +http://cm.bell-labs.com/sources/plan9/sys/src/cmd/awk/ + +as such, it's copyright is held by Lucent Technologies and distributed under the +Lucent Public License version 1.02 [http://www.opensource.org/licenses/lucent1.02.php]. + +Modifications were made by Jeff Sickel in order to build using Plan 9 from User +Space [http://swtch.com/plan9port/] to the following files: + + mkfile + re.c + diff --git a/awk/awk.h b/awk/awk.h @@ -182,3 +182,4 @@ extern int pairstack[], paircnt; #define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR ) #include "proto.h" + diff --git a/awk/awkgram.y b/awk/awkgram.y @@ -486,3 +486,4 @@ void checkdup(Node *vl, Cell *cp) /* check if name already in list */ } } } + diff --git a/awk/lex.c b/awk/lex.c @@ -86,8 +86,8 @@ Keyword keywords[] ={ /* keep sorted: binary searched */ { "system", FSYSTEM, BLTIN }, { "tolower", FTOLOWER, BLTIN }, { "toupper", FTOUPPER, BLTIN }, - { "while", WHILE, WHILE }, { "utf", FUTF, BLTIN }, + { "while", WHILE, WHILE }, }; #define DEBUG @@ -567,3 +567,4 @@ void unputstr(char *s) /* put a string back on input */ for (i = strlen(s)-1; i >= 0; i--) unput(s[i]); } + diff --git a/awk/lib.c b/awk/lib.c @@ -673,6 +673,32 @@ int is_number(char *s) { double r; char *ep; + + /* + * fast could-it-be-a-number check before calling strtod, + * which takes a surprisingly long time to reject non-numbers. + */ + switch (*s) { + case '0': case '1': case '2': case '3': case '4': + case '5': case '6': case '7': case '8': case '9': + case '\t': + case '\n': + case '\v': + case '\f': + case '\r': + case ' ': + case '-': + case '+': + case '.': + case 'n': /* nans */ + case 'N': + case 'i': /* infs */ + case 'I': + break; + default: + return 0; /* can't be a number */ + } + errno = 0; r = strtod(s, &ep); if (ep == s || r == HUGE_VAL || errno == ERANGE) @@ -684,3 +710,4 @@ int is_number(char *s) else return 0; } + diff --git a/awk/main.c b/awk/main.c @@ -57,7 +57,7 @@ int main(int argc, char *argv[]) cmdname = argv[0]; if (argc == 1) { - fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname); + fprintf(stderr, "Usage: %s [-F fieldsep] [-mf n] [-mr n] [-v var=value] [-f programfile | 'program'] [file ...]\n", cmdname); exit(1); } signal(SIGFPE, fpecatch); @@ -195,3 +195,4 @@ char *cursource(void) /* current source file name */ else return NULL; } + diff --git a/awk/maketab.c b/awk/maketab.c @@ -166,3 +166,4 @@ int main(int argc, char *argv[]) printf("}\n"); return 0; } + diff --git a/awk/parse.c b/awk/parse.c @@ -269,3 +269,4 @@ Node *itonp(int i) /* and vice versa */ { return (Node *) (long) i; } + diff --git a/awk/proto.h b/awk/proto.h @@ -22,6 +22,8 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ +#define getline p9getline + extern int yywrap(void); extern void setfname(Cell *); extern int constnode(Node *); @@ -175,3 +177,4 @@ extern Cell *gsub(Node **, int); extern FILE *popen(const char *, const char *); extern int pclose(FILE *); + diff --git a/awk/re.c b/awk/re.c @@ -25,15 +25,13 @@ THIS SOFTWARE. #define DEBUG #include <stdio.h> +#include <u.h> +#include <libc.h> #include <ctype.h> -#include <setjmp.h> -#include <math.h> -#include <string.h> -#include <stdlib.h> -#include <time.h> +#include <bio.h> +#include <regexp.h> #include "awk.h" #include "y.tab.h" -#include "regexp.h" /* This file provides the interface between the main body of * awk and the pattern matching package. It preprocesses @@ -187,7 +185,7 @@ void /* T/F match indication - matched string not exported */ int -match(void *p, char *s, char *q) +match(void *p, char *s, char *start) { return regexec((Reprog *) p, (char *) s, 0, 0); } @@ -222,10 +220,11 @@ nematch(void *p, char *s, char *start) } /* in the parsing of regular expressions, metacharacters like . have */ /* to be seen literally; \056 is not a metacharacter. */ -int + +int hexstr(char **pp) /* find and eval hex string at pp, return new p */ { - int c; + char c; int n = 0; int i; @@ -323,3 +322,4 @@ overflow(void) { FATAL("%s", "regular expression too big"); } + diff --git a/awk/run.c b/awk/run.c @@ -133,6 +133,7 @@ void run(Node *a) /* execution of parse tree starts here */ Cell *execute(Node *u) /* execute a node of the parse tree */ { + int nobj; Cell *(*proc)(Node **, int); Cell *x; Node *a; @@ -149,10 +150,11 @@ Cell *execute(Node *u) /* execute a node of the parse tree */ recbld(); return(x); } - if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */ + nobj = a->nobj; + if (notlegal(nobj)) /* probably a Cell* but too risky to print */ FATAL("illegal statement"); - proc = proctab[a->nobj-FIRSTTOKEN]; - x = (*proc)(a->narg, a->nobj); + proc = proctab[nobj-FIRSTTOKEN]; + x = (*proc)(a->narg, nobj); if (isfld(x) && !donefld) fldbld(); else if (isrec(x) && !donerec) @@ -901,8 +903,10 @@ int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversi if (isnum(x)) { if (getfval(x)) sprintf(p, fmt, (int) getfval(x)); - else + else{ *p++ = '\0'; + *p = '\0'; + } } else sprintf(p, fmt, getsval(x)[0]); break; @@ -1540,6 +1544,7 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis Cell *printstat(Node **a, int n) /* print a[0] */ { + int r; Node *x; Cell *y; FILE *fp; @@ -1553,14 +1558,15 @@ Cell *printstat(Node **a, int n) /* print a[0] */ fputs(getsval(y), fp); tempfree(y); if (x->nnext == NULL) - fputs(*ORS, fp); + r = fputs(*ORS, fp); else - fputs(*OFS, fp); + r = fputs(*OFS, fp); + if (r == EOF) + FATAL("write error on %s", filename(fp)); } if (a[1] != 0) - fflush(fp); - if (ferror(fp)) - FATAL("write error on %s", filename(fp)); + if (fflush(fp) == EOF) + FATAL("write error on %s", filename(fp)); return(True); } @@ -1890,3 +1896,4 @@ void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */ *pb_ptr = pb; *sptr_ptr = sptr; } + diff --git a/awk/tran.c b/awk/tran.c @@ -432,3 +432,4 @@ char *qstring(char *s, int delim) /* collect string up to next delim */ *bp++ = 0; return buf; } + diff --git a/bc/bc.1 b/bc/bc.1 @@ -159,7 +159,7 @@ Function definitions .B , .I L .B ){ -.PD +.PD0 .br .B auto .I L diff --git a/bc/bc.y b/bc/bc.y @@ -6,10 +6,8 @@ #define bsp_max 5000 Biobuf *in; - #define stdin bstdin - #define stdout bstdout - Biobuf stdin; - Biobuf stdout; + Biobuf bstdin; + Biobuf bstdout; char cary[1000]; char* cp = { cary }; char string[1000]; @@ -19,7 +17,7 @@ int bindx = 0; int lev = 0; int ln; - int* ttp; + char* ttp; char* ss = ""; int bstack[10] = { 0 }; char* numb[15] = @@ -28,8 +26,8 @@ " 6", " 7", " 8", " 9", " 10", " 11", " 12", " 13", " 14" }; - int* pre; - int* post; + char* pre; + char* post; long peekc = -1; int sargc; @@ -61,40 +59,39 @@ "u","v","w","x","y","z" }; char* dot = { "." }; - int bspace[bsp_max]; - int* bsp_nxt = { bspace }; + char* bspace[bsp_max]; + char** bsp_nxt = bspace; int bdebug = 0; int lflag; int cflag; int sflag; - int* bundle(int, ...); - void conout(int*, char*); + char* bundle(int, ...); + void conout(char*, char*); int cpeek(int, int, int); int getch(void); - int* geta(char*); - int* getf(char*); + char* geta(char*); + char* getf(char*); void getout(void); - void output(int*); + void output(char*); void pp(char*); - void routput(int*); + void routput(char*); void tp(char*); void yyerror(char*, ...); int yyparse(void); typedef void* pointer; -/* #pragma varargck type "lx" pointer */ + #pragma varargck type "lx" pointer %} %union { - int* iptr; char* cptr; int cc; } -%type <iptr> pstat stat stat1 def slist dlets e ase nase -%type <iptr> slist re fprefix cargs eora cons constant lora +%type <cptr> pstat stat stat1 def slist dlets e ase nase +%type <cptr> slist re fprefix cargs eora cons constant lora %type <cptr> crs %token <cptr> LETTER EQOP _AUTO DOT @@ -124,7 +121,7 @@ stuff: ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q"); conout(ttp, (char*)$1); rcrs = crs; - output((int*)""); /* this is horse puk!! */ + output(""); lev = bindx = 0; } @@ -550,8 +547,8 @@ def: _DEFINE LETTER '(' { $$ = getf($2); - pre = (int*)""; - post = (int*)""; + pre = (char*)""; + post = (char*)""; lev = 1; bindx = 0; bstack[bindx] = 0; @@ -789,76 +786,85 @@ loop: peekc = -1; if(ch >= 0) return ch; + ifile++; - if(ifile > sargc) { - if(ifile >= sargc+2) + if(ifile >= sargc) { + if(ifile >= sargc+1) getout(); - in = &stdin; + in = &bstdin; Binit(in, 0, OREAD); ln = 0; goto loop; } - Bterm(in); + if(in) + Bterm(in); if((in = Bopen(sargv[ifile], OREAD)) != 0){ ln = 0; ss = sargv[ifile]; goto loop; } + fprint(2, "open %s: %r\n", sargv[ifile]); yyerror("cannot open input file"); return 0; /* shut up ken */ } -int* +char* bundle(int a, ...) { - int i, *p, *q; - - p = &a; - i = *p++; + int i; + char **q; + va_list arg; + + i = a; + va_start(arg, a); q = bsp_nxt; if(bdebug) fprint(2, "bundle %d elements at %lx\n", i, q); while(i-- > 0) { if(bsp_nxt >= &bspace[bsp_max]) yyerror("bundling space exceeded"); - *bsp_nxt++ = *p++; + *bsp_nxt++ = va_arg(arg, char*); } *bsp_nxt++ = 0; - yyval.iptr = q; - return q; + va_end(arg); + yyval.cptr = (char*)q; + return (char*)q; } void -routput(int *p) +routput(char *p) { + char **pp; + if(bdebug) fprint(2, "routput(%lx)\n", p); - if(p >= &bspace[0] && p < &bspace[bsp_max]) { + if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) { /* part of a bundle */ - while(*p != 0) - routput((int*)(*p++)); + pp = (char**)p; + while(*pp != 0) + routput(*pp++); } else - Bprint(&stdout, (char*)p); /* character string */ + Bprint(&bstdout, p); /* character string */ } void -output(int *p) +output(char *p) { routput(p); bsp_nxt = &bspace[0]; - Bprint(&stdout, "\n"); - Bflush(&stdout); + Bprint(&bstdout, "\n"); + Bflush(&bstdout); cp = cary; crs = rcrs; } void -conout(int *p, char *s) +conout(char *p, char *s) { - Bprint(&stdout, "["); + Bprint(&bstdout, "["); routput(p); - Bprint(&stdout, "]s%s\n", s); - Bflush(&stdout); + Bprint(&bstdout, "]s%s\n", s); + Bflush(&bstdout); lev--; } @@ -867,8 +873,8 @@ yyerror(char *s, ...) { if(ifile > sargc) ss = "teletype"; - Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss); - Bflush(&stdout); + Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss); + Bflush(&bstdout); cp = cary; crs = rcrs; bindx = 0; @@ -881,9 +887,9 @@ pp(char *s) { /* puts the relevant stuff on pre and post for the letter s */ bundle(3, "S", s, pre); - pre = yyval.iptr; + pre = yyval.cptr; bundle(4, post, "L", s, "s."); - post = yyval.iptr; + post = yyval.cptr; } void @@ -891,45 +897,45 @@ tp(char *s) { /* same as pp, but for temps */ bundle(3, "0S", s, pre); - pre = yyval.iptr; + pre = yyval.cptr; bundle(4, post, "L", s, "s."); - post = yyval.iptr; + post = yyval.cptr; } void yyinit(int argc, char **argv) { - Binit(&stdout, 1, OWRITE); + Binit(&bstdout, 1, OWRITE); sargv = argv; - sargc = argc - 1; + sargc = argc; if(sargc == 0) { - in = &stdin; + in = &bstdin; Binit(in, 0, OREAD); - } else if((in = Bopen(sargv[1], OREAD)) == 0) + } else if((in = Bopen(sargv[0], OREAD)) == 0) yyerror("cannot open input file"); - ifile = 1; + ifile = 0; ln = 0; - ss = sargv[1]; + ss = sargv[0]; } void getout(void) { - Bprint(&stdout, "q"); - Bflush(&stdout); + Bprint(&bstdout, "q"); + Bflush(&bstdout); exits(0); } -int* +char* getf(char *p) { - return (int*)funtab[*p - 'a']; + return funtab[*p - 'a']; } -int* +char* geta(char *p) { - return (int*)atab[*p - 'a']; + return atab[*p - 'a']; } void @@ -937,37 +943,34 @@ main(int argc, char **argv) { int p[2]; - while(argc > 1 && *argv[1] == '-') { - switch(argv[1][1]) { - case 'd': - bdebug++; - break; - case 'c': - cflag++; - break; - case 'l': - lflag++; - break; - case 's': - sflag++; - break; - default: - fprint(2, "Usage: bc [-l] [-c] [file ...]\n"); - exits("usage"); - } - argc--; - argv++; - } + ARGBEGIN{ + case 'd': + bdebug++; + break; + case 'c': + cflag++; + break; + case 'l': + lflag++; + break; + case 's': + sflag++; + break; + default: + fprint(2, "Usage: bc [-l] [-c] [file ...]\n"); + exits("usage"); + }ARGEND + if(lflag) { - argv--; argc++; - argv[1] = unsharp("#9/lib/bclib"); + argv--; + *argv = unsharp("#9/lib/bclib"); } if(cflag) { yyinit(argc, argv); for(;;) yyparse(); - /* exits(0); */ + exits(0); } pipe(p); if(fork() == 0) { @@ -981,5 +984,5 @@ main(int argc, char **argv) dup(p[0], 0); close(p[0]); close(p[1]); - execlp("dc", "dc", (char*)0); + execl(unsharp("#9/bin/dc"), "dc", nil); } diff --git a/config.mk b/config.mk @@ -4,7 +4,9 @@ PREFIX = /usr/local/9 MANPREFIX = ${PREFIX}/share/man -VERSION = 20060209 +VERSION = 200907 +# 386, arm, etc31 +OBJTYPE = x86_64 # Linux/BSD CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. -DPREFIX="\"${PREFIX}\"" diff --git a/dc/dc.c b/dc/dc.c @@ -165,7 +165,6 @@ void release(Blk *p); Blk* dcgetwd(Blk *p); void putwd(Blk *p, Blk *c); Blk* lookwd(Blk *p); -char* nalloc(char *p, unsigned nbytes); int getstk(void); /********debug only**/ @@ -1222,7 +1221,7 @@ init(int argc, char *argv[]) readptr = &readstk[0]; k=0; sp = sptr = &symlst[0]; - while(sptr < &symlst[TBLSZ]) { + while(sptr < &symlst[TBLSZ-1]) { sptr->next = ++sp; sptr++; } @@ -2103,14 +2102,13 @@ copy(Blk *hptr, int size) if(size > maxsize) maxsize = size; sz = length(hptr); - ptr = nalloc(hptr->beg, size); + ptr = malloc(size); if(ptr == 0) { - garbage("copy"); - if((ptr = nalloc(hptr->beg, size)) == 0) { - Bprint(&bout,"copy size %d\n",size); - ospace("copy"); - } + Bprint(&bout,"copy size %d\n",size); + ospace("copy"); } + memmove(ptr, hptr->beg, sz); + memset(ptr+sz, 0, size-sz); if((hdr = hfree) == 0) hdr = morehd(); hfree = (Blk *)hdr->rd; @@ -2149,7 +2147,7 @@ seekc(Blk *hptr, int n) lbytes += nn - hptr->last; if(n > longest) longest = n; -/* free(hptr->beg); *//**/ +/* free(hptr->beg); */ p = realloc(hptr->beg, n); if(p == 0) { /* hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg); @@ -2194,7 +2192,7 @@ more(Blk *hptr) longest = size; lbytes += size/2; lmore++; -/* free(hptr->beg);*//**/ +/* free(hptr->beg);*/ p = realloc(hptr->beg, size); if(p == 0) { @@ -2269,19 +2267,6 @@ lookwd(Blk *p) return(*wp->rdw); } -char* -nalloc(char *p, unsigned nbytes) -{ - char *q, *r; - - q = r = malloc(nbytes); - if(q==0) - return(0); - while(nbytes--) - *q++ = *p++; - return(r); -} - int getstk(void) { diff --git a/grep/comp.c b/grep/comp.c @@ -128,12 +128,12 @@ loop: Rune tab1[] = { 0x007f, - 0x07ff, + 0x07ff }; Rune tab2[] = { 0x003f, - 0x0fff, + 0x0fff }; Re2 @@ -144,7 +144,7 @@ rclass(Rune p0, Rune p1) Re2 x; if(p0 > p1) - return re2char(0xff, 0xff); // no match + return re2char(0xff, 0xff); /* no match */ /* * bust range into same length diff --git a/grep/main.c b/grep/main.c @@ -21,6 +21,10 @@ main(int argc, char *argv[]) flags[ARGC()]++; break; + case 'q': /* gnu grep -q means plan 9 grep -s */ + flags['s']++; + break; + case 'E': /* ignore, turns gnu grep into egrep */ break; @@ -170,11 +174,11 @@ loop: increment(s, c); goto loop; } -// if(flags['2']) -// if(s->match) -// print("%d: %.2x**\n", s, c); -// else -// print("%d: %.2x\n", s, c); +/* if(flags['2']) */ +/* if(s->match) */ +/* print("%d: %.2x**\n", s, c); */ +/* else */ +/* print("%d: %.2x\n", s, c); */ lp++; s = ns; if(c == '\n') { diff --git a/grep/sub.c b/grep/sub.c @@ -30,7 +30,7 @@ sal(int n) State *s; s = mal(sizeof(*s)); -// s->next = mal(256*sizeof(*s->next)); +/* s->next = mal(256*sizeof(*s->next)); */ s->count = n; s->re = mal(n*sizeof(*state0->re)); return s; diff --git a/lib9/Makefile b/lib9/Makefile @@ -15,16 +15,203 @@ include ../config.mk LIB=lib9.a TARG=lib9 +O=o # following objects are not compiled for several reasons -# crypt.o -# netcrypt.o -# convD2M.o -# convM2D.o -# convM2S.o -# convS2M.o +# crypt.$(O) +# netcrypt.$(O) +# convD2M.$(O) +# convM2D.$(O) +# convM2S.$(O) +# convS2M.$(O) + +NUM=\ + fmt/charstod.$(O)\ + fmt/pow10.$(O)\ + +FMTOFILES=\ + fmt/dofmt.$(O)\ + fmt/fltfmt.$(O)\ + fmt/fmt.$(O)\ + fmt/fmtfd.$(O)\ + fmt/fmtfdflush.$(O)\ + fmt/fmtlocale.$(O)\ + fmtlock2.$(O)\ + fmt/fmtnull.$(O)\ + fmt/fmtprint.$(O)\ + fmt/fmtquote.$(O)\ + fmt/fmtrune.$(O)\ + fmt/fmtstr.$(O)\ + fmt/fmtvprint.$(O)\ + fmt/fprint.$(O)\ + fmt/nan64.$(O)\ + fmt/print.$(O)\ + fmt/runefmtstr.$(O)\ + fmt/runeseprint.$(O)\ + fmt/runesmprint.$(O)\ + fmt/runesnprint.$(O)\ + fmt/runesprint.$(O)\ + fmt/runevseprint.$(O)\ + fmt/runevsmprint.$(O)\ + fmt/runevsnprint.$(O)\ + fmt/seprint.$(O)\ + fmt/smprint.$(O)\ + fmt/snprint.$(O)\ + fmt/sprint.$(O)\ + fmt/strtod.$(O)\ + fmt/vfprint.$(O)\ + fmt/vseprint.$(O)\ + fmt/vsmprint.$(O)\ + fmt/vsnprint.$(O)\ + $(NUM)\ + +UTFOFILES=\ + utf/rune.$(O)\ + utf/runestrcat.$(O)\ + utf/runestrchr.$(O)\ + utf/runestrcmp.$(O)\ + utf/runestrcpy.$(O)\ + utf/runestrdup.$(O)\ + utf/runestrlen.$(O)\ + utf/runestrecpy.$(O)\ + utf/runestrncat.$(O)\ + utf/runestrncmp.$(O)\ + utf/runestrncpy.$(O)\ + utf/runestrrchr.$(O)\ + utf/runestrstr.$(O)\ + utf/runetype.$(O)\ + utf/utfecpy.$(O)\ + utf/utflen.$(O)\ + utf/utfnlen.$(O)\ + utf/utfrrune.$(O)\ + utf/utfrune.$(O)\ + utf/utfutf.$(O)\ + +BIOFILES=\ + bio/bbuffered.$(O)\ + bio/bfildes.$(O)\ + bio/bflush.$(O)\ + bio/bgetc.$(O)\ + bio/bgetrune.$(O)\ + bio/bgetd.$(O)\ + bio/binit.$(O)\ + bio/boffset.$(O)\ + bio/bprint.$(O)\ + bio/bputc.$(O)\ + bio/bputrune.$(O)\ + bio/brdline.$(O)\ + bio/brdstr.$(O)\ + bio/bread.$(O)\ + bio/bseek.$(O)\ + bio/bvprint.$(O)\ + bio/bwrite.$(O)\ + +REGEXFILES=\ + regex/regcomp.$(O)\ + regex/regerror.$(O)\ + regex/regexec.$(O)\ + regex/regsub.$(O)\ + regex/regaux.$(O)\ + regex/rregexec.$(O)\ + regex/rregsub.$(O)\ + +LIB9OFILES=\ + _exits.$(O)\ + _p9dialparse.$(O)\ + _p9dir.$(O)\ + announce.$(O)\ + argv0.$(O)\ + atexit.$(O)\ + atoi.$(O)\ + atol.$(O)\ + atoll.$(O)\ + atnotify.$(O)\ + await.$(O)\ + cistrcmp.$(O)\ + cistrncmp.$(O)\ + cistrstr.$(O)\ + cleanname.$(O)\ + create.$(O)\ + ctime.$(O)\ + dial.$(O)\ + dirfstat.$(O)\ + dirfwstat.$(O)\ + dirmodefmt.$(O)\ + dirread.$(O)\ + dirstat.$(O)\ + dirwstat.$(O)\ + dup.$(O)\ + encodefmt.$(O)\ + errstr.$(O)\ + exec.$(O)\ + execl.$(O)\ + exitcode.$(O)\ + fcallfmt.$(O)\ + get9root.$(O)\ + getcallerpc-$(OBJTYPE).$(O)\ + getenv.$(O)\ + getfields.$(O)\ + getnetconn.$(O)\ + getns.$(O)\ + getuser.$(O)\ + getwd.$(O)\ + jmp.$(O)\ + lrand.$(O)\ + lnrand.$(O)\ + main.$(O)\ + malloc.$(O)\ + malloctag.$(O)\ + mallocz.$(O)\ + nan.$(O)\ + needsrcquote.$(O)\ + needstack.$(O)\ + netmkaddr.$(O)\ + notify.$(O)\ + nrand.$(O)\ + nulldir.$(O)\ + open.$(O)\ + opentemp.$(O)\ + pin.$(O)\ + pipe.$(O)\ + post9p.$(O)\ + postnote.$(O)\ + qlock.$(O)\ + quote.$(O)\ + rand.$(O)\ + read9pmsg.$(O)\ + readcons.$(O)\ + readn.$(O)\ + rfork.$(O)\ + searchpath.$(O)\ + seek.$(O)\ + sendfd.$(O)\ + sleep.$(O)\ + strdup.$(O)\ + strecpy.$(O)\ + sysfatal.$(O)\ + syslog.$(O)\ + sysname.$(O)\ + time.$(O)\ + tm2sec.$(O)\ + tokenize.$(O)\ + truerand.$(O)\ + u16.$(O)\ + u32.$(O)\ + u64.$(O)\ + unsharp.$(O)\ + wait.$(O)\ + waitpid.$(O)\ + write.$(O)\ + zoneinfo.$(O)\ OFILES=\ + $(FMTOFILES)\ + $(UTFOFILES)\ + $(BIOFILES)\ + $(REGEXFILES)\ + $(LIB9OFILES) + +OFILESOLD=\ fmt/dofmt.o\ fmt/fltfmt.o\ fmt/fmt.o\ diff --git a/lib9/_exits.c b/lib9/_exits.c @@ -4,7 +4,7 @@ void _exits(char *s) { - if(s && *s) - _exit(1); - _exit(0); + if(s == 0 || *s == 0) + _exit(0); + _exit(exitcode(s)); } diff --git a/lib9/_p9dialparse.c b/lib9/_p9dialparse.c @@ -26,6 +26,8 @@ static struct { "tcp", "venti", 17034, "tcp", "wiki", 17035, "tcp", "secstore", 5356, + "udp", "dns", 53, + "tcp", "dns", 53, }; static int @@ -82,9 +84,6 @@ p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport) struct hostent *he; struct sockaddr_un *sockun; - if(strncmp(addr, "/net/", 5) == 0) - addr += 5; - *punix = nil; net = addr; if((host = strchr(net, '!')) == nil){ diff --git a/lib9/_p9dir.c b/lib9/_p9dir.c @@ -7,50 +7,67 @@ #include <pwd.h> #include <grp.h> -#if defined(__FreeBSD__) || defined(__OpenBSD__) +#if defined(__APPLE__) +#define _HAVESTGEN +#include <sys/disk.h> +static vlong +disksize(int fd, struct stat *st) +{ + u64int bc; + u32int bs; + + bs = 0; + bc = 0; + ioctl(fd, DKIOCGETBLOCKSIZE, &bs); + ioctl(fd, DKIOCGETBLOCKCOUNT, &bc); + if(bs >0 && bc > 0) + return bc*bs; + return 0; +} + +#elif defined(__FreeBSD__) +#define _HAVESTGEN +#include <sys/disk.h> +#include <sys/disklabel.h> +#include <sys/ioctl.h> +static vlong +disksize(int fd, struct stat *st) +{ + off_t mediasize; + + if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0) + return mediasize; + return 0; +} + +#elif defined(__OpenBSD__) +#define _HAVESTGEN #include <sys/disklabel.h> #include <sys/ioctl.h> -static int diskdev[] = { - 151, /* aacd */ - 116, /* ad */ - 157, /* ar */ - 118, /* afd */ - 133, /* amrd */ - 13, /* da */ - 102, /* fla */ - 109, /* idad */ - 95, /* md */ - 131, /* mlxd */ - 168, /* pst */ - 147, /* twed */ - 43, /* vn */ - 3, /* wd */ - 87, /* wfd */ -}; -static int -isdisk(struct stat *st) +static vlong +disksize(int fd, struct stat *st) { - int i, dev; + struct disklabel lab; + int n; if(!S_ISCHR(st->st_mode)) return 0; - dev = major(st->st_rdev); - for(i=0; i<nelem(diskdev); i++) - if(diskdev[i] == dev) - return 1; - return 0; + if(ioctl(fd, DIOCGDINFO, &lab) < 0) + return 0; + n = minor(st->st_rdev)&7; + if(n >= lab.d_npartitions) + return 0; + return (vlong)lab.d_partitions[n].p_size * lab.d_secsize; } -#define _HAVEDISKLABEL -#endif -#if defined(__linux__) +#elif defined(__linux__) #include <linux/hdreg.h> #include <linux/fs.h> #include <sys/ioctl.h> #undef major #define major(dev) ((int)(((dev) >> 8) & 0xff)) static vlong -disksize(int fd, int dev) +disksize(int fd, struct stat *st) { u64int u64; long l; @@ -64,18 +81,21 @@ disksize(int fd, int dev) return u64; #endif if(ioctl(fd, BLKGETSIZE, &l) >= 0) - return (vlong)l*512; + return l*512; if(ioctl(fd, HDIO_GETGEO, &geo) >= 0) return (vlong)geo.heads*geo.sectors*geo.cylinders*512; return 0; } -#define _HAVEDISKSIZE -#endif -#if !defined(__linux__) && !defined(__sun__) -#define _HAVESTGEN +#else +static vlong +disksize(int fd, struct stat *st) +{ + return 0; +} #endif +int _p9usepwlibrary = 1; /* * Caching the last group and passwd looked up is * a significant win (stupidly enough) on most systems. @@ -122,11 +142,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char * /* user */ if(p && st->st_uid == uid && p->pw_uid == uid) ; - else{ + else if(_p9usepwlibrary){ p = getpwuid(st->st_uid); uid = st->st_uid; } - if(p == nil){ + if(p == nil || st->st_uid != uid || p->pw_uid != uid){ snprint(tmp, sizeof tmp, "%d", (int)st->st_uid); s = tmp; }else @@ -145,11 +165,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char * /* group */ if(g && st->st_gid == gid && g->gr_gid == gid) ; - else{ + else if(_p9usepwlibrary){ g = getgrgid(st->st_gid); gid = st->st_gid; } - if(g == nil){ + if(g == nil || st->st_gid != gid || g->gr_gid != gid){ snprint(tmp, sizeof tmp, "%d", (int)st->st_gid); s = tmp; }else @@ -173,57 +193,41 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char * #ifdef _HAVESTGEN d->qid.vers = st->st_gen; #endif + if(d->qid.vers == 0) + d->qid.vers = st->st_mtime + st->st_ctime; d->mode = st->st_mode&0777; d->atime = st->st_atime; d->mtime = st->st_mtime; d->length = st->st_size; - if(S_ISDIR(st->st_mode)){ + if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */ + d->mode |= DMSYMLINK; + d->length = lst->st_size; + } + else if(S_ISDIR(st->st_mode)){ d->length = 0; d->mode |= DMDIR; d->qid.type = QTDIR; } - if(S_ISLNK(lst->st_mode)) /* yes, lst not st */ - d->mode |= DMSYMLINK; - if(S_ISFIFO(st->st_mode)) + else if(S_ISFIFO(st->st_mode)) d->mode |= DMNAMEDPIPE; - if(S_ISSOCK(st->st_mode)) + else if(S_ISSOCK(st->st_mode)) d->mode |= DMSOCKET; - if(S_ISBLK(st->st_mode)){ + else if(S_ISBLK(st->st_mode)){ d->mode |= DMDEVICE; d->qid.path = ('b'<<16)|st->st_rdev; } - if(S_ISCHR(st->st_mode)){ + else if(S_ISCHR(st->st_mode)){ d->mode |= DMDEVICE; d->qid.path = ('c'<<16)|st->st_rdev; } /* fetch real size for disks */ -#ifdef _HAVEDISKSIZE - if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){ - d->length = disksize(fd, major(st->st_dev)); - close(fd); - } -#endif -#ifdef _HAVEDISKLABEL - if(isdisk(st)){ - int fd, n; - struct disklabel lab; - - if((fd = open(name, O_RDONLY)) < 0) - goto nosize; - if(ioctl(fd, DIOCGDINFO, &lab) < 0) - goto nosize; - n = minor(st->st_rdev)&7; - if(n >= lab.d_npartitions) - goto nosize; - - d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize; - - nosize: - if(fd >= 0) + if(S_ISBLK(lst->st_mode) || S_ISCHR(lst->st_mode)){ + if((fd = open(name, O_RDONLY)) >= 0){ + d->length = disksize(fd, st); close(fd); + } } -#endif } return sz; diff --git a/lib9/atexit.c b/lib9/atexit.c @@ -50,5 +50,7 @@ exits(char *s) onex[i].f = 0; (*f)(); } - exit(s && *s ? 1 : 0); + if(s == 0 || *s == 0) + exit(0); + exit(exitcode(s)); } diff --git a/lib9/bio.h b/lib9/bio.h @@ -8,23 +8,8 @@ extern "C" { AUTOLIB(bio) #endif -#include <sys/types.h> /* for off_t */ -#include <stdarg.h> #include <fcntl.h> /* for O_RDONLY, O_WRONLY */ -#define OREAD 0 /* open for read */ -#define OWRITE 1 /* write */ -#define ORDWR 2 /* read and write */ -#define OEXEC 3 /* execute, == read but check execute permission */ -#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */ -#define OCEXEC 32 /* or'ed in, close on exec */ -#define ORCLOSE 64 /* or'ed in, remove on close */ -#define ODIRECT 128 /* or'ed in, direct access */ -#define ONONBLOCK 256 /* or'ed in, non-blocking call */ -#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */ -#define OLOCK 0x2000 /* or'ed in, lock after opening */ -#define OAPPEND 0x4000 /* or'ed in, append only */ - typedef struct Biobuf Biobuf; enum @@ -52,7 +37,7 @@ struct Biobuf int state; /* r/w/inactive */ int fid; /* open file */ int flag; /* magic if malloc'ed */ - off_t offset; /* offset of buffer in file */ + long long offset; /* offset of buffer in file */ int bsize; /* size of buffer */ unsigned char* bbuf; /* pointer to beginning of buffer */ unsigned char* ebuf; /* pointer to end of buffer */ @@ -85,7 +70,7 @@ long Bgetrune(Biobuf*); int Binit(Biobuf*, int, int); int Binits(Biobuf*, int, int, unsigned char*, int); int Blinelen(Biobuf*); -off_t Boffset(Biobuf*); +long long Boffset(Biobuf*); Biobuf* Bopen(char*, int); int Bprint(Biobuf*, char*, ...); int Bputc(Biobuf*, int); @@ -93,7 +78,7 @@ int Bputrune(Biobuf*, long); void* Brdline(Biobuf*, int); char* Brdstr(Biobuf*, int, int); long Bread(Biobuf*, void*, long); -off_t Bseek(Biobuf*, off_t, int); +long long Bseek(Biobuf*, long long, int); int Bterm(Biobuf*); int Bungetc(Biobuf*); int Bungetrune(Biobuf*); diff --git a/lib9/bio/bbuffered.c b/lib9/bio/bbuffered.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> int Bbuffered(Biobuf *bp) diff --git a/lib9/bio/bflush.c b/lib9/bio/bflush.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <unistd.h> int Bflush(Biobuf *bp) diff --git a/lib9/bio/bgetc.c b/lib9/bio/bgetc.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <unistd.h> int Bgetc(Biobuf *bp) diff --git a/lib9/bio/bgetd.c b/lib9/bio/bgetd.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> struct bgetd { diff --git a/lib9/bio/binit.c b/lib9/bio/binit.c @@ -1,8 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> -#include <stdlib.h> -#include <unistd.h> enum { @@ -125,13 +122,13 @@ Bopen(char *name, int mode) return 0; case OREAD: - f = open(name, OREAD); + f = open(name, mode); if(f < 0) return 0; break; case OWRITE: - f = creat(name, 0666); + f = create(name, mode, 0666); if(f < 0) return 0; } diff --git a/lib9/bio/boffset.c b/lib9/bio/boffset.c @@ -1,11 +1,10 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> -off_t +vlong Boffset(Biobuf *bp) { - off_t n; + vlong n; switch(bp->state) { default: diff --git a/lib9/bio/brdline.c b/lib9/bio/brdline.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <unistd.h> void* Brdline(Biobuf *bp, int delim) diff --git a/lib9/bio/brdstr.c b/lib9/bio/brdstr.c @@ -1,7 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <stdlib.h> -#include <unistd.h> static char* badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim) diff --git a/lib9/bio/bread.c b/lib9/bio/bread.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <unistd.h> long Bread(Biobuf *bp, void *ap, long count) diff --git a/lib9/bio/bseek.c b/lib9/bio/bseek.c @@ -1,13 +1,10 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> -#include <sys/types.h> -#include <unistd.h> -off_t -Bseek(Biobuf *bp, off_t offset, int base) +long long +Bseek(Biobuf *bp, long long offset, int base) { - long long n, d; + vlong n, d; int bufsz; switch(bp->state) { @@ -55,7 +52,7 @@ Bseek(Biobuf *bp, off_t offset, int base) case Bwactive: Bflush(bp); - n = lseek(bp->fid, offset, base); + n = seek(bp->fid, offset, base); break; } bp->offset = n; diff --git a/lib9/bio/bvprint.c b/lib9/bio/bvprint.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <fmt.h> static int fmtBflush(Fmt *f) @@ -30,10 +29,10 @@ Bvprint(Biobuf *bp, char *fmt, va_list arg) f.flush = fmtBflush; f.farg = bp; f.nfmt = 0; + fmtlocaleinit(&f, nil, nil, nil); n = fmtvprint(&f, fmt, arg); bp->ocount = (char*)f.to - (char*)f.stop; + if(n == 0) + n = f.nfmt; return n; } - - - diff --git a/lib9/bio/bwrite.c b/lib9/bio/bwrite.c @@ -1,6 +1,5 @@ #include "lib9.h" #include <bio.h> -#include <unistd.h> long Bwrite(Biobuf *bp, void *ap, long count) diff --git a/lib9/bio/lib9.std.h b/lib9/bio/lib9.std.h @@ -1,3 +1,6 @@ +#define _FILE_OFFSET_BITS 64 +#define _LARGEFILE64_SOURCE + #include <utf.h> #include <fmt.h> @@ -13,8 +16,11 @@ #define ORCLOSE 0 #define OTRUNC 0 - #define nil ((void*)0) typedef long long vlong; typedef unsigned long long uvlong; + +#define seek(fd, offset, whence) lseek(fd, offset, whence) +#define create(name, mode, perm) creat(name, perm) + diff --git a/lib9/convD2M.c b/lib9/convD2M.c @@ -3,30 +3,44 @@ #include <fcall.h> uint -sizeD2M(Dir *d) +sizeD2Mu(Dir *d, int dotu) { - char *sv[4]; - int i, ns; + char *sv[5]; + int i, ns, nstr, fixlen; sv[0] = d->name; sv[1] = d->uid; sv[2] = d->gid; sv[3] = d->muid; - + + fixlen = STATFIXLEN; + nstr = 4; + if(dotu){ + fixlen = STATFIXLENU; + sv[4] = d->ext; + nstr = 5; + } + ns = 0; - for(i = 0; i < 4; i++) + for(i = 0; i < nstr; i++) if(sv[i]) ns += strlen(sv[i]); - return STATFIXLEN + ns; + return fixlen + ns; } uint -convD2M(Dir *d, uchar *buf, uint nbuf) +sizeD2M(Dir *d) +{ + return sizeD2Mu(d, 0); +} + +uint +convD2Mu(Dir *d, uchar *buf, uint nbuf, int dotu) { uchar *p, *ebuf; - char *sv[4]; - int i, ns, nsv[4], ss; + char *sv[5]; + int i, ns, nsv[5], ss, nstr, fixlen; if(nbuf < BIT16SZ) return 0; @@ -39,8 +53,16 @@ convD2M(Dir *d, uchar *buf, uint nbuf) sv[2] = d->gid; sv[3] = d->muid; + fixlen = STATFIXLEN; + nstr = 4; + if(dotu){ + fixlen = STATFIXLENU; + sv[4] = d->ext; + nstr = 5; + } + ns = 0; - for(i = 0; i < 4; i++){ + for(i = 0; i < nstr; i++){ if(sv[i]) nsv[i] = strlen(sv[i]); else @@ -48,7 +70,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf) ns += nsv[i]; } - ss = STATFIXLEN + ns; + ss = fixlen + ns; /* set size befor erroring, so user can know how much is needed */ /* note that length excludes count field itself */ @@ -77,7 +99,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf) PBIT64(p, d->length); p += BIT64SZ; - for(i = 0; i < 4; i++){ + for(i = 0; i < nstr; i++){ ns = nsv[i]; if(p + ns + BIT16SZ > ebuf) return 0; @@ -87,9 +109,24 @@ convD2M(Dir *d, uchar *buf, uint nbuf) memmove(p, sv[i], ns); p += ns; } + + if(dotu){ + PBIT32(p, d->uidnum); + p += BIT32SZ; + PBIT32(p, d->gidnum); + p += BIT32SZ; + PBIT32(p, d->muidnum); + p += BIT32SZ; + } if(ss != p - buf) return 0; return p - buf; } + +uint +convD2M(Dir *d, uchar *buf, uint nbuf) +{ + return convD2Mu(d, buf, nbuf, 0); +} diff --git a/lib9/convM2D.c b/lib9/convM2D.c @@ -3,10 +3,10 @@ #include <fcall.h> int -statcheck(uchar *buf, uint nbuf) +statchecku(uchar *buf, uint nbuf, int dotu) { uchar *ebuf; - int i; + int i, nstr; ebuf = buf + nbuf; @@ -15,26 +15,38 @@ statcheck(uchar *buf, uint nbuf) buf += STATFIXLEN - 4 * BIT16SZ; - for(i = 0; i < 4; i++){ + nstr = 4; + if(dotu) + nstr = 5; + for(i = 0; i < nstr; i++){ if(buf + BIT16SZ > ebuf) return -1; buf += BIT16SZ + GBIT16(buf); } + if(dotu) + buf += 3*BIT32SZ; + if(buf != ebuf) return -1; return 0; } +int +statcheck(uchar *buf, uint nbuf) +{ + return statchecku(buf, nbuf, 0); +} + static char nullstring[] = ""; uint -convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +convM2Du(uchar *buf, uint nbuf, Dir *d, char *strs, int dotu) { uchar *p, *ebuf; - char *sv[4]; - int i, ns; + char *sv[5]; + int i, ns, nstr; if(nbuf < STATFIXLEN) return 0; @@ -62,7 +74,10 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) d->length = GBIT64(p); p += BIT64SZ; - for(i = 0; i < 4; i++){ + nstr = 4; + if(dotu) + nstr = 5; + for(i = 0; i < nstr; i++){ if(p + BIT16SZ > ebuf) return 0; ns = GBIT16(p); @@ -78,17 +93,38 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) p += ns; } + if(dotu){ + if(p + BIT32SZ*3 > ebuf) + return 0; + d->uidnum = GBIT32(p); + p += BIT32SZ; + d->gidnum = GBIT32(p); + p += BIT32SZ; + d->muidnum = GBIT32(p); + p += BIT32SZ; + } + if(strs){ d->name = sv[0]; d->uid = sv[1]; d->gid = sv[2]; d->muid = sv[3]; + d->ext = nullstring; + if(dotu) + d->ext = sv[4]; }else{ d->name = nullstring; d->uid = nullstring; d->gid = nullstring; d->muid = nullstring; + d->ext = nullstring; } return p - buf; } + +uint +convM2D(uchar *buf, uint nbuf, Dir *d, char *strs) +{ + return convM2Du(buf, nbuf, d, strs, 0); +} diff --git a/lib9/convM2S.c b/lib9/convM2S.c @@ -48,7 +48,7 @@ gqid(uchar *p, uchar *ep, Qid *q) * to test at end of routine. */ uint -convM2S(uchar *ap, uint nap, Fcall *f) +convM2Su(uchar *ap, uint nap, Fcall *f, int dotu) { uchar *p, *ep; uint i, size; @@ -161,6 +161,8 @@ convM2S(uchar *ap, uint nap, Fcall *f) p += BIT32SZ; f->mode = GBIT8(p); p += BIT8SZ; + if(dotu) + p = gstring(p, ep, &f->extension); break; case Tread: @@ -229,6 +231,13 @@ convM2S(uchar *ap, uint nap, Fcall *f) case Rerror: p = gstring(p, ep, &f->ename); + f->errornum = 0; + if(dotu){ + if(p+BIT16SZ > ep) + return 0; + f->errornum = GBIT16(p); + p += BIT16SZ; + } break; case Rflush: @@ -321,3 +330,9 @@ convM2S(uchar *ap, uint nap, Fcall *f) return size; return 0; } + +uint +convM2S(uchar *ap, uint nap, Fcall *f) +{ + return convM2Su(ap, nap, f, 0); +} diff --git a/lib9/convS2M.c b/lib9/convS2M.c @@ -46,7 +46,7 @@ stringsz(char *s) } uint -sizeS2M(Fcall *f) +sizeS2Mu(Fcall *f, int dotu) { uint n; int i; @@ -102,6 +102,8 @@ sizeS2M(Fcall *f) n += stringsz(f->name); n += BIT32SZ; n += BIT8SZ; + if(dotu) + n += stringsz(f->extension); break; case Tread: @@ -141,6 +143,8 @@ sizeS2M(Fcall *f) case Rerror: n += stringsz(f->ename); + if(dotu) + n += BIT16SZ; break; case Rflush: @@ -198,12 +202,18 @@ sizeS2M(Fcall *f) } uint -convS2M(Fcall *f, uchar *ap, uint nap) +sizeS2M(Fcall *f) +{ + return sizeS2Mu(f, 0); +} + +uint +convS2Mu(Fcall *f, uchar *ap, uint nap, int dotu) { uchar *p; uint i, size; - size = sizeS2M(f); + size = sizeS2Mu(f, dotu); if(size == 0) return 0; if(size > nap) @@ -279,6 +289,8 @@ convS2M(Fcall *f, uchar *ap, uint nap) p += BIT32SZ; PBIT8(p, f->mode); p += BIT8SZ; + if(dotu) + p = pstring(p, f->extension); break; case Tread: @@ -331,6 +343,10 @@ convS2M(Fcall *f, uchar *ap, uint nap) case Rerror: p = pstring(p, f->ename); + if(dotu){ + PBIT16(p, f->errornum); + p += BIT16SZ; + } break; case Rflush: @@ -397,3 +413,9 @@ convS2M(Fcall *f, uchar *ap, uint nap) return 0; return size; } + +uint +convS2M(Fcall *f, uchar *ap, uint nap) +{ + return convS2Mu(f, ap, nap, 0); +} diff --git a/lib9/crypt.c b/lib9/crypt.c @@ -0,0 +1,68 @@ +/* + * Data Encryption Standard + * D.P.Mitchell 83/06/08. + * + * block_cipher(key, block, decrypting) + * + * these routines use the non-standard 7 byte format + * for DES keys. + */ +#include <u.h> +#include <libc.h> +#include <auth.h> +#include <libsec.h> + +/* + * destructively encrypt the buffer, which + * must be at least 8 characters long. + */ +int +encrypt(void *key, void *vbuf, int n) +{ + ulong ekey[32]; + uchar *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + for(i = 0; i < n; i++){ + block_cipher(ekey, buf, 0); + buf += 7; + } + if(r) + block_cipher(ekey, buf - 7 + r, 0); + return 1; +} + +/* + * destructively decrypt the buffer, which + * must be at least 8 characters long. + */ +int +decrypt(void *key, void *vbuf, int n) +{ + ulong ekey[128]; + uchar *buf; + int i, r; + + if(n < 8) + return 0; + key_setup(key, ekey); + buf = vbuf; + n--; + r = n % 7; + n /= 7; + buf += n * 7; + if(r) + block_cipher(ekey, buf - 7 + r, 1); + for(i = 0; i < n; i++){ + buf -= 7; + block_cipher(ekey, buf, 1); + } + return 1; +} diff --git a/lib9/ctime.c b/lib9/ctime.c @@ -1,21 +1,135 @@ +/* + * This routine converts time as follows. + * The epoch is 0000 Jan 1 1970 GMT. + * The argument time is in seconds since then. + * The localtime(t) entry returns a pointer to an array + * containing + * + * seconds (0-59) + * minutes (0-59) + * hours (0-23) + * day of month (1-31) + * month (0-11) + * year-1970 + * weekday (0-6, Sun is 0) + * day of the year + * daylight savings flag + * + * The routine gets the daylight savings time from the environment. + * + * asctime(tvec)) + * where tvec is produced by localtime + * returns a ptr to a character string + * that has the ascii time in the form + * + * \\ + * Thu Jan 01 00:00:00 GMT 1970n0 + * 012345678901234567890123456789 + * 0 1 2 + * + * ctime(t) just calls localtime, then asctime. + */ + #include <u.h> #include <libc.h> -static -void -ct_numb(char *cp, int n) +#include "zoneinfo.h" + +static char dmsize[12] = { + 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; - cp[0] = ' '; - if(n >= 10) - cp[0] = (n/10)%10 + '0'; - cp[1] = n%10 + '0'; +#define dysize ctimedysize +static int dysize(int); +static void ct_numb(char*, int); + +char* +ctime(long t) +{ + return asctime(localtime(t)); +} + +Tm* +localtime(long tim) +{ + Tinfo ti; + Tm *ct; + + if (zonelookuptinfo(&ti, tim)!=-1) { + ct = gmtime(tim+ti.tzoff); + strncpy(ct->zone, ti.zone, sizeof ct->zone); + ct->zone[sizeof ct->zone-1] = 0; + ct->tzoff = ti.tzoff; + return ct; + } + return gmtime(tim); +} + +Tm* +gmtime(long tim) +{ + int d0, d1; + long hms, day; + static Tm xtime; + + /* + * break initial number into days + */ + hms = tim % 86400L; + day = tim / 86400L; + if(hms < 0) { + hms += 86400L; + day -= 1; + } + + /* + * generate hours:minutes:seconds + */ + xtime.sec = hms % 60; + d1 = hms / 60; + xtime.min = d1 % 60; + d1 /= 60; + xtime.hour = d1; + + /* + * day is the day number. + * generate day of the week. + * The addend is 4 mod 7 (1/1/1970 was Thursday) + */ + + xtime.wday = (day + 7340036L) % 7; + + /* + * year number + */ + if(day >= 0) + for(d1 = 1970; day >= dysize(d1); d1++) + day -= dysize(d1); + else + for (d1 = 1970; day < 0; d1--) + day += dysize(d1-1); + xtime.year = d1-1900; + xtime.yday = d0 = day; + + /* + * generate month + */ + + if(dysize(d1) == 366) + dmsize[1] = 29; + for(d1 = 0; d0 >= dmsize[d1]; d1++) + d0 -= dmsize[d1]; + dmsize[1] = 28; + xtime.mday = d0 + 1; + xtime.mon = d1; + strcpy(xtime.zone, "GMT"); + return &xtime; } char* asctime(Tm *t) { - int i; char *ncp; static char cbuf[30]; @@ -33,12 +147,6 @@ asctime(Tm *t) ct_numb(cbuf+14, t->min+100); ct_numb(cbuf+17, t->sec+100); ncp = t->zone; - for(i=0; i<3; i++) - if(ncp[i] == 0) - break; - for(; i<3; i++) - ncp[i] = '?'; - ncp = t->zone; cbuf[20] = *ncp++; cbuf[21] = *ncp++; cbuf[22] = *ncp; @@ -50,9 +158,24 @@ asctime(Tm *t) return cbuf; } -char* -ctime(long t) +static +int +dysize(int y) { - return asctime(localtime(t)); + + if(y%4 == 0 && (y%100 != 0 || y%400 == 0)) + return 366; + return 365; +} + +static +void +ct_numb(char *cp, int n) +{ + + cp[0] = ' '; + if(n >= 10) + cp[0] = (n/10)%10 + '0'; + cp[1] = n%10 + '0'; } diff --git a/lib9/debugmalloc.c b/lib9/debugmalloc.c @@ -111,13 +111,13 @@ p9malloc(ulong n) void *v; if(n == 0) n++; -//fprint(2, "%s %d malloc\n", argv0, getpid()); +/*fprint(2, "%s %d malloc\n", argv0, getpid()); */ lock(&malloclock); mallocpid = getpid(); v = malloc(n+Overhead); v = mark(v, getcallerpc(&n), n, MallocMagic); unlock(&malloclock); -//fprint(2, "%s %d donemalloc\n", argv0, getpid()); +/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */ return v; } @@ -127,13 +127,13 @@ p9free(void *v) if(v == nil) return; -//fprint(2, "%s %d free\n", argv0, getpid()); +/*fprint(2, "%s %d free\n", argv0, getpid()); */ lock(&malloclock); mallocpid = getpid(); v = mark(v, getcallerpc(&v), 0, FreeMagic); free(v); unlock(&malloclock); -//fprint(2, "%s %d donefree\n", argv0, getpid()); +/*fprint(2, "%s %d donefree\n", argv0, getpid()); */ } void* @@ -141,26 +141,26 @@ p9calloc(ulong a, ulong b) { void *v; -//fprint(2, "%s %d calloc\n", argv0, getpid()); +/*fprint(2, "%s %d calloc\n", argv0, getpid()); */ lock(&malloclock); mallocpid = getpid(); v = calloc(a*b+Overhead, 1); v = mark(v, getcallerpc(&a), a*b, CallocMagic); unlock(&malloclock); -//fprint(2, "%s %d donecalloc\n", argv0, getpid()); +/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */ return v; } void* p9realloc(void *v, ulong n) { -//fprint(2, "%s %d realloc\n", argv0, getpid()); +/*fprint(2, "%s %d realloc\n", argv0, getpid()); */ lock(&malloclock); mallocpid = getpid(); v = mark(v, getcallerpc(&v), 0, CheckMagic); v = realloc(v, n+Overhead); v = mark(v, getcallerpc(&v), n, ReallocMagic); unlock(&malloclock); -//fprint(2, "%s %d donerealloc\n", argv0, getpid()); +/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */ return v; } diff --git a/lib9/dial.c b/lib9/dial.c @@ -60,10 +60,6 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3) } free(buf); - memset(&sa, 0, sizeof sa); - memmove(&sa.sin_addr, &host, 4); - sa.sin_family = AF_INET; - sa.sin_port = htons(port); if((s = socket(AF_INET, proto, 0)) < 0) return -1; @@ -98,9 +94,17 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3) free(buf); } - if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){ - close(s); - return -1; + n = 1; + setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n); + if(host != 0){ + memset(&sa, 0, sizeof sa); + memmove(&sa.sin_addr, &host, 4); + sa.sin_family = AF_INET; + sa.sin_port = htons(port); + if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){ + close(s); + return -1; + } } if(proto == SOCK_STREAM){ int one = 1; @@ -114,6 +118,9 @@ Unix: free(buf); return -1; } + /* Allow regular files in addition to Unix sockets. */ + if((s = open(unix, ORDWR)) >= 0) + return s; memset(&su, 0, sizeof su); su.sun_family = AF_UNIX; if(strlen(unix)+1 > sizeof su.sun_path){ diff --git a/lib9/dirfwstat.c b/lib9/dirfwstat.c @@ -4,7 +4,7 @@ #include <sys/time.h> #include <sys/stat.h> -#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) +#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__) /* do nothing -- futimes exists and is fine */ #elif defined(__SunOS5_9__) @@ -48,6 +48,10 @@ dirfwstat(int fd, Dir *dir) if(futimes(fd, tv) < 0) ret = -1; } + if(~dir->length != 0){ + if(ftruncate(fd, dir->length) < 0) + ret = -1; + } return ret; } diff --git a/lib9/dirread.c b/lib9/dirread.c @@ -18,19 +18,25 @@ mygetdents(int fd, struct dirent *buf, int n) nn = getdirentries(fd, (void*)buf, n, &off); return nn; } -#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__) +#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) static int mygetdents(int fd, struct dirent *buf, int n) { long off; return getdirentries(fd, (void*)buf, n, &off); } -#elif defined(__sun__) +#elif defined(__sun__) || defined(__NetBSD__) static int mygetdents(int fd, struct dirent *buf, int n) { return getdents(fd, (void*)buf, n); } +#elif defined(__AIX__) +static int +mygetdents(int fd, struct dirent *buf, int n) +{ + return getdirent(fd, (void*)buf, n); +} #endif static int diff --git a/lib9/dirwstat.c b/lib9/dirwstat.c @@ -3,17 +3,29 @@ #include <libc.h> #include <sys/time.h> #include <utime.h> +#include <sys/stat.h> int dirwstat(char *file, Dir *dir) { + int ret; struct utimbuf ub; /* BUG handle more */ - if(~dir->mtime == 0) - return 0; - - ub.actime = dir->mtime; - ub.modtime = dir->mtime; - return utime(file, &ub); + ret = 0; + if(~dir->mode != 0){ + if(chmod(file, dir->mode) < 0) + ret = -1; + } + if(~dir->mtime != 0){ + ub.actime = dir->mtime; + ub.modtime = dir->mtime; + if(utime(file, &ub) < 0) + ret = -1; + } + if(~dir->length != 0){ + if(truncate(file, dir->length) < 0) + ret = -1; + } + return ret; } diff --git a/lib9/encodefmt.c b/lib9/encodefmt.c @@ -1,11 +1,4 @@ #include <lib9.h> -#include <ctype.h> -#include <stdlib.h> -#include "fmt.h" - -extern int enc64(char*, int, uchar*, int); -extern int enc32(char*, int, uchar*, int); -extern int enc16(char*, int, uchar*, int); int encodefmt(Fmt *f) @@ -16,7 +9,7 @@ encodefmt(Fmt *f) int ilen; int rv; uchar *b; - char obuf[64]; // rsc optimization + char obuf[64]; /* rsc optimization */ b = va_arg(f->args, uchar*); if(b == 0) @@ -51,7 +44,7 @@ encodefmt(Fmt *f) } else buf = obuf; - // convert + /* convert */ out = buf; switch(f->r){ case '<': diff --git a/lib9/errstr.c b/lib9/errstr.c @@ -12,7 +12,7 @@ enum { - EPLAN9 = 0x19283745, + EPLAN9 = 0x19283745 }; char *(*_syserrstr)(void); diff --git a/lib9/exitcode.c b/lib9/exitcode.c @@ -0,0 +1,9 @@ +#include <u.h> +#include <libc.h> + +int +exitcode(char *s) +{ + return 1; +} + diff --git a/lib9/fcallfmt.c b/lib9/fcallfmt.c @@ -124,7 +124,7 @@ fcallfmt(Fmt *fmt) break; case Rstat: p = seprint(buf, e, "Rstat tag %ud ", tag); - if(f->nstat > sizeof tmp) + if(f->stat == nil || f->nstat > sizeof tmp) seprint(p, e, " stat(%d bytes)", f->nstat); else{ d = (Dir*)tmp; @@ -135,7 +135,7 @@ fcallfmt(Fmt *fmt) break; case Twstat: /* 126 */ p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid); - if(f->nstat > sizeof tmp) + if(f->stat == nil || f->nstat > sizeof tmp) seprint(p, e, " stat(%d bytes)", f->nstat); else{ d = (Dir*)tmp; diff --git a/lib9/fmt.h b/lib9/fmt.h @@ -34,6 +34,18 @@ struct Fmt{ int width; int prec; unsigned long flags; + char *decimal; /* decimal point; cannot be "" */ + + /* For %'d */ + char *thousands; /* separator for thousands */ + + /* + * Each char is an integer indicating #digits before next separator. Values: + * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX) + * \x00: repeat previous indefinitely + * \x**: count that many + */ + char *grouping; /* descriptor of separator placement */ }; enum{ @@ -43,7 +55,8 @@ enum{ FmtSharp = FmtPrec << 1, FmtSpace = FmtSharp << 1, FmtSign = FmtSpace << 1, - FmtZero = FmtSign << 1, + FmtApost = FmtSign << 1, + FmtZero = FmtApost << 1, FmtUnsigned = FmtZero << 1, FmtShort = FmtUnsigned << 1, FmtLong = FmtShort << 1, @@ -64,6 +77,8 @@ double fmtcharstod(int(*f)(void*), void *vp); int fmtfdflush(Fmt *f); int fmtfdinit(Fmt *f, int fd, char *buf, int size); int fmtinstall(int c, int (*f)(Fmt*)); +int fmtnullinit(Fmt*); +void fmtlocaleinit(Fmt*, char*, char*, char*); int fmtprint(Fmt *f, char *fmt, ...); int fmtrune(Fmt *f, int r); int fmtrunestrcpy(Fmt *f, Rune *s); diff --git a/lib9/fmt/LICENSE b/lib9/fmt/LICENSE @@ -1,19 +1,22 @@ /* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. + * The authors of this software are Rob Pike and Ken Thompson, + * with contributions from Mike Burrows and Sean Dorward. + * + * Copyright (c) 2002-2006 by Lucent Technologies. + * Portions Copyright (c) 2004 Google Inc. + * * Permission to use, copy, modify, and distribute this software for any * purpose without fee is hereby granted, provided that this entire notice * is included in all copies of any software which is or includes a copy * or modification of this software and in all copies of the supporting * documentation for such software. * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. -*/ + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES + * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING + * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ This is a Unix port of the Plan 9 formatted I/O package. -Please send comments about the packaging -to Russ Cox <rsc@post.harvard.edu>. +Please send comments about the packaging to Russ Cox <rsc@swtch.com>. diff --git a/lib9/fmt/LICENSE b/lib9/fmt/NOTICE diff --git a/lib9/fmt/LICENSE b/lib9/fmt/README diff --git a/lib9/fmt/charstod.c b/lib9/fmt/charstod.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/dofmt.c b/lib9/fmt/dofmt.c @@ -1,16 +1,6 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ +/* Copyright (c) 2004 Google Inc.; see LICENSE */ + #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -97,7 +87,7 @@ __fmtflush(Fmt *f, void *t, int len) /* * put a formatted block of memory sz bytes long of n runes into the output buffer, - * left/right justified in a field of at least f->width charactes + * left/right justified in a field of at least f->width characters (if FmtWidth is set) */ int __fmtpad(Fmt *f, int n) @@ -139,8 +129,10 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz) m = (char*)vm; me = m + sz; - w = f->width; fl = f->flags; + w = 0; + if(fl & FmtWidth) + w = f->width; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ @@ -194,8 +186,10 @@ __fmtrcpy(Fmt *f, const void *vm, int n) int w; m = (Rune*)vm; - w = f->width; fl = f->flags; + w = 0; + if(fl & FmtWidth) + w = f->width; if((fl & FmtPrec) && n > f->prec) n = f->prec; if(f->runes){ @@ -252,15 +246,23 @@ int fmtstrcpy(Fmt *f, char *s) { int i, j; - Rune r; if(!s) return __fmtcpy(f, "<nil>", 5, 5); /* if precision is specified, make sure we don't wander off the end */ if(f->flags & FmtPrec){ +#ifdef PLAN9PORT + Rune r; i = 0; for(j=0; j<f->prec && s[i]; j++) i += chartorune(&r, s+i); +#else + /* ANSI requires precision in bytes, not Runes */ + for(i=0; i<f->prec; i++) + if(s[i] == 0) + break; + j = utfnlen(s, i); /* won't print partial at end */ +#endif return __fmtcpy(f, s, j, i); } return __fmtcpy(f, s, utflen(s), strlen(s)); @@ -324,10 +326,14 @@ __percentfmt(Fmt *f) int __ifmt(Fmt *f) { - char buf[70], *p, *conv; + char buf[140], *p, *conv; + /* 140: for 64 bits of binary + 3-byte sep every 4 digits */ uvlong vu; ulong u; int neg, base, i, n, fl, w, isv; + int ndig, len, excess, bytelen; + char *grouping; + char *thousands; neg = 0; fl = f->flags; @@ -339,11 +345,11 @@ __ifmt(Fmt *f) * Unsigned verbs for ANSI C */ switch(f->r){ - case 'x': - case 'X': case 'o': - case 'u': case 'p': + case 'u': + case 'x': + case 'X': fl |= FmtUnsigned; fl &= ~(FmtSign|FmtSpace); break; @@ -381,21 +387,25 @@ __ifmt(Fmt *f) u = va_arg(f->args, int); } conv = "0123456789abcdef"; + grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */ + thousands = f->thousands; switch(f->r){ case 'd': case 'i': case 'u': base = 10; - break; - case 'x': - base = 16; + grouping = f->grouping; break; case 'X': - base = 16; conv = "0123456789ABCDEF"; + /* fall through */ + case 'x': + base = 16; + thousands = ":"; break; case 'b': base = 2; + thousands = ":"; break; case 'o': base = 8; @@ -413,7 +423,11 @@ __ifmt(Fmt *f) } } p = buf + sizeof buf - 1; - n = 0; + n = 0; /* in runes */ + excess = 0; /* number of bytes > number runes */ + ndig = 0; + len = utflen(thousands); + bytelen = strlen(thousands); if(isv){ while(vu){ i = vu % base; @@ -422,6 +436,12 @@ __ifmt(Fmt *f) *p-- = ','; n++; } + if((fl & FmtApost) && __needsep(&ndig, &grouping)){ + n += len; + excess += bytelen - len; + p -= bytelen; + memmove(p+1, thousands, bytelen); + } *p-- = conv[i]; n++; } @@ -433,16 +453,47 @@ __ifmt(Fmt *f) *p-- = ','; n++; } + if((fl & FmtApost) && __needsep(&ndig, &grouping)){ + n += len; + excess += bytelen - len; + p -= bytelen; + memmove(p+1, thousands, bytelen); + } *p-- = conv[i]; n++; } } if(n == 0){ - *p-- = '0'; - n = 1; + /* + * "The result of converting a zero value with + * a precision of zero is no characters." - ANSI + * + * "For o conversion, # increases the precision, if and only if + * necessary, to force the first digit of the result to be a zero + * (if the value and precision are both 0, a single 0 is printed)." - ANSI + */ + if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){ + *p-- = '0'; + n = 1; + if(fl & FmtApost) + __needsep(&ndig, &grouping); + } + + /* + * Zero values don't get 0x. + */ + if(f->r == 'x' || f->r == 'X') + fl &= ~FmtSharp; } - for(w = f->prec; n < w && p > buf+3; n++) + for(w = f->prec; n < w && p > buf+3; n++){ + if((fl & FmtApost) && __needsep(&ndig, &grouping)){ + n += len; + excess += bytelen - len; + p -= bytelen; + memmove(p+1, thousands, bytelen); + } *p-- = '0'; + } if(neg || (fl & (FmtSign|FmtSpace))) n++; if(fl & FmtSharp){ @@ -456,9 +507,19 @@ __ifmt(Fmt *f) } } if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){ - for(w = f->width; n < w && p > buf+3; n++) + w = 0; + if(fl & FmtWidth) + w = f->width; + for(; n < w && p > buf+3; n++){ + if((fl & FmtApost) && __needsep(&ndig, &grouping)){ + n += len; + excess += bytelen - len; + p -= bytelen; + memmove(p+1, thousands, bytelen); + } *p-- = '0'; - f->width = 0; + } + f->flags &= ~FmtWidth; } if(fl & FmtSharp){ if(base == 16) @@ -473,7 +534,7 @@ __ifmt(Fmt *f) else if(fl & FmtSpace) *p-- = ' '; f->flags &= ~FmtPrec; - return __fmtcpy(f, p + 1, n, n); + return __fmtcpy(f, p + 1, n, n + excess); } int @@ -514,6 +575,9 @@ __flagfmt(Fmt *f) case '#': f->flags |= FmtSharp; break; + case '\'': + f->flags |= FmtApost; + break; case ' ': f->flags |= FmtSpace; break; diff --git a/lib9/fmt/dorfmt.c b/lib9/fmt/dorfmt.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -19,6 +7,7 @@ /* format the output into f->to and return the number of characters fmted */ +/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */ int dorfmt(Fmt *f, const Rune *fmt) { @@ -30,8 +19,8 @@ dorfmt(Fmt *f, const Rune *fmt) nfmt = f->nfmt; for(;;){ if(f->runes){ - rt = f->to; - rs = f->stop; + rt = (Rune*)f->to; + rs = (Rune*)f->stop; while((r = *fmt++) && r != '%'){ FMTRCHAR(f, rt, rs, r); } @@ -41,8 +30,8 @@ dorfmt(Fmt *f, const Rune *fmt) return f->nfmt - nfmt; f->stop = rs; }else{ - t = f->to; - s = f->stop; + t = (char*)f->to; + s = (char*)f->stop; while((r = *fmt++) && r != '%'){ FMTRUNE(f, t, f->stop, r); } @@ -53,7 +42,7 @@ dorfmt(Fmt *f, const Rune *fmt) f->stop = s; } - fmt = __fmtdispatch(f, (Rune*)fmt, 1); + fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1); if(fmt == nil) return -1; } diff --git a/lib9/fmt/errfmt.c b/lib9/fmt/errfmt.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <errno.h> #include <string.h> diff --git a/lib9/fmt/fltfmt.c b/lib9/fmt/fltfmt.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdio.h> #include <math.h> #include <float.h> @@ -18,11 +6,12 @@ #include <stdlib.h> #include <errno.h> #include <stdarg.h> -#include <ctype.h> #include <fmt.h> +#include <assert.h> #include "plan9.h" #include "fmt.h" #include "fmtdef.h" +#include "nan.h" enum { @@ -54,8 +43,8 @@ static double pows10[] = 1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149, 1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159, }; - -#define pow10(x) fmtpow10(x) +#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0]))) +#define pow10(x) fmtpow10(x) static double pow10(int n) @@ -65,330 +54,615 @@ pow10(int n) neg = 0; if(n < 0){ - if(n < DBL_MIN_10_EXP){ - return 0.; - } neg = 1; n = -n; - }else if(n > DBL_MAX_10_EXP){ - return HUGE_VAL; } - if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))) + + if(n < npows10) d = pows10[n]; else{ - d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1]; + d = pows10[npows10-1]; for(;;){ - n -= sizeof(pows10)/sizeof(pows10[0]) - 1; - if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){ + n -= npows10 - 1; + if(n < npows10){ d *= pows10[n]; break; } - d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1]; + d *= pows10[npows10 - 1]; } } - if(neg){ + if(neg) return 1./d; - } return d; } +/* + * add 1 to the decimal integer string a of length n. + * if 99999 overflows into 10000, return 1 to tell caller + * to move the virtual decimal point. + */ static int -xadd(char *a, int n, int v) +xadd1(char *a, int n) { char *b; int c; - if(n < 0 || n >= NSIGNIF) + if(n < 0 || n > NSIGNIF) return 0; - for(b = a+n; b >= a; b--) { - c = *b + v; + for(b = a+n-1; b >= a; b--) { + c = *b + 1; if(c <= '9') { *b = c; return 0; } *b = '0'; - v = 1; } - *a = '1'; /* overflow adding */ + /* + * need to overflow adding digit. + * shift number down and insert 1 at beginning. + * decimal is known to be 0s or we wouldn't + * have gotten this far. (e.g., 99999+1 => 00000) + */ + a[0] = '1'; return 1; } +/* + * subtract 1 from the decimal integer string a. + * if 10000 underflows into 09999, make it 99999 + * and return 1 to tell caller to move the virtual + * decimal point. this way, xsub1 is inverse of xadd1. + */ static int -xsub(char *a, int n, int v) +xsub1(char *a, int n) { char *b; int c; - for(b = a+n; b >= a; b--) { - c = *b - v; + if(n < 0 || n > NSIGNIF) + return 0; + for(b = a+n-1; b >= a; b--) { + c = *b - 1; if(c >= '0') { + if(c == '0' && b == a) { + /* + * just zeroed the top digit; shift everyone up. + * decimal is known to be 9s or we wouldn't + * have gotten this far. (e.g., 10000-1 => 09999) + */ + *b = '9'; + return 1; + } *b = c; return 0; } *b = '9'; - v = 1; } - *a = '9'; /* underflow subtracting */ - return 1; + /* + * can't get here. the number a is always normalized + * so that it has a nonzero first digit. + */ + abort(); } +/* + * format exponent like sprintf(p, "e%+02d", e) + */ static void -xdtoa(Fmt *fmt, char *s2, double f) +xfmtexp(char *p, int e, int ucase) { - char s1[NSIGNIF+10]; - double g, h; - int e, d, i, n; - int c1, c2, c3, c4, ucase, sign, chr, prec; + char se[9]; + int i; - prec = FDEFLT; - if(fmt->flags & FmtPrec) - prec = fmt->prec; - if(prec > FDIGIT) - prec = FDIGIT; - if(__isNaN(f)) { - strcpy(s2, "NaN"); - return; - } - if(__isInf(f, 1)) { - strcpy(s2, "+Inf"); - return; - } - if(__isInf(f, -1)) { - strcpy(s2, "-Inf"); - return; + *p++ = ucase ? 'E' : 'e'; + if(e < 0) { + *p++ = '-'; + e = -e; + } else + *p++ = '+'; + i = 0; + while(e) { + se[i++] = e % 10 + '0'; + e /= 10; } - sign = 0; + while(i < 2) + se[i++] = '0'; + while(i > 0) + *p++ = se[--i]; + *p++ = '\0'; +} + +/* + * compute decimal integer m, exp such that: + * f = m*10^exp + * m is as short as possible with losing exactness + * assumes special cases (NaN, +Inf, -Inf) have been handled. + */ +static void +xdtoa(double f, char *s, int *exp, int *neg, int *ns) +{ + int c, d, e2, e, ee, i, ndigit, oerrno; + char tmp[NSIGNIF+10]; + double g; + + oerrno = errno; /* in case strtod smashes errno */ + + /* + * make f non-negative. + */ + *neg = 0; if(f < 0) { f = -f; - sign++; - } - ucase = 0; - chr = fmt->r; - if(isupper(chr)) { - ucase = 1; - chr = tolower(chr); + *neg = 1; } - e = 0; - g = f; - if(g != 0) { - frexp(f, &e); - e = e * .301029995664; - if(e >= -150 && e <= +150) { - d = 0; - h = f; - } else { - d = e/2; - h = f * pow10(-d); - } - g = h * pow10(d-e); - while(g < 1) { - e--; - g = h * pow10(d-e); - } - while(g >= 10) { - e++; - g = h * pow10(d-e); - } + /* + * must handle zero specially. + */ + if(f == 0){ + *exp = 0; + s[0] = '0'; + s[1] = '\0'; + *ns = 1; + return; + } + + /* + * find g,e such that f = g*10^e. + * guess 10-exponent using 2-exponent, then fine tune. + */ + frexp(f, &e2); + e = (int)(e2 * .301029995664); + g = f * pow10(-e); + while(g < 1) { + e--; + g = f * pow10(-e); + } + while(g >= 10) { + e++; + g = f * pow10(-e); } /* - * convert NSIGNIF digits and convert - * back to get accuracy. + * convert NSIGNIF digits as a first approximation. */ for(i=0; i<NSIGNIF; i++) { - d = g; - s1[i] = d + '0'; - g = (g - d) * 10; + d = (int)g; + s[i] = d+'0'; + g = (g-d) * 10; } - s1[i] = 0; + s[i] = 0; /* - * try decimal rounding to eliminate 9s + * adjust e because s is 314159... not 3.14159... */ - c2 = prec + 1; - if(chr == 'f') - c2 += e; - if(c2 >= NSIGNIF-2) { - strcpy(s2, s1); - d = e; - s1[NSIGNIF-2] = '0'; - s1[NSIGNIF-1] = '0'; - sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); - g = strtod(s1, nil); - if(g == f) - goto found; - if(xadd(s1, NSIGNIF-3, 1)) { - e++; - sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); - } - g = strtod(s1, nil); - if(g == f) - goto found; - strcpy(s1, s2); - e = d; - } + e -= NSIGNIF-1; + xfmtexp(s+NSIGNIF, e, 0); /* - * convert back so s1 gets exact answer + * adjust conversion until strtod(s) == f exactly. */ - for(;;) { - sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1); - g = strtod(s1, nil); + for(i=0; i<10; i++) { + g = fmtstrtod(s, nil); if(f > g) { - if(xadd(s1, NSIGNIF-1, 1)) + if(xadd1(s, NSIGNIF)) { + /* gained a digit */ e--; + xfmtexp(s+NSIGNIF, e, 0); + } continue; } if(f < g) { - if(xsub(s1, NSIGNIF-1, 1)) + if(xsub1(s, NSIGNIF)) { + /* lost a digit */ e++; + xfmtexp(s+NSIGNIF, e, 0); + } continue; } break; } -found: /* - * sign + * play with the decimal to try to simplify. */ - d = 0; - i = 0; - if(sign) - s2[d++] = '-'; - else if(fmt->flags & FmtSign) - s2[d++] = '+'; - else if(fmt->flags & FmtSpace) - s2[d++] = ' '; /* - * copy into final place - * c1 digits of leading '0' - * c2 digits from conversion - * c3 digits of trailing '0' - * c4 digits after '.' + * bump last few digits up to 9 if we can + */ + for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { + c = s[i]; + if(c != '9') { + s[i] = '9'; + g = fmtstrtod(s, nil); + if(g != f) { + s[i] = c; + break; + } + } + } + + /* + * add 1 in hopes of turning 9s to 0s + */ + if(s[NSIGNIF-1] == '9') { + strcpy(tmp, s); + ee = e; + if(xadd1(tmp, NSIGNIF)) { + ee--; + xfmtexp(tmp+NSIGNIF, ee, 0); + } + g = fmtstrtod(tmp, nil); + if(g == f) { + strcpy(s, tmp); + e = ee; + } + } + + /* + * bump last few digits down to 0 as we can. + */ + for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) { + c = s[i]; + if(c != '0') { + s[i] = '0'; + g = fmtstrtod(s, nil); + if(g != f) { + s[i] = c; + break; + } + } + } + + /* + * remove trailing zeros. + */ + ndigit = NSIGNIF; + while(ndigit > 1 && s[ndigit-1] == '0'){ + e++; + --ndigit; + } + s[ndigit] = 0; + *exp = e; + *ns = ndigit; + errno = oerrno; +} + +#ifdef PLAN9PORT +static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" }; +#else +static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" }; +#endif + +int +__efgfmt(Fmt *fmt) +{ + char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t; + double f; + int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits; + int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2; + Rune r, *rs, *rt; + + if(fmt->flags&FmtLong) + f = va_arg(fmt->args, long double); + else + f = va_arg(fmt->args, double); + + /* + * extract formatting flags */ - c1 = 0; - c2 = prec + 1; - c3 = 0; - c4 = prec; + fl = fmt->flags; + fmt->flags = 0; + prec = FDEFLT; + if(fl & FmtPrec) + prec = fmt->prec; + chr = fmt->r; + ucase = 0; switch(chr) { - default: - if(xadd(s1, c2, 5)) - e++; + case 'A': + case 'E': + case 'F': + case 'G': + chr += 'a'-'A'; + ucase = 1; break; + } + + /* + * pick off special numbers. + */ + if(__isNaN(f)) { + s = special[0+ucase]; + special: + fmt->flags = fl & (FmtWidth|FmtLeft); + return __fmtcpy(fmt, s, strlen(s), strlen(s)); + } + if(__isInf(f, 1)) { + s = special[2+ucase]; + goto special; + } + if(__isInf(f, -1)) { + s = special[4+ucase]; + goto special; + } + + /* + * get exact representation. + */ + digits = buf; + xdtoa(f, digits, &exp, &neg, &ndigits); + + /* + * get locale's decimal point. + */ + dot = fmt->decimal; + if(dot == nil) + dot = "."; + dotwid = utflen(dot); + + /* + * now the formatting fun begins. + * compute parameters for actual fmt: + * + * pad: number of spaces to insert before/after field. + * z1: number of zeros to insert before digits + * z2: number of zeros to insert after digits + * point: number of digits to print before decimal point + * ndigits: number of digits to use from digits[] + * suf: trailing suffix, like "e-5" + */ + realchr = chr; + switch(chr){ case 'g': /* - * decide on 'e' of 'f' style convers + * convert to at most prec significant digits. (prec=0 means 1) + */ + if(prec == 0) + prec = 1; + if(ndigits > prec) { + if(digits[prec] >= '5' && xadd1(digits, prec)) + exp++; + exp += ndigits-prec; + ndigits = prec; + } + + /* + * extra rules for %g (implemented below): + * trailing zeros removed after decimal unless FmtSharp. + * decimal point only if digit follows. + */ + + /* fall through to %e */ + default: + case 'e': + /* + * one significant digit before decimal, no leading zeros. + */ + point = 1; + z1 = 0; + + /* + * decimal point is after ndigits digits right now. + * slide to be after first. + */ + e = exp + (ndigits-1); + + /* + * if this is %g, check exponent and convert prec */ - if(xadd(s1, c2, 5)) - e++; - if(e >= -5 && e <= prec) { - c1 = -e - 1; - c4 = prec - e; - chr = 'h'; // flag for 'f' style + if(realchr == 'g') { + if(-4 <= e && e < prec) + goto casef; + prec--; /* one digit before decimal; rest after */ + } + + /* + * compute trailing zero padding or truncate digits. + */ + if(1+prec >= ndigits) + z2 = 1+prec - ndigits; + else { + /* + * truncate digits + */ + assert(realchr != 'g'); + newndigits = 1+prec; + if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) { + /* + * had 999e4, now have 100e5 + */ + e++; + } + ndigits = newndigits; + z2 = 0; } + xfmtexp(suf, e, ucase); + sufwid = strlen(suf); break; + + casef: case 'f': - if(xadd(s1, c2+e, 5)) - e++; - c1 = -e; - if(c1 > prec) - c1 = c2; - c2 += e; + /* + * determine where digits go with respect to decimal point + */ + if(ndigits+exp > 0) { + point = ndigits+exp; + z1 = 0; + } else { + point = 1; + z1 = 1 + -(ndigits+exp); + } + + /* + * %g specifies prec = number of significant digits + * convert to number of digits after decimal point + */ + if(realchr == 'g') + prec += z1 - point; + + /* + * compute trailing zero padding or truncate digits. + */ + if(point+prec >= z1+ndigits) + z2 = point+prec - (z1+ndigits); + else { + /* + * truncate digits + */ + assert(realchr != 'g'); + newndigits = point+prec - z1; + if(newndigits < 0) { + z1 += newndigits; + newndigits = 0; + } else if(newndigits == 0) { + /* perhaps round up */ + if(digits[0] >= '5'){ + digits[0] = '1'; + newndigits = 1; + goto newdigit; + } + } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) { + /* + * digits was 999, is now 100; make it 1000 + */ + digits[newndigits++] = '0'; + newdigit: + /* + * account for new digit + */ + if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/ + z1--; + else /* 9.99 => 10.00 */ + point++; + } + z2 = 0; + ndigits = newndigits; + } + sufwid = 0; break; } - + /* - * clean up c1 c2 and c3 + * if %g is given without FmtSharp, remove trailing zeros. + * must do after truncation, so that e.g. print %.3g 1.001 + * produces 1, not 1.00. sorry, but them's the rules. */ - if(c1 < 0) - c1 = 0; - if(c2 < 0) - c2 = 0; - if(c2 > NSIGNIF) { - c3 = c2-NSIGNIF; - c2 = NSIGNIF; + if(realchr == 'g' && !(fl & FmtSharp)) { + if(z1+ndigits+z2 >= point) { + if(z1+ndigits < point) + z2 = point - (z1+ndigits); + else{ + z2 = 0; + while(z1+ndigits > point && digits[ndigits-1] == '0') + ndigits--; + } + } } /* - * copy digits + * compute width of all digits and decimal point and suffix if any */ - while(c1 > 0) { - if(c1+c2+c3 == c4) - s2[d++] = '.'; - s2[d++] = '0'; - c1--; - } - while(c2 > 0) { - if(c2+c3 == c4) - s2[d++] = '.'; - s2[d++] = s1[i++]; - c2--; + wid = z1+ndigits+z2; + if(wid > point) + wid += dotwid; + else if(wid == point){ + if(fl & FmtSharp) + wid += dotwid; + else + point++; /* do not print any decimal point */ } - while(c3 > 0) { - if(c3 == c4) - s2[d++] = '.'; - s2[d++] = '0'; - c3--; + wid += sufwid; + + /* + * determine sign + */ + sign = 0; + if(neg) + sign = '-'; + else if(fl & FmtSign) + sign = '+'; + else if(fl & FmtSpace) + sign = ' '; + if(sign) + wid++; + + /* + * compute padding + */ + pad = 0; + if((fl & FmtWidth) && fmt->width > wid) + pad = fmt->width - wid; + if(pad && !(fl & FmtLeft) && (fl & FmtZero)){ + z1 += pad; + point += pad; + pad = 0; } /* - * strip trailing '0' on g conv + * format the actual field. too bad about doing this twice. */ - if(fmt->flags & FmtSharp) { - if(0 == c4) - s2[d++] = '.'; - } else - if(chr == 'g' || chr == 'h') { - for(n=d-1; n>=0; n--) - if(s2[n] != '0') - break; - for(i=n; i>=0; i--) - if(s2[i] == '.') { - d = n; - if(i != n) - d++; - break; + if(fmt->runes){ + if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) + return -1; + rt = (Rune*)fmt->to; + rs = (Rune*)fmt->stop; + if(sign) + FMTRCHAR(fmt, rt, rs, sign); + while(z1>0 || ndigits>0 || z2>0) { + if(z1 > 0){ + z1--; + c = '0'; + }else if(ndigits > 0){ + ndigits--; + c = *digits++; + }else{ + z2--; + c = '0'; } - } - if(chr == 'e' || chr == 'g') { - if(ucase) - s2[d++] = 'E'; - else - s2[d++] = 'e'; - c1 = e; - if(c1 < 0) { - s2[d++] = '-'; - c1 = -c1; - } else - s2[d++] = '+'; - if(c1 >= 100) { - s2[d++] = c1/100 + '0'; - c1 = c1%100; + FMTRCHAR(fmt, rt, rs, c); + if(--point == 0) { + for(p = dot; *p; ){ + p += chartorune(&r, p); + FMTRCHAR(fmt, rt, rs, r); + } + } + } + fmt->nfmt += rt - (Rune*)fmt->to; + fmt->to = rt; + if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) + return -1; + if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0) + return -1; + }else{ + if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0) + return -1; + t = (char*)fmt->to; + s = (char*)fmt->stop; + if(sign) + FMTCHAR(fmt, t, s, sign); + while(z1>0 || ndigits>0 || z2>0) { + if(z1 > 0){ + z1--; + c = '0'; + }else if(ndigits > 0){ + ndigits--; + c = *digits++; + }else{ + z2--; + c = '0'; + } + FMTCHAR(fmt, t, s, c); + if(--point == 0) + for(p=dot; *p; p++) + FMTCHAR(fmt, t, s, *p); } - s2[d++] = c1/10 + '0'; - s2[d++] = c1%10 + '0'; + fmt->nfmt += t - (char*)fmt->to; + fmt->to = t; + if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0) + return -1; + if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0) + return -1; } - s2[d] = 0; -} - -static int -floatfmt(Fmt *fmt, double f) -{ - char s[FDIGIT+10]; - - xdtoa(fmt, s, f); - fmt->flags &= FmtWidth|FmtLeft; - __fmtcpy(fmt, s, strlen(s), strlen(s)); return 0; } -int -__efgfmt(Fmt *f) -{ - double d; - - d = va_arg(f->args, double); - return floatfmt(f, d); -} diff --git a/lib9/fmt/fmt.c b/lib9/fmt/fmt.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -29,7 +17,7 @@ struct Convfmt volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */ }; -struct +static struct { /* lock by calling __fmtlock, __fmtunlock */ int nfmt; @@ -40,6 +28,7 @@ static Convfmt knownfmt[] = { ' ', __flagfmt, '#', __flagfmt, '%', __percentfmt, + '\'', __flagfmt, '+', __flagfmt, ',', __flagfmt, '-', __flagfmt, diff --git a/lib9/fmt/fmtdef.h b/lib9/fmt/fmtdef.h @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY - * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ /* * dofmt -- format to a buffer @@ -53,6 +41,7 @@ void __fmtunlock(void); int __ifmt(Fmt *f); int __isInf(double d, int sign); int __isNaN(double d); +int __needsep(int*, char**); int __needsquotes(char *s, int *quotelenp); int __percentfmt(Fmt *f); void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout); @@ -66,9 +55,9 @@ int __strfmt(Fmt *f); #define FMTCHAR(f, t, s, c)\ do{\ if(t + 1 > (char*)s){\ - t = __fmtflush(f, t, 1);\ + t = (char*)__fmtflush(f, t, 1);\ if(t != nil)\ - s = f->stop;\ + s = (char*)f->stop;\ else\ return -1;\ }\ @@ -78,9 +67,9 @@ int __strfmt(Fmt *f); #define FMTRCHAR(f, t, s, c)\ do{\ if(t + 1 > (Rune*)s){\ - t = __fmtflush(f, t, sizeof(Rune));\ + t = (Rune*)__fmtflush(f, t, sizeof(Rune));\ if(t != nil)\ - s = f->stop;\ + s = (Rune*)f->stop;\ else\ return -1;\ }\ @@ -92,9 +81,9 @@ int __strfmt(Fmt *f); Rune _rune;\ int _runelen;\ if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\ - t = __fmtflush(f, t, _runelen);\ + t = (char*)__fmtflush(f, t, _runelen);\ if(t != nil)\ - s = f->stop;\ + s = (char*)f->stop;\ else\ return -1;\ }\ diff --git a/lib9/fmt/fmtfd.c b/lib9/fmt/fmtfd.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -40,7 +28,9 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size) f->to = buf; f->stop = buf + size; f->flush = __fmtFdFlush; - f->farg = (void*)fd; + f->farg = (void*)(uintptr_t)fd; + f->flags = 0; f->nfmt = 0; + fmtlocaleinit(f, nil, nil, nil); return 0; } diff --git a/lib9/fmt/fmtfdflush.c b/lib9/fmt/fmtfdflush.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <unistd.h> #include "plan9.h" @@ -27,7 +15,7 @@ __fmtFdFlush(Fmt *f) int n; n = (char*)f->to - (char*)f->start; - if(n && write((int)f->farg, f->start, n) != n) + if(n && write((uintptr)f->farg, f->start, n) != n) return 0; f->to = f->start; return 1; diff --git a/lib9/fmt/fmtlocale.c b/lib9/fmt/fmtlocale.c @@ -0,0 +1,55 @@ +/* Copyright (c) 2004 Google Inc.; see LICENSE */ + +#include <stdarg.h> +#include <string.h> +#include "plan9.h" +#include "fmt.h" +#include "fmtdef.h" + +/* + * Fill in the internationalization stuff in the State structure. + * For nil arguments, provide the sensible defaults: + * decimal is a period + * thousands separator is a comma + * thousands are marked every three digits + */ +void +fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping) +{ + if(decimal == nil || decimal[0] == '\0') + decimal = "."; + if(thousands == nil) + thousands = ","; + if(grouping == nil) + grouping = "\3"; + f->decimal = decimal; + f->thousands = thousands; + f->grouping = grouping; +} + +/* + * We are about to emit a digit in e.g. %'d. If that digit would + * overflow a thousands (e.g.) grouping, tell the caller to emit + * the thousands separator. Always advance the digit counter + * and pointer into the grouping descriptor. + */ +int +__needsep(int *ndig, char **grouping) +{ + int group; + + (*ndig)++; + group = *(unsigned char*)*grouping; + /* CHAR_MAX means no further grouping. \0 means we got the empty string */ + if(group == 0xFF || group == 0x7f || group == 0x00) + return 0; + if(*ndig > group){ + /* if we're at end of string, continue with this grouping; else advance */ + if((*grouping)[1] != '\0') + (*grouping)++; + *ndig = 1; + return 1; + } + return 0; +} + diff --git a/lib9/fmt/fmtlock.c b/lib9/fmt/fmtlock.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/fmtnull.c b/lib9/fmt/fmtnull.c @@ -0,0 +1,33 @@ +/* Copyright (c) 2004 Google Inc.; see LICENSE */ +#include <stdarg.h> +#include <string.h> +#include "plan9.h" +#include "fmt.h" +#include "fmtdef.h" + +/* + * Absorb output without using resources. + */ +static Rune nullbuf[32]; + +static int +__fmtnullflush(Fmt *f) +{ + f->to = nullbuf; + f->nfmt = 0; + return 0; +} + +int +fmtnullinit(Fmt *f) +{ + memset(f, 0, sizeof *f); + f->runes = 1; + f->start = nullbuf; + f->to = nullbuf; + f->stop = nullbuf+nelem(nullbuf); + f->flush = __fmtnullflush; + fmtlocaleinit(f, nil, nil, nil); + return 0; +} + diff --git a/lib9/fmt/fmtprint.c b/lib9/fmt/fmtprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/fmtquote.c b/lib9/fmt/fmtquote.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -103,6 +91,11 @@ __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int r /* advance output */ q->nbytesout += w; q->nrunesout++; + +#ifndef PLAN9PORT + /* ANSI requires precision in bytes, not Runes. */ + nin-= w-1; /* and then n-- in the loop */ +#endif } } @@ -120,8 +113,10 @@ qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f) rm = rin; rme = rm + q->nrunesin; - w = f->width; fl = f->flags; + w = 0; + if(fl & FmtWidth) + w = f->width; if(f->runes){ if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0) return -1; @@ -209,7 +204,7 @@ __quotestrfmt(int runesin, Fmt *f) outlen = (char*)f->stop - (char*)f->to; __quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes); -//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); +/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */ if(runesin){ if(!q.quoted) diff --git a/lib9/fmt/fmtrune.c b/lib9/fmt/fmtrune.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/fmtstr.c b/lib9/fmt/fmtstr.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdlib.h> #include <stdarg.h> #include "plan9.h" @@ -23,5 +11,6 @@ fmtstrflush(Fmt *f) if(f->start == nil) return nil; *(char*)f->to = '\0'; + f->to = f->start; return (char*)f->start; } diff --git a/lib9/fmt/fmtvprint.c b/lib9/fmt/fmtvprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/fprint.c b/lib9/fmt/fprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/nan.h b/lib9/fmt/nan.h @@ -0,0 +1,4 @@ +extern double __NaN(void); +extern double __Inf(int); +extern int __isNaN(double); +extern int __isInf(double, int); diff --git a/lib9/fmt/nan64.c b/lib9/fmt/nan64.c @@ -6,58 +6,67 @@ */ #include "plan9.h" +#include <assert.h> #include "fmt.h" #include "fmtdef.h" -#if defined (__APPLE__) || (__powerpc__) -#define _NEEDLL -#endif - static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001; static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000; static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000; +/* gcc sees through the obvious casts. */ +static uvlong +d2u(double d) +{ + union { + uvlong v; + double d; + } u; + assert(sizeof(u.d) == sizeof(u.v)); + u.d = d; + return u.v; +} + +static double +u2d(uvlong v) +{ + union { + uvlong v; + double d; + } u; + assert(sizeof(u.d) == sizeof(u.v)); + u.v = v; + return u.d; +} + double __NaN(void) { - uvlong *p; - - /* gcc complains about "return *(double*)&uvnan;" */ - p = &uvnan; - return *(double*)p; + return u2d(uvnan); } int __isNaN(double d) { uvlong x; - double *p; - - p = &d; - x = *(uvlong*)p; - return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0); + + x = d2u(d); + /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */ + return (x&uvinf) == uvinf && (x&~uvneginf) != 0; } double __Inf(int sign) { - uvlong *p; - - if(sign < 0) - p = &uvinf; - else - p = &uvneginf; - return *(double*)p; + return u2d(sign < 0 ? uvneginf : uvinf); } int __isInf(double d, int sign) { uvlong x; - double *p; - - p = &d; - x = *(uvlong*)p; + + x = d2u(d); if(sign == 0) return x==uvinf || x==uvneginf; else if(sign > 0) diff --git a/lib9/fmt/plan9.h b/lib9/fmt/plan9.h @@ -1,3 +1,5 @@ +#include <inttypes.h> + /* * compiler directive on Plan 9 */ @@ -14,12 +16,15 @@ #define ulong _fmtulong #define vlong _fmtvlong #define uvlong _fmtuvlong +#define uintptr _fmtuintptr + typedef unsigned char uchar; typedef unsigned short ushort; typedef unsigned int uint; typedef unsigned long ulong; typedef unsigned long long uvlong; typedef long long vlong; +typedef uintptr_t uintptr; /* * nil cannot be ((void*)0) on ANSI C, diff --git a/lib9/fmt/pow10.c b/lib9/fmt/pow10.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/print.c b/lib9/fmt/print.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/runefmtstr.c b/lib9/fmt/runefmtstr.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <stdlib.h> #include "plan9.h" @@ -23,5 +11,6 @@ runefmtstrflush(Fmt *f) if(f->start == nil) return nil; *(Rune*)f->to = '\0'; + f->to = f->start; return f->start; } diff --git a/lib9/fmt/runeseprint.c b/lib9/fmt/runeseprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/runesmprint.c b/lib9/fmt/runesmprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/runesnprint.c b/lib9/fmt/runesnprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/runesprint.c b/lib9/fmt/runesprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/fmt/runevseprint.c b/lib9/fmt/runevseprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -32,6 +20,7 @@ runevseprint(Rune *buf, Rune *e, char *fmt, va_list args) f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); + fmtlocaleinit(&f, nil, nil, nil); dofmt(&f, fmt); VA_END(f.args); *(Rune*)f.to = '\0'; diff --git a/lib9/fmt/runevsmprint.c b/lib9/fmt/runevsmprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ /* * Plan 9 port version must include libc.h in order to * get Plan 9 debugging malloc, which sometimes returns @@ -36,7 +24,7 @@ runeFmtStrFlush(Fmt *f) if(f->start == nil) return 0; - n = (int)f->farg; + n = (uintptr)f->farg; n *= 2; s = (Rune*)f->start; f->start = realloc(s, sizeof(Rune)*n); @@ -47,7 +35,7 @@ runeFmtStrFlush(Fmt *f) free(s); return 0; } - f->farg = (void*)n; + f->farg = (void*)(uintptr)n; f->to = (Rune*)f->start + ((Rune*)f->to - s); f->stop = (Rune*)f->start + n - 1; return 1; @@ -67,8 +55,9 @@ runefmtstrinit(Fmt *f) f->to = f->start; f->stop = (Rune*)f->start + n - 1; f->flush = runeFmtStrFlush; - f->farg = (void*)n; + f->farg = (void*)(uintptr)n; f->nfmt = 0; + fmtlocaleinit(f, nil, nil, nil); return 0; } diff --git a/lib9/fmt/runevsnprint.c b/lib9/fmt/runevsnprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <string.h> #include "plan9.h" @@ -32,6 +20,7 @@ runevsnprint(Rune *buf, int len, char *fmt, va_list args) f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); + fmtlocaleinit(&f, nil, nil, nil); dofmt(&f, fmt); VA_END(f.args); *(Rune*)f.to = '\0'; diff --git a/lib9/fmt/seprint.c b/lib9/fmt/seprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/smprint.c b/lib9/fmt/smprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/snprint.c b/lib9/fmt/snprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/sprint.c b/lib9/fmt/sprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include <fmt.h> #include "plan9.h" @@ -28,9 +16,12 @@ sprint(char *buf, char *fmt, ...) /* * on PowerPC, the stack is near the top of memory, so * we must be sure not to overflow a 32-bit pointer. + * + * careful! gcc-4.2 assumes buf+len < buf can never be true and + * optimizes the test away. casting to uintptr works around this bug. */ - if(buf+len < buf) - len = -(uint)buf-1; + if((uintptr)buf+len < (uintptr)buf) + len = -(uintptr)buf-1; va_start(args, fmt); n = vsnprint(buf, len, fmt, args); diff --git a/lib9/fmt/strtod.c b/lib9/fmt/strtod.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdlib.h> #include <math.h> #include <ctype.h> @@ -67,7 +55,7 @@ enum S4, /* _+#.# #S4 eS5 */ S5, /* _+#.#e +S6 #S7 */ S6, /* _+#.#e+ #S7 */ - S7, /* _+#.#e+# #S7 */ + S7 /* _+#.#e+# #S7 */ }; static int xcmp(char*, char*); @@ -239,7 +227,7 @@ fmtstrtod(const char *as, char **aas) /* close approx by naive conversion */ mid[0] = 0; mid[1] = 1; - for(i=0; c=a[i]; i++) { + for(i=0; (c=a[i]) != '\0'; i++) { mid[0] = mid[0]*10 + (c-'0'); mid[1] = mid[1]*10; if(i >= 8) @@ -521,7 +509,7 @@ xcmp(char *a, char *b) { int c1, c2; - while(c1 = *b++) { + while((c1 = *b++) != '\0') { c2 = *a++; if(isupper(c2)) c2 = tolower(c2); diff --git a/lib9/fmt/test.c b/lib9/fmt/test.c @@ -1,16 +1,6 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ +/* Copyright (c) 2004 Google Inc.; see LICENSE */ + #include <stdio.h> #include <stdarg.h> #include <utf.h> @@ -40,5 +30,24 @@ main(int argc, char *argv[]) print("%d\n", 23); print("%i\n", 23); print("%0.10d\n", 12345); + + /* test %4$d formats */ + print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222); + print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222); + print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20); + print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20); + print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20); + + /* test %'d formats */ + print("%'d %'d %'d\n", 1, 2222, 33333333); + print("%'019d\n", 0); + print("%08d %08d %08d\n", 1, 2222, 33333333); + print("%'08d %'08d %'08d\n", 1, 2222, 33333333); + print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345); + print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL); + print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL); + print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL); + print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL); + print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL); return 0; } diff --git a/lib9/fmt/vfprint.c b/lib9/fmt/vfprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" diff --git a/lib9/fmt/vseprint.c b/lib9/fmt/vseprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdarg.h> #include "plan9.h" #include "fmt.h" @@ -31,6 +19,7 @@ vseprint(char *buf, char *e, char *fmt, va_list args) f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); + fmtlocaleinit(&f, nil, nil, nil); dofmt(&f, fmt); VA_END(f.args); *(char*)f.to = '\0'; diff --git a/lib9/fmt/vsmprint.c b/lib9/fmt/vsmprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ /* * Plan 9 port version must include libc.h in order to * get Plan 9 debugging malloc, which sometimes returns @@ -36,7 +24,7 @@ fmtStrFlush(Fmt *f) if(f->start == nil) return 0; - n = (int)f->farg; + n = (uintptr)f->farg; n *= 2; s = (char*)f->start; f->start = realloc(s, n); @@ -47,7 +35,7 @@ fmtStrFlush(Fmt *f) free(s); return 0; } - f->farg = (void*)n; + f->farg = (void*)(uintptr)n; f->to = (char*)f->start + ((char*)f->to - s); f->stop = (char*)f->start + n - 1; return 1; @@ -67,8 +55,9 @@ fmtstrinit(Fmt *f) f->to = f->start; f->stop = (char*)f->start + n - 1; f->flush = fmtStrFlush; - f->farg = (void*)n; + f->farg = (void*)(uintptr)n; f->nfmt = 0; + fmtlocaleinit(f, nil, nil, nil); return 0; } diff --git a/lib9/fmt/vsnprint.c b/lib9/fmt/vsnprint.c @@ -1,16 +1,4 @@ -/* - * The authors of this software are Rob Pike and Ken Thompson. - * Copyright (c) 2002 by Lucent Technologies. - * Permission to use, copy, modify, and distribute this software for any - * purpose without fee is hereby granted, provided that this entire notice - * is included in all copies of any software which is or includes a copy - * or modification of this software and in all copies of the supporting - * documentation for such software. - * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED - * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE - * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY - * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. - */ +/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */ #include <stdlib.h> #include <stdarg.h> #include "plan9.h" @@ -32,6 +20,7 @@ vsnprint(char *buf, int len, char *fmt, va_list args) f.farg = nil; f.nfmt = 0; VA_COPY(f.args,args); + fmtlocaleinit(&f, nil, nil, nil); dofmt(&f, fmt); VA_END(f.args); *(char*)f.to = '\0'; diff --git a/lib9/getcallerpc-arm.c b/lib9/getcallerpc-arm.c @@ -0,0 +1,8 @@ +#include <lib9.h> + +ulong +getcallerpc(void *x) +{ + return ((ulong*)x)[-2]; +} + diff --git a/lib9/getnetconn.c b/lib9/getnetconn.c @@ -91,12 +91,12 @@ getnetconninfo(char *dir, int fd) nci->spec = unknown; if(nci->dir == nil || nci->root == nil) goto err; - sn = sizeof sn; + sn = sizeof u; if(getsockname(fd, &u.sa, &sn) < 0) goto err; if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0) goto err; - sn = sizeof sn; + sn = sizeof u; if(getpeername(fd, &u.sa, &sn) < 0) goto err; if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0) diff --git a/lib9/getns.c b/lib9/getns.c @@ -2,6 +2,17 @@ #include <libc.h> #include <ctype.h> +static int +isme(char *uid) +{ + int n; + char *p; + + n = strtol(uid, &p, 10); + if(*p == 0 && p > uid) + return n == getuid(); + return strcmp(getuser(), uid) == 0; +} /* * Absent other hints, it works reasonably well to use * the X11 display name as the name space identifier. @@ -18,8 +29,15 @@ nsfromdisplay(void) char *disp, *p; if((disp = getenv("DISPLAY")) == nil){ +#ifdef __APPLE__ + // Might be running native GUI on OS X. + disp = strdup(":0.0"); + if(disp == nil) + return nil; +#else werrstr("$DISPLAY not set"); return nil; +#endif } /* canonicalize: xxx:0.0 => xxx:0 */ @@ -31,6 +49,11 @@ nsfromdisplay(void) if(strcmp(p, ".0") == 0) *p = 0; } + + /* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */ + for(p=disp; *p; p++) + if(*p == '/') + *p = '_'; p = smprint("/tmp/ns.%s.%s", getuser(), disp); free(disp); @@ -48,7 +71,7 @@ nsfromdisplay(void) free(p); return nil; } - if((d->mode&0777) != 0700 || strcmp(d->uid, getuser()) != 0){ + if((d->mode&0777) != 0700 || !isme(d->uid)){ werrstr("bad name space dir %s", p); free(p); free(d); diff --git a/lib9/lib9.h b/lib9/lib9.h @@ -1,17 +1,2 @@ -#include <string.h> -#include "utf.h" - -#define nil ((void*)0) - -#define uchar _fmtuchar -#define ushort _fmtushort -#define uint _fmtuint -#define ulong _fmtulong -#define vlong _fmtvlong -#define uvlong _fmtuvlong - -typedef unsigned char uchar; -typedef unsigned short ushort; -typedef unsigned int uint; -typedef unsigned long ulong; - +#include <u.h> +#include <libc.h> diff --git a/lib9/libc.h b/lib9/libc.h @@ -349,7 +349,7 @@ extern vlong p9nsec(void); enum { PNPROC = 1, - PNGROUP = 2, + PNGROUP = 2 }; /* extern int abs(int); <stdlib.h> */ @@ -376,6 +376,7 @@ extern int dec16(uchar*, int, char*, int); extern int enc16(char*, int, uchar*, int); extern int encodefmt(Fmt*); extern int dirmodefmt(Fmt*); +extern int exitcode(char*); extern void exits(char*); extern double frexp(double, int*); extern ulong getcallerpc(void*); @@ -390,7 +391,7 @@ extern int iounit(int); /* extern double ldexp(double, int); <math.h> */ extern void p9longjmp(p9jmp_buf, int); extern char* mktemp(char*); -extern int opentemp(char*); +extern int opentemp(char*, int); /* extern double modf(double, double*); <math.h> */ extern void p9notejmp(void*, p9jmp_buf, int); extern void perror(const char*); @@ -416,6 +417,9 @@ extern long p9time(long*); extern void needstack(int); extern char* readcons(char*, char*, int); +extern void (*_pin)(void); +extern void (*_unpin)(void); + #ifndef NOPLAN9DEFINES #define atexit p9atexit #define atexitdont p9atexitdont @@ -670,7 +674,7 @@ enum RFNOWAIT = (1<<6), RFCNAMEG = (1<<10), RFCENVG = (1<<11), - RFCFDG = (1<<12), + RFCFDG = (1<<12) /* RFREND = (1<<13), */ /* RFNOMNT = (1<<14) */ }; @@ -789,6 +793,7 @@ extern int p9waitpid(void); extern long write(int, void*, long); extern long writev(int, IOchunk*, int); */ +extern long p9write(int, void*, long); /* extern int wstat(char*, uchar*, int); give up */ extern ulong rendezvous(ulong, ulong); @@ -809,6 +814,7 @@ extern ulong rendezvous(ulong, ulong); #define open p9open #define pipe p9pipe #define waitfor p9waitfor +#define write p9write #endif extern Dir* dirstat(char*); @@ -828,7 +834,8 @@ extern char* get9root(void); extern char* unsharp(char*); extern int sendfd(int, int); extern int recvfd(int); -extern int post9pservice(int, char*); +extern int post9pservice(int, char*, char*); +extern int chattyfuse; /* external names that we don't want to step on */ #ifndef NOPLAN9DEFINES @@ -900,7 +907,7 @@ extern int post9pservice(int, char*); #ifdef __GNUC__ # if __GNUC__ >= 3 # undef USED -# define USED(x) { ulong __y __attribute__ ((unused)); __y = (ulong)(x); } +# define USED(x) ((void)(x)) # endif #endif diff --git a/lib9/malloctag.c b/lib9/malloctag.c @@ -1,9 +1,5 @@ #include <lib9.h> -extern long p9lrand(void); -#define USED(x) if(x){}else{} -#define lrand p9lrand - void setmalloctag(void *v, ulong t) { diff --git a/lib9/nan.c b/lib9/nan.c @@ -1,6 +1,6 @@ #include <u.h> #include <libc.h> -#include "nan.h" +#include "fmt/nan.h" double NaN(void) diff --git a/lib9/netcrypt.c b/lib9/netcrypt.c @@ -0,0 +1,18 @@ +#include <u.h> +#include <libc.h> +#include <auth.h> + +int +netcrypt(void *key, void *chal) +{ + uchar buf[8], *p; + + strncpy((char*)buf, chal, 7); + buf[7] = '\0'; + for(p = buf; *p && *p != '\n'; p++) + ; + *p = '\0'; + encrypt(key, buf, 8); + sprint(chal, "%.2ux%.2ux%.2ux%.2ux", buf[0], buf[1], buf[2], buf[3]); + return 1; +} diff --git a/lib9/netmkaddr.c b/lib9/netmkaddr.c @@ -16,21 +16,25 @@ netmkaddr(char *linear, char *defnet, char *defsrv) */ cp = strchr(linear, '!'); if(cp == 0){ - if(defnet==0){ - if(defsrv) - snprint(addr, sizeof(addr), "net!%s!%s", - linear, defsrv); - else - snprint(addr, sizeof(addr), "net!%s", linear); + if(defnet == 0) + defnet = "net"; + /* allow unix sockets to omit unix! prefix */ + if(access(linear, 0) >= 0){ + snprint(addr, sizeof(addr), "unix!%s", linear); + return addr; } - else { - if(defsrv) - snprint(addr, sizeof(addr), "%s!%s!%s", defnet, - linear, defsrv); - else - snprint(addr, sizeof(addr), "%s!%s", defnet, - linear); + /* allow host:service in deference to Unix convention */ + if((cp = strchr(linear, ':')) != nil){ + snprint(addr, sizeof(addr), "%s!%.*s!%s", + defnet, utfnlen(linear, cp-linear), + linear, cp+1); + return addr; } + if(defsrv) + snprint(addr, sizeof(addr), "%s!%s!%s", + defnet, linear, defsrv); + else + snprint(addr, sizeof(addr), "%s!%s", defnet, linear); return addr; } @@ -42,11 +46,17 @@ netmkaddr(char *linear, char *defnet, char *defsrv) return linear; /* + * if the network is unix, no service + */ + if(strncmp(linear, "unix!", 5) == 0) + return linear; + + /* * add default service */ if(defsrv == 0) return linear; - snprint(addr, sizeof(addr), "%s!%s", linear, defsrv); + snprint(addr, sizeof(addr), "%s!%s", linear, defsrv); return addr; } diff --git a/lib9/notify.c b/lib9/notify.c @@ -38,6 +38,7 @@ enum { Restart = 1<<0, Ignore = 1<<1, + NoNotify = 1<<2, }; static Sig sigs[] = { @@ -58,7 +59,7 @@ static Sig sigs[] = { SIGPIPE, Ignore, SIGALRM, 0, SIGTERM, 0, - SIGTSTP, Restart|Ignore, + SIGTSTP, Restart|Ignore|NoNotify, /* SIGTTIN, Restart|Ignore, */ /* SIGTTOU, Restart|Ignore, */ SIGXCPU, 0, @@ -67,10 +68,10 @@ static Sig sigs[] = { SIGUSR1, 0, SIGUSR2, 0, #ifdef SIGWINCH - SIGWINCH, Restart|Ignore, + SIGWINCH, Restart|Ignore|NoNotify, #endif #ifdef SIGINFO - SIGINFO, Restart|Ignore, + SIGINFO, Restart|Ignore|NoNotify, #endif }; @@ -266,7 +267,7 @@ noteinit(void) */ if(handler(sig->sig) != SIG_DFL) continue; - notifyseton(sig->sig, 1); + notifyseton(sig->sig, !(sig->flags&NoNotify)); } } diff --git a/lib9/nrand.c b/lib9/nrand.c @@ -1,7 +1,5 @@ #include <lib9.h> -extern long p9lrand(void); -#define lrand p9lrand #define MASK 0x7fffffffL int diff --git a/lib9/nulldir.c b/lib9/nulldir.c @@ -5,5 +5,5 @@ void nulldir(Dir *d) { memset(d, ~0, sizeof(Dir)); - d->name = d->uid = d->gid = d->muid = ""; + d->name = d->uid = d->gid = d->muid = d->ext = ""; } diff --git a/lib9/opentemp.c b/lib9/opentemp.c @@ -2,14 +2,19 @@ #include <libc.h> int -opentemp(char *template) +opentemp(char *template, int mode) { - int fd; + int fd, fd1; fd = mkstemp(template); if(fd < 0) return -1; - remove(template); - return fd; + if((fd1 = open(template, mode)) < 0){ + remove(template); + close(fd); + return -1; + } + close(fd); + return fd1; } diff --git a/lib9/pin.c b/lib9/pin.c @@ -0,0 +1,11 @@ +#include <u.h> +#include <libc.h> + +static void +nop(void) +{ +} + +void (*_pin)(void) = nop; +void (*_unpin)(void) = nop; + diff --git a/lib9/portdate b/lib9/portdate @@ -1,30 +1,55 @@ -dofmt.c 2004/1225 -dorfmt.c 2004/1225 -errfmt.c 2004/1225 -fltfmt.c 2004/1225 -fmt.c 2004/1225 -fmtfd.c 2004/1225 -fmtlock.c 2004/1225 -fmtprint.c 2004/1225 -fmtquote.c 2004/1225 -fmtrune.c 2004/1225 -fmtstr.c 2004/1225 -fmtvprint.c 2004/1225 -fprint.c 2004/1225 -print.c 2004/1225 -runefmtstr.c 2004/1225 -runeseprint.c 2004/1225 -runesmprint.c 2004/1225 -runesnprint.c 2004/1225 -runesprint.c 2004/1225 -runevseprint.c 2004/1225 -runevsmprint.c 2004/1225 -runevsnprint.c 2004/1225 -seprint.c 2004/1225 -smprint.c 2004/1225 -snprint.c 2004/1225 -sprint.c 2004/1225 -vfprint.c 2004/1225 -vseprint.c 2004/1225 -vsmprint.c 2004/1225 -vsnprint.c 2004/1225 +announce.c 2004/1225 +atexit.c 2004/1225 +atnotify.c 2004/1225 +atol.c 2004/1225 +atoll.c 2004/1225 +cistrcmp.c 2004/1225 +cistrncmp.c 2004/1225 +cistrstr.c 2004/1225 +cleanname.c 2004/1225 +convD2M.c 2004/1225 +convM2D.c 2004/1225 +convM2S.c 2004/1225 +convS2M.c 2004/1225 +ctime.c 2004/1225 +dial.c 2004/1225 +dirfstat.c 2004/1225 +dirfwstat.c 2004/1225 +dirmodefmt.c 2004/1225 +dirread.c 2004/1225 +dirstat.c 2004/1225 +dirwstat.c 2004/1225 +encodefmt.c 2004/1225 +fcallfmt.c 2004/1225 +fork.c 2004/1225 +getenv.c 2004/1225 +getfields.c 2004/1225 +getuser.c 2004/1225 +getwd.c 2004/1225 +lnrand.c 2004/1225 +lock.c 2004/1225 +lrand.c 2004/1225 +malloc.c 2004/1225 +nan.c 2004/1225 +needsrcquote.c 2004/1225 +netmkaddr.c 2004/1225 +nrand.c 2004/1225 +nulldir.c 2004/1225 +postnote.c 2004/1225 +qlock.c 2004/1225 +quote.c 2004/1225 +rand.c 2004/1225 +read9pmsg.c 2004/1225 +readn.c 2004/1225 +strdup.c 2004/1225 +strecpy.c 2004/1225 +sysfatal.c 2004/1225 +sysname.c 2004/1225 +time.c 2004/1225 +tokenize.c 2004/1225 +truerand.c 2004/1225 +u16.c 2004/1225 +u32.c 2004/1225 +u64.c 2004/1225 +wait.c 2004/1225 +waitpid.c 2004/1225 diff --git a/lib9/post9p.c b/lib9/post9p.c @@ -1,46 +1,83 @@ #include <u.h> #include <libc.h> +int chattyfuse; + int -post9pservice(int fd, char *name) +post9pservice(int fd, char *name, char *mtpt) { - int i; - char *ns, *s; + int i, pid; + char *ns, *addr; Waitmsg *w; - if(strchr(name, '!')) /* assume is already network address */ - s = strdup(name); - else{ - if((ns = getns()) == nil) - return -1; - s = smprint("unix!%s/%s", ns, name); - free(ns); - } - if(s == nil) - return -1; - switch(fork()){ - case -1: + if(name == nil && mtpt == nil){ + close(fd); + werrstr("nothing to do"); return -1; - case 0: - dup(fd, 0); - dup(fd, 1); - for(i=3; i<20; i++) - close(i); - execlp("9pserve", "9pserve", "-u", s, (char*)0); - fprint(2, "exec 9pserve: %r\n"); - _exits("exec"); - default: - w = wait(); - if(w == nil) + } + + if(name){ + if(strchr(name, '!')) /* assume is already network address */ + addr = strdup(name); + else{ + if((ns = getns()) == nil) + return -1; + addr = smprint("unix!%s/%s", ns, name); + free(ns); + } + if(addr == nil) + return -1; + switch(pid = fork()){ + case -1: return -1; + case 0: + dup(fd, 0); + dup(fd, 1); + for(i=3; i<20; i++) + close(i); + execlp("9pserve", "9pserve", "-u", addr, (char*)0); + fprint(2, "exec 9pserve: %r\n"); + _exits("exec"); + } close(fd); - free(s); + w = waitfor(pid); + if(w == nil) + return -1; if(w->msg && w->msg[0]){ free(w); werrstr("9pserve failed"); return -1; } free(w); - return 0; + if(mtpt){ + /* reopen */ + if((fd = dial(addr, nil, nil, nil)) < 0){ + werrstr("cannot reopen for mount: %r"); + return -1; + } + } + free(addr); + } + if(mtpt){ + switch(pid = rfork(RFFDG|RFPROC|RFNOWAIT)){ + case -1: + return -1; + case 0: + dup(fd, 0); + for(i=3; i<20; i++) + close(i); + + /* Try v9fs on Linux, which will mount 9P directly. */ + execlp("mount9p", "mount9p", "-", mtpt, (char*)0); + + if(chattyfuse) + execlp("9pfuse", "9pfuse", "-D", "-", mtpt, (char*)0); + else + execlp("9pfuse", "9pfuse", "-", mtpt, (char*)0); + fprint(2, "exec 9pfuse: %r\n"); + _exits("exec"); + } + close(fd); } + return 0; } diff --git a/lib9/rand.c b/lib9/rand.c @@ -1,8 +1,5 @@ #include <lib9.h> -extern long p9lrand(void); -#define lrand p9lrand - int p9rand(void) { diff --git a/lib9/readn.c b/lib9/readn.c @@ -1,5 +1,4 @@ #include <lib9.h> -#include <unistd.h> long readn(int f, void *av, long n) diff --git a/lib9/regex/regcomp.c b/lib9/regex/regcomp.c @@ -261,18 +261,18 @@ optimize(Reprog *pp) case STAR: case PLUS: case QUEST: - *(char **)&inst->u1.right += diff; + inst->u1.right = (void*)((char*)inst->u1.right + diff); break; case CCLASS: case NCCLASS: - *(char **)&inst->u1.right += diff; + inst->u1.right = (void*)((char*)inst->u1.right + diff); cl = inst->u1.cp; - *(char **)&cl->end += diff; + cl->end = (void*)((char*)cl->end + diff); break; } - *(char **)&inst->u2.left += diff; + inst->u2.left = (void*)((char*)inst->u2.left + diff); } - *(char **)&npp->startinst += diff; + npp->startinst = (void*)((char*)npp->startinst + diff); return npp; } diff --git a/lib9/regex/regexec.c b/lib9/regex/regexec.c @@ -58,7 +58,7 @@ regexec1(Reprog *progp, /* program to run */ p = utfrune(s, '\n'); if(p == 0 || s == j->eol) return match; - s = p; + s = p+1; break; } } diff --git a/lib9/regex/rregexec.c b/lib9/regex/rregexec.c @@ -25,6 +25,7 @@ rregexec1(Reprog *progp, /* program to run */ Relist* tle; /* ends of this and next list */ Relist* nle; int match; + Rune *p; match = 0; checkstart = j->startchar; @@ -44,20 +45,18 @@ rregexec1(Reprog *progp, /* program to run */ if(checkstart) { switch(j->starttype) { case RUNE: - while(*s != j->startchar) { - if(*s == 0 || s == j->reol) - return match; - s++; - } + p = runestrchr(s, j->startchar); + if(p == 0 || p == j->reol) + return match; + s = p; break; case BOL: if(s == bol) break; - while(*s != '\n') { - if(*s == 0 || s == j->reol) - return match; - s++; - } + p = runestrchr(s, '\n'); + if(p == 0 || s == j->reol) + return match; + s = p+1; break; } } diff --git a/lib9/rfork.c b/lib9/rfork.c @@ -17,11 +17,12 @@ p9rfork(int flags) int p[2]; int n; char buf[128], *q; + extern char **environ; if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){ /* check other flags before we commit */ - flags &= ~(RFPROC|RFFDG); - n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT)); + flags &= ~(RFPROC|RFFDG|RFENVG); + n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG)); if(n){ werrstr("unknown flags %08ux in rfork", n); return -1; @@ -99,9 +100,12 @@ p9rfork(int flags) } if(pid != 0) return pid; + if(flags&RFCENVG) + if(environ) + *environ = nil; } if(flags&RFPROC){ - werrstr("cannot use rfork for shared memory -- use ffork"); + werrstr("cannot use rfork for shared memory -- use libthread"); return -1; } if(flags&RFNAMEG){ diff --git a/lib9/sendfd.c b/lib9/sendfd.c @@ -78,7 +78,10 @@ recvfd(int s) if((n=recvmsg(s, &msg, 0)) < 0) return -1; - + if(n == 0){ + werrstr("unexpected EOF"); + return -1; + } cmsg = CMSG_FIRSTHDR(&msg); fd = *(int*)CMSG_DATA(cmsg); return fd; diff --git a/lib9/sleep.c b/lib9/sleep.c @@ -1,9 +1,21 @@ #include <u.h> #define NOPLAN9DEFINES +#include <sys/param.h> #include <sys/time.h> #include <sched.h> #include <libc.h> +#if defined(__NetBSD__) || (defined(__OpenBSD__) && OpenBSD <= 200611) +#if !defined(sched_yield) +# define sched_yield() \ + do{ struct timespec ts; \ + ts.tv_sec = 0; \ + ts.tv_nsec = 0; \ + nanosleep(&ts, 0); \ + }while(0) +#endif +#endif + int p9sleep(long milli) { diff --git a/lib9/sysfatal.c b/lib9/sysfatal.c @@ -1,10 +1,5 @@ #include <lib9.h> -#include <stdarg.h> -#include "fmt.h" -extern char *argv0; -extern void __fixargv0(void); -extern void exits(char*); void (*_sysfatal)(char*, ...); void diff --git a/lib9/test.c b/lib9/test.c @@ -0,0 +1,8 @@ +#include <lib9.h> + +int +main(int argc, char **argv) +{ + werrstr("hello world"); + print("%r\n"); +} diff --git a/lib9/testfltfmt.c b/lib9/testfltfmt.c @@ -0,0 +1,183 @@ +#include <u.h> +#include <libc.h> +#include <stdio.h> + +/* + * try all combination of flags and float conversions + * with some different widths & precisions + */ + +#define Njust 2 +#define Nplus 3 +#define Nalt 2 +#define Nzero 2 +#define Nspec 5 +#define Nwidth 5 +#define Nprec 5 + +static double fmtvals[] = { + 3.1415925535897932e15, + 3.1415925535897932e14, + 3.1415925535897932e13, + 3.1415925535897932e12, + 3.1415925535897932e11, + 3.1415925535897932e10, + 3.1415925535897932e9, + 3.1415925535897932e8, + 3.1415925535897932e7, + 3.1415925535897932e6, + 3.1415925535897932e5, + 3.1415925535897932e4, + 3.1415925535897932e3, + 3.1415925535897932e2, + 3.1415925535897932e1, + 3.1415925535897932e0, + 3.1415925535897932e-1, + 3.1415925535897932e-2, + 3.1415925535897932e-3, + 3.1415925535897932e-4, + 3.1415925535897932e-5, + 3.1415925535897932e-6, + 3.1415925535897932e-7, + 3.1415925535897932e-8, + 3.1415925535897932e-9, + 3.1415925535897932e-10, + 3.1415925535897932e-11, + 3.1415925535897932e-12, + 3.1415925535897932e-13, + 3.1415925535897932e-14, + 3.1415925535897932e-15, +}; + +/* + * are the numbers close? + * used to compare long numbers where the last few digits are garbage + * due to precision problems + */ +static int +numclose(char *num1, char *num2) +{ + int ndig; + double d1, d2; + enum { MAXDIG = 15 }; + + d1 = fmtstrtod(num1, 0); + d2 = fmtstrtod(num2, 0); + if(d1 != d2) + return 0; + + ndig = 0; + while (*num1) { + if (*num1 >= '0' && *num1 <= '9') { + ndig++; + if (ndig > MAXDIG) { + if (!(*num2 >= '0' && *num2 <= '9')) { + return 0; + } + } else if (*num1 != *num2) { + return 0; + } + } else if (*num1 != *num2) { + return 0; + } else if (*num1 == 'e' || *num1 == 'E') { + ndig = 0; + } + num1++; + num2++; + } + if (*num1 || !num2) + return 0; + return 1; +} + +static void +doit(int just, int plus, int alt, int zero, int width, int prec, int spec) +{ + char format[256]; + char *p; + const char *s; + int i; + + p = format; + *p++ = '%'; + if (just > 0) + *p++ = "-"[just - 1]; + if (plus > 0) + *p++ = "+ "[plus - 1]; + if (alt > 0) + *p++ = "#"[alt - 1]; + if (zero > 0) + *p++ = "0"[zero - 1]; + + s = ""; + switch (width) { + case 1: s = "1"; break; + case 2: s = "5"; break; + case 3: s = "10"; break; + case 4: s = "15"; break; + } + strcpy(p, s); + + s = ""; + switch (prec) { + case 1: s = ".0"; break; + case 2: s = ".2"; break; + case 3: s = ".5"; break; + case 4: s = ".15"; break; + } + strcat(p, s); + + p = strchr(p, '\0'); + *p++ = "efgEG"[spec]; + *p = '\0'; + + for (i = 0; i < sizeof(fmtvals) / sizeof(fmtvals[0]); i++) { + char ref[1024], buf[1024]; + Rune rbuf[1024]; + double d1, d2; + + sprintf(ref, format, fmtvals[i]); + snprint(buf, sizeof(buf), format, fmtvals[i]); + if (strcmp(ref, buf) != 0 + && !numclose(ref, buf)) { + d1 = fmtstrtod(ref, 0); + d2 = fmtstrtod(buf, 0); + fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n", + format, + ref, d1==fmtvals[i] ? "" : " (ref is inexact!)", + buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)"); + // exits("oops"); + } + + /* Check again with output to rune string */ + runesnprint(rbuf, 1024, format, fmtvals[i]); + snprint(buf, sizeof(buf), "%S", rbuf); + if (strcmp(ref, buf) != 0 + && !numclose(ref, buf)) { + d1 = fmtstrtod(ref, 0); + d2 = fmtstrtod(buf, 0); + fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n", + format, + ref, d1==fmtvals[i] ? "" : " (ref is inexact!)", + buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)"); + // exits("oops"); + } + } +} + +void +main(int argc, char **argv) +{ + int just, plus, alt, zero, width, prec, spec; + + for (just = 0; just < Njust; just++) + for (plus = 0; plus < Nplus; plus++) + for (alt = 0; alt < Nalt; alt++) + for (zero = 0; zero < Nzero; zero++) + for (width = 0; width < Nwidth; width++) + for (prec = 0; prec < Nprec; prec++) + for (spec = 0; spec < Nspec; spec++) + doit(just, plus, alt, zero, width, prec, spec); + + exits(0); +} diff --git a/lib9/testfmt.c b/lib9/testfmt.c @@ -0,0 +1,148 @@ +#include <u.h> +#include <libc.h> +#include <stdio.h> + +int failed; + +/* Consume argument and ignore it */ +int +Zflag(Fmt* f) +{ + if(va_arg(f->args, int)) + ; + return 1; /* it's a flag */ +} + +void +verify(char *s, char *t) +{ + if(strcmp(s, t) != 0){ + failed = 1; + fprintf(stderr, "error: (%s) != (%s)\n", s, t); + } + free(s); +} + +Rune lightsmiley = 0x263a; +Rune darksmiley = 0x263b; + +/* Test printer that loads unusual decimal point and separator */ +char* +mysmprint(char *fmt, ...) +{ + Fmt f; + + if(fmtstrinit(&f) < 0) + return 0; + va_start(f.args, fmt); + f.decimal = smprint("%C", lightsmiley); + f.thousands = smprint("%C", darksmiley); + f.grouping = "\1\2\3\4"; + if(dofmt(&f, fmt) < 0) + return 0; + va_end(f.args); + return fmtstrflush(&f); +} + +double near1[] = { + 0.5, + 0.95, + 0.995, + 0.9995, + 0.99995, + 0.999995, + 0.9999995, + 0.99999995, + 0.999999995, +}; + +void +main(int argc, char **argv) +{ + int i, j; + + quotefmtinstall(); + fmtinstall('Z', Zflag); + fmtinstall(L'\x263a', Zflag); +#ifdef PLAN9PORT +{ extern int __ifmt(Fmt*); + fmtinstall('i', __ifmt); +} +#endif + + verify(smprint("hello world"), "hello world"); +#ifdef PLAN9PORT + verify(smprint("x: %ux", 0x87654321), "x: 87654321"); +#else + verify(smprint("x: %x", 0x87654321), "x: 87654321"); +#endif + verify(smprint("d: %d", 0x87654321), "d: -2023406815"); + verify(smprint("s: %s", "hi there"), "s: hi there"); + verify(smprint("q: %q", "hi i'm here"), "q: 'hi i''m here'"); + verify(smprint("c: %c", '!'), "c: !"); + verify(smprint("g: %g %g %g", 3.14159, 3.14159e10, 3.14159e-10), "g: 3.14159 3.14159e+10 3.14159e-10"); + verify(smprint("e: %e %e %e", 3.14159, 3.14159e10, 3.14159e-10), "e: 3.141590e+00 3.141590e+10 3.141590e-10"); + verify(smprint("f: %f %f %f", 3.14159, 3.14159e10, 3.14159e-10), "f: 3.141590 31415900000.000000 0.000000"); + verify(smprint("smiley: %C", (Rune)0x263a), "smiley: \xe2\x98\xba"); + verify(smprint("%g %.18g", 2e25, 2e25), "2e+25 2e+25"); + verify(smprint("%2.18g", 1.0), " 1"); + verify(smprint("%f", 3.1415927/4), "0.785398"); + verify(smprint("%d", 23), "23"); + verify(smprint("%i", 23), "23"); + verify(smprint("%Zi", 1234, 23), "23"); + + /* ANSI and their wacky corner cases */ + verify(smprint("%.0d", 0), ""); + verify(smprint("%.0o", 0), ""); + verify(smprint("%.0x", 0), ""); + verify(smprint("%#.0o", 0), "0"); + verify(smprint("%#.0x", 0), ""); + + /* difficult floating point tests that many libraries get wrong */ + verify(smprint("%.100f", 1.0), "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000"); + verify(smprint("%.100g", 1.0), "1"); + verify(smprint("%0100f", 1.0), "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000"); + for(i=1; i<9; i++) + for(j=0; j<=i; j++) + verify(smprint("%.*g", j, near1[i]), "1"); + + /* test $ reorderings */ + verify(smprint("%3$d %4$06d %2$d %1$d", 444, 333, 111, 222), "111 000222 333 444"); + verify(smprint("%3$Zd %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444"); + verify(smprint("%3$d %4$*5$06d %2$d %1$d", 444, 333, 111, 222, 20), "111 000222 333 444"); + verify(smprint("%3$hd %4$*5$06d %2$d %1$d", 444, 333, (short)111, 222, 20), "111 000222 333 444"); + verify(smprint("%3$\xe2\x98\xba""d %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444"); + + /* test %'d formats */ + verify(smprint("%'d %'d %'d", 1, 2222, 33333333), "1 2,222 33,333,333"); + verify(smprint("%'019d", 0), "000,000,000,000,000"); + verify(smprint("%'08d %'08d %'08d", 1, 2222, 33333333), "0,000,001 0,002,222 33,333,333"); +#ifdef PLAN9PORT + verify(smprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001"); +#else + verify(smprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001"); +#endif + verify(smprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222,222,222 3,333,333,333,333"); + verify(smprint("%'019lld %'019lld %'019lld", 1LL, 222222222LL, 3333333333333LL), "000,000,000,000,001 000,000,222,222,222 003,333,333,333,333"); +#ifdef PLAN9PORT + verify(smprint("%'llux %'lluX %'llub", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001"); +#else + verify(smprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001"); +#endif + + /* test %'d with custom (utf-8!) separators */ + /* x and b still use : */ + verify(mysmprint("%'d %'d %'d", 1, 2222, 33333333), "1 2\xe2\x98\xbb""22\xe2\x98\xbb""2 33\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3"); +#ifdef PLAN9PORT + verify(mysmprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001"); +#else + verify(mysmprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001"); +#endif + verify(mysmprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222\xe2\x98\xbb""222\xe2\x98\xbb""22\xe2\x98\xbb""2 333\xe2\x98\xbb""3333\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3"); + verify(mysmprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001"); + verify(mysmprint("%.4f", 3.14159), "3\xe2\x98\xba""1416"); + + if(failed) + sysfatal("tests failed"); + exits(0); +} diff --git a/lib9/testprint.c b/lib9/testprint.c @@ -0,0 +1,14 @@ +#include <u.h> +#include <libc.h> + +void +main(int argc, char **argv) +{ + char c; + + c = argv[1][strlen(argv[1])-1]; + if(c == 'f' || c == 'e' || c == 'g' || c == 'F' || c == 'E' || c == 'G') + print(argv[1], atof(argv[2])); + else if(c == 'x' || c == 'u' || c == 'd' || c == 'c' || c == 'C' || c == 'X') + print(argv[1], atoi(argv[2])); +} diff --git a/lib9/tm2sec.c b/lib9/tm2sec.c @@ -0,0 +1,110 @@ +#include <u.h> +#include <libc.h> + +#include "zoneinfo.h" + +#define SEC2MIN 60L +#define SEC2HOUR (60L*SEC2MIN) +#define SEC2DAY (24L*SEC2HOUR) + +/* + * days per month plus days/year + */ +static int dmsize[] = +{ + 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; +static int ldmsize[] = +{ + 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 +}; + +/* + * return the days/month for the given year + */ +static int * +yrsize(int y) +{ + if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0)) + return ldmsize; + else + return dmsize; +} + +/* + * compute seconds since Jan 1 1970 GMT + * and convert to our timezone. + */ +long +tm2sec(Tm *tm) +{ + Tinfo ti0, ti1, *ti; + long secs; + int i, yday, year, *d2m; + + secs = 0; + + /* + * seconds per year + */ + year = tm->year + 1900; + for(i = 1970; i < year; i++){ + d2m = yrsize(i); + secs += d2m[0] * SEC2DAY; + } + + /* + * if mday is set, use mon and mday to compute yday + */ + if(tm->mday){ + yday = 0; + d2m = yrsize(year); + for(i=0; i<tm->mon; i++) + yday += d2m[i+1]; + yday += tm->mday-1; + }else{ + yday = tm->yday; + } + secs += yday * SEC2DAY; + + /* + * hours, minutes, seconds + */ + secs += tm->hour * SEC2HOUR; + secs += tm->min * SEC2MIN; + secs += tm->sec; + + /* + * Assume the local time zone if zone is not GMT + */ + if(strcmp(tm->zone, "GMT") != 0) { + i = zonelookuptinfo(&ti0, secs); + ti = &ti0; + if (i != -1) + if (ti->tzoff!=0) { + /* + * to what local time period `secs' belongs? + */ + if (ti->tzoff>0) { + /* + * east of GMT; check previous local time transition + */ + if (ti->t+ti->tzoff > secs) + if (zonetinfo(&ti1, i-1)!=-1) + ti = &ti1; + } else + /* + * west of GMT; check next local time transition + */ + if (zonetinfo(&ti1, i+1)) + if (ti1.t+ti->tzoff < secs) + ti = &ti1; +// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff, (long)secs); + secs -= ti->tzoff; + } + } + + if(secs < 0) + secs = 0; + return secs; +} diff --git a/lib9/truerand.c b/lib9/truerand.c @@ -15,7 +15,7 @@ truerand(void) if(randfd < 0 || read(randfd, buf, 1) != 1) randfd = open(randfile="/dev/srandom", OREAD); /* OpenBSD */ if(randfd < 0) - sysfatal("can't open /dev/random: %r"); + sysfatal("can't open %s: %r", randfile); fcntl(randfd, F_SETFD, FD_CLOEXEC); } for(i=0; i<sizeof(buf); i += n) diff --git a/lib9/u.h b/lib9/u.h @@ -7,9 +7,10 @@ extern "C" { #define __BSD_VISIBLE 1 /* FreeBSD 5.x */ #if defined(__sun__) # define __EXTENSIONS__ 1 /* SunOS */ -# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) +# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__) /* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */ # else + /* What's left? */ # define __MAKECONTEXT_V2_SOURCE 1 # endif #endif @@ -20,6 +21,17 @@ extern "C" { # define _XOPEN_SOURCE 1000 # define _XOPEN_SOURCE_EXTENDED 1 #endif +#if defined(__FreeBSD__) +# include <sys/cdefs.h> + /* for strtoll */ +# undef __ISO_C_VISIBLE +# define __ISO_C_VISIBLE 1999 +# undef __LONG_LONG_SUPPORTED +# define __LONG_LONG_SUPPORTED +#endif +#if defined(__AIX__) +# define _XOPEN_SOURCE 1 +#endif #define _LARGEFILE64_SOURCE 1 #define _FILE_OFFSET_BITS 64 @@ -33,8 +45,6 @@ extern "C" { #include <assert.h> #include <setjmp.h> #include <stddef.h> -#include <utf.h> -#include <fmt.h> #include <math.h> #include <ctype.h> /* for tolower */ @@ -138,6 +148,7 @@ typedef int8_t s8int; typedef uint16_t u16int; typedef int16_t s16int; typedef uintptr_t uintptr; +typedef intptr_t intptr; typedef uint32_t u32int; typedef int32_t s32int; @@ -150,17 +161,23 @@ typedef int32_t s32int; * Funny-named symbols to tip off 9l to autolink. */ #define AUTOLIB(x) static int __p9l_autolib_ ## x = 1; +#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1; /* * Gcc is too smart for its own good. */ #if defined(__GNUC__) +# undef strcmp /* causes way too many warnings */ # if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__)) # undef AUTOLIB # define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak)); +# undef AUTOFRAMEWORK +# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak)); # else # undef AUTOLIB # define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused)); +# undef AUTOFRAMEWORK +# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused)); # endif #endif diff --git a/lib9/utf.h b/lib9/utf.h @@ -11,7 +11,7 @@ enum UTFmax = 3, /* maximum bytes per rune */ Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */ Runeself = 0x80, /* rune and UTF sequences are the same (<) */ - Runeerror = 0xFFFD, /* decoding error in UTF */ + Runeerror = 0xFFFD /* decoding error in UTF */ }; /* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */ diff --git a/lib9/utf/NOTICE b/lib9/utf/NOTICE @@ -0,0 +1,13 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 1998-2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ diff --git a/lib9/utf/README b/lib9/utf/README @@ -0,0 +1,13 @@ +/* + * The authors of this software are Rob Pike and Ken Thompson. + * Copyright (c) 1998-2002 by Lucent Technologies. + * Permission to use, copy, modify, and distribute this software for any + * purpose without fee is hereby granted, provided that this entire notice + * is included in all copies of any software which is or includes a copy + * or modification of this software and in all copies of the supporting + * documentation for such software. + * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED + * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY + * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY + * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. + */ diff --git a/lib9/lib9.h b/lib9/utf/lib9.h diff --git a/lib9/utf/rune.c b/lib9/utf/rune.c @@ -37,7 +37,7 @@ enum Maskx = (1<<Bitx)-1, /* 0011 1111 */ Testx = Maskx ^ 0xFF, /* 1100 0000 */ - Bad = Runeerror, + Bad = Runeerror }; int diff --git a/lib9/utf/utfecpy.c b/lib9/utf/utfecpy.c @@ -11,6 +11,7 @@ * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE. */ +#define _BSD_SOURCE 1 /* memccpy */ #include <stdarg.h> #include <string.h> #include "plan9.h" diff --git a/lib9/write.c b/lib9/write.c @@ -0,0 +1,23 @@ +#include <u.h> +#define NOPLAN9DEFINES +#include <libc.h> + +long +p9write(int f, void *av, long n) +{ + char *a; + long m, t; + + a = av; + t = 0; + while(t < n){ + m = write(f, a+t, n-t); + if(m <= 0){ + if(t == 0) + return m; + break; + } + t += m; + } + return t; +} diff --git a/lib9/zoneinfo.c b/lib9/zoneinfo.c @@ -0,0 +1,215 @@ +#include <u.h> +#include <libc.h> + +/* + * Access local time entries of zoneinfo files. + * Formats 0 and 2 are supported, and 4-byte timestamps + * + * Copyright © 2008 M. Teichgräber + * Contributed under the terms of the Lucent Public License 1.02. + */ +#include "zoneinfo.h" + +static +struct Zoneinfo +{ + int timecnt; /* # of transition times */ + int typecnt; /* # of local time types */ + int charcnt; /* # of characters of time zone abbreviation strings */ + + uchar *ptime; + uchar *ptype; + uchar *ptt; + uchar *pzone; +} z; + +static uchar *tzdata; + +static +uchar* +readtzfile(char *file) +{ + uchar *p; + int fd; + Dir *d; + + fd = open(file, OREAD); + if (fd<0) + return nil; + d = dirfstat(fd); + if (d==nil) + return nil; + p = malloc(d->length); + if (p!=nil) + readn(fd, p, d->length); + free(d); + close(fd); + return p; +} +static char *zonefile; +void +tzfile(char *f) +{ + if (tzdata!=nil) { + free(tzdata); + tzdata = nil; + } + z.timecnt = 0; + zonefile = f; +} + +static +long +get4(uchar *p) +{ + return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3]; +} + +enum { + TTinfosz = 4+1+1, +}; + +static +int +parsehead(void) +{ + uchar *p; + int ver; + + ver = tzdata[4]; + if (ver!=0) + if (ver!='2') + return -1; + + p = tzdata + 4 + 1 + 15; + + z.timecnt = get4(p+3*4); + z.typecnt = get4(p+4*4); + if (z.typecnt==0) + return -1; + z.charcnt = get4(p+5*4); + z.ptime = p+6*4; + z.ptype = z.ptime + z.timecnt*4; + z.ptt = z.ptype + z.timecnt; + z.pzone = z.ptt + z.typecnt*TTinfosz; + return 0; +} + +static +void +ttinfo(Tinfo *ti, int tti) +{ + uchar *p; + int i; + + i = z.ptype[tti]; + assert(i<z.typecnt); + p = z.ptt + i*TTinfosz; + ti->tzoff = get4(p); + ti->dlflag = p[4]; + assert(p[5]<z.charcnt); + ti->zone = (char*)z.pzone + p[5]; +} + +static +void +readtimezone(void) +{ + char *tmp; + + z.timecnt = 0; + switch (zonefile==nil) { + default: + if ((tmp=getenv("timezone"))!=nil) { + tzdata = readtzfile(tmp); + free(tmp); + break; + } + zonefile = "/etc/localtime"; + /* fall through */ + case 0: + tzdata = readtzfile(zonefile); + } + if (tzdata==nil) + return; + + if (strncmp("TZif", (char*)tzdata, 4)!=0) + goto errfree; + + if (parsehead()==-1) { + errfree: + free(tzdata); + tzdata = nil; + z.timecnt = 0; + return; + } +} + +static +tlong +gett4(uchar *p) +{ + long l; + + l = get4(p); + if (l<0) + return 0; + return l; +} +int +zonetinfo(Tinfo *ti, int i) +{ + if (tzdata==nil) + readtimezone(); + if (i<0 || i>=z.timecnt) + return -1; + ti->t = gett4(z.ptime + 4*i); + ttinfo(ti, i); + return i; +} + +int +zonelookuptinfo(Tinfo *ti, tlong t) +{ + uchar *p; + int i; + tlong oldtt, tt; + + if (tzdata==nil) + readtimezone(); + oldtt = 0; + p = z.ptime; + for (i=0; i<z.timecnt; i++) { + tt = gett4(p); + if (t<tt) + break; + oldtt = tt; + p += 4; + } + if (i>0) { + ttinfo(ti, i-1); + ti->t = oldtt; +// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone); + return i-1; + } + return -1; +} + +void +zonedump(int fd) +{ + int i; + uchar *p; + tlong t; + Tinfo ti; + + if (tzdata==nil) + readtimezone(); + p = z.ptime; + for (i=0; i<z.timecnt; i++) { + t = gett4(p); + ttinfo(&ti, i); + fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone); + p += 4; + } +} diff --git a/lib9/zoneinfo.h b/lib9/zoneinfo.h @@ -0,0 +1,19 @@ +#define zonetinfo _p9zonetinfo +#define zonedump _p9zonedump +#define zonelookuptinfo _p9zonelookuptinfo + +typedef long tlong; + +typedef +struct Tinfo +{ + long t; + int tzoff; + int dlflag; + char *zone; +} Tinfo; + +extern int zonelookuptinfo(Tinfo*, tlong); +extern int zonetinfo(Tinfo*, int); +extern void zonedump(int fd); + diff --git a/ls/ls.c b/ls/ls.c @@ -227,17 +227,16 @@ format(Dir *db, char *name) db->qid.type); if(lflag) Bprint(&bin, - Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*ud %*s %s %*llud %s %q\n", + "%M %C %*ud %*s %s %*llud %s ", db->mode, db->type, vwidth, db->dev, -uwidth, db->uid, db->gid, (int)(glwidth-strlen(db->gid)), db->length, - asciitime(uflag? db->atime : db->mtime), name); - else - Bprint(&bin, - Qflag? "%s%s\n" : "%q%s\n", - name, fileflag(db)); + asciitime(uflag? db->atime : db->mtime)); + Bprint(&bin, + Qflag? "%s%s\n" : "%q%s\n", + name, fileflag(db)); } void diff --git a/mk/Makefile b/mk/Makefile @@ -1,37 +0,0 @@ -# basename - basename unix port from plan9 -# Depends on ../lib9 - -TARG = mk -OFILES = arc.o archive.o bufblock.o env.o file.o graph.o job.o\ - lex.o main.o match.o mk.o parse.o recipe.o rc.o rule.o\ - run.o sh.o shell.o shprint.o symtab.o var.o varsub.o\ - word.o unix.o -MANFILES = ${TARG}.1 - -include ../config.mk - -all: ${TARG} - @echo built ${TARG} - -install: ${TARG} - @mkdir -p ${DESTDIR}${PREFIX}/bin - @cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/ - @chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG} - @mkdir -p ${DESTDIR}${MANPREFIX}/man1 - @cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1 - @chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES} - -uninstall: - rm -f ${DESTDIR}${PREFIX}/bin/${TARG} - rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES} - -.c.o: - @echo CC $*.c - @${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c - -clean: - rm -f ${OFILES} ${TARG} - -${TARG}: ${OFILES} - @echo LD ${TARG} - @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9 diff --git a/mk/NOTICE b/mk/NOTICE @@ -1,27 +0,0 @@ -Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved. -Portions Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk). All rights reserved. -Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved. -Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved. - -Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000, -Vita Nuova Holdings Limited has the right to determine (within a specified scope) -the form and content of sublicences for this software. - -Vita Nuova Holdings Limited now makes this software available as Free -Software under the terms of the `GNU General Public LIcense, Version 2' -(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for -the full terms and conditions). One of the conditions of that licence -is that you must keep intact all notices that refer to that licence and to the absence of -of any warranty: for this software, note that includes this NOTICE file in particular. - -This suite of programs is distributed in the hope that it will be useful, -but WITHOUT ANY WARRANTY; without even the implied warranty of -MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the -`GNU General Public License' for more details. - -This copyright NOTICE applies to all files in this directory and -subdirectories, unless another copyright notice appears in a given -file or subdirectory. If you take code from this software to use in -other programs, you must somehow include with it an appropriate -copyright notice that includes the copyright notice and the other -notices above. diff --git a/mk/README b/mk/README @@ -1,7 +0,0 @@ -This is a Unix port of mk, -originally done for the Inferno operating system. - -Russ Cox repackaged this to build as a standalone -Unix program. Send comments about packaging to -Russ Cox <rsc@post.harvard.edu> - diff --git a/mk/arc.c b/mk/arc.c @@ -1,52 +0,0 @@ -#include "mk.h" - -Arc * -newarc(Node *n, Rule *r, char *stem, Resub *match) -{ - Arc *a; - - a = (Arc *)Malloc(sizeof(Arc)); - a->n = n; - a->r = r; - a->stem = strdup(stem); - rcopy(a->match, match, NREGEXP); - a->next = 0; - a->flag = 0; - a->prog = r->prog; - return(a); -} - -void -dumpa(char *s, Arc *a) -{ - char buf[1024]; - - Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'", - s, a, a->n, a->r, a->flag, a->stem); - if(a->prog) - Bprint(&bout, " prog='%s'", a->prog); - Bprint(&bout, "\n"); - - if(a->n){ - snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:""); - dumpn(buf, a->n); - } -} - -void -nrep(void) -{ - Symtab *sym; - Word *w; - - sym = symlook("NREP", S_VAR, 0); - if(sym){ - w = (Word *) sym->value; - if (w && w->s && *w->s) - nreps = atoi(w->s); - } - if(nreps < 1) - nreps = 1; - if(DEBUG(D_GRAPH)) - Bprint(&bout, "nreps = %d\n", nreps); -} diff --git a/mk/archive.c b/mk/archive.c @@ -1,253 +0,0 @@ -#include "mk.h" -#define ARMAG "!<arch>\n" -#define SARMAG 8 - -#define ARFMAG "`\n" -#define SARNAME 16 - -struct ar_hdr -{ - char name[SARNAME]; - char date[12]; - char uid[6]; - char gid[6]; - char mode[8]; - char size[10]; - char fmag[2]; -}; -#define SAR_HDR (SARNAME+44) - -static int dolong = 1; - -static void atimes(char *); -static char *split(char*, char**); - -long -readn(int f, void *av, long n) -{ - char *a; - long m, t; - - a = av; - t = 0; - while(t < n){ - m = read(f, a+t, n-t); - if(m <= 0){ - if(t == 0) - return m; - break; - } - t += m; - } - return t; -} -long -atimeof(int force, char *name) -{ - Symtab *sym; - long t; - char *archive, *member, buf[512]; - - archive = split(name, &member); - if(archive == 0) - Exit(); - - t = mtime(archive); - sym = symlook(archive, S_AGG, 0); - if(sym){ - if(force || (t > (long)sym->value)){ - atimes(archive); - sym->value = (void *)t; - } - } - else{ - atimes(archive); - /* mark the aggegate as having been done */ - symlook(strdup(archive), S_AGG, "")->value = (void *)t; - } - /* truncate long member name to sizeof of name field in archive header */ - if(dolong) - snprint(buf, sizeof(buf), "%s(%s)", archive, member); - else - snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member); - sym = symlook(buf, S_TIME, 0); - if (sym) - return (long)sym->value; /* uggh */ - return 0; -} - -void -atouch(char *name) -{ - char *archive, *member; - int fd, i; - struct ar_hdr h; - long t; - - archive = split(name, &member); - if(archive == 0) - Exit(); - - fd = open(archive, ORDWR); - if(fd < 0){ - fd = create(archive, OWRITE, 0666); - if(fd < 0){ - fprint(2, "create %s: %r\n", archive); - Exit(); - } - write(fd, ARMAG, SARMAG); - } - if(symlook(name, S_TIME, 0)){ - /* hoon off and change it in situ */ - LSEEK(fd, SARMAG, 0); - while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){ - for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--) - ; - h.name[i+1]=0; - if(strcmp(member, h.name) == 0){ - t = SARNAME-sizeof(h); /* ughgghh */ - LSEEK(fd, t, 1); - fprint(fd, "%-12ld", time(0)); - break; - } - t = atol(h.size); - if(t&01) t++; - LSEEK(fd, t, 1); - } - } - close(fd); -} - -static void -atimes(char *ar) -{ - struct ar_hdr h; - long t; - int fd, i, namelen; - char buf[2048], *p, *strings; - char name[1024]; - Symtab *sym; - - strings = nil; - fd = open(ar, OREAD); - if(fd < 0) - return; - - if(read(fd, buf, SARMAG) != SARMAG){ - close(fd); - return; - } - while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){ - t = atol(h.date); - if(t == 0) /* as it sometimes happens; thanks ken */ - t = 1; - namelen = 0; - if(memcmp(h.name, "#1/", 3) == 0){ /* BSD */ - namelen = atoi(h.name+3); - if(namelen >= sizeof name){ - namelen = 0; - goto skip; - } - if(readn(fd, name, namelen) != namelen) - break; - name[namelen] = 0; - }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */ - /* date, uid, gid, mode all ' ' */ - for(i=2; i<16+12+6+6+8; i++) - if(h.name[i] != ' ') - goto skip; - t = atol(h.size); - if(t&01) - t++; - free(strings); - strings = malloc(t+1); - if(strings){ - if(readn(fd, strings, t) != t){ - free(strings); - strings = nil; - break; - } - strings[t] = 0; - continue; - } - goto skip; - }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){ - i = strtol(h.name+1, &p, 10); - if(*p != ' ' || i >= strlen(strings)) - goto skip; - p = strings+i; - for(; *p && *p != '/'; p++) - ; - namelen = p-(strings+i); - if(namelen >= sizeof name){ - namelen = 0; - goto skip; - } - memmove(name, strings+i, namelen); - name[namelen] = 0; - namelen = 0; - }else{ - strncpy(name, h.name, sizeof(h.name)); - for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--) - ; - if(name[i] == '/') /* system V bug */ - i--; - name[i+1]=0; - } - snprint(buf, sizeof buf, "%s(%s)", ar, name); - sym = symlook(strdup(buf), S_TIME, (void *)t); - sym->value = (void *)t; - skip: - t = atol(h.size); - if(t&01) t++; - t -= namelen; - LSEEK(fd, t, 1); - } - close(fd); - free(strings); -} - -static int -type(char *file) -{ - int fd; - char buf[SARMAG]; - - fd = open(file, OREAD); - if(fd < 0){ - if(symlook(file, S_BITCH, 0) == 0){ - if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0) - Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file); - symlook(file, S_BITCH, (void *)file); - } - return 1; - } - if(read(fd, buf, SARMAG) != SARMAG){ - close(fd); - return 0; - } - close(fd); - return !strncmp(ARMAG, buf, SARMAG); -} - -static char* -split(char *name, char **member) -{ - char *p, *q; - - p = strdup(name); - q = utfrune(p, '('); - if(q){ - *q++ = 0; - if(member) - *member = q; - q = utfrune(q, ')'); - if (q) - *q = 0; - if(type(p)) - return p; - free(p); - fprint(2, "mk: '%s' is not an archive\n", name); - } - return 0; -} diff --git a/mk/bufblock.c b/mk/bufblock.c @@ -1,88 +0,0 @@ -#include "mk.h" - -static Bufblock *freelist; -#define QUANTA 4096 - -Bufblock * -newbuf(void) -{ - Bufblock *p; - - if (freelist) { - p = freelist; - freelist = freelist->next; - } else { - p = (Bufblock *) Malloc(sizeof(Bufblock)); - p->start = Malloc(QUANTA*sizeof(*p->start)); - p->end = p->start+QUANTA; - } - p->current = p->start; - *p->start = 0; - p->next = 0; - return p; -} - -void -freebuf(Bufblock *p) -{ - p->next = freelist; - freelist = p; -} - -void -growbuf(Bufblock *p) -{ - int n; - Bufblock *f; - char *cp; - - n = p->end-p->start+QUANTA; - /* search the free list for a big buffer */ - for (f = freelist; f; f = f->next) { - if (f->end-f->start >= n) { - memcpy(f->start, p->start, p->end-p->start); - cp = f->start; - f->start = p->start; - p->start = cp; - cp = f->end; - f->end = p->end; - p->end = cp; - f->current = f->start; - break; - } - } - if (!f) { /* not found - grow it */ - p->start = Realloc(p->start, n); - p->end = p->start+n; - } - p->current = p->start+n-QUANTA; -} - -void -bufcpy(Bufblock *buf, char *cp, int n) -{ - - while (n--) - insert(buf, *cp++); -} - -void -insert(Bufblock *buf, int c) -{ - - if (buf->current >= buf->end) - growbuf(buf); - *buf->current++ = c; -} - -void -rinsert(Bufblock *buf, Rune r) -{ - int n; - - n = runelen(r); - if (buf->current+n > buf->end) - growbuf(buf); - runetochar(buf->current, &r); - buf->current += n; -} diff --git a/mk/env.c b/mk/env.c @@ -1,149 +0,0 @@ -#include "mk.h" - -enum { - ENVQUANTA=10 -}; - -Envy *envy; -static int nextv; - -static char *myenv[] = -{ - "target", - "stem", - "prereq", - "pid", - "nproc", - "newprereq", - "alltarget", - "newmember", - "stem0", /* must be in order from here */ - "stem1", - "stem2", - "stem3", - "stem4", - "stem5", - "stem6", - "stem7", - "stem8", - "stem9", - 0, -}; - -void -initenv(void) -{ - char **p; - - for(p = myenv; *p; p++) - symlook(*p, S_INTERNAL, (void *)""); - readenv(); /* o.s. dependent */ -} - -static void -envinsert(char *name, Word *value) -{ - static int envsize; - - if (nextv >= envsize) { - envsize += ENVQUANTA; - envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy)); - } - envy[nextv].name = name; - envy[nextv++].values = value; -} - -static void -envupd(char *name, Word *value) -{ - Envy *e; - - for(e = envy; e->name; e++) - if(strcmp(name, e->name) == 0){ - delword(e->values); - e->values = value; - return; - } - e->name = name; - e->values = value; - envinsert(0,0); -} - -static void -ecopy(Symtab *s) -{ - char **p; - - if(symlook(s->name, S_NOEXPORT, 0)) - return; - for(p = myenv; *p; p++) - if(strcmp(*p, s->name) == 0) - return; - envinsert(s->name, (Word *) s->value); -} - -void -execinit(void) -{ - char **p; - - nextv = 0; - for(p = myenv; *p; p++) - envinsert(*p, stow("")); - - symtraverse(S_VAR, ecopy); - envinsert(0, 0); -} - -Envy* -buildenv(Job *j, int slot) -{ - char **p, *cp, *qp; - Word *w, *v, **l; - int i; - char buf[256]; - - envupd("target", wdup(j->t)); - if(j->r->attr&REGEXP) - envupd("stem",newword("")); - else - envupd("stem", newword(j->stem)); - envupd("prereq", wdup(j->p)); - sprint(buf, "%d", getpid()); - envupd("pid", newword(buf)); - sprint(buf, "%d", slot); - envupd("nproc", newword(buf)); - envupd("newprereq", wdup(j->np)); - envupd("alltarget", wdup(j->at)); - l = &v; - v = w = wdup(j->np); - while(w){ - cp = strchr(w->s, '('); - if(cp){ - qp = strchr(cp+1, ')'); - if(qp){ - *qp = 0; - strcpy(w->s, cp+1); - l = &w->next; - w = w->next; - continue; - } - } - *l = w->next; - free(w->s); - free(w); - w = *l; - } - envupd("newmember", v); - /* update stem0 -> stem9 */ - for(p = myenv; *p; p++) - if(strcmp(*p, "stem0") == 0) - break; - for(i = 0; *p; i++, p++){ - if((j->r->attr&REGEXP) && j->match[i]) - envupd(*p, newword(j->match[i])); - else - envupd(*p, newword("")); - } - return envy; -} diff --git a/mk/file.c b/mk/file.c @@ -1,90 +0,0 @@ -#include "mk.h" - -/* table-driven version in bootes dump of 12/31/96 */ - -long -mtime(char *name) -{ - return mkmtime(name); -} - -long -timeof(char *name, int force) -{ - Symtab *sym; - long t; - - if(utfrune(name, '(')) - return atimeof(force, name); /* archive */ - - if(force) - return mtime(name); - - - sym = symlook(name, S_TIME, 0); - if (sym) - return (long) sym->value; /* uggh */ - - t = mtime(name); - if(t == 0) - return 0; - - symlook(name, S_TIME, (void*)t); /* install time in cache */ - return t; -} - -void -touch(char *name) -{ - Bprint(&bout, "touch(%s)\n", name); - if(nflag) - return; - - if(utfrune(name, '(')) - atouch(name); /* archive */ - else if(chgtime(name) < 0) { - fprint(2, "%s: %r\n", name); - Exit(); - } -} - -void -delete(char *name) -{ - if(utfrune(name, '(') == 0) { /* file */ - if(remove(name) < 0) - fprint(2, "remove %s: %r\n", name); - } else - fprint(2, "hoon off; mk can'tdelete archive members\n"); -} - -void -timeinit(char *s) -{ - long t; - char *cp; - Rune r; - int c, n; - - t = time(0); - while (*s) { - cp = s; - do{ - n = chartorune(&r, s); - if (r == ' ' || r == ',' || r == '\n') - break; - s += n; - } while(*s); - c = *s; - *s = 0; - symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t; - if (c) - *s++ = c; - while(*s){ - n = chartorune(&r, s); - if(r != ' ' && r != ',' && r != '\n') - break; - s += n; - } - } -} diff --git a/mk/fns.h b/mk/fns.h @@ -1,88 +0,0 @@ -#undef waitfor -#define waitfor mkwaitfor - -void addrule(char*, Word*, char*, Word*, int, int, char*); -void addrules(Word*, Word*, char*, int, int, char*); -void addw(Word*, char*); -void assert(char*, int); -int assline(Biobuf *, Bufblock *); -long atimeof(int,char*); -void atouch(char*); -void bufcpy(Bufblock *, char *, int); -Envy *buildenv(Job*, int); -void catchnotes(void); -int chgtime(char*); -void clrmade(Node*); -void delete(char*); -void delword(Word*); -int dorecipe(Node*); -void dumpa(char*, Arc*); -void dumpj(char*, Job*, int); -void dumpn(char*, Node*); -void dumpr(char*, Rule*); -void dumpv(char*); -void dumpw(char*, Word*); -void execinit(void); -int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*); -void Exit(void); -void expunge(int, char*); -void freebuf(Bufblock*); -void front(char*); -Node *graph(char*); -void growbuf(Bufblock *); -void initenv(void); -void initshell(void); -void insert(Bufblock *, int); -void ipop(void); -void ipush(void); -void killchildren(char*); -void *Malloc(int); -char *maketmp(int*); -int match(char*, char*, char*, Shell*); -char *membername(char*, int, char*); -void mk(char*); -unsigned long mkmtime(char*); -long mtime(char*); -Arc *newarc(Node*, Rule*, char*, Resub*); -Bufblock *newbuf(void); -Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*); -Word *newword(char*); -int nextrune(Biobuf*, int); -int nextslot(void); -void nproc(void); -void nrep(void); -int outofdate(Node*, Arc*, int); -void parse(char*, int, int); -int pipecmd(char*, Envy*, int*, Shell*, Word*); -void popshell(void); -void prusage(void); -void pushshell(void); -void rcopy(char**, Resub*, int); -void readenv(void); -void *Realloc(void*, int); -void rinsert(Bufblock *, Rune); -char *rulecnt(void); -void run(Job*); -char *setshell(Word*); -void setvar(char*, void*); -int shargv(Word*, int, char***); -char *shname(char*); -void shprint(char*, Envy*, Bufblock*, Shell*); -Word *stow(char*); -void subst(char*, char*, char*); -void symdel(char*, int); -void syminit(void); -Symtab *symlook(char*, int, void*); -void symstat(void); -void symtraverse(int, void(*)(Symtab*)); -void timeinit(char*); -long timeof(char*, int); -void touch(char*); -void update(int, Node*); -void usage(void); -Word *varsub(char**); -int waitfor(char*); -int waitup(int, int*); -Word *wdup(Word*); -int work(Node*, Node*, Arc*); -char *wtos(Word*, int); diff --git a/mk/graph.c b/mk/graph.c @@ -1,279 +0,0 @@ -#include "mk.h" - -static Node *applyrules(char *, char *); -static void togo(Node *); -static int vacuous(Node *); -static Node *newnode(char *); -static void trace(char *, Arc *); -static void cyclechk(Node *); -static void ambiguous(Node *); -static void attribute(Node *); - -Node * -graph(char *target) -{ - Node *node; - char *cnt; - - cnt = rulecnt(); - node = applyrules(target, cnt); - free(cnt); - cyclechk(node); - node->flags |= PROBABLE; /* make sure it doesn't get deleted */ - vacuous(node); - ambiguous(node); - attribute(node); - return(node); -} - -static Node * -applyrules(char *target, char *cnt) -{ - Symtab *sym; - Node *node; - Rule *r; - Arc head, *a = &head; - Word *w; - char stem[NAMEBLOCK], buf[NAMEBLOCK]; - Resub rmatch[NREGEXP]; - -/* print("applyrules(%lux='%s')\n", target, target);*//**/ - sym = symlook(target, S_NODE, 0); - if(sym) - return (Node *)(sym->value); - target = strdup(target); - node = newnode(target); - head.n = 0; - head.next = 0; - sym = symlook(target, S_TARGET, 0); - memset((char*)rmatch, 0, sizeof(rmatch)); - for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){ - if(r->attr&META) continue; - if(strcmp(target, r->target)) continue; - if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */ - if(cnt[r->rule] >= nreps) continue; - cnt[r->rule]++; - node->flags |= PROBABLE; - -/* if(r->attr&VIR) - * node->flags |= VIRTUAL; - * if(r->attr&NOREC) - * node->flags |= NORECIPE; - * if(r->attr&DEL) - * node->flags |= DELETE; - */ - if(!r->tail || !r->tail->s || !*r->tail->s) { - a->next = newarc((Node *)0, r, "", rmatch); - a = a->next; - } else - for(w = r->tail; w; w = w->next){ - a->next = newarc(applyrules(w->s, cnt), r, "", rmatch); - a = a->next; - } - cnt[r->rule]--; - head.n = node; - } - for(r = metarules; r; r = r->next){ - if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */ - if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) - continue; - if(r->attr&REGEXP){ - stem[0] = 0; - patrule = r; - memset((char*)rmatch, 0, sizeof(rmatch)); - if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0) - continue; - } else { - if(!match(node->name, r->target, stem, r->shellt)) continue; - } - if(cnt[r->rule] >= nreps) continue; - cnt[r->rule]++; - -/* if(r->attr&VIR) - * node->flags |= VIRTUAL; - * if(r->attr&NOREC) - * node->flags |= NORECIPE; - * if(r->attr&DEL) - * node->flags |= DELETE; - */ - - if(!r->tail || !r->tail->s || !*r->tail->s) { - a->next = newarc((Node *)0, r, stem, rmatch); - a = a->next; - } else - for(w = r->tail; w; w = w->next){ - if(r->attr&REGEXP) - regsub(w->s, buf, sizeof buf, rmatch, NREGEXP); - else - subst(stem, w->s, buf); - a->next = newarc(applyrules(buf, cnt), r, stem, rmatch); - a = a->next; - } - cnt[r->rule]--; - } - a->next = node->prereqs; - node->prereqs = head.next; - return(node); -} - -static void -togo(Node *node) -{ - Arc *la, *a; - - /* delete them now */ - la = 0; - for(a = node->prereqs; a; la = a, a = a->next) - if(a->flag&TOGO){ - if(a == node->prereqs) - node->prereqs = a->next; - else - la->next = a->next, a = la; - } -} - -static int -vacuous(Node *node) -{ - Arc *la, *a; - int vac = !(node->flags&PROBABLE); - - if(node->flags&READY) - return(node->flags&VACUOUS); - node->flags |= READY; - for(a = node->prereqs; a; a = a->next) - if(a->n && vacuous(a->n) && (a->r->attr&META)) - a->flag |= TOGO; - else - vac = 0; - /* if a rule generated arcs that DON'T go; no others from that rule go */ - for(a = node->prereqs; a; a = a->next) - if((a->flag&TOGO) == 0) - for(la = node->prereqs; la; la = la->next) - if((la->flag&TOGO) && (la->r == a->r)){ - la->flag &= ~TOGO; - } - togo(node); - if(vac) - node->flags |= VACUOUS; - return(vac); -} - -static Node * -newnode(char *name) -{ - register Node *node; - - node = (Node *)Malloc(sizeof(Node)); - symlook(name, S_NODE, (void *)node); - node->name = name; - node->time = timeof(name, 0); - node->prereqs = 0; - node->flags = node->time? PROBABLE : 0; - node->next = 0; - return(node); -} - -void -dumpn(char *s, Node *n) -{ - char buf[1024]; - Arc *a; - - snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:""); - Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n", - s, n->name, n, n->time, n->flags, n->next); - for(a = n->prereqs; a; a = a->next) - dumpa(buf, a); -} - -static void -trace(char *s, Arc *a) -{ - fprint(2, "\t%s", s); - while(a){ - fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line, - a->n? a->n->name:""); - if(a->n){ - for(a = a->n->prereqs; a; a = a->next) - if(*a->r->recipe) break; - } else - a = 0; - } - fprint(2, "\n"); -} - -static void -cyclechk(Node *n) -{ - Arc *a; - - if((n->flags&CYCLE) && n->prereqs){ - fprint(2, "mk: cycle in graph detected at target %s\n", n->name); - Exit(); - } - n->flags |= CYCLE; - for(a = n->prereqs; a; a = a->next) - if(a->n) - cyclechk(a->n); - n->flags &= ~CYCLE; -} - -static void -ambiguous(Node *n) -{ - Arc *a; - Rule *r = 0; - Arc *la; - int bad = 0; - - la = 0; - for(a = n->prereqs; a; a = a->next){ - if(a->n) - ambiguous(a->n); - if(*a->r->recipe == 0) continue; - if(r == 0) - r = a->r, la = a; - else{ - if(r->recipe != a->r->recipe){ - if((r->attr&META) && !(a->r->attr&META)){ - la->flag |= TOGO; - r = a->r, la = a; - } else if(!(r->attr&META) && (a->r->attr&META)){ - a->flag |= TOGO; - continue; - } - } - if(r->recipe != a->r->recipe){ - if(bad == 0){ - fprint(2, "mk: ambiguous recipes for %s:\n", n->name); - bad = 1; - trace(n->name, la); - } - trace(n->name, a); - } - } - } - if(bad) - Exit(); - togo(n); -} - -static void -attribute(Node *n) -{ - register Arc *a; - - for(a = n->prereqs; a; a = a->next){ - if(a->r->attr&VIR) - n->flags |= VIRTUAL; - if(a->r->attr&NOREC) - n->flags |= NORECIPE; - if(a->r->attr&DEL) - n->flags |= DELETE; - if(a->n) - attribute(a->n); - } - if(n->flags&VIRTUAL) - n->time = 0; -} diff --git a/mk/job.c b/mk/job.c @@ -1,33 +0,0 @@ -#include "mk.h" - -Job * -newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar) -{ - register Job *j; - - j = (Job *)Malloc(sizeof(Job)); - j->r = r; - j->n = nlist; - j->stem = stem; - j->match = match; - j->p = pre; - j->np = npre; - j->t = tar; - j->at = atar; - j->nproc = -1; - j->next = 0; - return(j); -} - -void -dumpj(char *s, Job *j, int all) -{ - Bprint(&bout, "%s\n", s); - while(j){ - Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n", - j, j->r, j->n, j->stem, j->nproc); - Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n", - wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' ')); - j = all? j->next : 0; - } -} diff --git a/mk/lex.c b/mk/lex.c @@ -1,146 +0,0 @@ -#include "mk.h" - -static int bquote(Biobuf*, Bufblock*); - -/* - * Assemble a line skipping blank lines, comments, and eliding - * escaped newlines - */ -int -assline(Biobuf *bp, Bufblock *buf) -{ - int c; - int lastc; - - buf->current=buf->start; - while ((c = nextrune(bp, 1)) >= 0){ - switch(c) - { - case '\r': /* consumes CRs for Win95 */ - continue; - case '\n': - if (buf->current != buf->start) { - insert(buf, 0); - return 1; - } - break; /* skip empty lines */ - case '\\': - case '\'': - case '"': - rinsert(buf, c); - if (shellt->escapetoken(bp, buf, 1, c) == 0) - Exit(); - break; - case '`': - if (bquote(bp, buf) == 0) - Exit(); - break; - case '#': - lastc = '#'; - while ((c = Bgetc(bp)) != '\n') { - if (c < 0) - goto eof; - if(c != '\r') - lastc = c; - } - mkinline++; - if (lastc == '\\') - break; /* propagate escaped newlines??*/ - if (buf->current != buf->start) { - insert(buf, 0); - return 1; - } - break; - default: - rinsert(buf, c); - break; - } - } -eof: - insert(buf, 0); - return *buf->start != 0; -} - -/* - * assemble a back-quoted shell command into a buffer - */ -static int -bquote(Biobuf *bp, Bufblock *buf) -{ - int c, line, term; - int start; - - line = mkinline; - while((c = Bgetrune(bp)) == ' ' || c == '\t') - ; - if(c == '{'){ - term = '}'; /* rc style */ - while((c = Bgetrune(bp)) == ' ' || c == '\t') - ; - } else - term = '`'; /* sh style */ - - start = buf->current-buf->start; - for(;c > 0; c = nextrune(bp, 0)){ - if(c == term){ - insert(buf, '\n'); - insert(buf,0); - buf->current = buf->start+start; - execinit(); - execsh(0, buf->current, buf, envy, shellt, shellcmd); - return 1; - } - if(c == '\n') - break; - if(c == '\'' || c == '"' || c == '\\'){ - insert(buf, c); - if(!shellt->escapetoken(bp, buf, 1, c)) - return 0; - continue; - } - rinsert(buf, c); - } - SYNERR(line); - fprint(2, "missing closing %c after `\n", term); - return 0; -} - -/* - * get next character stripping escaped newlines - * the flag specifies whether escaped newlines are to be elided or - * replaced with a blank. - */ -int -nextrune(Biobuf *bp, int elide) -{ - int c, c2; - static int savec; - - if(savec){ - c = savec; - savec = 0; - return c; - } - - for (;;) { - c = Bgetrune(bp); - if (c == '\\') { - c2 = Bgetrune(bp); - if(c2 == '\r'){ - savec = c2; - c2 = Bgetrune(bp); - } - if (c2 == '\n') { - savec = 0; - mkinline++; - if (elide) - continue; - return ' '; - } - Bungetrune(bp); - } - if (c == '\n') - mkinline++; - return c; - } -} diff --git a/mk/main.c b/mk/main.c @@ -1,287 +0,0 @@ -#include "mk.h" - -#define MKFILE "mkfile" - -int debug; -Rule *rules, *metarules; -int nflag = 0; -int tflag = 0; -int iflag = 0; -int kflag = 0; -int aflag = 0; -int uflag = 0; -char *explain = 0; -Word *target1; -int nreps = 1; -Job *jobs; -Biobuf bout; -Rule *patrule; -void badusage(void); -#ifdef PROF -short buf[10000]; -#endif - -int -main(int argc, char **argv) -{ - Word *w; - char *s, *temp; - char *files[256], **f = files, **ff; - int sflag = 0; - int i; - int tfd = -1; - Biobuf tb; - Bufblock *buf; - Bufblock *whatif; - - /* - * start with a copy of the current environment variables - * instead of sharing them - */ - - Binit(&bout, 1, OWRITE); - buf = newbuf(); - whatif = 0; - USED(argc); - for(argv++; *argv && (**argv == '-'); argv++) - { - bufcpy(buf, argv[0], strlen(argv[0])); - insert(buf, ' '); - switch(argv[0][1]) - { - case 'a': - aflag = 1; - break; - case 'd': - if(*(s = &argv[0][2])) - while(*s) switch(*s++) - { - case 'p': debug |= D_PARSE; break; - case 'g': debug |= D_GRAPH; break; - case 'e': debug |= D_EXEC; break; - } - else - debug = 0xFFFF; - break; - case 'e': - explain = &argv[0][2]; - break; - case 'f': - if(*++argv == 0) - badusage(); - *f++ = *argv; - bufcpy(buf, argv[0], strlen(argv[0])); - insert(buf, ' '); - break; - case 'i': - iflag = 1; - break; - case 'k': - kflag = 1; - break; - case 'n': - nflag = 1; - break; - case 's': - sflag = 1; - break; - case 't': - tflag = 1; - break; - case 'u': - uflag = 1; - break; - case 'w': - if(whatif == 0) - whatif = newbuf(); - else - insert(whatif, ' '); - if(argv[0][2]) - bufcpy(whatif, &argv[0][2], strlen(&argv[0][2])); - else { - if(*++argv == 0) - badusage(); - bufcpy(whatif, &argv[0][0], strlen(&argv[0][0])); - } - break; - default: - badusage(); - } - } -#ifdef PROF - { - extern etext(); - monitor(main, etext, buf, sizeof buf, 300); - } -#endif - - if(aflag) - iflag = 1; - usage(); - syminit(); - initshell(); - initenv(); - usage(); - - /* - assignment args become null strings - */ - temp = 0; - for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){ - bufcpy(buf, argv[i], strlen(argv[i])); - insert(buf, ' '); - if(tfd < 0){ - temp = maketmp(&tfd); - if(temp == 0) { - fprint(2, "temp file: %r\n"); - Exit(); - } - Binit(&tb, tfd, OWRITE); - } - Bprint(&tb, "%s\n", argv[i]); - *argv[i] = 0; - } - if(tfd >= 0){ - Bflush(&tb); - LSEEK(tfd, 0L, 0); - parse("command line args", tfd, 1); - remove(temp); - } - - if (buf->current != buf->start) { - buf->current--; - insert(buf, 0); - } - symlook("MKFLAGS", S_VAR, (void *) stow(buf->start)); - buf->current = buf->start; - for(i = 0; argv[i]; i++){ - if(*argv[i] == 0) continue; - if(i) - insert(buf, ' '); - bufcpy(buf, argv[i], strlen(argv[i])); - } - insert(buf, 0); - symlook("MKARGS", S_VAR, (void *) stow(buf->start)); - freebuf(buf); - - if(f == files){ - if(access(MKFILE, 4) == 0) - parse(MKFILE, open(MKFILE, 0), 0); - } else - for(ff = files; ff < f; ff++) - parse(*ff, open(*ff, 0), 0); - if(DEBUG(D_PARSE)){ - dumpw("default targets", target1); - dumpr("rules", rules); - dumpr("metarules", metarules); - dumpv("variables"); - } - if(whatif){ - insert(whatif, 0); - timeinit(whatif->start); - freebuf(whatif); - } - execinit(); - /* skip assignment args */ - while(*argv && (**argv == 0)) - argv++; - - catchnotes(); - if(*argv == 0){ - if(target1) - for(w = target1; w; w = w->next) - mk(w->s); - else { - fprint(2, "mk: nothing to mk\n"); - Exit(); - } - } else { - if(sflag){ - for(; *argv; argv++) - if(**argv) - mk(*argv); - } else { - Word *head, *tail, *t; - - /* fake a new rule with all the args as prereqs */ - tail = 0; - t = 0; - for(; *argv; argv++) - if(**argv){ - if(tail == 0) - tail = t = newword(*argv); - else { - t->next = newword(*argv); - t = t->next; - } - } - if(tail->next == 0) - mk(tail->s); - else { - head = newword("command line arguments"); - addrules(head, tail, strdup(""), VIR, mkinline, 0); - mk(head->s); - } - } - } - if(uflag) - prusage(); - exits(0); - return 0; -} - -void -badusage(void) -{ - - fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n"); - Exit(); -} - -void * -Malloc(int n) -{ - register void *s; - - s = malloc(n); - if(!s) { - fprint(2, "mk: cannot alloc %d bytes\n", n); - Exit(); - } - return(s); -} - -void * -Realloc(void *s, int n) -{ - if(s) - s = realloc(s, n); - else - s = malloc(n); - if(!s) { - fprint(2, "mk: cannot alloc %d bytes\n", n); - Exit(); - } - return(s); -} - -void -assert(char *s, int n) -{ - if(!n){ - fprint(2, "mk: Assertion ``%s'' failed.\n", s); - Exit(); - } -} - -void -regerror(char *s) -{ - if(patrule) - fprint(2, "mk: %s:%d: regular expression error; %s\n", - patrule->file, patrule->line, s); - else - fprint(2, "mk: %s:%d: regular expression error; %s\n", - infile, mkinline, s); - Exit(); -} diff --git a/mk/match.c b/mk/match.c @@ -1,49 +0,0 @@ -#include "mk.h" - -int -match(char *name, char *template, char *stem, Shell *sh) -{ - Rune r; - int n; - - while(*name && *template){ - n = chartorune(&r, template); - if (PERCENT(r)) - break; - while (n--) - if(*name++ != *template++) - return 0; - } - if(!PERCENT(*template)) - return 0; - n = strlen(name)-strlen(template+1); - if (n < 0) - return 0; - if (strcmp(template+1, name+n)) - return 0; - strncpy(stem, name, n); - stem[n] = 0; - if(*template == '&') - return !sh->charin(stem, "./"); - return 1; -} - -void -subst(char *stem, char *template, char *dest) -{ - Rune r; - char *s; - int n; - - while(*template){ - n = chartorune(&r, template); - if (PERCENT(r)) { - template += n; - for (s = stem; *s; s++) - *dest++ = *s; - } else - while (n--) - *dest++ = *template++; - } - *dest = 0; -} diff --git a/mk/mk.1 b/mk/mk.1 @@ -1,691 +0,0 @@ -.TH MK 1 -.SH NAME -mk \- maintain (make) related files -.SH SYNOPSIS -.B mk -[ -.B -f -.I mkfile -] ... -[ -.I option ... -] -[ -.I target ... -] -.SH DESCRIPTION -.I Mk -uses the dependency rules specified in -.I mkfile -to control the update (usually by compilation) of -.I targets -(usually files) -from the source files upon which they depend. -The -.I mkfile -(default -.LR mkfile ) -contains a -.I rule -for each target that identifies the files and other -targets upon which it depends and an -.IR sh (1) -script, a -.IR recipe , -to update the target. -The script is run if the target does not exist -or if it is older than any of the files it depends on. -.I Mkfile -may also contain -.I meta-rules -that define actions for updating implicit targets. -If no -.I target -is specified, the target of the first rule (not meta-rule) in -.I mkfile -is updated. -.PP -The environment variable -.B $NPROC -determines how many targets may be updated simultaneously; -Some operating systems, e.g., Plan 9, set -.B $NPROC -automatically to the number of CPUs on the current machine. -.PP -Options are: -.TP \w'\fL-d[egp]\ 'u -.B -a -Assume all targets to be out of date. -Thus, everything is updated. -.PD 0 -.TP -.BR -d [ egp ] -Produce debugging output -.RB ( p -is for parsing, -.B g -for graph building, -.B e -for execution). -.TP -.B -e -Explain why each target is made. -.TP -.B -i -Force any missing intermediate targets to be made. -.TP -.B -k -Do as much work as possible in the face of errors. -.TP -.B -n -Print, but do not execute, the commands -needed to update the targets. -.TP -.B -s -Make the command line arguments sequentially rather than in parallel. -.TP -.B -t -Touch (update the modified date of) file targets, without -executing any recipes. -.TP -.BI -w target1 , target2,... -Pretend the modify time for each -.I target -is the current time; useful in conjunction with -.B -n -to learn what updates would be triggered by -modifying the -.IR targets . -.PD -.SS The \fLmkfile\fP -A -.I mkfile -consists of -.I assignments -(described under `Environment') and -.IR rules . -A rule contains -.I targets -and a -.IR tail . -A target is a literal string -and is normally a file name. -The tail contains zero or more -.I prerequisites -and an optional -.IR recipe , -which is an -.B shell -script. -Each line of the recipe must begin with white space. -A rule takes the form -.IP -.EX -target: prereq1 prereq2 - \f2recipe using\fP prereq1, prereq2 \f2to build\fP target -.EE -.PP -When the recipe is executed, -the first character on every line is elided. -.PP -After the colon on the target line, a rule may specify -.IR attributes , -described below. -.PP -A -.I meta-rule -has a target of the form -.IB A % B -where -.I A -and -.I B -are (possibly empty) strings. -A meta-rule acts as a rule for any potential target whose -name matches -.IB A % B -with -.B % -replaced by an arbitrary string, called the -.IR stem . -In interpreting a meta-rule, -the stem is substituted for all occurrences of -.B % -in the prerequisite names. -In the recipe of a meta-rule, the environment variable -.B $stem -contains the string matched by the -.BR % . -For example, a meta-rule to compile a C program using -.IR 9c (1) -might be: -.IP -.EX -%: %.c - 9c -c $stem.c - 9l -o $stem $stem.o -.EE -.PP -Meta-rules may contain an ampersand -.B & -rather than a percent sign -.BR % . -A -.B % -matches a maximal length string of any characters; -an -.B & -matches a maximal length string of any characters except period -or slash. -.PP -The text of the -.I mkfile -is processed as follows. -Lines beginning with -.B < -followed by a file name are replaced by the contents of the named -file. -Lines beginning with -.B "<|" -followed by a file name are replaced by the output -of the execution of the named -file. -Blank lines and comments, which run from unquoted -.B # -characters to the following newline, are deleted. -The character sequence backslash-newline is deleted, -so long lines in -.I mkfile -may be folded. -Non-recipe lines are processed by substituting for -.BI `{ command } -the output of the -.I command -when run by -.IR sh . -References to variables are replaced by the variables' values. -Special characters may be quoted using single quotes -.BR \&'' -as in -.IR sh (1). -.PP -Assignments and rules are distinguished by -the first unquoted occurrence of -.B : -(rule) -or -.B = -(assignment). -.PP -A later rule may modify or override an existing rule under the -following conditions: -.TP -\- -If the targets of the rules exactly match and one rule -contains only a prerequisite clause and no recipe, the -clause is added to the prerequisites of the other rule. -If either or both targets are virtual, the recipe is -always executed. -.TP -\- -If the targets of the rules match exactly and the -prerequisites do not match and both rules -contain recipes, -.I mk -reports an ``ambiguous recipe'' error. -.TP -\- -If the target and prerequisites of both rules match exactly, -the second rule overrides the first. -.SS Environment -Rules may make use of -shell -environment variables. -A legal reference of the form -.B $OBJ -or -.B ${name} -is expanded as in -.IR sh (1). -A reference of the form -.BI ${name: A % B = C\fL%\fID\fL}\fR, -where -.I A, B, C, D -are (possibly empty) strings, -has the value formed by expanding -.B $name -and substituting -.I C -for -.I A -and -.I D -for -.I B -in each word in -.B $name -that matches pattern -.IB A % B\f1. -.PP -Variables can be set by -assignments of the form -.I - var\fL=\fR[\fIattr\fL=\fR]\fIvalue\fR -.br -Blanks in the -.I value -break it into words. -Such variables are exported -to the environment of -recipes as they are executed, unless -.BR U , -the only legal attribute -.IR attr , -is present. -The initial value of a variable is -taken from (in increasing order of precedence) -the default values below, -.I mk's -environment, the -.IR mkfiles , -and any command line assignment as an argument to -.IR mk . -A variable assignment argument overrides the first (but not any subsequent) -assignment to that variable. -.PP -The variable -.B MKFLAGS -contains all the option arguments (arguments starting with -.L - -or containing -.LR = ) -and -.B MKARGS -contains all the targets in the call to -.IR mk . -.PP -The variable -.B MKSHELL -contains the shell command line -.I mk -uses to run recipes. -If the first word of the command ends in -.B rc -or -.BR rcsh , -.I mk -uses -.IR rc (1)'s -quoting rules; otherwise it uses -.IR sh (1)'s. -The -.B MKSHELL -variable is consulted when the mkfile is read, not when it is executed, -so that different shells can be used within a single mkfile: -.IP -.EX -MKSHELL=$PLAN9/bin/rc -use-rc:V: - for(i in a b c) echo $i - -MKSHELL=sh -use-sh:V: - for i in a b c; do echo $i; done -.EE -.LP -Mkfiles included via -.B < -or -.B <| -.RI ( q.v. ) -see their own private copy of -.BR MKSHELL , -which always starts set to -.B sh . -.PP -Dynamic information may be included in the mkfile by using a line of the form -.IP -\fR<|\fIcommand\fR \fIargs\fR -.LP -This runs the command -.I command -with the given arguments -.I args -and pipes its standard output to -.I mk -to be included as part of the mkfile. For instance, the Inferno kernels -use this technique -to run a shell command with an awk script and a configuration -file as arguments in order for -the -.I awk -script to process the file and output a set of variables and their values. -.SS Execution -.PP -During execution, -.I mk -determines which targets must be updated, and in what order, -to build the -.I names -specified on the command line. -It then runs the associated recipes. -.PP -A target is considered up to date if it has no prerequisites or -if all its prerequisites are up to date and it is newer -than all its prerequisites. -Once the recipe for a target has executed, the target is -considered up to date. -.PP -The date stamp -used to determine if a target is up to date is computed -differently for different types of targets. -If a target is -.I virtual -(the target of a rule with the -.B V -attribute), -its date stamp is initially zero; when the target is -updated the date stamp is set to -the most recent date stamp of its prerequisites. -Otherwise, if a target does not exist as a file, -its date stamp is set to the most recent date stamp of its prerequisites, -or zero if it has no prerequisites. -Otherwise, the target is the name of a file and -the target's date stamp is always that file's modification date. -The date stamp is computed when the target is needed in -the execution of a rule; it is not a static value. -.PP -Nonexistent targets that have prerequisites -and are themselves prerequisites are treated specially. -Such a target -.I t -is given the date stamp of its most recent prerequisite -and if this causes all the targets which have -.I t -as a prerequisite to be up to date, -.I t -is considered up to date. -Otherwise, -.I t -is made in the normal fashion. -The -.B -i -flag overrides this special treatment. -.PP -Files may be made in any order that respects -the preceding restrictions. -.PP -A recipe is executed by supplying the recipe as standard input to -the command -.BR /bin/sh . -(Note that unlike -.IR make , -.I mk -feeds the entire recipe to the shell rather than running each line -of the recipe separately.) -The environment is augmented by the following variables: -.TP 14 -.B $alltarget -all the targets of this rule. -.TP -.B $newprereq -the prerequisites that caused this rule to execute. -.TP -.B $newmember -the prerequisites that are members of an aggregate -that caused this rule to execute. -When the prerequisites of a rule are members of an -aggregate, -.B $newprereq -contains the name of the aggregate and out of date -members, while -.B $newmember -contains only the name of the members. -.TP -.B $nproc -the process slot for this recipe. -It satisfies -.RB 0≤ $nproc < $NPROC . -.TP -.B $pid -the process id for the -.I mk -executing the recipe. -.TP -.B $prereq -all the prerequisites for this rule. -.TP -.B $stem -if this is a meta-rule, -.B $stem -is the string that matched -.B % -or -.BR & . -Otherwise, it is empty. -For regular expression meta-rules (see below), the variables -.LR stem0 ", ...," -.L stem9 -are set to the corresponding subexpressions. -.TP -.B $target -the targets for this rule that need to be remade. -.PP -These variables are available only during the execution of a recipe, -not while evaluating the -.IR mkfile . -.PP -Unless the rule has the -.B Q -attribute, -the recipe is printed prior to execution -with recognizable environment variables expanded. -Commands returning error status -cause -.I mk -to terminate. -.PP -Recipes and backquoted -.B rc -commands in places such as assignments -execute in a copy of -.I mk's -environment; changes they make to -environment variables are not visible from -.IR mk . -.PP -Variable substitution in a rule is done when -the rule is read; variable substitution in the recipe is done -when the recipe is executed. For example: -.IP -.EX -bar=a.c -foo: $bar - $CC -o foo $bar -bar=b.c -.EE -.PP -will compile -.B b.c -into -.BR foo , -if -.B a.c -is newer than -.BR foo . -.SS Aggregates -Names of the form -.IR a ( b ) -refer to member -.I b -of the aggregate -.IR a . -Currently, the only aggregates supported are -.I 9ar -(see -.IR 9c (1)) -archives. -.SS Attributes -The colon separating the target from the prerequisites -may be -immediately followed by -.I attributes -and another colon. -The attributes are: -.TP -.B D -If the recipe exits with a non-null status, the target is deleted. -.TP -.B E -Continue execution if the recipe draws errors. -.TP -.B N -If there is no recipe, the target has its time updated. -.TP -.B n -The rule is a meta-rule that cannot be a target of a virtual rule. -Only files match the pattern in the target. -.TP -.B P -The characters after the -.B P -until the terminating -.B : -are taken as a program name. -It will be invoked as -.B "sh -c prog 'arg1' 'arg2'" -and should return a zero exit status -if and only if arg1 is up to date with respect to arg2. -Date stamps are still propagated in the normal way. -.TP -.B Q -The recipe is not printed prior to execution. -.TP -.B R -The rule is a meta-rule using regular expressions. -In the rule, -.B % -has no special meaning. -The target is interpreted as a regular expression as defined in -.IR regexp (7). -The prerequisites may contain references -to subexpressions in form -.BI \e n\f1, -as in the substitute command of -.IR sed (1). -.TP -.B U -The targets are considered to have been updated -even if the recipe did not do so. -.TP -.B V -The targets of this rule are marked as virtual. -They are distinct from files of the same name. -.PD -.SH EXAMPLES -A simple mkfile to compile a program: -.IP -.EX -.ta 8n +8n +8n +8n +8n +8n +8n -</$objtype/mkfile - -prog: a.$O b.$O c.$O - $LD $LDFLAGS -o $target $prereq - -%.$O: %.c - $CC $CFLAGS $stem.c -.EE -.PP -Override flag settings in the mkfile: -.IP -.EX -% mk target 'CFLAGS=-S -w' -.EE -.PP -Maintain a library: -.IP -.EX -libc.a(%.$O):N: %.$O -libc.a: libc.a(abs.$O) libc.a(access.$O) libc.a(alarm.$O) ... - ar r libc.a $newmember -.EE -.PP -String expression variables to derive names from a master list: -.IP -.EX -NAMES=alloc arc bquote builtins expand main match mk var word -OBJ=${NAMES:%=%.$O} -.EE -.PP -Regular expression meta-rules: -.IP -.EX -([^/]*)/(.*)\e.$O:R: \e1/\e2.c - cd $stem1; $CC $CFLAGS $stem2.c -.EE -.PP -A correct way to deal with -.IR yacc (1) -grammars. -The file -.B lex.c -includes the file -.B x.tab.h -rather than -.B y.tab.h -in order to reflect changes in content, not just modification time. -.IP -.EX -lex.$O: x.tab.h -x.tab.h: y.tab.h - cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h -y.tab.c y.tab.h: gram.y - $YACC -d gram.y -.EE -.PP -The above example could also use the -.B P -attribute for the -.B x.tab.h -rule: -.IP -.EX -x.tab.h:Pcmp -s: y.tab.h - cp y.tab.h x.tab.h -.EE -.SH SOURCE -.B \*9/src/cmd/mk -.SH SEE ALSO -.IR sh (1), -.IR regexp (7) -.PP -A. Hume, -``Mk: a Successor to Make'' -(Tenth Edition Research Unix Manuals). -.PP -Andrew G. Hume and Bob Flandrena, -``Maintaining Files on Plan 9 with Mk''. -DOCPREFIX/doc/mk.pdf -.SH HISTORY -Andrew Hume wrote -.I mk -for Tenth Edition Research Unix. -It was later ported to Plan 9. -This software is a port of the Plan 9 version back to Unix. -.SH BUGS -Identical recipes for regular expression meta-rules only have one target. -.PP -Seemingly appropriate input like -.B CFLAGS=-DHZ=60 -is parsed as an erroneous attribute; correct it by inserting -a space after the first -.LR = . -.PP -The recipes printed by -.I mk -before being passed to -the shell -for execution are sometimes erroneously expanded -for printing. Don't trust what's printed; rely -on what the shell -does. diff --git a/mk/mk.c b/mk/mk.c @@ -1,234 +0,0 @@ -#include "mk.h" - -int runerrs; - -void -mk(char *target) -{ - Node *node; - int did = 0; - - nproc(); /* it can be updated dynamically */ - nrep(); /* it can be updated dynamically */ - runerrs = 0; - node = graph(target); - if(DEBUG(D_GRAPH)){ - dumpn("new target\n", node); - Bflush(&bout); - } - clrmade(node); - while(node->flags&NOTMADE){ - if(work(node, (Node *)0, (Arc *)0)) - did = 1; /* found something to do */ - else { - if(waitup(1, (int *)0) > 0){ - if(node->flags&(NOTMADE|BEINGMADE)){ - assert("must be run errors", runerrs); - break; /* nothing more waiting */ - } - } - } - } - if(node->flags&BEINGMADE) - waitup(-1, (int *)0); - while(jobs) - waitup(-2, (int *)0); - assert("target didn't get done", runerrs || (node->flags&MADE)); - if(did == 0) - Bprint(&bout, "mk: '%s' is up to date\n", node->name); -} - -void -clrmade(Node *n) -{ - Arc *a; - - n->flags &= ~(CANPRETEND|PRETENDING); - if(strchr(n->name, '(') ==0 || n->time) - n->flags |= CANPRETEND; - MADESET(n, NOTMADE); - for(a = n->prereqs; a; a = a->next) - if(a->n) - clrmade(a->n); -} - -static void -unpretend(Node *n) -{ - MADESET(n, NOTMADE); - n->flags &= ~(CANPRETEND|PRETENDING); - n->time = 0; -} - -static char* -dir(void) -{ - static char buf[1024]; - - return getcwd(buf, sizeof buf); -} - -int -work(Node *node, Node *p, Arc *parc) -{ - Arc *a, *ra; - int weoutofdate; - int ready; - int did = 0; - - /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);*//**/ - if(node->flags&BEINGMADE) - return(did); - if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){ - if(explain) - fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n", - node->name, node->time, p->name, p->time); - unpretend(node); - } - /* - have a look if we are pretending in case - someone has been unpretended out from underneath us - */ - if(node->flags&MADE){ - if(node->flags&PRETENDING){ - node->time = 0; - }else - return(did); - } - /* consider no prerequsite case */ - if(node->prereqs == 0){ - if(node->time == 0){ - fprint(2, "mk: don't know how to make '%s' in %s\n", node->name, dir()); - if(kflag){ - node->flags |= BEINGMADE; - runerrs++; - } else - Exit(); - } else - MADESET(node, MADE); - return(did); - } - /* - now see if we are out of date or what - */ - ready = 1; - weoutofdate = aflag; - ra = 0; - for(a = node->prereqs; a; a = a->next) - if(a->n){ - did = work(a->n, node, a) || did; - if(a->n->flags&(NOTMADE|BEINGMADE)) - ready = 0; - if(outofdate(node, a, 0)){ - weoutofdate = 1; - if((ra == 0) || (ra->n == 0) - || (ra->n->time < a->n->time)) - ra = a; - } - } else { - if(node->time == 0){ - if(ra == 0) - ra = a; - weoutofdate = 1; - } - } - if(ready == 0) /* can't do anything now */ - return(did); - if(weoutofdate == 0){ - MADESET(node, MADE); - return(did); - } - /* - can we pretend to be made? - */ - if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND)) - && p && ra->n && !outofdate(p, ra, 0)){ - node->flags &= ~CANPRETEND; - MADESET(node, MADE); - if(explain && ((node->flags&PRETENDING) == 0)) - fprint(1, "pretending %s has time %ld\n", node->name, node->time); - node->flags |= PRETENDING; - return(did); - } - /* - node is out of date and we REALLY do have to do something. - quickly rescan for pretenders - */ - for(a = node->prereqs; a; a = a->next) - if(a->n && (a->n->flags&PRETENDING)){ - if(explain) - Bprint(&bout, "unpretending %s because of %s because of %s\n", - a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites"); - - unpretend(a->n); - did = work(a->n, node, a) || did; - ready = 0; - } - if(ready == 0) /* try later unless nothing has happened for -k's sake */ - return(did || work(node, p, parc)); - did = dorecipe(node) || did; - return(did); -} - -void -update(int fake, Node *node) -{ - Arc *a; - - MADESET(node, fake? BEINGMADE : MADE); - if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){ - node->time = timeof(node->name, 1); - node->flags &= ~(CANPRETEND|PRETENDING); - for(a = node->prereqs; a; a = a->next) - if(a->prog) - outofdate(node, a, 1); - } else { - node->time = 1; - for(a = node->prereqs; a; a = a->next) - if(a->n && outofdate(node, a, 1)) - node->time = a->n->time; - } -/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);*//**/ -} - -static int -pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd) -{ - char buf[3*NAMEBLOCK]; - int pid; - - Bflush(&bout); - snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q); - pid = pipecmd(buf, 0, 0, sh, shcmd); - while(waitup(-3, &pid) >= 0) - ; - return(pid? 2:1); -} - -int -outofdate(Node *node, Arc *arc, int eval) -{ - char buf[3*NAMEBLOCK], *str; - Symtab *sym; - int ret; - - str = 0; - if(arc->prog){ - snprint(buf, sizeof buf, "%s%c%s", node->name, 0377, arc->n->name); - sym = symlook(buf, S_OUTOFDATE, 0); - if(sym == 0 || eval){ - if(sym == 0) - str = strdup(buf); - ret = pcmp(arc->prog, node->name, arc->n->name, arc->r->shellt, arc->r->shellcmd); - if(sym) - sym->value = (void *)ret; - else - symlook(str, S_OUTOFDATE, (void *)ret); - } else - ret = (int)sym->value; - return(ret-1); - } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */ - return 1; - else - return node->time <= arc->n->time; -} diff --git a/mk/mk.h b/mk/mk.h @@ -1,182 +0,0 @@ -#include "sys.h" - -#undef assert -#define assert mkassert -extern Biobuf bout; - -typedef struct Bufblock -{ - struct Bufblock *next; - char *start; - char *end; - char *current; -} Bufblock; - -typedef struct Word -{ - char *s; - struct Word *next; -} Word; - -typedef struct Envy -{ - char *name; - Word *values; -} Envy; - -extern Envy *envy; - -typedef struct Shell -{ - char *name; - char *termchars; /* used in parse.c to isolate assignment attribute */ - int iws; /* inter-word separator in environment */ - char *(*charin)(char*, char*); /* search for unescaped characters */ - char *(*expandquote)(char*, Rune, Bufblock*); /* extract escaped token */ - int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* input escaped token */ - char *(*copyq)(char*, Rune, Bufblock*); /* check for quoted strings */ - int (*matchname)(char*); /* does name match */ -} Shell; - -typedef struct Rule -{ - char *target; /* one target */ - Word *tail; /* constituents of targets */ - char *recipe; /* do it ! */ - short attr; /* attributes */ - short line; /* source line */ - char *file; /* source file */ - Word *alltargets; /* all the targets */ - int rule; /* rule number */ - Reprog *pat; /* reg exp goo */ - char *prog; /* to use in out of date */ - struct Rule *chain; /* hashed per target */ - struct Rule *next; - Shell *shellt; /* shell to use with this rule */ - Word *shellcmd; -} Rule; - -extern Rule *rules, *metarules, *patrule; - -/* Rule.attr */ -#define META 0x0001 -#define UNUSED 0x0002 -#define UPD 0x0004 -#define QUIET 0x0008 -#define VIR 0x0010 -#define REGEXP 0x0020 -#define NOREC 0x0040 -#define DEL 0x0080 -#define NOVIRT 0x0100 - -#define NREGEXP 10 - -typedef struct Arc -{ - short flag; - struct Node *n; - Rule *r; - char *stem; - char *prog; - char *match[NREGEXP]; - struct Arc *next; -} Arc; - - /* Arc.flag */ -#define TOGO 1 - -typedef struct Node -{ - char *name; - long time; - unsigned short flags; - Arc *prereqs; - struct Node *next; /* list for a rule */ -} Node; - - /* Node.flags */ -#define VIRTUAL 0x0001 -#define CYCLE 0x0002 -#define READY 0x0004 -#define CANPRETEND 0x0008 -#define PRETENDING 0x0010 -#define NOTMADE 0x0020 -#define BEINGMADE 0x0040 -#define MADE 0x0080 -#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEINGMADE|MADE))|(m) -#define PROBABLE 0x0100 -#define VACUOUS 0x0200 -#define NORECIPE 0x0400 -#define DELETE 0x0800 -#define NOMINUSE 0x1000 - -typedef struct Job -{ - Rule *r; /* master rule for job */ - Node *n; /* list of node targets */ - char *stem; - char **match; - Word *p; /* prerequistes */ - Word *np; /* new prerequistes */ - Word *t; /* targets */ - Word *at; /* all targets */ - int nproc; /* slot number */ - struct Job *next; -} Job; -extern Job *jobs; - -typedef struct Symtab -{ - short space; - char *name; - void *value; - struct Symtab *next; -} Symtab; - -enum { - S_VAR, /* variable -> value */ - S_TARGET, /* target -> rule */ - S_TIME, /* file -> time */ - S_PID, /* pid -> products */ - S_NODE, /* target name -> node */ - S_AGG, /* aggregate -> time */ - S_BITCH, /* bitched about aggregate not there */ - S_NOEXPORT, /* var -> noexport */ - S_OVERRIDE, /* can't override */ - S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */ - S_MAKEFILE, /* target -> node */ - S_MAKEVAR, /* dumpable mk variable */ - S_EXPORTED, /* var -> current exported value */ - S_WESET, /* variable; we set in the mkfile */ - S_INTERNAL /* an internal mk variable (e.g., stem, target) */ -}; - -extern int debug; -extern int nflag, tflag, iflag, kflag, aflag, mflag; -extern int mkinline; -extern char *infile; -extern int nreps; -extern char *explain; -extern Shell *shellt; -extern Word *shellcmd; - -extern Shell shshell, rcshell; - -#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline)) -#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line)) -#define NAMEBLOCK 1000 -#define BIGBLOCK 20000 - -#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n')) -#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", (r))) - -#define DEBUG(x) (debug&(x)) -#define D_PARSE 0x01 -#define D_GRAPH 0x02 -#define D_EXEC 0x04 - -#define LSEEK(f,o,p) seek(f,o,p) - -#define PERCENT(ch) (((ch) == '%') || ((ch) == '&')) - -#include "fns.h" diff --git a/mk/parse.c b/mk/parse.c @@ -1,318 +0,0 @@ -#include "mk.h" - -char *infile; -int mkinline; -static int rhead(char *, Word **, Word **, int *, char **); -static char *rbody(Biobuf*); -extern Word *target1; - -void -parse(char *f, int fd, int varoverride) -{ - int hline; - char *body; - Word *head, *tail; - int attr, set, pid; - char *prog, *p; - int newfd; - Biobuf in; - Bufblock *buf; - char *err; - - if(fd < 0){ - fprint(2, "open %s: %r\n", f); - Exit(); - } - pushshell(); - ipush(); - infile = strdup(f); - mkinline = 1; - Binit(&in, fd, OREAD); - buf = newbuf(); - while(assline(&in, buf)){ - hline = mkinline; - switch(rhead(buf->start, &head, &tail, &attr, &prog)) - { - case '<': - p = wtos(tail, ' '); - if(*p == 0){ - SYNERR(-1); - fprint(2, "missing include file name\n"); - Exit(); - } - newfd = open(p, OREAD); - if(newfd < 0){ - fprint(2, "warning: skipping missing include file %s: %r\n", p); - } else - parse(p, newfd, 0); - break; - case '|': - p = wtos(tail, ' '); - if(*p == 0){ - SYNERR(-1); - fprint(2, "missing include program name\n"); - Exit(); - } - execinit(); - pid=pipecmd(p, envy, &newfd, shellt, shellcmd); - if(newfd < 0){ - fprint(2, "warning: skipping missing program file %s: %r\n", p); - } else - parse(p, newfd, 0); - while(waitup(-3, &pid) >= 0) - ; - if(pid != 0){ - fprint(2, "bad include program status\n"); - Exit(); - } - break; - case ':': - body = rbody(&in); - addrules(head, tail, body, attr, hline, prog); - break; - case '=': - if(head->next){ - SYNERR(-1); - fprint(2, "multiple vars on left side of assignment\n"); - Exit(); - } - if(symlook(head->s, S_OVERRIDE, 0)){ - set = varoverride; - } else { - set = 1; - if(varoverride) - symlook(head->s, S_OVERRIDE, (void *)""); - } - if(set){ -/* -char *cp; -dumpw("tail", tail); -cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp); -*/ - setvar(head->s, (void *) tail); - symlook(head->s, S_WESET, (void *)""); - if(strcmp(head->s, "MKSHELL") == 0){ - if((err = setshell(tail)) != nil){ - SYNERR(hline); - fprint(2, "%s\n", err); - Exit(); - break; - } - } - } - if(attr) - symlook(head->s, S_NOEXPORT, (void *)""); - break; - default: - SYNERR(hline); - fprint(2, "expected one of :<=\n"); - Exit(); - break; - } - } - close(fd); - freebuf(buf); - ipop(); - popshell(); -} - -void -addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog) -{ - Word *w; - - assert("addrules args", head && body); - /* tuck away first non-meta rule as default target*/ - if(target1 == 0 && !(attr&REGEXP)){ - for(w = head; w; w = w->next) - if(shellt->charin(w->s, "%&")) - break; - if(w == 0) - target1 = wdup(head); - } - for(w = head; w; w = w->next) - addrule(w->s, tail, body, head, attr, hline, prog); -} - -static int -rhead(char *line, Word **h, Word **t, int *attr, char **prog) -{ - char *p; - char *pp; - int sep; - Rune r; - int n; - Word *w; - - p = shellt->charin(line,":=<"); - if(p == 0) - return('?'); - sep = *p; - *p++ = 0; - if(sep == '<' && *p == '|'){ - sep = '|'; - p++; - } - *attr = 0; - *prog = 0; - if(sep == '='){ - pp = shellt->charin(p, shellt->termchars); /* termchars is shell-dependent */ - if (pp && *pp == '=') { - while (p != pp) { - n = chartorune(&r, p); - switch(r) - { - default: - SYNERR(-1); - fprint(2, "unknown attribute '%c'\n",*p); - Exit(); - case 'U': - *attr = 1; - break; - } - p += n; - } - p++; /* skip trailing '=' */ - } - } - if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){ - while (*p) { - n = chartorune(&r, p); - if (r == ':') - break; - p += n; - switch(r) - { - default: - SYNERR(-1); - fprint(2, "unknown attribute '%c'\n", p[-1]); - Exit(); - case 'D': - *attr |= DEL; - break; - case 'E': - *attr |= NOMINUSE; - break; - case 'n': - *attr |= NOVIRT; - break; - case 'N': - *attr |= NOREC; - break; - case 'P': - pp = utfrune(p, ':'); - if (pp == 0 || *pp == 0) - goto eos; - *pp = 0; - *prog = strdup(p); - *pp = ':'; - p = pp; - break; - case 'Q': - *attr |= QUIET; - break; - case 'R': - *attr |= REGEXP; - break; - case 'U': - *attr |= UPD; - break; - case 'V': - *attr |= VIR; - break; - } - } - if (*p++ != ':') { - eos: - SYNERR(-1); - fprint(2, "missing trailing :\n"); - Exit(); - } - } - *h = w = stow(line); - if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') { - SYNERR(mkinline-1); - fprint(2, "no var on left side of assignment/rule\n"); - Exit(); - } - *t = stow(p); - return(sep); -} - -static char * -rbody(Biobuf *in) -{ - Bufblock *buf; - int r, lastr; - char *p; - - lastr = '\n'; - buf = newbuf(); - for(;;){ - r = Bgetrune(in); - if (r < 0) - break; - if (lastr == '\n') { - if (r == '#') - rinsert(buf, r); - else if (r != ' ' && r != '\t') { - Bungetrune(in); - break; - } - } else - rinsert(buf, r); - lastr = r; - if (r == '\n') - mkinline++; - } - insert(buf, 0); - p = strdup(buf->start); - freebuf(buf); - return p; -} - -struct input -{ - char *file; - int line; - struct input *next; -}; -static struct input *inputs = 0; - -void -ipush(void) -{ - struct input *in, *me; - - me = (struct input *)Malloc(sizeof(*me)); - me->file = infile; - me->line = mkinline; - me->next = 0; - if(inputs == 0) - inputs = me; - else { - for(in = inputs; in->next; ) - in = in->next; - in->next = me; - } -} - -void -ipop(void) -{ - struct input *in, *me; - - assert("pop input list", inputs != 0); - if(inputs->next == 0){ - me = inputs; - inputs = 0; - } else { - for(in = inputs; in->next->next; ) - in = in->next; - me = in->next; - in->next = 0; - } - infile = me->file; - mkinline = me->line; - free((char *)me); -} diff --git a/mk/rc.c b/mk/rc.c @@ -1,194 +0,0 @@ -#include "mk.h" - -/* - * This file contains functions that depend on rc's syntax. Most - * of the routines extract strings observing rc's escape conventions - */ - - -/* - * skip a token in single quotes. - */ -static char * -squote(char *cp) -{ - Rune r; - int n; - - while(*cp){ - n = chartorune(&r, cp); - if(r == '\'') { - n += chartorune(&r, cp+n); - if(r != '\'') - return(cp); - } - cp += n; - } - SYNERR(-1); /* should never occur */ - fprint(2, "missing closing '\n"); - return 0; -} - -/* - * search a string for characters in a pattern set - * characters in quotes and variable generators are escaped - */ -char * -rccharin(char *cp, char *pat) -{ - Rune r; - int n, vargen; - - vargen = 0; - while(*cp){ - n = chartorune(&r, cp); - switch(r){ - case '\'': /* skip quoted string */ - cp = squote(cp+1); /* n must = 1 */ - if(!cp) - return 0; - break; - case '$': - if(*(cp+1) == '{') - vargen = 1; - break; - case '}': - if(vargen) - vargen = 0; - else if(utfrune(pat, r)) - return cp; - break; - default: - if(vargen == 0 && utfrune(pat, r)) - return cp; - break; - } - cp += n; - } - if(vargen){ - SYNERR(-1); - fprint(2, "missing closing } in pattern generator\n"); - } - return 0; -} - -/* - * extract an escaped token. Possible escape chars are single-quote, - * double-quote,and backslash. Only the first is valid for rc. the - * others are just inserted into the receiving buffer. - */ -char* -rcexpandquote(char *s, Rune r, Bufblock *b) -{ - if (r != '\'') { - rinsert(b, r); - return s; - } - - while(*s){ - s += chartorune(&r, s); - if(r == '\'') { - if(*s == '\'') - s++; - else - return s; - } - rinsert(b, r); - } - return 0; -} - -/* - * Input an escaped token. Possible escape chars are single-quote, - * double-quote and backslash. Only the first is a valid escape for - * rc; the others are just inserted into the receiving buffer. - */ -int -rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) -{ - int c, line; - - if(esc != '\'') - return 1; - - line = mkinline; - while((c = nextrune(bp, 0)) > 0){ - if(c == '\''){ - if(preserve) - rinsert(buf, c); - c = Bgetrune(bp); - if (c < 0) - break; - if(c != '\''){ - Bungetrune(bp); - return 1; - } - } - rinsert(buf, c); - } - SYNERR(line); fprint(2, "missing closing %c\n", esc); - return 0; -} - -/* - * copy a single-quoted string; s points to char after opening quote - */ -static char * -copysingle(char *s, Bufblock *buf) -{ - Rune r; - - while(*s){ - s += chartorune(&r, s); - rinsert(buf, r); - if(r == '\'') - break; - } - return s; -} -/* - * check for quoted strings. backquotes are handled here; single quotes above. - * s points to char after opening quote, q. - */ -char * -rccopyq(char *s, Rune q, Bufblock *buf) -{ - if(q == '\'') /* copy quoted string */ - return copysingle(s, buf); - - if(q != '`') /* not quoted */ - return s; - - while(*s){ /* copy backquoted string */ - s += chartorune(&q, s); - rinsert(buf, q); - if(q == '}') - break; - if(q == '\'') - s = copysingle(s, buf); /* copy quoted string */ - } - return s; -} - -static int -rcmatchname(char *name) -{ - char *p; - - if((p = strchr(name, '/')) != nil) - name = p+1; - if(name[0] == 'r' && name[1] == 'c') - return 1; - return 0; -} - -Shell rcshell = { - "rc", - "'= \t", - '\1', - rccharin, - rcexpandquote, - rcescapetoken, - rccopyq, - rcmatchname, -}; diff --git a/mk/recipe.c b/mk/recipe.c @@ -1,117 +0,0 @@ -#include "mk.h" - -int -dorecipe(Node *node) -{ - char buf[BIGBLOCK]; - register Node *n; - Rule *r = 0; - Arc *a, *aa; - Word head, ahead, lp, ln, *w, *ww, *aw; - Symtab *s; - int did = 0; - - aa = 0; - /* - pick up the rule - */ - for(a = node->prereqs; a; a = a->next) - if(*a->r->recipe) - r = (aa = a)->r; - /* - no recipe? go to buggery! - */ - if(r == 0){ - if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){ - fprint(2, "mk: no recipe to make '%s'\n", node->name); - Exit(); - } - if(strchr(node->name, '(') && node->time == 0) - MADESET(node, MADE); - else - update(0, node); - if(tflag){ - if(!(node->flags&VIRTUAL)) - touch(node->name); - else if(explain) - Bprint(&bout, "no touch of virtual '%s'\n", node->name); - } - return(did); - } - /* - build the node list - */ - node->next = 0; - head.next = 0; - ww = &head; - ahead.next = 0; - aw = &ahead; - if(r->attr&REGEXP){ - ww->next = newword(node->name); - aw->next = newword(node->name); - } else { - for(w = r->alltargets; w; w = w->next){ - if(r->attr&META) - subst(aa->stem, w->s, buf); - else - strcpy(buf, w->s); - aw->next = newword(buf); - aw = aw->next; - if((s = symlook(buf, S_NODE, 0)) == 0) - continue; /* not a node we are interested in */ - n = (Node *)s->value; - if(aflag == 0 && n->time) { - for(a = n->prereqs; a; a = a->next) - if(a->n && outofdate(n, a, 0)) - break; - if(a == 0) - continue; - } - ww->next = newword(buf); - ww = ww->next; - if(n == node) continue; - n->next = node->next; - node->next = n; - } - } - for(n = node; n; n = n->next) - if((n->flags&READY) == 0) - return(did); - /* - gather the params for the job - */ - lp.next = ln.next = 0; - for(n = node; n; n = n->next){ - for(a = n->prereqs; a; a = a->next){ - if(a->n){ - addw(&lp, a->n->name); - if(outofdate(n, a, 0)){ - addw(&ln, a->n->name); - if(explain) - fprint(1, "%s(%ld) < %s(%ld)\n", - n->name, n->time, a->n->name, a->n->time); - } - } else { - if(explain) - fprint(1, "%s has no prerequisites\n", - n->name); - } - } - MADESET(n, BEINGMADE); - } - /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));*//**/ - run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next)); - return(1); -} - -void -addw(Word *w, char *s) -{ - Word *lw; - - for(lw = w; w = w->next; lw = w){ - if(strcmp(s, w->s) == 0) - return; - } - lw->next = newword(s); -} diff --git a/mk/rule.c b/mk/rule.c @@ -1,110 +0,0 @@ -#include "mk.h" - -static Rule *lr, *lmr; -static int rcmp(Rule *r, char *target, Word *tail); -static int nrules = 0; - -void -addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog) -{ - Rule *r; - Rule *rr; - Symtab *sym; - int reuse; - - r = 0; - reuse = 0; - if(sym = symlook(head, S_TARGET, 0)){ - for(r = (Rule *)sym->value; r; r = r->chain) - if(rcmp(r, head, tail) == 0){ - reuse = 1; - break; - } - } - if(r == 0) - r = (Rule *)Malloc(sizeof(Rule)); - r->shellt = shellt; - r->shellcmd = shellcmd; - r->target = head; - r->tail = tail; - r->recipe = body; - r->line = hline; - r->file = infile; - r->attr = attr; - r->alltargets = ahead; - r->prog = prog; - r->rule = nrules++; - if(!reuse){ - rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value; - if(rr != r){ - r->chain = rr->chain; - rr->chain = r; - } else - r->chain = 0; - } - if(!reuse) - r->next = 0; - if((attr&REGEXP) || shellt->charin(head, "%&")){ - r->attr |= META; - if(reuse) - return; - if(attr&REGEXP){ - patrule = r; - r->pat = regcomp(head); - } - if(metarules == 0) - metarules = lmr = r; - else { - lmr->next = r; - lmr = r; - } - } else { - if(reuse) - return; - r->pat = 0; - if(rules == 0) - rules = lr = r; - else { - lr->next = r; - lr = r; - } - } -} - -void -dumpr(char *s, Rule *r) -{ - Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n", - s, r, r->shellt->name, wtos(r->shellcmd, ' ')); - for(; r; r = r->next){ - Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld alltarget='%s'", - r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' ')); - if(r->prog) - Bprint(&bout, " prog='%s'", r->prog); - Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, ' ')); - Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe); - } -} - -static int -rcmp(Rule *r, char *target, Word *tail) -{ - Word *w; - - if(strcmp(r->target, target)) - return 1; - for(w = r->tail; w && tail; w = w->next, tail = tail->next) - if(strcmp(w->s, tail->s)) - return 1; - return(w || tail); -} - -char * -rulecnt(void) -{ - char *s; - - s = Malloc(nrules); - memset(s, 0, nrules); - return(s); -} diff --git a/mk/run.c b/mk/run.c @@ -1,296 +0,0 @@ -#include "mk.h" - -typedef struct Event -{ - int pid; - Job *job; -} Event; -static Event *events; -static int nevents, nrunning, nproclimit; - -typedef struct Process -{ - int pid; - int status; - struct Process *b, *f; -} Process; -static Process *phead, *pfree; -static void sched(void); -static void pnew(int, int), pdelete(Process *); - -int pidslot(int); - -void -run(Job *j) -{ - Job *jj; - - if(jobs){ - for(jj = jobs; jj->next; jj = jj->next) - ; - jj->next = j; - } else - jobs = j; - j->next = 0; - /* this code also in waitup after parse redirect */ - if(nrunning < nproclimit) - sched(); -} - -static void -sched(void) -{ - char *flags; - Job *j; - Bufblock *buf; - int slot; - Node *n; - Envy *e; - - if(jobs == 0){ - usage(); - return; - } - j = jobs; - jobs = j->next; - if(DEBUG(D_EXEC)) - fprint(1, "firing up job for target %s\n", wtos(j->t, ' ')); - slot = nextslot(); - events[slot].job = j; - buf = newbuf(); - e = buildenv(j, slot); - shprint(j->r->recipe, e, buf, j->r->shellt); - if(!tflag && (nflag || !(j->r->attr&QUIET))) - Bwrite(&bout, buf->start, (long)strlen(buf->start)); - freebuf(buf); - if(nflag||tflag){ - for(n = j->n; n; n = n->next){ - if(tflag){ - if(!(n->flags&VIRTUAL)) - touch(n->name); - else if(explain) - Bprint(&bout, "no touch of virtual '%s'\n", n->name); - } - n->time = time((long *)0); - MADESET(n, MADE); - } - } else { - if(DEBUG(D_EXEC)) - fprint(1, "recipe='%s'", j->r->recipe);/**/ - Bflush(&bout); - if(j->r->attr&NOMINUSE) - flags = 0; - else - flags = "-e"; - events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd); - usage(); - nrunning++; - if(DEBUG(D_EXEC)) - fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid); - } -} - -int -waitup(int echildok, int *retstatus) -{ - Envy *e; - int pid; - int slot; - Symtab *s; - Word *w; - Job *j; - char buf[ERRMAX]; - Bufblock *bp; - int uarg = 0; - int done; - Node *n; - Process *p; - extern int runerrs; - - /* first check against the proces slist */ - if(retstatus) - for(p = phead; p; p = p->f) - if(p->pid == *retstatus){ - *retstatus = p->status; - pdelete(p); - return(-1); - } -again: /* rogue processes */ - pid = waitfor(buf); - if(pid == -1){ - if(echildok > 0) - return(1); - else { - fprint(2, "mk: (waitup %d): %r\n", echildok); - Exit(); - } - } - if(DEBUG(D_EXEC)) - fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf); - if(retstatus && pid == *retstatus){ - *retstatus = buf[0]? 1:0; - return(-1); - } - slot = pidslot(pid); - if(slot < 0){ - if(DEBUG(D_EXEC)) - fprint(2, "mk: wait returned unexpected process %d\n", pid); - pnew(pid, buf[0]? 1:0); - goto again; - } - j = events[slot].job; - usage(); - nrunning--; - events[slot].pid = -1; - if(buf[0]){ - e = buildenv(j, slot); - bp = newbuf(); - shprint(j->r->recipe, e, bp, j->r->shellt); - front(bp->start); - fprint(2, "mk: %s: exit status=%s", bp->start, buf); - freebuf(bp); - for(n = j->n, done = 0; n; n = n->next) - if(n->flags&DELETE){ - if(done++ == 0) - fprint(2, ", deleting"); - fprint(2, " '%s'", n->name); - delete(n->name); - } - fprint(2, "\n"); - if(kflag){ - runerrs++; - uarg = 1; - } else { - jobs = 0; - Exit(); - } - } - for(w = j->t; w; w = w->next){ - if((s = symlook(w->s, S_NODE, 0)) == 0) - continue; /* not interested in this node */ - update(uarg, (Node *)s->value); - } - if(nrunning < nproclimit) - sched(); - return(0); -} - -void -nproc(void) -{ - Symtab *sym; - Word *w; - - if(sym = symlook("NPROC", S_VAR, 0)) { - w = (Word *) sym->value; - if (w && w->s && w->s[0]) - nproclimit = atoi(w->s); - } - if(nproclimit < 1) - nproclimit = 1; - if(DEBUG(D_EXEC)) - fprint(1, "nprocs = %d\n", nproclimit); - if(nproclimit > nevents){ - if(nevents) - events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event)); - else - events = (Event *)Malloc(nproclimit*sizeof(Event)); - while(nevents < nproclimit) - events[nevents++].pid = 0; - } -} - -int -nextslot(void) -{ - int i; - - for(i = 0; i < nproclimit; i++) - if(events[i].pid <= 0) return i; - assert("out of slots!!", 0); - return 0; /* cyntax */ -} - -int -pidslot(int pid) -{ - int i; - - for(i = 0; i < nevents; i++) - if(events[i].pid == pid) return(i); - if(DEBUG(D_EXEC)) - fprint(2, "mk: wait returned unexpected process %d\n", pid); - return(-1); -} - - -static void -pnew(int pid, int status) -{ - Process *p; - - if(pfree){ - p = pfree; - pfree = p->f; - } else - p = (Process *)Malloc(sizeof(Process)); - p->pid = pid; - p->status = status; - p->f = phead; - phead = p; - if(p->f) - p->f->b = p; - p->b = 0; -} - -static void -pdelete(Process *p) -{ - if(p->f) - p->f->b = p->b; - if(p->b) - p->b->f = p->f; - else - phead = p->f; - p->f = pfree; - pfree = p; -} - -void -killchildren(char *msg) -{ - Process *p; - - kflag = 1; /* to make sure waitup doesn't exit */ - jobs = 0; /* make sure no more get scheduled */ - for(p = phead; p; p = p->f) - expunge(p->pid, msg); - while(waitup(1, (int *)0) == 0) - ; - Bprint(&bout, "mk: %s\n", msg); - Exit(); -} - -static long tslot[1000]; -static long tick; - -void -usage(void) -{ - long t; - - time(&t); - if(tick) - tslot[nrunning] += (t-tick); - tick = t; -} - -void -prusage(void) -{ - int i; - - usage(); - for(i = 0; i <= nevents; i++) - fprint(1, "%d: %ld\n", i, tslot[i]); -} diff --git a/mk/sh.c b/mk/sh.c @@ -1,206 +0,0 @@ -#include "mk.h" - -/* - * This file contains functions that depend on the shell's syntax. Most - * of the routines extract strings observing the shell's escape conventions. - */ - - -/* - * skip a token in quotes. - */ -static char * -squote(char *cp, int c) -{ - Rune r; - int n; - - while(*cp){ - n = chartorune(&r, cp); - if(r == c) - return cp; - if(r == '\\') - n += chartorune(&r, cp+n); - cp += n; - } - SYNERR(-1); /* should never occur */ - fprint(2, "missing closing '\n"); - return 0; -} -/* - * search a string for unescaped characters in a pattern set - */ -static char * -shcharin(char *cp, char *pat) -{ - Rune r; - int n, vargen; - - vargen = 0; - while(*cp){ - n = chartorune(&r, cp); - switch(r){ - case '\\': /* skip escaped char */ - cp += n; - n = chartorune(&r, cp); - break; - case '\'': /* skip quoted string */ - case '"': - cp = squote(cp+1, r); /* n must = 1 */ - if(!cp) - return 0; - break; - case '$': - if(*(cp+1) == '{') - vargen = 1; - break; - case '}': - if(vargen) - vargen = 0; - else if(utfrune(pat, r)) - return cp; - break; - default: - if(vargen == 0 && utfrune(pat, r)) - return cp; - break; - } - cp += n; - } - if(vargen){ - SYNERR(-1); - fprint(2, "missing closing } in pattern generator\n"); - } - return 0; -} - -/* - * extract an escaped token. Possible escape chars are single-quote, - * double-quote,and backslash. - */ -static char* -shexpandquote(char *s, Rune esc, Bufblock *b) -{ - Rune r; - - if (esc == '\\') { - s += chartorune(&r, s); - rinsert(b, r); - return s; - } - - while(*s){ - s += chartorune(&r, s); - if(r == esc) - return s; - if (r == '\\') { - rinsert(b, r); - s += chartorune(&r, s); - } - rinsert(b, r); - } - return 0; -} - -/* - * Input an escaped token. Possible escape chars are single-quote, - * double-quote and backslash. - */ -static int -shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc) -{ - int c, line; - - if(esc == '\\') { - c = Bgetrune(bp); - if(c == '\r') - c = Bgetrune(bp); - if (c == '\n') - mkinline++; - rinsert(buf, c); - return 1; - } - - line = mkinline; - while((c = nextrune(bp, 0)) >= 0){ - if(c == esc){ - if(preserve) - rinsert(buf, c); - return 1; - } - if(c == '\\') { - rinsert(buf, c); - c = Bgetrune(bp); - if(c == '\r') - c = Bgetrune(bp); - if (c < 0) - break; - if (c == '\n') - mkinline++; - } - rinsert(buf, c); - } - SYNERR(line); fprint(2, "missing closing %c\n", esc); - return 0; -} - -/* - * copy a quoted string; s points to char after opening quote - */ -static char * -copysingle(char *s, Rune q, Bufblock *buf) -{ - Rune r; - - while(*s){ - s += chartorune(&r, s); - rinsert(buf, r); - if(r == q) - break; - } - return s; -} -/* - * check for quoted strings. backquotes are handled here; single quotes above. - * s points to char after opening quote, q. - */ -static char * -shcopyq(char *s, Rune q, Bufblock *buf) -{ - if(q == '\'' || q == '"') /* copy quoted string */ - return copysingle(s, q, buf); - - if(q != '`') /* not quoted */ - return s; - - while(*s){ /* copy backquoted string */ - s += chartorune(&q, s); - rinsert(buf, q); - if(q == '`') - break; - if(q == '\'' || q == '"') - s = copysingle(s, q, buf); /* copy quoted string */ - } - return s; -} - -static int -shmatchname(char *name) -{ - USED(name); - - return 1; -} - - -Shell shshell = { - "sh", - "\"'= \t", /*used in parse.c to isolate assignment attribute*/ - ' ', /* inter-word separator in env */ - shcharin, - shexpandquote, - shescapetoken, - shcopyq, - shmatchname, -}; - diff --git a/mk/shell.c b/mk/shell.c @@ -1,80 +0,0 @@ -#include "mk.h" - -static Shell *shells[] = { - &rcshell, - &shshell, -}; - -Shell *shelldefault = &shshell; - -Shell *shellt; -Word *shellcmd; - -typedef struct Shellstack Shellstack; -struct Shellstack -{ - Shell *t; - Word *w; - Shellstack *next; -}; - -Shellstack *shellstack; - -char* -setshell(Word *w) -{ - int i; - - if(w->s == nil) - return "shell name not found on line"; - - for(i=0; i<nelem(shells); i++) - if(shells[i]->matchname(w->s)) - break; - if(i == nelem(shells)) - return "cannot determine shell type"; - shellt = shells[i]; - shellcmd = w; - return nil; -} - -void -initshell(void) -{ - shellcmd = stow(shelldefault->name); - shellt = shelldefault; - setvar("MKSHELL", shellcmd); -} - -void -pushshell(void) -{ - Shellstack *s; - - /* save */ - s = Malloc(sizeof *s); - s->t = shellt; - s->w = shellcmd; - s->next = shellstack; - shellstack = s; - - initshell(); /* reset to defaults */ -} - -void -popshell(void) -{ - Shellstack *s; - - if(shellstack == nil){ - fprint(2, "internal shellstack error\n"); - Exit(); - } - - s = shellstack; - shellstack = s->next; - shellt = s->t; - shellcmd = s->w; - setvar("MKSHELL", shellcmd); - free(s); -} diff --git a/mk/shprint.c b/mk/shprint.c @@ -1,125 +0,0 @@ -#include "mk.h" - -static char *vexpand(char*, Envy*, Bufblock*); - -#define getfields mkgetfields - -static int -getfields(char *str, char **args, int max, int mflag, char *set) -{ - Rune r; - int nr, intok, narg; - - if(max <= 0) - return 0; - - narg = 0; - args[narg] = str; - if(!mflag) - narg++; - intok = 0; - for(;; str += nr) { - nr = chartorune(&r, str); - if(r == 0) - break; - if(utfrune(set, r)) { - if(narg >= max) - break; - *str = 0; - intok = 0; - args[narg] = str + nr; - if(!mflag) - narg++; - } else { - if(!intok && mflag) - narg++; - intok = 1; - } - } - return narg; -} - -void -shprint(char *s, Envy *env, Bufblock *buf, Shell *sh) -{ - int n; - Rune r; - - while(*s) { - n = chartorune(&r, s); - if (r == '$') - s = vexpand(s, env, buf); - else { - rinsert(buf, r); - s += n; - s = sh->copyq(s, r, buf); /*handle quoted strings*/ - } - } - insert(buf, 0); -} - -static char * -mygetenv(char *name, Envy *env) -{ - if (!env) - return 0; - if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0) - return 0; - /* only resolve internal variables and variables we've set */ - for(; env->name; env++){ - if (strcmp(env->name, name) == 0) - return wtos(env->values, ' '); - } - return 0; -} - -static char * -vexpand(char *w, Envy *env, Bufblock *buf) -{ - char *s, carry, *p, *q; - - assert("vexpand no $", *w == '$'); - p = w+1; /* skip dollar sign */ - if(*p == '{') { - p++; - q = utfrune(p, '}'); - if (!q) - q = strchr(p, 0); - } else - q = shname(p); - carry = *q; - *q = 0; - s = mygetenv(p, env); - *q = carry; - if (carry == '}') - q++; - if (s) { - bufcpy(buf, s, strlen(s)); - free(s); - } else /* copy name intact*/ - bufcpy(buf, w, q-w); - return(q); -} - -void -front(char *s) -{ - char *t, *q; - int i, j; - char *flds[512]; - - q = strdup(s); - i = getfields(q, flds, 512, 0, " \t\n"); - if(i > 5){ - flds[4] = flds[i-1]; - flds[3] = "..."; - i = 5; - } - t = s; - for(j = 0; j < i; j++){ - for(s = flds[j]; *s; *t++ = *s++); - *t++ = ' '; - } - *t = 0; - free(q); -} diff --git a/mk/symtab.c b/mk/symtab.c @@ -1,97 +0,0 @@ -#include "mk.h" - -#define NHASH 4099 -#define HASHMUL 79L /* this is a good value */ -static Symtab *hash[NHASH]; - -void -syminit(void) -{ - Symtab **s, *ss, *next; - - for(s = hash; s < &hash[NHASH]; s++){ - for(ss = *s; ss; ss = next){ - next = ss->next; - free((char *)ss); - } - *s = 0; - } -} - -Symtab * -symlook(char *sym, int space, void *install) -{ - long h; - char *p; - Symtab *s; - - for(p = sym, h = space; *p; h += *p++) - h *= HASHMUL; - if(h < 0) - h = ~h; - h %= NHASH; - for(s = hash[h]; s; s = s->next) - if((s->space == space) && (strcmp(s->name, sym) == 0)) - return(s); - if(install == 0) - return(0); - s = (Symtab *)Malloc(sizeof(Symtab)); - s->space = space; - s->name = sym; - s->value = install; - s->next = hash[h]; - hash[h] = s; - return(s); -} - -void -symdel(char *sym, int space) -{ - long h; - char *p; - Symtab *s, *ls; - - /* multiple memory leaks */ - - for(p = sym, h = space; *p; h += *p++) - h *= HASHMUL; - if(h < 0) - h = ~h; - h %= NHASH; - for(s = hash[h], ls = 0; s; ls = s, s = s->next) - if((s->space == space) && (strcmp(s->name, sym) == 0)){ - if(ls) - ls->next = s->next; - else - hash[h] = s->next; - free((char *)s); - } -} - -void -symtraverse(int space, void (*fn)(Symtab*)) -{ - Symtab **s, *ss; - - for(s = hash; s < &hash[NHASH]; s++) - for(ss = *s; ss; ss = ss->next) - if(ss->space == space) - (*fn)(ss); -} - -void -symstat(void) -{ - Symtab **s, *ss; - int n; - int l[1000]; - - memset((char *)l, 0, sizeof(l)); - for(s = hash; s < &hash[NHASH]; s++){ - for(ss = *s, n = 0; ss; ss = ss->next) - n++; - l[n]++; - } - for(n = 0; n < 1000; n++) - if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n); -} diff --git a/mk/sys.h b/mk/sys.h @@ -1,5 +0,0 @@ -#include <u.h> -#include <libc.h> -#include <bio.h> -#include <regexp.h> - diff --git a/mk/sys.std.h b/mk/sys.std.h @@ -1,22 +0,0 @@ -#include <utf.h> -#include <fmt.h> -#include <bio.h> -#include <regexp9.h> -#include <stdlib.h> -#include <unistd.h> -#include <fcntl.h> -#include <string.h> -#include <ctype.h> -#include <time.h> - -#define OREAD O_RDONLY -#define OWRITE O_WRONLY -#define ORDWR O_RDWR -#define nil 0 -#define nelem(x) (sizeof(x)/sizeof((x)[0])) -#define seek lseek -#define remove unlink -#define exits(x) exit(x && *(char*)x ? 1 : 0) -#define USED(x) if(x){}else -#define create(name, mode, perm) open(name, mode|O_CREAT, perm) -#define ERRMAX 256 diff --git a/mk/unix.c b/mk/unix.c @@ -1,341 +0,0 @@ -#define NOPLAN9DEFINES -#include "mk.h" -#include <sys/wait.h> -#include <signal.h> -#include <sys/stat.h> -#include <sys/time.h> - -char *shell = "/bin/sh"; -char *shellname = "sh"; - -extern char **environ; - -static void -mkperror(char *s) -{ - fprint(2, "%s: %r\n", s); -} - -void -readenv(void) -{ - char **p, *s; - Word *w; - - for(p = environ; *p; p++){ -/* rsc 5/5/2004 -- This misparses fn#cd={whatever} - s = shname(*p); - if(*s == '=') { - *s = 0; - w = newword(s+1); - } else - w = newword(""); -*/ - s = strchr(*p, '='); - if(s){ - *s = 0; - w = newword(s+1); - } else - w = newword(""); - if (symlook(*p, S_INTERNAL, 0)) - continue; - s = strdup(*p); - setvar(s, (void *)w); - symlook(s, S_EXPORTED, (void*)"")->value = (void*)""; - } -} - -/* - * done on child side of fork, so parent's env is not affected - * and we don't care about freeing memory because we're going - * to exec immediately after this. - */ -void -exportenv(Envy *e, Shell *sh) -{ - int i; - char **p; - static char buf[16384]; - - p = 0; - for(i = 0; e->name; e++, i++) { - p = (char**) Realloc(p, (i+2)*sizeof(char*)); - if(e->values) - snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, sh->iws)); - else - snprint(buf, sizeof buf, "%s=", e->name); - p[i] = strdup(buf); - } - p[i] = 0; - environ = p; -} - -int -waitfor(char *msg) -{ - int status; - int pid; - - *msg = 0; - pid = wait(&status); - if(pid > 0) { - if(status&0x7f) { - if(status&0x80) - snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f); - else - snprint(msg, ERRMAX, "signal %d", status&0x7f); - } else if(status&0xff00) - snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff); - } - return pid; -} - -void -expunge(int pid, char *msg) -{ - if(strcmp(msg, "interrupt")) - kill(pid, SIGINT); - else - kill(pid, SIGHUP); -} - -int mypid; - -int -shargv(Word *cmd, int extra, char ***pargv) -{ - char **argv; - int i, n; - Word *w; - - n = 0; - for(w=cmd; w; w=w->next) - n++; - - argv = Malloc((n+extra+1)*sizeof(argv[0])); - i = 0; - for(w=cmd; w; w=w->next) - argv[i++] = w->s; - argv[n] = 0; - *pargv = argv; - return n; -} - -int -execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd) -{ - char *p, **argv; - int tot, n, pid, in[2], out[2]; - - if(buf && pipe(out) < 0){ - mkperror("pipe"); - Exit(); - } - pid = fork(); - mypid = getpid(); - if(pid < 0){ - mkperror("mk fork"); - Exit(); - } - if(pid == 0){ - if(buf) - close(out[0]); - if(pipe(in) < 0){ - mkperror("pipe"); - Exit(); - } - pid = fork(); - if(pid < 0){ - mkperror("mk fork"); - Exit(); - } - if(pid != 0){ - dup2(in[0], 0); - if(buf){ - dup2(out[1], 1); - close(out[1]); - } - close(in[0]); - close(in[1]); - if (e) - exportenv(e, sh); - n = shargv(shellcmd, 1, &argv); - argv[n++] = args; - argv[n] = 0; - execvp(argv[0], argv); - mkperror(shell); - _exit(1); - } - close(out[1]); - close(in[0]); - if(DEBUG(D_EXEC)) - fprint(1, "starting: %s\n", cmd); - p = cmd+strlen(cmd); - while(cmd < p){ - n = write(in[1], cmd, p-cmd); - if(n < 0) - break; - cmd += n; - } - close(in[1]); - _exit(0); - } - if(buf){ - close(out[1]); - tot = 0; - for(;;){ - if (buf->current >= buf->end) - growbuf(buf); - n = read(out[0], buf->current, buf->end-buf->current); - if(n <= 0) - break; - buf->current += n; - tot += n; - } - if (tot && buf->current[-1] == '\n') - buf->current--; - close(out[0]); - } - return pid; -} - -int -pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd) -{ - int pid, pfd[2]; - int n; - char **argv; - - if(DEBUG(D_EXEC)) - fprint(1, "pipecmd='%s'\n", cmd);/**/ - - if(fd && pipe(pfd) < 0){ - mkperror("pipe"); - Exit(); - } - pid = fork(); - if(pid < 0){ - mkperror("mk fork"); - Exit(); - } - if(pid == 0){ - if(fd){ - close(pfd[0]); - dup2(pfd[1], 1); - close(pfd[1]); - } - if(e) - exportenv(e, sh); - n = shargv(shellcmd, 2, &argv); - argv[n++] = "-c"; - argv[n++] = cmd; - argv[n] = 0; - execvp(argv[0], argv); - mkperror(shell); - _exit(1); - } - if(fd){ - close(pfd[1]); - *fd = pfd[0]; - } - return pid; -} - -void -Exit(void) -{ - while(wait(0) >= 0) - ; - exits("error"); -} - -static struct -{ - int sig; - char *msg; -} sigmsgs[] = -{ - SIGALRM, "alarm", - SIGFPE, "sys: fp: fptrap", - SIGPIPE, "sys: write on closed pipe", - SIGILL, "sys: trap: illegal instruction", -// SIGSEGV, "sys: segmentation violation", - 0, 0 -}; - -static void -notifyf(int sig) -{ - int i; - - for(i = 0; sigmsgs[i].msg; i++) - if(sigmsgs[i].sig == sig) - killchildren(sigmsgs[i].msg); - - /* should never happen */ - signal(sig, SIG_DFL); - kill(getpid(), sig); -} - -void -catchnotes(void) -{ - int i; - - for(i = 0; sigmsgs[i].msg; i++) - signal(sigmsgs[i].sig, notifyf); -} - -char* -maketmp(int *pfd) -{ - static char temp[] = "/tmp/mkargXXXXXX"; - static char buf[100]; - int fd; - - strcpy(buf, temp); - fd = mkstemp(buf); - if(fd < 0) - return 0; - *pfd = fd; - return buf; -} - -int -chgtime(char *name) -{ - if(access(name, 0) >= 0) - return utimes(name, 0); - return close(creat(name, 0666)); -} - -void -rcopy(char **to, Resub *match, int n) -{ - int c; - char *p; - - *to = match->s.sp; /* stem0 matches complete target */ - for(to++, match++; --n > 0; to++, match++){ - if(match->s.sp && match->e.ep){ - p = match->e.ep; - c = *p; - *p = 0; - *to = strdup(match->s.sp); - *p = c; - } - else - *to = 0; - } -} - -unsigned long -mkmtime(char *name) -{ - struct stat st; - - if(stat(name, &st) < 0) - return 0; - - return st.st_mtime; -} diff --git a/mk/var.c b/mk/var.c @@ -1,41 +0,0 @@ -#include "mk.h" - -void -setvar(char *name, void *value) -{ - symlook(name, S_VAR, value)->value = value; - symlook(name, S_MAKEVAR, (void*)""); -} - -static void -print1(Symtab *s) -{ - Word *w; - - Bprint(&bout, "\t%s=", s->name); - for (w = (Word *) s->value; w; w = w->next) - Bprint(&bout, "'%s'", w->s); - Bprint(&bout, "\n"); -} - -void -dumpv(char *s) -{ - Bprint(&bout, "%s:\n", s); - symtraverse(S_VAR, print1); -} - -char * -shname(char *a) -{ - Rune r; - int n; - - while (*a) { - n = chartorune(&r, a); - if (!WORDCHR(r)) - break; - a += n; - } - return a; -} diff --git a/mk/varsub.c b/mk/varsub.c @@ -1,256 +0,0 @@ -#include "mk.h" - -static Word *subsub(Word*, char*, char*); -static Word *expandvar(char**); -static Bufblock *varname(char**); -static Word *extractpat(char*, char**, char*, char*); -static int submatch(char*, Word*, Word*, int*, char**); -static Word *varmatch(char *, char**); - -Word * -varsub(char **s) -{ - Bufblock *b; - Word *w; - - if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/ - return expandvar(s); - - b = varname(s); - if(b == 0) - return 0; - - w = varmatch(b->start, s); - freebuf(b); - return w; -} - -/* - * extract a variable name - */ -static Bufblock* -varname(char **s) -{ - Bufblock *b; - char *cp; - Rune r; - int n; - - b = newbuf(); - cp = *s; - for(;;){ - n = chartorune(&r, cp); - if (!WORDCHR(r)) - break; - rinsert(b, r); - cp += n; - } - if (b->current == b->start){ - SYNERR(-1); - fprint(2, "missing variable name <%s>\n", *s); - freebuf(b); - return 0; - } - *s = cp; - insert(b, 0); - return b; -} - -static Word* -varmatch(char *name, char **s) -{ - Word *w; - Symtab *sym; - char *cp; - - sym = symlook(name, S_VAR, 0); - if(sym){ - /* check for at least one non-NULL value */ - for (w = (Word*)sym->value; w; w = w->next) - if(w->s && *w->s) - return wdup(w); - } - for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */ - ; - *s = cp; - return 0; -} - -static Word* -expandvar(char **s) -{ - Word *w; - Bufblock *buf; - Symtab *sym; - char *cp, *begin, *end; - - begin = *s; - (*s)++; /* skip the '{' */ - buf = varname(s); - if (buf == 0) - return 0; - cp = *s; - if (*cp == '}') { /* ${name} variant*/ - (*s)++; /* skip the '}' */ - w = varmatch(buf->start, s); - freebuf(buf); - return w; - } - if (*cp != ':') { - SYNERR(-1); - fprint(2, "bad variable name <%s>\n", buf->start); - freebuf(buf); - return 0; - } - cp++; - end = shellt->charin(cp , "}"); - if(end == 0){ - SYNERR(-1); - fprint(2, "missing '}': %s\n", begin); - Exit(); - } - *end = 0; - *s = end+1; - - sym = symlook(buf->start, S_VAR, 0); - if(sym == 0 || sym->value == 0) - w = newword(buf->start); - else - w = subsub((Word*) sym->value, cp, end); - freebuf(buf); - return w; -} - -static Word* -extractpat(char *s, char **r, char *term, char *end) -{ - int save; - char *cp; - Word *w; - - cp = shellt->charin(s, term); - if(cp){ - *r = cp; - if(cp == s) - return 0; - save = *cp; - *cp = 0; - w = stow(s); - *cp = save; - } else { - *r = end; - w = stow(s); - } - return w; -} - -static Word* -subsub(Word *v, char *s, char *end) -{ - int nmid; - Word *head, *tail, *w, *h; - Word *a, *b, *c, *d; - Bufblock *buf; - char *cp, *enda; - - a = extractpat(s, &cp, "=%&", end); - b = c = d = 0; - if(PERCENT(*cp)) - b = extractpat(cp+1, &cp, "=", end); - if(*cp == '=') - c = extractpat(cp+1, &cp, "&%", end); - if(PERCENT(*cp)) - d = stow(cp+1); - else if(*cp) - d = stow(cp); - - head = tail = 0; - buf = newbuf(); - for(; v; v = v->next){ - h = w = 0; - if(submatch(v->s, a, b, &nmid, &enda)){ - /* enda points to end of A match in source; - * nmid = number of chars between end of A and start of B - */ - if(c){ - h = w = wdup(c); - while(w->next) - w = w->next; - } - if(PERCENT(*cp) && nmid > 0){ - if(w){ - bufcpy(buf, w->s, strlen(w->s)); - bufcpy(buf, enda, nmid); - insert(buf, 0); - free(w->s); - w->s = strdup(buf->start); - } else { - bufcpy(buf, enda, nmid); - insert(buf, 0); - h = w = newword(buf->start); - } - buf->current = buf->start; - } - if(d && *d->s){ - if(w){ - - bufcpy(buf, w->s, strlen(w->s)); - bufcpy(buf, d->s, strlen(d->s)); - insert(buf, 0); - free(w->s); - w->s = strdup(buf->start); - w->next = wdup(d->next); - while(w->next) - w = w->next; - buf->current = buf->start; - } else - h = w = wdup(d); - } - } - if(w == 0) - h = w = newword(v->s); - - if(head == 0) - head = h; - else - tail->next = h; - tail = w; - } - freebuf(buf); - delword(a); - delword(b); - delword(c); - delword(d); - return head; -} - -static int -submatch(char *s, Word *a, Word *b, int *nmid, char **enda) -{ - Word *w; - int n; - char *end; - - n = 0; - for(w = a; w; w = w->next){ - n = strlen(w->s); - if(strncmp(s, w->s, n) == 0) - break; - } - if(a && w == 0) /* a == NULL matches everything*/ - return 0; - - *enda = s+n; /* pointer to end a A part match */ - *nmid = strlen(s)-n; /* size of remainder of source */ - end = *enda+*nmid; - for(w = b; w; w = w->next){ - n = strlen(w->s); - if(strcmp(w->s, end-n) == 0){ - *nmid -= n; - break; - } - } - if(b && w == 0) /* b == NULL matches everything */ - return 0; - return 1; -} diff --git a/mk/word.c b/mk/word.c @@ -1,180 +0,0 @@ -#include "mk.h" - -static Word *nextword(char**); - -Word* -newword(char *s) -{ - Word *w; - - w = (Word *)Malloc(sizeof(Word)); - w->s = strdup(s); - w->next = 0; - return(w); -} - -Word * -stow(char *s) -{ - Word *head, *w, *new; - - w = head = 0; - while(*s){ - new = nextword(&s); - if(new == 0) - break; - if (w) - w->next = new; - else - head = w = new; - while(w->next) - w = w->next; - - } - if (!head) - head = newword(""); - return(head); -} - -char * -wtos(Word *w, int sep) -{ - Bufblock *buf; - char *cp; - - buf = newbuf(); - for(; w; w = w->next){ - for(cp = w->s; *cp; cp++) - insert(buf, *cp); - if(w->next) - insert(buf, sep); - } - insert(buf, 0); - cp = strdup(buf->start); - freebuf(buf); - return(cp); -} - -Word* -wdup(Word *w) -{ - Word *v, *new, *base; - - v = base = 0; - while(w){ - new = newword(w->s); - if(v) - v->next = new; - else - base = new; - v = new; - w = w->next; - } - return base; -} - -void -delword(Word *w) -{ - Word *v; - - while(v = w){ - w = w->next; - if(v->s) - free(v->s); - free(v); - } -} - -/* - * break out a word from a string handling quotes, executions, - * and variable expansions. - */ -static Word* -nextword(char **s) -{ - Bufblock *b; - Word *head, *tail, *w; - Rune r; - char *cp; - - cp = *s; - b = newbuf(); - head = tail = 0; - while(*cp == ' ' || *cp == '\t') /* leading white space */ - cp++; - while(*cp){ - cp += chartorune(&r, cp); - switch(r) - { - case ' ': - case '\t': - case '\n': - goto out; - case '\\': - case '\'': - case '"': - cp = shellt->expandquote(cp, r, b); - if(cp == 0){ - fprint(2, "missing closing quote: %s\n", *s); - Exit(); - } - break; - case '$': - w = varsub(&cp); - if(w == 0) - break; - if(b->current != b->start){ - bufcpy(b, w->s, strlen(w->s)); - insert(b, 0); - free(w->s); - w->s = strdup(b->start); - b->current = b->start; - } - if(head){ - bufcpy(b, tail->s, strlen(tail->s)); - bufcpy(b, w->s, strlen(w->s)); - insert(b, 0); - free(tail->s); - tail->s = strdup(b->start); - tail->next = w->next; - free(w->s); - free(w); - b->current = b->start; - } else - tail = head = w; - while(tail->next) - tail = tail->next; - break; - default: - rinsert(b, r); - break; - } - } -out: - *s = cp; - if(b->current != b->start){ - if(head){ - cp = b->current; - bufcpy(b, tail->s, strlen(tail->s)); - bufcpy(b, b->start, cp-b->start); - insert(b, 0); - free(tail->s); - tail->s = strdup(cp); - } else { - insert(b, 0); - head = newword(b->start); - } - } - freebuf(b); - return head; -} - -void -dumpw(char *s, Word *w) -{ - Bprint(&bout, "%s", s); - for(; w; w = w->next) - Bprint(&bout, " '%s'", w->s); - Bputc(&bout, '\n'); -} diff --git a/rc/Makefile b/rc/Makefile @@ -4,7 +4,7 @@ TARG = rc OFILES = code.o exec.o getflags.o glob.o here.o io.o lex.o \ pcmd.o pfnc.o simple.o subr.o trap.o tree.o unixcrap.o \ - var.o y.tab.o plan9ish.o + var.o y.tab.o plan9ish.o havefork.o YFILES = syn.y MANFILES = rc.1 @@ -23,6 +23,7 @@ all: depend: @echo YACC ${YFILES} @${YACC} -d ${YFILES} + @cp y.tab.h x.tab.h install: ${TARG} @mkdir -p ${DESTDIR}${PREFIX}/bin diff --git a/rc/code.c b/rc/code.c @@ -7,9 +7,9 @@ #define c1 t->child[1] #define c2 t->child[2] int codep, ncode; -#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++) -#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++) -#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++) +#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++) +#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++) +#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++) void stuffdot(int); char *fnstr(tree*); void outcode(tree*, int); @@ -17,22 +17,33 @@ void codeswitch(tree*, int); int iscase(tree*); code *codecopy(code*); void codefree(code*); -int morecode(void){ + +int +morecode(void) +{ ncode+=100; - codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]); - if(codebuf==0) panic("Can't realloc %d bytes in morecode!", + codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]); + if(codebuf==0) + panic("Can't realloc %d bytes in morecode!", ncode*sizeof codebuf[0]); + memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]); return 0; } -void stuffdot(int a){ - if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a); - codebuf[a].i=codep; + +void +stuffdot(int a) +{ + if(a<0 || codep<=a) + panic("Bad address %d in stuffdot", a); + codebuf[a].i = codep; } -int compile(tree *t) + +int +compile(tree *t) { - ncode=100; - codebuf=(code *)emalloc(ncode*sizeof codebuf[0]); - codep=0; + ncode = 100; + codebuf = (code *)emalloc(ncode*sizeof codebuf[0]); + codep = 0; emiti(0); /* reference count */ outcode(t, flag['e']?1:0); if(nerror){ @@ -44,31 +55,39 @@ int compile(tree *t) emitf(0); return 1; } -void cleanhere(char *f) + +void +cleanhere(char *f) { emitf(Xdelhere); emits(strdup(f)); } -char *fnstr(tree *t) + +char* +fnstr(tree *t) { - io *f=openstr(); + io *f = openstr(); char *v; extern char nl; - char svnl=nl; + char svnl = nl; nl=';'; pfmt(f, "%t", t); - nl=svnl; - v=f->strp; - f->strp=0; + nl = svnl; + v = f->strp; + f->strp = 0; closeio(f); return v; } -void outcode(tree *t, int eflag) + +void +outcode(tree *t, int eflag) { int p, q; tree *tt; - if(t==0) return; - if(t->type!=NOT && t->type!=';') runq->iflast=0; + if(t==0) + return; + if(t->type!=NOT && t->type!=';') + runq->iflast = 0; switch(t->type){ default: pfmt(err, "bad type %d in outcode\n", t->type); @@ -92,10 +111,13 @@ void outcode(tree *t, int eflag) break; case '&': emitf(Xasync); - p=emiti(0); - outcode(c0, eflag); - emitf(Xexit); - stuffdot(p); + if(havefork){ + p = emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); + } else + emits(fnstr(c0)); break; case ';': outcode(c0, eflag); @@ -110,15 +132,18 @@ void outcode(tree *t, int eflag) break; case '`': emitf(Xbackq); - p=emiti(0); - outcode(c0, 0); - emitf(Xexit); - stuffdot(p); + if(havefork){ + p = emiti(0); + outcode(c0, 0); + emitf(Xexit); + stuffdot(p); + } else + emits(fnstr(c0)); break; case ANDAND: outcode(c0, 0); emitf(Xtrue); - p=emiti(0); + p = emiti(0); outcode(c1, eflag); stuffdot(p); break; @@ -144,7 +169,7 @@ void outcode(tree *t, int eflag) outcode(c0, eflag); if(c1){ emitf(Xfn); - p=emiti(0); + p = emiti(0); emits(fnstr(c1)); outcode(c1, eflag); emitf(Xunlocal); /* get rid of $* */ @@ -157,22 +182,23 @@ void outcode(tree *t, int eflag) case IF: outcode(c0, 0); emitf(Xif); - p=emiti(0); + p = emiti(0); outcode(c1, eflag); emitf(Xwastrue); stuffdot(p); break; case NOT: - if(!runq->iflast) yyerror("`if not' does not follow `if(...)'"); + if(!runq->iflast) + yyerror("`if not' does not follow `if(...)'"); emitf(Xifnot); - p=emiti(0); + p = emiti(0); outcode(c0, eflag); stuffdot(p); break; case OROR: outcode(c0, 0); emitf(Xfalse); - p=emiti(0); + p = emiti(0); outcode(c1, eflag); stuffdot(p); break; @@ -183,15 +209,20 @@ void outcode(tree *t, int eflag) emitf(Xmark); outcode(c0, eflag); emitf(Xsimple); - if(eflag) emitf(Xeflag); + if(eflag) + emitf(Xeflag); break; case SUBSHELL: emitf(Xsubshell); - p=emiti(0); - outcode(c0, eflag); - emitf(Xexit); - stuffdot(p); - if(eflag) emitf(Xeflag); + if(havefork){ + p = emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); + } else + emits(fnstr(c0)); + if(eflag) + emitf(Xeflag); break; case SWITCH: codeswitch(t, eflag); @@ -202,14 +233,16 @@ void outcode(tree *t, int eflag) emitf(Xmark); outcode(c0, eflag); emitf(Xmatch); - if(eflag) emitf(Xeflag); + if(eflag) + emitf(Xeflag); break; case WHILE: - q=codep; + q = codep; outcode(c0, 0); - if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */ + if(q==codep) + emitf(Xsettrue); /* empty condition == while(true) */ emitf(Xtrue); - p=emiti(0); + p = emiti(0); outcode(c1, eflag); emitf(Xjump); emiti(q); @@ -235,8 +268,8 @@ void outcode(tree *t, int eflag) emitf(Xmark); outcode(c0, eflag); emitf(Xlocal); - p=emitf(Xfor); - q=emiti(0); + p = emitf(Xfor); + q = emiti(0); outcode(c2, eflag); emitf(Xjump); emiti(p); @@ -263,10 +296,14 @@ void outcode(tree *t, int eflag) case PIPEFD: emitf(Xpipefd); emiti(t->rtype); - p=emiti(0); - outcode(c0, eflag); - emitf(Xexit); - stuffdot(p); + if(havefork){ + p = emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); + } else { + emits(fnstr(c0)); + } break; case REDIR: emitf(Xmark); @@ -283,28 +320,31 @@ void outcode(tree *t, int eflag) case HERE: emitf(Xread); break; + case RDWR: + emitf(Xrdwr); + break; } emiti(t->fd0); outcode(c1, eflag); emitf(Xpopredir); break; case '=': - tt=t; - for(;t && t->type=='=';t=c2); + tt = t; + for(;t && t->type=='=';t = c2); if(t){ - for(t=tt;t->type=='=';t=c2){ + for(t = tt;t->type=='=';t = c2){ emitf(Xmark); outcode(c1, eflag); emitf(Xmark); outcode(c0, eflag); emitf(Xlocal); } - t=tt; - outcode(c2, eflag); - for(;t->type=='=';t=c2) emitf(Xunlocal); + outcode(t, eflag); + for(t = tt; t->type=='='; t = c2) + emitf(Xunlocal); } else{ - for(t=tt;t;t=c2){ + for(t = tt;t;t = c2){ emitf(Xmark); outcode(c1, eflag); emitf(Xmark); @@ -312,17 +352,22 @@ void outcode(tree *t, int eflag) emitf(Xassign); } } - t=tt; /* so tests below will work */ + t = tt; /* so tests below will work */ break; case PIPE: emitf(Xpipe); emiti(t->fd0); emiti(t->fd1); - p=emiti(0); - q=emiti(0); - outcode(c0, eflag); - emitf(Xexit); - stuffdot(p); + if(havefork){ + p = emiti(0); + q = emiti(0); + outcode(c0, eflag); + emitf(Xexit); + stuffdot(p); + } else { + emits(fnstr(c0)); + q = emiti(0); + } outcode(c1, eflag); emitf(Xreturn); stuffdot(q); @@ -330,8 +375,8 @@ void outcode(tree *t, int eflag) break; } if(t->type!=NOT && t->type!=';') - runq->iflast=t->type==IF; - else if(c0) runq->iflast=c0->type==IF; + runq->iflast = t->type==IF; + else if(c0) runq->iflast = c0->type==IF; } /* * switch code looks like this: @@ -353,7 +398,9 @@ void outcode(tree *t, int eflag) * leave: * Xpopm */ -void codeswitch(tree *t, int eflag) + +void +codeswitch(tree *t, int eflag) { int leave; /* patch jump address to leave switch */ int out; /* jump here to leave switch */ @@ -368,23 +415,23 @@ void codeswitch(tree *t, int eflag) emitf(Xmark); outcode(c0, eflag); emitf(Xjump); - nextcase=emiti(0); - out=emitf(Xjump); - leave=emiti(0); + nextcase = emiti(0); + out = emitf(Xjump); + leave = emiti(0); stuffdot(nextcase); - t=c1->child[0]; + t = c1->child[0]; while(t->type==';'){ - tt=c1; + tt = c1; emitf(Xmark); - for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag); + for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag); emitf(Xcase); - nextcase=emiti(0); - t=tt; + nextcase = emiti(0); + t = tt; for(;;){ if(t->type==';'){ if(iscase(c0)) break; outcode(c0, eflag); - t=c1; + t = c1; } else{ if(!iscase(t)) outcode(t, eflag); @@ -398,23 +445,32 @@ void codeswitch(tree *t, int eflag) stuffdot(leave); emitf(Xpopm); } -int iscase(tree *t) + +int +iscase(tree *t) { - if(t->type!=SIMPLE) return 0; - do t=c0; while(t->type==ARGLIST); + if(t->type!=SIMPLE) + return 0; + do t = c0; while(t->type==ARGLIST); return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0; } -code *codecopy(code *cp) + +code* +codecopy(code *cp) { cp[0].i++; return cp; } -void codefree(code *cp) + +void +codefree(code *cp) { code *p; - if(--cp[0].i!=0) return; - for(p=cp+1;p->f;p++){ + if(--cp[0].i!=0) + return; + for(p = cp+1;p->f;p++){ if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite + || p->f==Xrdwr || p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse || p->f==Xfor || p->f==Xjump || p->f==Xsubshell || p->f==Xtrue) p++; diff --git a/rc/exec.c b/rc/exec.c @@ -1,12 +1,3 @@ -#include <u.h> -#include <signal.h> -#if defined(PLAN9PORT) && defined(__sun__) -# define BSD_COMP /* sigh. for TIOCNOTTY */ -#endif -#ifdef __sun__ -#include <sys/termios.h> -#endif -#include <sys/ioctl.h> #include "rc.h" #include "getflags.h" #include "exec.h" @@ -16,90 +7,118 @@ * Start executing the given code at the given pc with the given redirection */ char *argv0="rc"; -void start(code *c, int pc, var *local) -{ - struct thread *p=new(struct thread); - p->code=codecopy(c); - p->pc=pc; - p->argv=0; - p->redir=p->startredir=runq?runq->redir:0; - p->local=local; - p->cmdfile=0; - p->cmdfd=0; - p->eof=0; - p->iflag=0; - p->lineno=1; - p->pid=-1; - p->ret=runq; - runq=p; -} -word *newword(char *wd, word *next) -{ - word *p=new(word); - p->word=strdup(wd); - p->next=next; + +void +start(code *c, int pc, var *local) +{ + struct thread *p = new(struct thread); + + p->code = codecopy(c); + p->pc = pc; + p->argv = 0; + p->redir = p->startredir = runq?runq->redir:0; + p->local = local; + p->cmdfile = 0; + p->cmdfd = 0; + p->eof = 0; + p->iflag = 0; + p->lineno = 1; + p->ret = runq; + runq = p; +} + +word* +newword(char *wd, word *next) +{ + word *p = new(word); + p->word = strdup(wd); + p->next = next; return p; } -void pushword(char *wd) + +void +pushword(char *wd) { - if(runq->argv==0) panic("pushword but no argv!", 0); - runq->argv->words=newword(wd, runq->argv->words); + if(runq->argv==0) + panic("pushword but no argv!", 0); + runq->argv->words = newword(wd, runq->argv->words); } -void popword(void){ + +void +popword(void) +{ word *p; - if(runq->argv==0) panic("popword but no argv!", 0); - p=runq->argv->words; - if(p==0) panic("popword but no word!", 0); - runq->argv->words=p->next; + if(runq->argv==0) + panic("popword but no argv!", 0); + p = runq->argv->words; + if(p==0) + panic("popword but no word!", 0); + runq->argv->words = p->next; efree(p->word); efree((char *)p); } -void freelist(word *w) + +void +freelist(word *w) { word *nw; while(w){ - nw=w->next; + nw = w->next; efree(w->word); efree((char *)w); - w=nw; + w = nw; } } -void pushlist(void){ - list *p=new(list); - p->next=runq->argv; - p->words=0; - runq->argv=p; -} -void poplist(void){ - list *p=runq->argv; - if(p==0) panic("poplist but no argv", 0); + +void +pushlist(void) +{ + list *p = new(list); + p->next = runq->argv; + p->words = 0; + runq->argv = p; +} + +void +poplist(void) +{ + list *p = runq->argv; + if(p==0) + panic("poplist but no argv", 0); freelist(p->words); - runq->argv=p->next; + runq->argv = p->next; efree((char *)p); } -int count(word *w) + +int +count(word *w) { int n; - for(n=0;w;n++) w=w->next; + for(n = 0;w;n++) w = w->next; return n; } -void pushredir(int type, int from, int to){ - redir * rp=new(redir); - rp->type=type; - rp->from=from; - rp->to=to; - rp->next=runq->redir; - runq->redir=rp; -} -var *newvar(char *name, var *next) -{ - var *v=new(var); - v->name=name; - v->val=0; - v->fn=0; - v->changed=0; - v->fnchanged=0; - v->next=next; + +void +pushredir(int type, int from, int to) +{ + redir * rp = new(redir); + rp->type = type; + rp->from = from; + rp->to = to; + rp->next = runq->redir; + runq->redir = rp; +} + +var* +newvar(char *name, var *next) +{ + var *v = new(var); + v->name = name; + v->val = 0; + v->fn = 0; + v->changed = 0; + v->fnchanged = 0; + v->next = next; v->changefn = 0; return v; } @@ -117,52 +136,59 @@ main(int argc, char *argv[]) char num[12], *rcmain; int i; - argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1); - if(argc==-1) usage("[file [arg ...]]"); - if(argv[0][0]=='-') flag['l']=flagset; - if(flag['I']) flag['i'] = 0; + /* needed for rcmain later */ + putenv("PLAN9", unsharp("#9")); + + argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1); + if(argc==-1) + usage("[file [arg ...]]"); + if(argv[0][0]=='-') + flag['l'] = flagset; + if(flag['I']) + flag['i'] = 0; else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset; - rcmain=flag['m']?flag['m'][0]:Rcmain(); - err=openfd(2); + rcmain = flag['m'] ? flag['m'][0] : Rcmain(); + err = openfd(2); kinit(); Trapinit(); Vinit(); - itoa(num, mypid=getpid()); + inttoascii(num, mypid = getpid()); pathinit(); setvar("pid", newword(num, (word *)0)); setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0) :(word *)0); setvar("rcname", newword(argv[0], (word *)0)); - i=0; - bootstrap[i++].i=1; - bootstrap[i++].f=Xmark; - bootstrap[i++].f=Xword; + i = 0; + bootstrap[i++].i = 1; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xword; bootstrap[i++].s="*"; - bootstrap[i++].f=Xassign; - bootstrap[i++].f=Xmark; - bootstrap[i++].f=Xmark; - bootstrap[i++].f=Xword; + bootstrap[i++].f = Xassign; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xmark; + bootstrap[i++].f = Xword; bootstrap[i++].s="*"; - bootstrap[i++].f=Xdol; - bootstrap[i++].f=Xword; - bootstrap[i++].s=rcmain; - bootstrap[i++].f=Xword; + bootstrap[i++].f = Xdol; + bootstrap[i++].f = Xword; + bootstrap[i++].s = rcmain; + bootstrap[i++].f = Xword; bootstrap[i++].s="."; - bootstrap[i++].f=Xsimple; - bootstrap[i++].f=Xexit; - bootstrap[i].i=0; + bootstrap[i++].f = Xsimple; + bootstrap[i++].f = Xexit; + bootstrap[i].i = 0; start(bootstrap, 1, (var *)0); /* prime bootstrap argv */ pushlist(); argv0 = strdup(argv[0]); - for(i=argc-1;i!=0;--i) pushword(argv[i]); + for(i = argc-1;i!=0;--i) pushword(argv[i]); for(;;){ - if(flag['r']) pfnc(err, runq); + if(flag['r']) + pfnc(err, runq); runq->pc++; (*runq->code[runq->pc-1].f)(); - if(ntrap) dotrap(); + if(ntrap) + dotrap(); } - return 0; } /* * Opcode routines @@ -198,6 +224,7 @@ main(int argc, char *argv[]) * Xpipefd[type]{... Xreturn} connect {} to pipe (input or output, * depending on type), push /dev/fd/?? * Xpopm(value) pop value from stack + * Xrdwr(file)[fd] open file for reading and writing * Xread(file)[fd] open file to read * Xsettraps(names){... Xreturn} define trap functions * Xshowtraps print trap list @@ -209,16 +236,24 @@ main(int argc, char *argv[]) * Xword[string] push string * Xwrite(file)[fd] open file to write */ -void Xappend(void){ + +void +Xappend(void) +{ char *file; int f; switch(count(runq->argv->words)){ - default: Xerror1(">> requires singleton"); return; - case 0: Xerror1(">> requires file"); return; - case 1: break; + default: + Xerror1(">> requires singleton"); + return; + case 0: + Xerror1(">> requires file"); + return; + case 1: + break; } - file=runq->argv->words->word; - if((f=open(file, 1))<0 && (f=Creat(file))<0){ + file = runq->argv->words->word; + if((f = open(file, 1))<0 && (f = Creat(file))<0){ pfmt(err, "%s: ", file); Xerror("can't open"); return; @@ -228,126 +263,114 @@ void Xappend(void){ runq->pc++; poplist(); } -void Xasync(void){ - int null=open("/dev/null", 0); - int tty; - int pid; - char npid[10]; - if(null<0){ - Xerror("Can't open /dev/null\n"); - return; - } - switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){ - case -1: - close(null); - Xerror("try again"); - break; - case 0: - /* - * I don't know what the right thing to do here is, - * so this is all experimentally determined. - * If we just dup /dev/null onto 0, then running - * ssh foo & will reopen /dev/tty, try to read a password, - * get a signal, and repeat, in a tight loop, forever. - * Arguably this is a bug in ssh (it behaves the same - * way under bash as under rc) but I'm fixing it here - * anyway. If we dissociate the process from the tty, - * then it won't be able to open /dev/tty ever again. - * The SIG_IGN on SIGTTOU makes writing the tty - * (via fd 1 or 2, for example) succeed even though - * our pgrp is not the terminal's controlling pgrp. - */ - if((tty=open("/dev/tty", OREAD)) >= 0){ - /* - * Should make reads of tty fail, writes succeed. - */ - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - ioctl(tty, TIOCNOTTY); - close(tty); - } - if(isatty(0)) - pushredir(ROPEN, null, 0); - else - close(null); - start(runq->code, runq->pc+1, runq->local); - runq->ret=0; - break; - default: - close(null); - runq->pc=runq->code[runq->pc].i; - itoa(npid, pid); - setvar("apid", newword(npid, (word *)0)); - break; - } -} -void Xsettrue(void){ + +void +Xsettrue(void) +{ setstatus(""); } -void Xbang(void){ + +void +Xbang(void) +{ setstatus(truestatus()?"false":""); } -void Xclose(void){ + +void +Xclose(void) +{ pushredir(RCLOSE, runq->code[runq->pc].i, 0); runq->pc++; } -void Xdup(void){ + +void +Xdup(void) +{ pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i); runq->pc+=2; } -void Xeflag(void){ + +void +Xeflag(void) +{ if(eflagok && !truestatus()) Xexit(); } -void Xexit(void){ + +void +Xexit(void) +{ struct var *trapreq; struct word *starval; - static int beenhere=0; + static int beenhere = 0; if(getpid()==mypid && !beenhere){ - trapreq=vlook("sigexit"); + trapreq = vlook("sigexit"); if(trapreq->fn){ - beenhere=1; + beenhere = 1; --runq->pc; - starval=vlook("*")->val; + starval = vlook("*")->val; start(trapreq->fn, trapreq->pc, (struct var *)0); - runq->local=newvar(strdup("*"), runq->local); - runq->local->val=copywords(starval, (struct word *)0); - runq->local->changed=1; - runq->redir=runq->startredir=0; + runq->local = newvar(strdup("*"), runq->local); + runq->local->val = copywords(starval, (struct word *)0); + runq->local->changed = 1; + runq->redir = runq->startredir = 0; return; } } Exit(getstatus()); } -void Xfalse(void){ - if(truestatus()) runq->pc=runq->code[runq->pc].i; + +void +Xfalse(void) +{ + if(truestatus()) runq->pc = runq->code[runq->pc].i; else runq->pc++; } int ifnot; /* dynamic if not flag */ -void Xifnot(void){ + +void +Xifnot(void) +{ if(ifnot) runq->pc++; else - runq->pc=runq->code[runq->pc].i; + runq->pc = runq->code[runq->pc].i; } -void Xjump(void){ - runq->pc=runq->code[runq->pc].i; + +void +Xjump(void) +{ + runq->pc = runq->code[runq->pc].i; } -void Xmark(void){ + +void +Xmark(void) +{ pushlist(); } -void Xpopm(void){ + +void +Xpopm(void) +{ poplist(); } -void Xread(void){ + +void +Xread(void) +{ char *file; int f; switch(count(runq->argv->words)){ - default: Xerror1("< requires singleton\n"); return; - case 0: Xerror1("< requires file\n"); return; - case 1: break; + default: + Xerror1("< requires singleton\n"); + return; + case 0: + Xerror1("< requires file\n"); + return; + case 1: + break; } - file=runq->argv->words->word; - if((f=open(file, 0))<0){ + file = runq->argv->words->word; + if((f = open(file, 0))<0){ pfmt(err, "%s: ", file); Xerror("can't open"); return; @@ -356,51 +379,110 @@ void Xread(void){ runq->pc++; poplist(); } -void turfredir(void){ + +void +Xrdwr(void) +{ + char *file; + int f; + + switch(count(runq->argv->words)){ + default: + Xerror1("<> requires singleton\n"); + return; + case 0: + Xerror1("<> requires file\n"); + return; + case 1: + break; + } + file = runq->argv->words->word; + if((f = open(file, ORDWR))<0){ + pfmt(err, "%s: ", file); + Xerror("can't open"); + return; + } + pushredir(ROPEN, f, runq->code[runq->pc].i); + runq->pc++; + poplist(); +} + +void +turfredir(void) +{ while(runq->redir!=runq->startredir) Xpopredir(); } -void Xpopredir(void){ - struct redir *rp=runq->redir; - if(rp==0) panic("turfredir null!", 0); - runq->redir=rp->next; - if(rp->type==ROPEN) close(rp->from); + +void +Xpopredir(void) +{ + struct redir *rp = runq->redir; + if(rp==0) + panic("turfredir null!", 0); + runq->redir = rp->next; + if(rp->type==ROPEN) + close(rp->from); efree((char *)rp); } -void Xreturn(void){ - struct thread *p=runq; + +void +Xreturn(void) +{ + struct thread *p = runq; turfredir(); while(p->argv) poplist(); codefree(p->code); - runq=p->ret; + runq = p->ret; efree((char *)p); - if(runq==0) Exit(getstatus()); + if(runq==0) + Exit(getstatus()); } -void Xtrue(void){ + +void +Xtrue(void) +{ if(truestatus()) runq->pc++; - else runq->pc=runq->code[runq->pc].i; + else runq->pc = runq->code[runq->pc].i; } -void Xif(void){ - ifnot=1; + +void +Xif(void) +{ + ifnot = 1; if(truestatus()) runq->pc++; - else runq->pc=runq->code[runq->pc].i; + else runq->pc = runq->code[runq->pc].i; } -void Xwastrue(void){ - ifnot=0; + +void +Xwastrue(void) +{ + ifnot = 0; } -void Xword(void){ + +void +Xword(void) +{ pushword(runq->code[runq->pc++].s); } -void Xwrite(void){ + +void +Xwrite(void) +{ char *file; int f; switch(count(runq->argv->words)){ - default: Xerror1("> requires singleton\n"); return; - case 0: Xerror1("> requires file\n"); return; - case 1: break; + default: + Xerror1("> requires singleton\n"); + return; + case 0: + Xerror1("> requires file\n"); + return; + case 1: + break; } - file=runq->argv->words->word; - if((f=Creat(file))<0){ + file = runq->argv->words->word; + if((f = Creat(file))<0){ pfmt(err, "%s: ", file); Xerror("can't open"); return; @@ -409,31 +491,35 @@ void Xwrite(void){ runq->pc++; poplist(); } -char *_list2str(word *words, int c){ + +char* +list2str(word *words) +{ char *value, *s, *t; - int len=0; + int len = 0; word *ap; - for(ap=words;ap;ap=ap->next) + for(ap = words;ap;ap = ap->next) len+=1+strlen(ap->word); - value=emalloc(len+1); - s=value; - for(ap=words;ap;ap=ap->next){ - for(t=ap->word;*t;) *s++=*t++; - *s++=c; - } - if(s==value) *s='\0'; + value = emalloc(len+1); + s = value; + for(ap = words;ap;ap = ap->next){ + for(t = ap->word;*t;) *s++=*t++; + *s++=' '; + } + if(s==value) + *s='\0'; else s[-1]='\0'; return value; } -char *list2str(word *words){ - return _list2str(words, ' '); -} -void Xmatch(void){ + +void +Xmatch(void) +{ word *p; char *subject; - subject=list2str(runq->argv->words); + subject = list2str(runq->argv->words); setstatus("no match"); - for(p=runq->argv->next->words;p;p=p->next) + for(p = runq->argv->next->words;p;p = p->next) if(match(subject, p->word, '\0')){ setstatus(""); break; @@ -442,14 +528,17 @@ void Xmatch(void){ poplist(); poplist(); } -void Xcase(void){ + +void +Xcase(void) +{ word *p; char *s; - int ok=0; - s=list2str(runq->argv->next->words); - for(p=runq->argv->words;p;p=p->next){ + int ok = 0; + s = list2str(runq->argv->next->words); + for(p = runq->argv->words;p;p = p->next){ if(match(s, p->word, '\0')){ - ok=1; + ok = 1; break; } } @@ -457,28 +546,33 @@ void Xcase(void){ if(ok) runq->pc++; else - runq->pc=runq->code[runq->pc].i; + runq->pc = runq->code[runq->pc].i; poplist(); } -word *conclist(word *lp, word *rp, word *tail) + +word* +conclist(word *lp, word *rp, word *tail) { char *buf; word *v; if(lp->next || rp->next) - tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next, + tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next, tail); - buf=emalloc(strlen(lp->word)+strlen(rp->word)+1); + buf = emalloc(strlen(lp->word)+strlen(rp->word)+1); strcpy(buf, lp->word); strcat(buf, rp->word); - v=newword(buf, tail); + v = newword(buf, tail); efree(buf); return v; } -void Xconc(void){ - word *lp=runq->argv->words; - word *rp=runq->argv->next->words; - word *vp=runq->argv->next->next->words; - int lc=count(lp), rc=count(rp); + +void +Xconc(void) +{ + word *lp = runq->argv->words; + word *rp = runq->argv->next->words; + word *vp = runq->argv->next->next->words; + int lc = count(lp), rc = count(rp); if(lc!=0 || rc!=0){ if(lc==0 || rc==0){ Xerror1("null list in concatenation"); @@ -488,42 +582,50 @@ void Xconc(void){ Xerror1("mismatched list lengths in concatenation"); return; } - vp=conclist(lp, rp, vp); + vp = conclist(lp, rp, vp); } poplist(); poplist(); - runq->argv->words=vp; + runq->argv->words = vp; } -void Xassign(void){ + +void +Xassign(void) +{ var *v; if(count(runq->argv->words)!=1){ Xerror1("variable name not singleton!"); return; } deglob(runq->argv->words->word); - v=vlook(runq->argv->words->word); + v = vlook(runq->argv->words->word); poplist(); globlist(); freewords(v->val); - v->val=runq->argv->words; - v->changed=1; + v->val = runq->argv->words; + v->changed = 1; if(v->changefn) v->changefn(v); - runq->argv->words=0; + runq->argv->words = 0; poplist(); } /* * copy arglist a, adding the copy to the front of tail */ -word *copywords(word *a, word *tail) + +word* +copywords(word *a, word *tail) { - word *v=0, **end; - for(end=&v;a;a=a->next,end=&(*end)->next) - *end=newword(a->word, 0); - *end=tail; + word *v = 0, **end; + for(end=&v;a;a = a->next,end=&(*end)->next) + *end = newword(a->word, 0); + *end = tail; return v; } -void Xdol(void){ + +void +Xdol(void) +{ word *a, *star; char *s, *t; int n; @@ -531,24 +633,27 @@ void Xdol(void){ Xerror1("variable name not singleton!"); return; } - s=runq->argv->words->word; + s = runq->argv->words->word; deglob(s); - n=0; - for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; - a=runq->argv->next->words; + n = 0; + for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; + a = runq->argv->next->words; if(n==0 || *t) - a=copywords(vlook(s)->val, a); + a = copywords(vlook(s)->val, a); else{ - star=vlook("*")->val; + star = vlook("*")->val; if(star && 1<=n && n<=count(star)){ - while(--n) star=star->next; - a=newword(star->word, a); + while(--n) star = star->next; + a = newword(star->word, a); } } poplist(); - runq->argv->words=a; + runq->argv->words = a; } -void Xqdol(void){ + +void +Xqdol(void) +{ word *a, *p; char *s; int n; @@ -556,20 +661,20 @@ void Xqdol(void){ Xerror1("variable name not singleton!"); return; } - s=runq->argv->words->word; + s = runq->argv->words->word; deglob(s); - a=vlook(s)->val; + a = vlook(s)->val; poplist(); - n=count(a); + n = count(a); if(n==0){ pushword(""); return; } - for(p=a;p;p=p->next) n+=strlen(p->word); - s=emalloc(n); + for(p = a;p;p = p->next) n+=strlen(p->word); + s = emalloc(n); if(a){ strcpy(s, a->word); - for(p=a->next;p;p=p->next){ + for(p = a->next;p;p = p->next){ strcat(s, " "); strcat(s, p->word); } @@ -579,37 +684,77 @@ void Xqdol(void){ pushword(s); efree(s); } -word *subwords(word *val, int len, word *sub, word *a) + +word* +copynwords(word *a, word *tail, int n) { - int n; + word *v, **end; + + v = 0; + end = &v; + while(n-- > 0){ + *end = newword(a->word, 0); + end = &(*end)->next; + a = a->next; + } + *end = tail; + return v; +} + +word* +subwords(word *val, int len, word *sub, word *a) +{ + int n, m; char *s; - if(!sub) return a; - a=subwords(val, len, sub->next, a); - s=sub->word; + if(!sub) + return a; + a = subwords(val, len, sub->next, a); + s = sub->word; deglob(s); - n=0; - while('0'<=*s && *s<='9') n=n*10+ *s++ -'0'; - if(n<1 || len<n) return a; - for(;n!=1;--n) val=val->next; - return newword(val->word, a); -} -void Xsub(void){ + m = 0; + n = 0; + while('0'<=*s && *s<='9') + n = n*10+ *s++ -'0'; + if(*s == '-'){ + if(*++s == 0) + m = len - n; + else{ + while('0'<=*s && *s<='9') + m = m*10+ *s++ -'0'; + m -= n; + } + } + if(n<1 || n>len || m<0) + return a; + if(n+m>len) + m = len-n; + while(--n > 0) + val = val->next; + return copynwords(val, a, m+1); +} + +void +Xsub(void) +{ word *a, *v; char *s; if(count(runq->argv->next->words)!=1){ Xerror1("variable name not singleton!"); return; } - s=runq->argv->next->words->word; + s = runq->argv->next->words->word; deglob(s); - a=runq->argv->next->next->words; - v=vlook(s)->val; - a=subwords(v, count(v), runq->argv->words, a); + a = runq->argv->next->next->words; + v = vlook(s)->val; + a = subwords(v, count(v), runq->argv->words, a); poplist(); poplist(); - runq->argv->words=a; + runq->argv->words = a; } -void Xcount(void){ + +void +Xcount(void) +{ word *a; char *s, *t; int n; @@ -618,112 +763,102 @@ void Xcount(void){ Xerror1("variable name not singleton!"); return; } - s=runq->argv->words->word; + s = runq->argv->words->word; deglob(s); - n=0; - for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0'; + n = 0; + for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0'; if(n==0 || *t){ - a=vlook(s)->val; - itoa(num, count(a)); + a = vlook(s)->val; + inttoascii(num, count(a)); } else{ - a=vlook("*")->val; - itoa(num, a && 1<=n && n<=count(a)?1:0); + a = vlook("*")->val; + inttoascii(num, a && 1<=n && n<=count(a)?1:0); } poplist(); pushword(num); } -void Xlocal(void){ + +void +Xlocal(void) +{ if(count(runq->argv->words)!=1){ Xerror1("variable name must be singleton\n"); return; } deglob(runq->argv->words->word); - runq->local=newvar(strdup(runq->argv->words->word), runq->local); - runq->local->val=copywords(runq->argv->next->words, (word *)0); - runq->local->changed=1; + runq->local = newvar(strdup(runq->argv->words->word), runq->local); + runq->local->val = copywords(runq->argv->next->words, (word *)0); + runq->local->changed = 1; poplist(); poplist(); } -void Xunlocal(void){ - var *v=runq->local, *hid; - if(v==0) panic("Xunlocal: no locals!", 0); - runq->local=v->next; - hid=vlook(v->name); - hid->changed=1; + +void +Xunlocal(void) +{ + var *v = runq->local, *hid; + if(v==0) + panic("Xunlocal: no locals!", 0); + runq->local = v->next; + hid = vlook(v->name); + hid->changed = 1; efree(v->name); freewords(v->val); efree((char *)v); } -void freewords(word *w) + +void +freewords(word *w) { word *nw; while(w){ efree(w->word); - nw=w->next; + nw = w->next; efree((char *)w); - w=nw; + w = nw; } } -void Xfn(void){ + +void +Xfn(void) +{ var *v; word *a; int end; - end=runq->code[runq->pc].i; - for(a=runq->argv->words;a;a=a->next){ - v=gvlook(a->word); - if(v->fn) codefree(v->fn); - v->fn=codecopy(runq->code); - v->pc=runq->pc+2; - v->fnchanged=1; - } - runq->pc=end; + end = runq->code[runq->pc].i; + for(a = runq->argv->words;a;a = a->next){ + v = gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn = codecopy(runq->code); + v->pc = runq->pc+2; + v->fnchanged = 1; + } + runq->pc = end; poplist(); } -void Xdelfn(void){ + +void +Xdelfn(void) +{ var *v; word *a; - for(a=runq->argv->words;a;a=a->next){ - v=gvlook(a->word); - if(v->fn) codefree(v->fn); - v->fn=0; - v->fnchanged=1; + for(a = runq->argv->words;a;a = a->next){ + v = gvlook(a->word); + if(v->fn) + codefree(v->fn); + v->fn = 0; + v->fnchanged = 1; } poplist(); } -void Xpipe(void){ - struct thread *p=runq; - int pc=p->pc, forkid; - int lfd=p->code[pc++].i; - int rfd=p->code[pc++].i; - int pfd[2]; - if(pipe(pfd)<0){ - Xerror("can't get pipe"); - return; - } - switch(forkid=fork()){ - case -1: - Xerror("try again"); - break; - case 0: - start(p->code, pc+2, runq->local); - runq->ret=0; - close(pfd[PRD]); - pushredir(ROPEN, pfd[PWR], lfd); - break; - default: - start(p->code, p->code[pc].i, runq->local); - close(pfd[PWR]); - pushredir(ROPEN, pfd[PRD], rfd); - p->pc=p->code[pc+1].i; - p->pid=forkid; - break; - } -} -char *concstatus(char *s, char *t) + +char* +concstatus(char *s, char *t) { static char v[NSTATUS+1]; - int n=strlen(s); + int n = strlen(s); strncpy(v, s, NSTATUS); if(n<NSTATUS){ v[n]='|'; @@ -732,7 +867,10 @@ char *concstatus(char *s, char *t) v[NSTATUS]='\0'; return v; } -void Xpipewait(void){ + +void +Xpipewait(void) +{ char status[NSTATUS+1]; if(runq->pid==-1) setstatus(concstatus(runq->status, getstatus())); @@ -744,31 +882,35 @@ void Xpipewait(void){ setstatus(concstatus(getstatus(), status)); } } -void Xrdcmds(void){ - struct thread *p=runq; + +void +Xrdcmds(void) +{ + struct thread *p = runq; word *prompt; flush(err); - nerror=0; + nerror = 0; if(flag['s'] && !truestatus()) pfmt(err, "status=%v\n", vlook("status")->val); if(runq->iflag){ - prompt=vlook("prompt")->val; + prompt = vlook("prompt")->val; if(prompt) - promptstr=prompt->word; + promptstr = prompt->word; else promptstr="% "; } Noerror(); if(yyparse()){ if(!p->iflag || p->eof && !Eintr()){ - if(p->cmdfile) efree(p->cmdfile); + if(p->cmdfile) + efree(p->cmdfile); closeio(p->cmdfd); Xreturn(); /* should this be omitted? */ } else{ if(Eintr()){ pchr(err, '\n'); - p->eof=0; + p->eof = 0; } --p->pc; /* go back for next command */ } @@ -780,7 +922,9 @@ void Xrdcmds(void){ } freenodes(); } -void Xerror(char *s) + +void +Xerror(char *s) { if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) pfmt(err, "rc: %s: %r\n", s); @@ -790,7 +934,9 @@ void Xerror(char *s) setstatus("error"); while(!runq->iflag) Xreturn(); } -void Xerror1(char *s) + +void +Xerror1(char *s) { if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0) pfmt(err, "rc: %s\n", s); @@ -800,150 +946,55 @@ void Xerror1(char *s) setstatus("error"); while(!runq->iflag) Xreturn(); } -void Xbackq(void){ - char wd[8193]; - int c; - char *s, *ewd=&wd[8192], *stop; - struct io *f; - var *ifs=vlook("ifs"); - word *v, *nextv; - int pfd[2]; - int pid; - stop=ifs->val?ifs->val->word:""; - if(pipe(pfd)<0){ - Xerror("can't make pipe"); - return; - } - switch(pid=fork()){ - case -1: Xerror("try again"); - close(pfd[PRD]); - close(pfd[PWR]); - return; - case 0: - close(pfd[PRD]); - start(runq->code, runq->pc+1, runq->local); - pushredir(ROPEN, pfd[PWR], 1); - return; - default: - close(pfd[PWR]); - f=openfd(pfd[PRD]); - s=wd; - v=0; - while((c=rchr(f))!=EOF){ - if(strchr(stop, c) || s==ewd){ - if(s!=wd){ - *s='\0'; - v=newword(wd, v); - s=wd; - } - } - else *s++=c; - } - if(s!=wd){ - *s='\0'; - v=newword(wd, v); - } - closeio(f); - Waitfor(pid, 0); - /* v points to reversed arglist -- reverse it onto argv */ - while(v){ - nextv=v->next; - v->next=runq->argv->words; - runq->argv->words=v; - v=nextv; - } - runq->pc=runq->code[runq->pc].i; - return; - } -} -/* - * Who should wait for the exit from the fork? - */ -void Xpipefd(void){ - struct thread *p=runq; - int pc=p->pc; - char name[40]; - int pfd[2]; - int sidefd, mainfd; - if(pipe(pfd)<0){ - Xerror("can't get pipe"); - return; - } - if(p->code[pc].i==READ){ - sidefd=pfd[PWR]; - mainfd=pfd[PRD]; - } - else{ - sidefd=pfd[PRD]; - mainfd=pfd[PWR]; - } - switch(fork()){ - case -1: - Xerror("try again"); - break; - case 0: - start(p->code, pc+2, runq->local); - close(mainfd); - pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); - runq->ret=0; - break; - default: - close(sidefd); - pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */ - strcpy(name, Fdprefix); - itoa(name+strlen(name), mainfd); - pushword(name); - p->pc=p->code[pc+1].i; - break; - } -} -void Xsubshell(void){ - int pid; - switch(pid=fork()){ - case -1: - Xerror("try again"); - break; - case 0: - start(runq->code, runq->pc+1, runq->local); - runq->ret=0; - break; - default: - Waitfor(pid, 1); - runq->pc=runq->code[runq->pc].i; - break; - } -} -void setstatus(char *s) + +void +setstatus(char *s) { setvar("status", newword(s, (word *)0)); } -char *getstatus(void){ - var *status=vlook("status"); + +char* +getstatus(void) +{ + var *status = vlook("status"); return status->val?status->val->word:""; } -int truestatus(void){ + +int +truestatus(void) +{ char *s; - for(s=getstatus();*s;s++) - if(*s!='|' && *s!='0') return 0; + for(s = getstatus();*s;s++) + if(*s!='|' && *s!='0') + return 0; return 1; } -void Xdelhere(void){ + +void +Xdelhere(void) +{ Unlink(runq->code[runq->pc++].s); } -void Xfor(void){ + +void +Xfor(void) +{ if(runq->argv->words==0){ poplist(); - runq->pc=runq->code[runq->pc].i; + runq->pc = runq->code[runq->pc].i; } else{ freelist(runq->local->val); - runq->local->val=runq->argv->words; - runq->local->changed=1; - runq->argv->words=runq->argv->words->next; - runq->local->val->next=0; + runq->local->val = runq->argv->words; + runq->local->changed = 1; + runq->argv->words = runq->argv->words->next; + runq->local->val->next = 0; runq->pc++; } } -void Xglob(void){ + +void +Xglob(void) +{ globlist(); } diff --git a/rc/exec.h b/rc/exec.h @@ -5,6 +5,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void) extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void); extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void); extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void); +extern void Xrdwr(void); extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void); extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void); @@ -51,7 +52,6 @@ struct thread{ int iflag; /* interactive? */ int lineno; /* linenumber */ int pid; /* process for Xpipewait to wait for */ - int done; /* have we seen a wait message for this process? */ char status[NSTATUS]; /* status for Xpipewait */ tree *treenodes; /* tree nodes created by this process */ thread *ret; /* who continues when this finishes */ @@ -61,12 +61,16 @@ code *codecopy(code*); code *codebuf; /* compiler output */ int ntrap; /* number of outstanding traps */ int trap[NSIG]; /* number of outstanding traps per type */ -extern struct builtin{ +struct builtin{ char *name; void (*fnc)(void); -}Builtin[]; +}; +extern struct builtin Builtin[]; int eflagok; /* kludge flag so that -e doesn't exit in startup */ +int havefork; + void execcd(void), execwhatis(void), execeval(void), execexec(void); +int execforkexec(void); void execexit(void), execshift(void); void execwait(void), execumask(void), execdot(void), execflag(void); void execfunc(var*), execcmds(io *); diff --git a/rc/fns.h b/rc/fns.h @@ -7,13 +7,14 @@ int Eintr(void); int Executable(char*); void Execute(word*, word*); void Exit(char*); +int ForkExecute(char*, char**, int, int, int); int Globsize(char*); int Isatty(int); void Memcpy(char*, char*, long); void Noerror(void); int Opendir(char*); long Read(int, char*, long); -int Readdir(int, char*); +int Readdir(int, char*, int); long Seek(int, long, long); void Trapinit(void); void Unlink(char*); @@ -21,24 +22,29 @@ void Updenv(void); void Vinit(void); int Waitfor(int, int); long Write(int, char*, long); +void addwaitpid(int); int advance(void); int back(int); void cleanhere(char*); void codefree(code*); int compile(tree*); char * list2str(word*); -char * _list2str(word*, int); int count(word*); void deglob(char*); +void delwaitpid(int); void dotrap(void); void freenodes(void); void freewords(word*); void globlist(void); +int havewaitpid(int); int idchr(int); -void itoa(char*, long); +void inttoascii(char*, long); void kinit(void); +int mapfd(int); int match(char*, char*, int); int matchfn(char*, char*); +char** mkargv(word*); +void clearwaitpids(void); void panic(char*, int); void pathinit(void); void poplist(void); @@ -48,9 +54,9 @@ void pushlist(void); void pushredir(int, int, int); void pushword(char*); void readhere(void); +word* searchpath(char*); void setstatus(char*); void setvar(char*, word*); -void _setvar(char*, word*, int); void skipnl(void); void start(code*, int, var*); int truestatus(void); diff --git a/rc/getflags.c b/rc/getflags.c @@ -3,7 +3,7 @@ #include "rc.h" #include "getflags.h" #include "fns.h" -char *flagset[]={"<flag>"}; +char *flagset[] = {"<flag>"}; char **flag[NFLAG]; char cmdline[NCMDLINE+1]; char *cmdname; @@ -19,105 +19,118 @@ static int reason; #define FLAGSYN 3 #define BADFLAG 4 static int badflag; -int getflags(int argc, char *argv[], char *flags, int stop) + +int +getflags(int argc, char *argv[], char *flags, int stop) { char *s, *t; int i, j, c, count; - flagarg=flags; - if(cmdname==0) cmdname=argv[0]; - s=cmdline; - for(i=0;i!=argc;i++){ - for(t=argv[i];*t;t++) + flagarg = flags; + if(cmdname==0) + cmdname = argv[0]; + s = cmdline; + for(i = 0;i!=argc;i++){ + for(t = argv[i];*t;t++) if(s!=&cmdline[NCMDLINE]) *s++=*t; if(i!=argc-1 && s!=&cmdline[NCMDLINE]) *s++=' '; } *s='\0'; - i=1; + i = 1; while(i!=argc){ if(argv[i][0]!='-' || argv[i][1]=='\0'){ - if(stop) return argc; + if(stop) + return argc; i++; continue; } - s=argv[i]+1; + s = argv[i]+1; while(*s){ c=*s++; - count=scanflag(c, flags); - if(count==-1) return -1; - if(flag[c]){ reason=RESET; badflag=c; return -1; } + count = scanflag(c, flags); + if(count==-1) + return -1; + if(flag[c]){ reason = RESET; badflag = c; return -1; } if(count==0){ - flag[c]=flagset; + flag[c] = flagset; if(*s=='\0'){ - for(j=i+1;j<=argc;j++) - argv[j-1]=argv[j]; + for(j = i+1;j<=argc;j++) + argv[j-1] = argv[j]; --argc; } } else{ if(*s=='\0'){ - for(j=i+1;j<=argc;j++) - argv[j-1]=argv[j]; + for(j = i+1;j<=argc;j++) + argv[j-1] = argv[j]; --argc; - s=argv[i]; + s = argv[i]; } if(argc-i<count){ - reason=FEWARGS; - badflag=c; + reason = FEWARGS; + badflag = c; return -1; } reverse(argv+i, argv+argc); reverse(argv+i, argv+argc-count); reverse(argv+argc-count+1, argv+argc); argc-=count; - flag[c]=argv+argc+1; - flag[c][0]=s; + flag[c] = argv+argc+1; + flag[c][0] = s; s=""; } } } return argc; } -static void reverse(char **p, char **q) + +static void +reverse(char **p, char **q) { char *t; - for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; } + for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; } } -static int scanflag(int c, char *f) + +static int +scanflag(int c, char *f) { int fc, count; - if(0<=c && c<NFLAG) while(*f){ - if(*f==' '){ - f++; - continue; - } - fc=*f++; - if(*f==':'){ - f++; - if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; } - count=0; - while('0'<=*f && *f<='9') count=count*10+*f++-'0'; - } - else - count=0; - if(*f=='['){ - do{ + if(0<=c && c<NFLAG) + while(*f){ + if(*f==' '){ + f++; + continue; + } + fc=*f++; + if(*f==':'){ + f++; + if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; } + count = 0; + while('0'<=*f && *f<='9') count = count*10+*f++-'0'; + } + else + count = 0; + if(*f=='['){ + do{ + f++; + if(*f=='\0'){ reason = FLAGSYN; return -1; } + }while(*f!=']'); f++; - if(*f=='\0'){ reason=FLAGSYN; return -1; } - }while(*f!=']'); - f++; + } + if(c==fc) + return count; } - if(c==fc) return count; - } - reason=BADFLAG; - badflag=c; + reason = BADFLAG; + badflag = c; return -1; } -void usage(char *tail) + +void +usage(char *tail) { char *s, *t, c; - int count, nflag=0; + int count, nflag = 0; switch(reason){ case RESET: errs("Flag -"); @@ -140,46 +153,52 @@ void usage(char *tail) } errs("Usage: "); errs(cmdname); - for(s=flagarg;*s;){ + for(s = flagarg;*s;){ c=*s; - if(*s++==' ') continue; + if(*s++==' ') + continue; if(*s==':'){ s++; - count=0; - while('0'<=*s && *s<='9') count=count*10+*s++-'0'; + count = 0; + while('0'<=*s && *s<='9') count = count*10+*s++-'0'; } - else count=0; + else count = 0; if(count==0){ - if(nflag==0) errs(" [-"); + if(nflag==0) + errs(" [-"); nflag++; errc(c); } if(*s=='['){ s++; while(*s!=']' && *s!='\0') s++; - if(*s==']') s++; + if(*s==']') + s++; } } - if(nflag) errs("]"); - for(s=flagarg;*s;){ + if(nflag) + errs("]"); + for(s = flagarg;*s;){ c=*s; - if(*s++==' ') continue; + if(*s++==' ') + continue; if(*s==':'){ s++; - count=0; - while('0'<=*s && *s<='9') count=count*10+*s++-'0'; + count = 0; + while('0'<=*s && *s<='9') count = count*10+*s++-'0'; } - else count=0; + else count = 0; if(count!=0){ errs(" [-"); errc(c); if(*s=='['){ s++; - t=s; + t = s; while(*s!=']' && *s!='\0') s++; errs(" "); errn(t, s-t); - if(*s==']') s++; + if(*s==']') + s++; } else while(count--) errs(" arg"); @@ -188,7 +207,8 @@ void usage(char *tail) else if(*s=='['){ s++; while(*s!=']' && *s!='\0') s++; - if(*s==']') s++; + if(*s==']') + s++; } } if(tail){ @@ -198,20 +218,27 @@ void usage(char *tail) errs("\n"); Exit("bad flags"); } -static void errn(char *s, int count) + +static void +errn(char *s, int count) { while(count){ errc(*s++); --count; } } -static void errs(char *s) + +static void +errs(char *s) { while(*s) errc(*s++); } #define NBUF 80 -static char buf[NBUF], *bufp=buf; -static void errc(int c){ +static char buf[NBUF], *bufp = buf; + +static void +errc(int c) +{ *bufp++=c; if(bufp==&buf[NBUF] || c=='\n'){ Write(2, buf, bufp-buf); - bufp=buf; + bufp = buf; } } diff --git a/rc/glob.c b/rc/glob.c @@ -6,68 +6,77 @@ struct word *globv; /* * delete all the GLOB marks from s, in place */ -void deglob(char *s) + +void +deglob(char *s) { - char *t=s; + char *t = s; do{ - if(*t==GLOB) t++; + if(*t==GLOB) + t++; *s++=*t; }while(*t++); } -int globcmp(const void *s, const void *t) + +int +globcmp(const void *s, const void *t) { return strcmp(*(char**)s, *(char**)t); } -void globsort(word *left, word *right) + +void +globsort(word *left, word *right) { char **list; word *a; - int n=0; - for(a=left;a!=right;a=a->next) n++; - list=(char **)emalloc(n*sizeof(char *)); - for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word; - qsort((char *)list, n, sizeof(char *), globcmp); - for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n]; + int n = 0; + for(a = left;a!=right;a = a->next) n++; + list = (char **)emalloc(n*sizeof(char *)); + for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word; + qsort((void *)list, n, sizeof(void *), globcmp); + for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n]; efree((char *)list); } /* * Push names prefixed by globname and suffixed by a match of p onto the astack. * namep points to the end of the prefix in globname. */ -void globdir(char *p, char *namep) + +void +globdir(char *p, char *namep) { char *t, *newp; int f; /* scan the pattern looking for a component with a metacharacter in it */ if(*p=='\0'){ - globv=newword(globname, globv); + globv = newword(globname, globv); return; } - t=namep; - newp=p; + t = namep; + newp = p; while(*newp){ if(*newp==GLOB) break; *t=*newp++; if(*t++=='/'){ - namep=t; - p=newp; + namep = t; + p = newp; } } /* If we ran out of pattern, append the name if accessible */ if(*newp=='\0'){ *t='\0'; if(access(globname, 0)==0) - globv=newword(globname, globv); + globv = newword(globname, globv); return; } /* read the directory and recur for any entry that matches */ *namep='\0'; - if((f=Opendir(globname[0]?globname:"."))<0) return; + if((f = Opendir(globname[0]?globname:"."))<0) return; while(*newp!='/' && *newp!='\0') newp++; - while(Readdir(f, namep)){ + while(Readdir(f, namep, *newp=='/')){ if(matchfn(namep, p)){ - for(t=namep;*t;t++); + for(t = namep;*t;t++); globdir(newp, t); } } @@ -77,22 +86,24 @@ void globdir(char *p, char *namep) * Push all file names matched by p on the current thread's stack. * If there are no matches, the list consists of p. */ -void glob(char *p) + +void +glob(char *p) { - word *svglobv=globv; - int globlen=Globsize(p); + word *svglobv = globv; + int globlen = Globsize(p); if(!globlen){ deglob(p); - globv=newword(p, globv); + globv = newword(p, globv); return; } - globname=emalloc(globlen); + globname = emalloc(globlen); globname[0]='\0'; globdir(p, globname); efree(globname); if(svglobv==globv){ deglob(p); - globv=newword(p, globv); + globv = newword(p, globv); } else globsort(globv, svglobv); @@ -100,12 +111,18 @@ void glob(char *p) /* * Do p and q point at equal utf codes */ -int equtf(char *p, char *q){ - if(*p!=*q) return 0; + +int +equtf(char *p, char *q) +{ + if(*p!=*q) + return 0; if(twobyte(*p)) return p[1]==q[1]; if(threebyte(*p)){ - if(p[1]!=q[1]) return 0; - if(p[1]=='\0') return 1; /* broken code at end of string! */ + if(p[1]!=q[1]) + return 0; + if(p[1]=='\0') + return 1; /* broken code at end of string! */ return p[2]==q[2]; } return 1; @@ -114,7 +131,10 @@ int equtf(char *p, char *q){ * Return a pointer to the next utf code in the string, * not jumping past nuls in broken utf codes! */ -char *nextutf(char *p){ + +char* +nextutf(char *p) +{ if(twobyte(*p)) return p[1]=='\0'?p+1:p+2; if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3; return p+1; @@ -122,7 +142,10 @@ char *nextutf(char *p){ /* * Convert the utf code at *p to a unicode value */ -int unicode(char *p){ + +int +unicode(char *p) +{ int u=*p&0xff; if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f); if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f); @@ -135,77 +158,97 @@ int unicode(char *p){ * ? matches any single character * [...] matches the enclosed list of characters */ -int matchfn(char *s, char *p) + +int +matchfn(char *s, char *p) { if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.') return 0; return match(s, p, '/'); } -int match(char *s, char *p, int stop) + +int +match(char *s, char *p, int stop) { int compl, hit, lo, hi, t, c; - for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){ + for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){ if(*p!=GLOB){ if(!equtf(p, s)) return 0; } else switch(*++p){ case GLOB: - if(*s!=GLOB) return 0; + if(*s!=GLOB) + return 0; break; case '*': for(;;){ if(match(s, nextutf(p), stop)) return 1; - if(!*s) break; - s=nextutf(s); + if(!*s) + break; + s = nextutf(s); } return 0; case '?': - if(*s=='\0') return 0; + if(*s=='\0') + return 0; break; case '[': - if(*s=='\0') return 0; - c=unicode(s); + if(*s=='\0') + return 0; + c = unicode(s); p++; compl=*p=='~'; - if(compl) p++; - hit=0; + if(compl) + p++; + hit = 0; while(*p!=']'){ - if(*p=='\0') return 0; /* syntax error */ - lo=unicode(p); - p=nextutf(p); - if(*p!='-') hi=lo; + if(*p=='\0') + return 0; /* syntax error */ + lo = unicode(p); + p = nextutf(p); + if(*p!='-') + hi = lo; else{ p++; - if(*p=='\0') return 0; /* syntax error */ - hi=unicode(p); - p=nextutf(p); - if(hi<lo){ t=lo; lo=hi; hi=t; } + if(*p=='\0') + return 0; /* syntax error */ + hi = unicode(p); + p = nextutf(p); + if(hi<lo){ t = lo; lo = hi; hi = t; } } - if(lo<=c && c<=hi) hit=1; + if(lo<=c && c<=hi) + hit = 1; } - if(compl) hit=!hit; - if(!hit) return 0; + if(compl) + hit=!hit; + if(!hit) + return 0; break; } } return *s=='\0'; } -void globlist1(word *gl) + +void +globlist1(word *gl) { if(gl){ globlist1(gl->next); glob(gl->word); } } -void globlist(void){ + +void +globlist(void) +{ word *a; - globv=0; + globv = 0; globlist1(runq->argv->words); poplist(); pushlist(); if(globv){ - for(a=globv;a->next;a=a->next); - a->next=runq->argv->words; - runq->argv->words=globv; + for(a = globv;a->next;a = a->next); + a->next = runq->argv->words; + runq->argv->words = globv; } } diff --git a/rc/havefork.c b/rc/havefork.c @@ -1,5 +1,9 @@ #include <u.h> #include <signal.h> +#if defined(PLAN9PORT) && defined(__sun__) +# define BSD_COMP /* sigh. for TIOCNOTTY */ +#endif +#include <sys/ioctl.h> #include "rc.h" #include "getflags.h" #include "exec.h" @@ -12,10 +16,9 @@ void Xasync(void) { int null = open("/dev/null", 0); + int tty; int pid; - int tcpgrp, pgrp; char npid[10]; - if(null<0){ Xerror("Can't open /dev/null\n"); return; @@ -26,17 +29,39 @@ Xasync(void) Xerror("try again"); break; case 0: + clearwaitpids(); /* - * Should make reads of tty fail, writes succeed. + * I don't know what the right thing to do here is, + * so this is all experimentally determined. + * If we just dup /dev/null onto 0, then running + * ssh foo & will reopen /dev/tty, try to read a password, + * get a signal, and repeat, in a tight loop, forever. + * Arguably this is a bug in ssh (it behaves the same + * way under bash as under rc) but I'm fixing it here + * anyway. If we dissociate the process from the tty, + * then it won't be able to open /dev/tty ever again. + * The SIG_IGN on SIGTTOU makes writing the tty + * (via fd 1 or 2, for example) succeed even though + * our pgrp is not the terminal's controlling pgrp. */ - signal(SIGTTIN, SIG_IGN); - signal(SIGTTOU, SIG_IGN); - - pushredir(ROPEN, null, 0); + if((tty = open("/dev/tty", OREAD)) >= 0){ + /* + * Should make reads of tty fail, writes succeed. + */ + signal(SIGTTIN, SIG_IGN); + signal(SIGTTOU, SIG_IGN); + ioctl(tty, TIOCNOTTY); + close(tty); + } + if(isatty(0)) + pushredir(ROPEN, null, 0); + else + close(null); start(runq->code, runq->pc+1, runq->local); runq->ret = 0; break; default: + addwaitpid(pid); close(null); runq->pc = runq->code[runq->pc].i; inttoascii(npid, pid); @@ -62,12 +87,14 @@ Xpipe(void) Xerror("try again"); break; case 0: + clearwaitpids(); start(p->code, pc+2, runq->local); runq->ret = 0; close(pfd[PRD]); pushredir(ROPEN, pfd[PWR], lfd); break; default: + addwaitpid(forkid); start(p->code, p->code[pc].i, runq->local); close(pfd[PWR]); pushredir(ROPEN, pfd[PRD], rfd); @@ -103,11 +130,13 @@ Xbackq(void) close(pfd[PWR]); return; case 0: + clearwaitpids(); close(pfd[PRD]); start(runq->code, runq->pc+1, runq->local); pushredir(ROPEN, pfd[PWR], 1); return; default: + addwaitpid(pid); close(pfd[PWR]); f = openfd(pfd[PRD]); s = wd; @@ -144,7 +173,7 @@ void Xpipefd(void) { struct thread *p = runq; - int pc = p->pc; + int pc = p->pc, pid; char name[40]; int pfd[2]; int sidefd, mainfd; @@ -160,17 +189,19 @@ Xpipefd(void) sidefd = pfd[PRD]; mainfd = pfd[PWR]; } - switch(fork()){ + switch(pid = fork()){ case -1: Xerror("try again"); break; case 0: + clearwaitpids(); start(p->code, pc+2, runq->local); close(mainfd); pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0); runq->ret = 0; break; default: + addwaitpid(pid); close(sidefd); pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */ strcpy(name, Fdprefix); @@ -190,10 +221,12 @@ Xsubshell(void) Xerror("try again"); break; case 0: + clearwaitpids(); start(runq->code, runq->pc+1, runq->local); runq->ret = 0; break; default: + addwaitpid(pid); Waitfor(pid, 1); runq->pc = runq->code[runq->pc].i; break; @@ -211,6 +244,7 @@ execforkexec(void) case -1: return -1; case 0: + clearwaitpids(); pushword("exec"); execexec(); strcpy(buf, "can't exec: "); @@ -218,5 +252,6 @@ execforkexec(void) errstr(buf+n, ERRMAX-n); Exit(buf); } + addwaitpid(pid); return pid; } diff --git a/rc/here.c b/rc/here.c @@ -3,32 +3,37 @@ #include "io.h" #include "fns.h" struct here *here, **ehere; -int ser=0; +int ser = 0; char tmp[]="/tmp/here0000.0000"; char hex[]="0123456789abcdef"; void psubst(io*, char*); void pstrs(io*, word*); -void hexnum(char *p, int n) + +void +hexnum(char *p, int n) { *p++=hex[(n>>12)&0xF]; *p++=hex[(n>>8)&0xF]; *p++=hex[(n>>4)&0xF]; - *p=hex[n&0xF]; + *p = hex[n&0xF]; } -tree *heredoc(tree *tag) + +tree* +heredoc(tree *tag) { - struct here *h=new(struct here); - if(tag->type!=WORD) yyerror("Bad here tag"); - h->next=0; + struct here *h = new(struct here); + if(tag->type!=WORD) + yyerror("Bad here tag"); + h->next = 0; if(here) - *ehere=h; + *ehere = h; else - here=h; + here = h; ehere=&h->next; - h->tag=tag; + h->tag = tag; hexnum(&tmp[9], getpid()); hexnum(&tmp[14], ser++); - h->name=strdup(tmp); + h->name = strdup(tmp); return token(tmp, WORD); } /* @@ -36,27 +41,32 @@ tree *heredoc(tree *tag) * missubstitution, or a misrecognized EOF marker. */ #define NLINE 4096 -void readhere(void){ + +void +readhere(void) +{ struct here *h, *nexth; io *f; char *s, *tag; int c, subst; char line[NLINE+1]; - for(h=here;h;h=nexth){ + for(h = here;h;h = nexth){ subst=!h->tag->quoted; - tag=h->tag->str; - c=Creat(h->name); - if(c<0) yyerror("can't create here document"); - f=openfd(c); - s=line; + tag = h->tag->str; + c = Creat(h->name); + if(c<0) + yyerror("can't create here document"); + f = openfd(c); + s = line; pprompt(); - while((c=rchr(runq->cmdfd))!=EOF){ + while((c = rchr(runq->cmdfd))!=EOF){ if(c=='\n' || s==&line[NLINE]){ *s='\0'; - if(strcmp(line, tag)==0) break; - if(subst) psubst(f, line); + if(tag && strcmp(line, tag)==0) break; + if(subst) + psubst(f, line); else pstr(f, line); - s=line; + s = line; if(c=='\n'){ pprompt(); pchr(f, c); @@ -68,13 +78,15 @@ void readhere(void){ flush(f); closeio(f); cleanhere(h->name); - nexth=h->next; + nexth = h->next; efree((char *)h); } - here=0; - doprompt=1; + here = 0; + doprompt = 1; } -void psubst(io *f, char *s) + +void +psubst(io *f, char *s) { char *t, *u; int savec, n; @@ -83,48 +95,55 @@ void psubst(io *f, char *s) if(*s!='$'){ if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){ pchr(f, *s++); - if(*s=='\0') break; + if(*s=='\0') + break; } else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){ pchr(f, *s++); - if(*s=='\0') break; + if(*s=='\0') + break; pchr(f, *s++); - if(*s=='\0') break; + if(*s=='\0') + break; } pchr(f, *s++); } else{ t=++s; - if(*t=='$') pchr(f, *t++); + if(*t=='$') + pchr(f, *t++); else{ while(*t && idchr(*t)) t++; savec=*t; *t='\0'; - n=0; - for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0'; + n = 0; + for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0'; if(n && *u=='\0'){ - star=vlook("*")->val; + star = vlook("*")->val; if(star && 1<=n && n<=count(star)){ - while(--n) star=star->next; + while(--n) star = star->next; pstr(f, star->word); } } else pstrs(f, vlook(s)->val); - *t=savec; - if(savec=='^') t++; + *t = savec; + if(savec=='^') + t++; } - s=t; + s = t; } } } -void pstrs(io *f, word *a) + +void +pstrs(io *f, word *a) { if(a){ while(a->next && a->next->word){ pstr(f, a->word); pchr(f, ' '); - a=a->next; + a = a->next; } pstr(f, a->word); } diff --git a/rc/io.c b/rc/io.c @@ -2,68 +2,121 @@ #include "exec.h" #include "io.h" #include "fns.h" -int pfmtnest=0; -void pfmt(io *f, char *fmt, ...){ +int pfmtnest = 0; + +void +pfmt(io *f, char *fmt, ...) +{ va_list ap; char err[ERRMAX]; va_start(ap, fmt); pfmtnest++; for(;*fmt;fmt++) - if(*fmt!='%') pchr(f, *fmt); + if(*fmt!='%') + pchr(f, *fmt); else switch(*++fmt){ - case '\0': va_end(ap); return; - case 'c': pchr(f, va_arg(ap, int)); break; - case 'd': pdec(f, va_arg(ap, int)); break; - case 'o': poct(f, va_arg(ap, unsigned)); break; - case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/ - case 'Q': pquo(f, va_arg(ap, char *)); break; - case 'q': pwrd(f, va_arg(ap, char *)); break; - case 'r': errstr(err, sizeof err); pstr(f, err); break; - case 's': pstr(f, va_arg(ap, char *)); break; - case 't': pcmd(f, va_arg(ap, struct tree *)); break; - case 'v': pval(f, va_arg(ap, struct word *)); break; - default: pchr(f, *fmt); break; + case '\0': + va_end(ap); + return; + case 'c': + pchr(f, va_arg(ap, int)); + break; + case 'd': + pdec(f, va_arg(ap, int)); + break; + case 'o': + poct(f, va_arg(ap, unsigned)); + break; + case 'p': + pptr(f, va_arg(ap, void*)); + break; + case 'Q': + pquo(f, va_arg(ap, char *)); + break; + case 'q': + pwrd(f, va_arg(ap, char *)); + break; + case 'r': + rerrstr(err, sizeof err); pstr(f, err); + break; + case 's': + pstr(f, va_arg(ap, char *)); + break; + case 't': + pcmd(f, va_arg(ap, struct tree *)); + break; + case 'v': + pval(f, va_arg(ap, struct word *)); + break; + default: + pchr(f, *fmt); + break; } va_end(ap); - if(--pfmtnest==0) flush(f); + if(--pfmtnest==0) + flush(f); } -void pchr(io *b, int c) + +void +pchr(io *b, int c) { - if(b->bufp==b->ebuf) fullbuf(b, c); + if(b->bufp==b->ebuf) + fullbuf(b, c); else *b->bufp++=c; } -int rchr(io *b) + +int +rchr(io *b) { - if(b->bufp==b->ebuf) return emptybuf(b); + if(b->bufp==b->ebuf) + return emptybuf(b); return *b->bufp++ & 0xFF; } -void pquo(io *f, char *s) +void +pquo(io *f, char *s) { pchr(f, '\''); for(;*s;s++) - if(*s=='\'') pfmt(f, "''"); + if(*s=='\'') + pfmt(f, "''"); else pchr(f, *s); pchr(f, '\''); } -void pwrd(io *f, char *s) + +void +pwrd(io *f, char *s) { char *t; - for(t=s;*t;t++) if(!wordchr(*t)) break; - if(t==s || *t) pquo(f, s); + for(t = s;*t;t++) if(!wordchr(*t)) break; + if(t==s || *t) + pquo(f, s); else pstr(f, s); } -void phex(io *f, long p) + +void +pptr(io *f, void *v) { int n; - for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); + uintptr p; + + p = (uintptr)v; + if(sizeof(uintptr) == sizeof(uvlong) && p>>32) + for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); + + for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]); } -void pstr(io *f, char *s) + +void +pstr(io *f, char *s) { - if(s==0) s="(null)"; + if(s==0) + s="(null)"; while(*s) pchr(f, *s++); } -void pdec(io *f, long n) + +void +pdec(io *f, int n) { if(n<0){ n=-n; @@ -73,110 +126,136 @@ void pdec(io *f, long n) return; } /* n is two's complement minimum integer */ - n=1-n; + n = 1-n; pchr(f, '-'); pdec(f, n/10); pchr(f, n%10+'1'); return; } - if(n>9) pdec(f, n/10); + if(n>9) + pdec(f, n/10); pchr(f, n%10+'0'); } -void poct(io *f, ulong n) + +void +poct(io *f, unsigned n) { - if(n>7) poct(f, n>>3); + if(n>7) + poct(f, n>>3); pchr(f, (n&7)+'0'); } -void pval(io *f, word *a) + +void +pval(io *f, word *a) { if(a){ while(a->next && a->next->word){ pwrd(f, a->word); pchr(f, ' '); - a=a->next; + a = a->next; } pwrd(f, a->word); } } -int fullbuf(io *f, int c) + +int +fullbuf(io *f, int c) { flush(f); return *f->bufp++=c; } -void flush(io *f) + +void +flush(io *f) { int n; char *s; if(f->strp){ - n=f->ebuf-f->strp; - f->strp=realloc(f->strp, n+101); - if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101); - f->bufp=f->strp+n; - f->ebuf=f->bufp+100; - for(s=f->bufp;s<=f->ebuf;s++) *s='\0'; + n = f->ebuf-f->strp; + f->strp = realloc(f->strp, n+101); + if(f->strp==0) + panic("Can't realloc %d bytes in flush!", n+101); + f->bufp = f->strp+n; + f->ebuf = f->bufp+100; + for(s = f->bufp;s<=f->ebuf;s++) *s='\0'; } else{ - n=f->bufp-f->buf; + n = f->bufp-f->buf; if(n && Write(f->fd, f->buf, n) < 0){ Write(3, "Write error\n", 12); - if(ntrap) dotrap(); + if(ntrap) + dotrap(); } - f->bufp=f->buf; - f->ebuf=f->buf+NBUF; + f->bufp = f->buf; + f->ebuf = f->buf+NBUF; } } -io *openfd(int fd){ - io *f; - f=new(struct io); - f->fd=fd; - f->bufp=f->ebuf=f->buf; - f->strp=0; + +io* +openfd(int fd) +{ + io *f = new(struct io); + f->fd = fd; + f->bufp = f->ebuf = f->buf; + f->strp = 0; return f; } -io *openstr(void){ - io *f=new(struct io); + +io* +openstr(void) +{ + io *f = new(struct io); char *s; f->fd=-1; - f->bufp=f->strp=emalloc(101); - f->ebuf=f->bufp+100; - for(s=f->bufp;s<=f->ebuf;s++) *s='\0'; + f->bufp = f->strp = emalloc(101); + f->ebuf = f->bufp+100; + for(s = f->bufp;s<=f->ebuf;s++) *s='\0'; return f; } /* * Open a corebuffer to read. EOF occurs after reading len * characters from buf. */ -io *opencore(char *s, int len) + +io* +opencore(char *s, int len) { - io *f=new(struct io); - char *buf=emalloc(len); + io *f = new(struct io); + char *buf = emalloc(len); f->fd= -1 /*open("/dev/null", 0)*/; - f->bufp=f->strp=buf; - f->ebuf=buf+len; + f->bufp = f->strp = buf; + f->ebuf = buf+len; Memcpy(buf, s, len); return f; } -/* -void rewind(io *io) + +void +iorewind(io *io) { - if(io->fd==-1) io->bufp=io->strp; + if(io->fd==-1) + io->bufp = io->strp; else{ - io->bufp=io->ebuf=io->buf; + io->bufp = io->ebuf = io->buf; Seek(io->fd, 0L, 0); } } -*/ -void closeio(io *io) + +void +closeio(io *io) { - if(io->fd>=0) close(io->fd); - if(io->strp) efree(io->strp); + if(io->fd>=0) + close(io->fd); + if(io->strp) + efree(io->strp); efree((char *)io); } -int emptybuf(io *f) + +int +emptybuf(io *f) { int n; - if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF; - f->bufp=f->buf; - f->ebuf=f->buf+n; + if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF; + f->bufp = f->buf; + f->ebuf = f->buf+n; return *f->bufp++&0xff; } diff --git a/rc/io.h b/rc/io.h @@ -18,9 +18,9 @@ int rchr(io*); void closeio(io*); void flush(io*); int fullbuf(io*, int); -void pdec(io*, long); -void poct(io*, ulong); -void phex(io*, long); +void pdec(io*, int); +void poct(io*, unsigned); +void pptr(io*, void*); void pquo(io*, char*); void pwrd(io*, char*); void pstr(io*, char*); diff --git a/rc/lex.c b/rc/lex.c @@ -4,11 +4,15 @@ #include "getflags.h" #include "fns.h" int getnext(void); -int wordchr(int c) + +int +wordchr(int c) { return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF; } -int idchr(int c) + +int +idchr(int c) { /* * Formerly: @@ -17,127 +21,170 @@ int idchr(int c) */ return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c); } -int future=EOF; -int doprompt=1; +int future = EOF; +int doprompt = 1; int inquote; +int incomm; /* * Look ahead in the input stream */ -int nextc(void){ - if(future==EOF) future=getnext(); + +int +nextc(void) +{ + if(future==EOF) + future = getnext(); return future; } /* * Consume the lookahead character. */ -int advance(void){ - int c=nextc(); - lastc=future; - future=EOF; + +int +advance(void) +{ + int c = nextc(); + lastc = future; + future = EOF; return c; } /* * read a character from the input stream */ -int getnext(void){ - register int c; - static int peekc=EOF; + +int +getnext(void) +{ + int c; + static int peekc = EOF; if(peekc!=EOF){ - c=peekc; - peekc=EOF; + c = peekc; + peekc = EOF; return c; } - if(runq->eof) return EOF; - if(doprompt) pprompt(); - c=rchr(runq->cmdfd); + if(runq->eof) + return EOF; + if(doprompt) + pprompt(); + c = rchr(runq->cmdfd); if(!inquote && c=='\\'){ - c=rchr(runq->cmdfd); - if(c=='\n'){ - doprompt=1; + c = rchr(runq->cmdfd); + if(c=='\n' && !incomm){ /* don't continue a comment */ + doprompt = 1; c=' '; } else{ - peekc=c; + peekc = c; c='\\'; } } - doprompt=doprompt || c=='\n' || c==EOF; - if(c==EOF) runq->eof++; + doprompt = doprompt || c=='\n' || c==EOF; + if(c==EOF) + runq->eof++; else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c); return c; } -void pprompt(void){ + +void +pprompt(void) +{ var *prompt; if(runq->iflag){ pstr(err, promptstr); flush(err); - prompt=vlook("prompt"); + prompt = vlook("prompt"); if(prompt->val && prompt->val->next) - promptstr=prompt->val->next->word; + promptstr = prompt->val->next->word; else promptstr="\t"; } runq->lineno++; - doprompt=0; + doprompt = 0; } -void skipwhite(void){ + +void +skipwhite(void) +{ int c; for(;;){ - c=nextc(); - if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */ + c = nextc(); + /* Why did this used to be if(!inquote && c=='#') ?? */ + if(c=='#'){ + incomm = 1; for(;;){ - c=nextc(); - if(c=='\n' || c==EOF) break; + c = nextc(); + if(c=='\n' || c==EOF) { + incomm = 0; + break; + } advance(); } } - if(c==' ' || c=='\t') advance(); + if(c==' ' || c=='\t') + advance(); else return; } } -void skipnl(void){ - register int c; + +void +skipnl(void) +{ + int c; for(;;){ skipwhite(); - c=nextc(); - if(c!='\n') return; + c = nextc(); + if(c!='\n') + return; advance(); } } -int nextis(int c){ + +int +nextis(int c) +{ if(nextc()==c){ advance(); return 1; } return 0; } -char *addtok(char *p, int val){ - if(p==0) return 0; - if(p==&tok[NTOK]){ - *p=0; + +char* +addtok(char *p, int val) +{ + if(p==0) + return 0; + if(p==&tok[NTOK-1]){ + *p = 0; yyerror("token buffer too short"); return 0; } *p++=val; return p; } -char *addutf(char *p, int c){ - p=addtok(p, c); + +char* +addutf(char *p, int c) +{ + p = addtok(p, c); if(twobyte(c)) /* 2-byte escape */ return addtok(p, advance()); if(threebyte(c)){ /* 3-byte escape */ - p=addtok(p, advance()); + p = addtok(p, advance()); return addtok(p, advance()); } return p; } int lastdol; /* was the last token read '$' or '$#' or '"'? */ int lastword; /* was the last token read a word or compound word terminator? */ -int yylex(void){ - register int c, d=nextc(); - register char *w=tok; - register struct tree *t; - yylval.tree=0; + +int +yylex(void) +{ + int c, d = nextc(); + char *w = tok; + struct tree *t; + yylval.tree = 0; /* * Embarassing sneakiness: if the last token read was a quoted or unquoted * WORD then we alter the meaning of what follows. If the next character @@ -146,7 +193,7 @@ int yylex(void){ * we insert a `^' before it. */ if(lastword){ - lastword=0; + lastword = 0; if(d=='('){ advance(); strcpy(tok, "( [SUB]"); @@ -157,15 +204,15 @@ int yylex(void){ return '^'; } } - inquote=0; + inquote = 0; skipwhite(); - switch(c=advance()){ + switch(c = advance()){ case EOF: - lastdol=0; + lastdol = 0; strcpy(tok, "EOF"); return EOF; case '$': - lastdol=1; + lastdol = 1; if(nextis('#')){ strcpy(tok, "$#"); return COUNT; @@ -177,7 +224,7 @@ int yylex(void){ strcpy(tok, "$"); return '$'; case '&': - lastdol=0; + lastdol = 0; if(nextis('&')){ skipnl(); strcpy(tok, "&&"); @@ -186,7 +233,7 @@ int yylex(void){ strcpy(tok, "&"); return '&'; case '|': - lastdol=0; + lastdol = 0; if(nextis(c)){ skipnl(); strcpy(tok, "||"); @@ -194,7 +241,7 @@ int yylex(void){ } case '<': case '>': - lastdol=0; + lastdol = 0; /* * funny redirection tokens: * redir: arrow | arrow '[' fd ']' @@ -204,121 +251,128 @@ int yylex(void){ * some possibilities are nonsensical and get a message. */ *w++=c; - t=newtree(); + t = newtree(); switch(c){ case '|': - t->type=PIPE; - t->fd0=1; - t->fd1=0; + t->type = PIPE; + t->fd0 = 1; + t->fd1 = 0; break; case '>': - t->type=REDIR; + t->type = REDIR; if(nextis(c)){ - t->rtype=APPEND; + t->rtype = APPEND; *w++=c; } - else t->rtype=WRITE; - t->fd0=1; + else t->rtype = WRITE; + t->fd0 = 1; break; case '<': - t->type=REDIR; + t->type = REDIR; if(nextis(c)){ - t->rtype=HERE; + t->rtype = HERE; *w++=c; - } - else t->rtype=READ; - t->fd0=0; + } else if (nextis('>')){ + t->rtype = RDWR; + *w++=c; + } else t->rtype = READ; + t->fd0 = 0; break; } if(nextis('[')){ *w++='['; - c=advance(); + c = advance(); + *w++=c; if(c<'0' || '9'<c){ RedirErr: - *w++ = c; - *w=0; + *w = 0; yyerror(t->type==PIPE?"pipe syntax" :"redirection syntax"); return EOF; } - t->fd0=0; + t->fd0 = 0; do{ - t->fd0=t->fd0*10+c-'0'; + t->fd0 = t->fd0*10+c-'0'; *w++=c; - c=advance(); + c = advance(); }while('0'<=c && c<='9'); if(c=='='){ *w++='='; - if(t->type==REDIR) t->type=DUP; - c=advance(); + if(t->type==REDIR) + t->type = DUP; + c = advance(); if('0'<=c && c<='9'){ - t->rtype=DUPFD; - t->fd1=t->fd0; - t->fd0=0; + t->rtype = DUPFD; + t->fd1 = t->fd0; + t->fd0 = 0; do{ - t->fd0=t->fd0*10+c-'0'; + t->fd0 = t->fd0*10+c-'0'; *w++=c; - c=advance(); + c = advance(); }while('0'<=c && c<='9'); } else{ - if(t->type==PIPE) goto RedirErr; - t->rtype=CLOSE; + if(t->type==PIPE) + goto RedirErr; + t->rtype = CLOSE; } } - *w=0; if(c!=']' || t->type==DUP && (t->rtype==HERE || t->rtype==APPEND)) goto RedirErr; *w++=']'; } *w='\0'; - yylval.tree=t; - if(t->type==PIPE) skipnl(); + yylval.tree = t; + if(t->type==PIPE) + skipnl(); return t->type; case '\'': - lastdol=0; - lastword=1; - inquote=1; + lastdol = 0; + lastword = 1; + inquote = 1; for(;;){ - c=advance(); - if(c==EOF) break; + c = advance(); + if(c==EOF) + break; if(c=='\''){ if(nextc()!='\'') break; advance(); } - w=addutf(w, c); + w = addutf(w, c); } - if(w!=0) *w='\0'; - t=token(tok, WORD); - t->quoted=1; - yylval.tree=t; + if(w!=0) + *w='\0'; + t = token(tok, WORD); + t->quoted = 1; + yylval.tree = t; return t->type; } if(!wordchr(c)){ - lastdol=0; - tok[0]=c; + lastdol = 0; + tok[0] = c; tok[1]='\0'; return c; } for(;;){ /* next line should have (char)c==GLOB, but ken's compiler is broken */ if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB) - w=addtok(w, GLOB); - w=addutf(w, c); - c=nextc(); + w = addtok(w, GLOB); + w = addutf(w, c); + c = nextc(); if(lastdol?!idchr(c):!wordchr(c)) break; advance(); } - lastword=1; - lastdol=0; - if(w!=0) *w='\0'; - t=klook(tok); - if(t->type!=WORD) lastword=0; - t->quoted=0; - yylval.tree=t; + lastword = 1; + lastdol = 0; + if(w!=0) + *w='\0'; + t = klook(tok); + if(t->type!=WORD) + lastword = 0; + t->quoted = 0; + yylval.tree = t; return t->type; } - diff --git a/rc/pcmd.c b/rc/pcmd.c @@ -5,39 +5,66 @@ char nl='\n'; /* change to semicolon for bourne-proofing */ #define c0 t->child[0] #define c1 t->child[1] #define c2 t->child[2] -void pdeglob(io *f, char *s) + +void +pdeglob(io *f, char *s) { while(*s){ - if(*s==GLOB) s++; + if(*s==GLOB) + s++; pchr(f, *s++); } } -void pcmd(io *f, tree *t) + +void +pcmd(io *f, tree *t) { - if(t==0) return; + if(t==0) + return; switch(t->type){ - default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break; - case '$': pfmt(f, "$%t", c0); break; - case '"': pfmt(f, "$\"%t", c0); break; - case '&': pfmt(f, "%t&", c0); break; - case '^': pfmt(f, "%t^%t", c0, c1); break; - case '`': pfmt(f, "`%t", c0); break; - case ANDAND: pfmt(f, "%t && %t", c0, c1); break; - case BANG: pfmt(f, "! %t", c0); break; - case BRACE: pfmt(f, "{%t}", c0); break; - case COUNT: pfmt(f, "$#%t", c0); break; - case FN: pfmt(f, "fn %t %t", c0, c1); break; - case IF: pfmt(f, "if%t%t", c0, c1); break; - case NOT: pfmt(f, "if not %t", c0); break; - case OROR: pfmt(f, "%t || %t", c0, c1); break; + default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); + break; + case '$': pfmt(f, "$%t", c0); + break; + case '"': pfmt(f, "$\"%t", c0); + break; + case '&': pfmt(f, "%t&", c0); + break; + case '^': pfmt(f, "%t^%t", c0, c1); + break; + case '`': pfmt(f, "`%t", c0); + break; + case ANDAND: pfmt(f, "%t && %t", c0, c1); + break; + case BANG: pfmt(f, "! %t", c0); + break; + case BRACE: pfmt(f, "{%t}", c0); + break; + case COUNT: pfmt(f, "$#%t", c0); + break; + case FN: pfmt(f, "fn %t %t", c0, c1); + break; + case IF: pfmt(f, "if%t%t", c0, c1); + break; + case NOT: pfmt(f, "if not %t", c0); + break; + case OROR: pfmt(f, "%t || %t", c0, c1); + break; case PCMD: - case PAREN: pfmt(f, "(%t)", c0); break; - case SUB: pfmt(f, "$%t(%t)", c0, c1); break; - case SIMPLE: pfmt(f, "%t", c0); break; - case SUBSHELL: pfmt(f, "@ %t", c0); break; - case SWITCH: pfmt(f, "switch %t %t", c0, c1); break; - case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break; - case WHILE: pfmt(f, "while %t%t", c0, c1); break; + case PAREN: pfmt(f, "(%t)", c0); + break; + case SUB: pfmt(f, "$%t(%t)", c0, c1); + break; + case SIMPLE: pfmt(f, "%t", c0); + break; + case SUBSHELL: pfmt(f, "@ %t", c0); + break; + case SWITCH: pfmt(f, "switch %t %t", c0, c1); + break; + case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); + break; + case WHILE: pfmt(f, "while %t%t", c0, c1); + break; case ARGLIST: if(c0==0) pfmt(f, "%t", c1); @@ -48,22 +75,26 @@ void pcmd(io *f, tree *t) break; case ';': if(c0){ - if(c1) pfmt(f, "%t%c%t", c0, nl, c1); + if(c1) + pfmt(f, "%t%c%t", c0, nl, c1); else pfmt(f, "%t", c0); } else pfmt(f, "%t", c1); break; case WORDS: - if(c0) pfmt(f, "%t ", c0); + if(c0) + pfmt(f, "%t ", c0); pfmt(f, "%t", c1); break; case FOR: pfmt(f, "for(%t", c0); - if(c1) pfmt(f, " in %t", c1); + if(c1) + pfmt(f, " in %t", c1); pfmt(f, ")%t", c2); break; case WORD: - if(t->quoted) pfmt(f, "%Q", t->str); + if(t->quoted) + pfmt(f, "%Q", t->str); else pdeglob(f, t->str); break; case DUP: @@ -79,27 +110,35 @@ void pcmd(io *f, tree *t) case HERE: pchr(f, '<'); case READ: + case RDWR: pchr(f, '<'); - if(t->fd0!=0) pfmt(f, "[%d]", t->fd0); + if(t->rtype==RDWR) + pchr(f, '>'); + if(t->fd0!=0) + pfmt(f, "[%d]", t->fd0); break; case APPEND: pchr(f, '>'); case WRITE: pchr(f, '>'); - if(t->fd0!=1) pfmt(f, "[%d]", t->fd0); + if(t->fd0!=1) + pfmt(f, "[%d]", t->fd0); break; } pfmt(f, "%t", c0); - if(c1) pfmt(f, " %t", c1); + if(c1) + pfmt(f, " %t", c1); break; case '=': pfmt(f, "%t=%t", c0, c1); - if(c2) pfmt(f, " %t", c2); + if(c2) + pfmt(f, " %t", c2); break; case PIPE: pfmt(f, "%t|", c0); if(t->fd1==0){ - if(t->fd0!=1) pfmt(f, "[%d]", t->fd0); + if(t->fd0!=1) + pfmt(f, "[%d]", t->fd0); } else pfmt(f, "[%d=%d]", t->fd0, t->fd1); pfmt(f, "%t", c1); diff --git a/rc/pfnc.c b/rc/pfnc.c @@ -5,7 +5,7 @@ struct{ void (*f)(void); char *name; -}fname[]={ +}fname[] = { Xappend, "Xappend", Xasync, "Xasync", Xbang, "Xbang", @@ -18,6 +18,7 @@ struct{ Xjump, "Xjump", Xmark, "Xmark", Xpopm, "Xpopm", + Xrdwr, "Xrdwr", Xread, "Xread", Xreturn, "Xreturn", Xtrue, "Xtrue", @@ -50,18 +51,21 @@ struct{ Xrdfn, "Xrdfn", Xqdol, "Xqdol", 0}; -void pfnc(io *fd, thread *t) + +void +pfnc(io *fd, thread *t) { int i; - void (*fn)(void)=t->code[t->pc].f; + void (*fn)(void) = t->code[t->pc].f; list *a; pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc); - for(i=0;fname[i].f;i++) if(fname[i].f==fn){ + for(i = 0;fname[i].f;i++) if(fname[i].f==fn){ pstr(fd, fname[i].name); break; } - if(!fname[i].f) pfmt(fd, "%p", fn); - for(a=t->argv;a;a=a->next) pfmt(fd, " (%v)", a->words); + if(!fname[i].f) + pfmt(fd, "%p", fn); + for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words); pchr(fd, '\n'); flush(fd); } diff --git a/rc/plan9ish.c b/rc/plan9ish.c @@ -27,12 +27,11 @@ char *syssigname[]={ char* Rcmain(void) { - static char Rcmain[] = PREFIX"/etc/rcmain"; - char *rcmain = getenv("RCMAIN"); - return rcmain ? rcmain : Rcmain; + return unsharp("#9/rcmain"); } char Fdprefix[]="/dev/fd/"; +long readnb(int, char *, long); void execfinit(void); void execbind(void); void execmount(void); @@ -129,7 +128,7 @@ void Vinit(void){ for(s=*env;*s && *s!='(' && *s!='=';s++); switch(*s){ case '\0': - // pfmt(err, "rc: odd environment %q?\n", *env); + /* pfmt(err, "rc: odd environment %q?\n", *env); */ break; case '=': *s='\0'; @@ -200,7 +199,10 @@ int Waitfor(int pid, int unused0){ Waitmsg *w; char errbuf[ERRMAX]; + if(pid >= 0 && !havewaitpid(pid)) + return 0; while((w = wait()) != nil){ + delwaitpid(w->pid); if(w->pid==pid){ if(strncmp(w->msg, "signal: ", 8) == 0) fprint(mapfd(2), "%d: %s\n", w->pid, w->msg); @@ -208,7 +210,7 @@ int Waitfor(int pid, int unused0){ free(w); return 0; } - if(strncmp(w->msg, "signal: ", 8) == 0) + if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0) fprint(2, "%d: %s\n", w->pid, w->msg); for(p=runq->ret;p;p=p->ret) if(p->pid==w->pid){ @@ -218,7 +220,7 @@ int Waitfor(int pid, int unused0){ free(w); } - errstr(errbuf, sizeof errbuf); + rerrstr(errbuf, sizeof errbuf); if(strcmp(errbuf, "interrupted")==0) return -1; return 0; } @@ -412,9 +414,11 @@ int Opendir(char *name) close(f); return -1; } -int Readdir(int f, char *p) +int Readdir(int f, char *p, int onlydirs) { int n; + USED(onlydirs); /* only advisory */ + if(f<0 || f>=NFD) return 0; if(dir[f].i==dir[f].n){ /* read */ @@ -490,7 +494,7 @@ long Read(int fd, char *buf, long cnt) { int i; - i = read(fd, buf, cnt); + i = readnb(fd, buf, cnt); if(ntrap) dotrap(); return i; } @@ -547,3 +551,54 @@ void Memcpy(char *a, char *b, long n) void *Malloc(ulong n){ return malloc(n); } + +int +exitcode(char *msg) +{ + int n; + + n = atoi(msg); + if(n == 0) + n = 1; + return n; +} + +int *waitpids; +int nwaitpids; + +void +addwaitpid(int pid) +{ + waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]); + if(waitpids == 0) + panic("Can't realloc %d waitpids", nwaitpids+1); + waitpids[nwaitpids++] = pid; +} + +void +delwaitpid(int pid) +{ + int r, w; + + for(r=w=0; r<nwaitpids; r++) + if(waitpids[r] != pid) + waitpids[w++] = waitpids[r]; + nwaitpids = w; +} + +void +clearwaitpids(void) +{ + nwaitpids = 0; +} + +int +havewaitpid(int pid) +{ + int i; + + for(i=0; i<nwaitpids; i++) + if(waitpids[i] == pid) + return 1; + return 0; +} diff --git a/rc/rc.1 b/rc/rc.1 @@ -208,6 +208,11 @@ If is followed by a parenthesized list of subscripts, the value substituted is a list composed of the requested elements (origin 1). The parenthesis must follow the variable name with no spaces. +Subscripts can also take the form +.IB m - n +or +.IB m - +to indicate a sequence of elements. Assignments to variables are described below. .HP .BI $# argument diff --git a/rc/rc.h b/rc/rc.h @@ -26,7 +26,7 @@ #define YYMAXDEPTH 500 #ifndef PAREN #ifndef YYMAJOR -#include "y.tab.h" +#include "x.tab.h" #endif #endif @@ -80,6 +80,7 @@ char tok[NTOK]; #define HERE 4 #define DUPFD 5 #define CLOSE 6 +#define RDWR 7 struct var{ char *name; /* ascii name */ word *val; /* value */ diff --git a/rc/simple.c b/rc/simple.c @@ -15,22 +15,24 @@ exitnext(void){ while(c->f==Xpopredir) c++; return c->f==Xexit; } -void Xsimple(void){ + +void +Xsimple(void) +{ word *a; - thread *p=runq; + thread *p = runq; var *v; struct builtin *bp; - int pid, n; - char buf[ERRMAX]; + int pid; globlist(); - a=runq->argv->words; + a = runq->argv->words; if(a==0){ Xerror1("empty argument list"); return; } if(flag['x']) pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */ - v=gvlook(a->word); + v = gvlook(a->word); if(v->fn) execfunc(v); else{ @@ -41,10 +43,10 @@ void Xsimple(void){ poplist(); return; } - a=a->next; + a = a->next; popword(); } - for(bp=Builtin;bp->name;bp++) + for(bp = Builtin;bp->name;bp++) if(strcmp(a->word, bp->name)==0){ (*bp->fnc)(); return; @@ -58,30 +60,22 @@ void Xsimple(void){ else{ flush(err); Updenv(); /* necessary so changes don't go out again */ - switch(pid=fork()){ - case -1: + if((pid = execforkexec()) < 0){ Xerror("try again"); return; - case 0: - pushword("exec"); - execexec(); - strcpy(buf, "can't exec: "); - n = strlen(buf); - errstr(buf+n, ERRMAX-n); - Exit(buf); - default: - kidpid = pid; - poplist(); - /* interrupts don't get us out */ - while(Waitfor(pid, 1) < 0) - ; - kidpid = 0; } + + /* interrupts don't get us out */ + poplist(); + while(Waitfor(pid, 1) < 0) + ; } } } -struct word nullpath={ "", 0}; -void doredir(redir *rp) +struct word nullpath = { "", 0}; + +void +doredir(redir *rp) { if(rp){ doredir(rp->next); @@ -92,22 +86,32 @@ void doredir(redir *rp) close(rp->from); } break; - case RDUP: Dup(rp->from, rp->to); break; - case RCLOSE: close(rp->from); break; + case RDUP: + Dup(rp->from, rp->to); + break; + case RCLOSE: + close(rp->from); + break; } } } -word *searchpath(char *w){ + +word* +searchpath(char *w) +{ word *path; if(strncmp(w, "/", 1)==0 /* || strncmp(w, "#", 1)==0 */ || strncmp(w, "./", 2)==0 || strncmp(w, "../", 3)==0 - || (path=vlook("path")->val)==0) + || (path = vlook("path")->val)==0) path=&nullpath; return path; } -void execexec(void){ + +void +execexec(void) +{ popword(); /* "exec" */ if(runq->argv->words==0){ Xerror1("empty argument list"); @@ -117,19 +121,24 @@ void execexec(void){ Execute(runq->argv->words, searchpath(runq->argv->words->word)); poplist(); } -void execfunc(var *func) + +void +execfunc(var *func) { word *starval; popword(); - starval=runq->argv->words; - runq->argv->words=0; + starval = runq->argv->words; + runq->argv->words = 0; poplist(); - start(func->fn, func->pc, (struct var *)0); - runq->local=newvar(strdup("*"), runq->local); - runq->local->val=starval; - runq->local->changed=1; + start(func->fn, func->pc, runq->local); + runq->local = newvar(strdup("*"), runq->local); + runq->local->val = starval; + runq->local->changed = 1; } -int dochdir(char *word){ + +int +dochdir(char *word) +{ /* report to /dev/wdir if it exists and we're interactive */ static int wdirfd = -2; if(chdir(word)<0) return -1; @@ -141,21 +150,26 @@ int dochdir(char *word){ } return 1; } -void execcd(void){ - word *a=runq->argv->words; + +void +execcd(void) +{ + word *a = runq->argv->words; word *cdpath; char dir[512]; setstatus("can't cd"); - cdpath=vlook("cdpath")->val; + cdpath = vlook("cdpath")->val; switch(count(a)){ default: pfmt(err, "Usage: cd [directory]\n"); break; case 2: - if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath; - for(;cdpath;cdpath=cdpath->next){ + if(a->next->word[0]=='/' || cdpath==0) + cdpath=&nullpath; + for(;cdpath;cdpath = cdpath->next){ strcpy(dir, cdpath->word); - if(dir[0]) strcat(dir, "/"); + if(dir[0]) + strcat(dir, "/"); strcat(dir, a->next->word); if(dochdir(dir)>=0){ if(strlen(cdpath->word) @@ -165,10 +179,11 @@ void execcd(void){ break; } } - if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word); + if(cdpath==0) + pfmt(err, "Can't cd %s: %r\n", a->next->word); break; case 1: - a=vlook("HOME")->val; + a = vlook("home")->val; if(count(a)>=1){ if(dochdir(a->word)>=0) setstatus(""); @@ -181,14 +196,22 @@ void execcd(void){ } poplist(); } -void execexit(void){ + +void +execexit(void) +{ switch(count(runq->argv->words)){ - default: pfmt(err, "Usage: exit [status]\nExiting anyway\n"); - case 2: setstatus(runq->argv->words->next->word); + default: + pfmt(err, "Usage: exit [status]\nExiting anyway\n"); + case 2: + setstatus(runq->argv->words->next->word); case 1: Xexit(); } } -void execshift(void){ + +void +execshift(void) +{ int n; word *a; var *star; @@ -198,72 +221,87 @@ void execshift(void){ setstatus("shift usage"); poplist(); return; - case 2: n=atoi(runq->argv->words->next->word); break; - case 1: n=1; break; + case 2: + n = atoi(runq->argv->words->next->word); + break; + case 1: + n = 1; + break; } - star=vlook("*"); + star = vlook("*"); for(;n && star->val;--n){ - a=star->val->next; + a = star->val->next; efree(star->val->word); efree((char *)star->val); - star->val=a; - star->changed=1; + star->val = a; + star->changed = 1; } setstatus(""); poplist(); } -int octal(char *s) + +int +octal(char *s) { - int n=0; + int n = 0; while(*s==' ' || *s=='\t' || *s=='\n') s++; - while('0'<=*s && *s<='7') n=n*8+*s++-'0'; + while('0'<=*s && *s<='7') n = n*8+*s++-'0'; return n; } -int mapfd(int fd) + +int +mapfd(int fd) { redir *rp; - for(rp=runq->redir;rp;rp=rp->next){ + for(rp = runq->redir;rp;rp = rp->next){ switch(rp->type){ case RCLOSE: - if(rp->from==fd) fd=-1; + if(rp->from==fd) + fd=-1; break; case RDUP: case ROPEN: - if(rp->to==fd) fd=rp->from; + if(rp->to==fd) + fd = rp->from; break; } } return fd; } union code rdcmds[4]; -void execcmds(io *f) + +void +execcmds(io *f) { - static int first=1; + static int first = 1; if(first){ - rdcmds[0].i=1; - rdcmds[1].f=Xrdcmds; - rdcmds[2].f=Xreturn; - first=0; + rdcmds[0].i = 1; + rdcmds[1].f = Xrdcmds; + rdcmds[2].f = Xreturn; + first = 0; } start(rdcmds, 1, runq->local); - runq->cmdfd=f; - runq->iflast=0; + runq->cmdfd = f; + runq->iflast = 0; } -void execeval(void){ + +void +execeval(void) +{ char *cmdline, *s, *t; - int len=0; + int len = 0; word *ap; if(count(runq->argv->words)<=1){ Xerror1("Usage: eval cmd ..."); return; } - eflagok=1; - for(ap=runq->argv->words->next;ap;ap=ap->next) + eflagok = 1; + for(ap = runq->argv->words->next;ap;ap = ap->next) len+=1+strlen(ap->word); - cmdline=emalloc(len); - s=cmdline; - for(ap=runq->argv->words->next;ap;ap=ap->next){ - for(t=ap->word;*t;) *s++=*t++; + cmdline = emalloc(len); + s = cmdline; + for(ap = runq->argv->words->next;ap;ap = ap->next){ + for(t = ap->word;*t;) *s++=*t++; *s++=' '; } s[-1]='\n'; @@ -272,36 +310,39 @@ void execeval(void){ efree(cmdline); } union code dotcmds[14]; -void execdot(void){ - int iflag=0; + +void +execdot(void) +{ + int iflag = 0; int fd; list *av; - thread *p=runq; + thread *p = runq; char *zero; - static int first=1; + static int first = 1; char file[512]; word *path; if(first){ - dotcmds[0].i=1; - dotcmds[1].f=Xmark; - dotcmds[2].f=Xword; + dotcmds[0].i = 1; + dotcmds[1].f = Xmark; + dotcmds[2].f = Xword; dotcmds[3].s="0"; - dotcmds[4].f=Xlocal; - dotcmds[5].f=Xmark; - dotcmds[6].f=Xword; + dotcmds[4].f = Xlocal; + dotcmds[5].f = Xmark; + dotcmds[6].f = Xword; dotcmds[7].s="*"; - dotcmds[8].f=Xlocal; - dotcmds[9].f=Xrdcmds; - dotcmds[10].f=Xunlocal; - dotcmds[11].f=Xunlocal; - dotcmds[12].f=Xreturn; - first=0; + dotcmds[8].f = Xlocal; + dotcmds[9].f = Xrdcmds; + dotcmds[10].f = Xunlocal; + dotcmds[11].f = Xunlocal; + dotcmds[12].f = Xreturn; + first = 0; } else - eflagok=1; + eflagok = 1; popword(); if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){ - iflag=1; + iflag = 1; popword(); } /* get input file */ @@ -309,18 +350,20 @@ void execdot(void){ Xerror1("Usage: . [-i] file [arg ...]"); return; } - zero=strdup(p->argv->words->word); + zero = strdup(p->argv->words->word); popword(); fd=-1; - for(path=searchpath(zero);path;path=path->next){ + for(path = searchpath(zero);path;path = path->next){ strcpy(file, path->word); - if(file[0]) strcat(file, "/"); + if(file[0]) + strcat(file, "/"); strcat(file, zero); + if((fd = open(file, 0))>=0) break; if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */ - fd=Dup1(0); - if(fd>=0) break; + fd = Dup1(0); + if(fd>=0) + break; } - if((fd=open(file, 0))>=0) break; } if(fd<0){ pfmt(err, "%s: ", zero); @@ -331,38 +374,41 @@ void execdot(void){ /* set up for a new command loop */ start(dotcmds, 1, (struct var *)0); pushredir(RCLOSE, fd, 0); - runq->cmdfile=zero; - runq->cmdfd=openfd(fd); - runq->iflag=iflag; - runq->iflast=0; + runq->cmdfile = zero; + runq->cmdfd = openfd(fd); + runq->iflag = iflag; + runq->iflast = 0; /* push $* value */ pushlist(); - runq->argv->words=p->argv->words; + runq->argv->words = p->argv->words; /* free caller's copy of $* */ - av=p->argv; - p->argv=av->next; + av = p->argv; + p->argv = av->next; efree((char *)av); /* push $0 value */ pushlist(); pushword(zero); ndot++; } -void execflag(void){ + +void +execflag(void) +{ char *letter, *val; switch(count(runq->argv->words)){ case 2: setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set"); break; case 3: - letter=runq->argv->words->next->word; - val=runq->argv->words->next->next->word; + letter = runq->argv->words->next->word; + val = runq->argv->words->next->next->word; if(strlen(letter)==1){ if(strcmp(val, "+")==0){ - flag[(uchar)letter[0]]=flagset; + flag[(uchar)letter[0]] = flagset; break; } if(strcmp(val, "-")==0){ - flag[(uchar)letter[0]]=0; + flag[(uchar)letter[0]] = 0; break; } } @@ -372,53 +418,57 @@ void execflag(void){ } poplist(); } -void execwhatis(void){ /* mildly wrong -- should fork before writing */ + +void +execwhatis(void){ /* mildly wrong -- should fork before writing */ word *a, *b, *path; var *v; struct builtin *bp; char file[512]; struct io out[1]; int found, sep; - a=runq->argv->words->next; + a = runq->argv->words->next; if(a==0){ Xerror1("Usage: whatis name ..."); return; } setstatus(""); - out->fd=mapfd(1); - out->bufp=out->buf; - out->ebuf=&out->buf[NBUF]; - out->strp=0; - for(;a;a=a->next){ - v=vlook(a->word); + out->fd = mapfd(1); + out->bufp = out->buf; + out->ebuf = &out->buf[NBUF]; + out->strp = 0; + for(;a;a = a->next){ + v = vlook(a->word); if(v->val){ pfmt(out, "%s=", a->word); if(v->val->next==0) pfmt(out, "%q\n", v->val->word); else{ sep='('; - for(b=v->val;b && b->word;b=b->next){ + for(b = v->val;b && b->word;b = b->next){ pfmt(out, "%c%q", sep, b->word); sep=' '; } pfmt(out, ")\n"); } - found=1; + found = 1; } else - found=0; - v=gvlook(a->word); - if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); + found = 0; + v = gvlook(a->word); + if(v->fn) + pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s); else{ - for(bp=Builtin;bp->name;bp++) + for(bp = Builtin;bp->name;bp++) if(strcmp(a->word, bp->name)==0){ pfmt(out, "builtin %s\n", a->word); break; } if(!bp->name){ - for(path=searchpath(a->word);path;path=path->next){ + for(path = searchpath(a->word);path;path = path->next){ strcpy(file, path->word); - if(file[0]) strcat(file, "/"); + if(file[0]) + strcat(file, "/"); strcat(file, a->word); if(Executable(file)){ pfmt(out, "%s\n", file); @@ -435,11 +485,20 @@ void execwhatis(void){ /* mildly wrong -- should fork before writing */ poplist(); flush(err); } -void execwait(void){ + +void +execwait(void) +{ switch(count(runq->argv->words)){ - default: Xerror1("Usage: wait [pid]"); return; - case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break; - case 1: Waitfor(-1, 0); break; + default: + Xerror1("Usage: wait [pid]"); + return; + case 2: + Waitfor(atoi(runq->argv->words->next->word), 0); + break; + case 1: + Waitfor(-1, 0); + break; } poplist(); } diff --git a/rc/subr.c b/rc/subr.c @@ -2,20 +2,30 @@ #include "exec.h" #include "io.h" #include "fns.h" -char *emalloc(long n){ - char *p=(char *)Malloc(n); - if(p==0) panic("Can't malloc %d bytes", n); -/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } *//**/ + +char* +emalloc(long n) +{ + char *p = (char *)Malloc(n); + if(p==0) + panic("Can't malloc %d bytes", n); +/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/ + memset(p, 0, n); return p; } -void efree(char *p) + +void +efree(char *p) { -/* pfmt(err, "free %p\n", p); flush(err); *//**/ - if(p) free(p); +/* pfmt(err, "free %p\n", p); flush(err); /**/ + if(p) + free(p); else pfmt(err, "free 0\n"); } extern int lastword, lastdol; -void yyerror(char *m) + +void +yyerror(char *m) { pfmt(err, "rc: "); if(runq->cmdfile && !runq->iflag) @@ -24,17 +34,21 @@ void yyerror(char *m) pfmt(err, "%s: ", runq->cmdfile); else if(!runq->iflag) pfmt(err, "line %d: ", runq->lineno); - if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok); + if(tok[0] && tok[0]!='\n') + pfmt(err, "token %q: ", tok); pfmt(err, "%s\n", m); flush(err); - lastword=0; - lastdol=0; + lastword = 0; + lastdol = 0; while(lastc!='\n' && lastc!=EOF) advance(); nerror++; setvar("status", newword(m, (word *)0)); } char *bp; -void iacvt(int n){ + +static void +iacvt(int n) +{ if(n<0){ *bp++='-'; n=-n; /* doesn't work for n==-inf */ @@ -43,13 +57,17 @@ void iacvt(int n){ iacvt(n/10); *bp++=n%10+'0'; } -void itoa(char *s, long n) + +void +inttoascii(char *s, long n) { - bp=s; + bp = s; iacvt(n); *bp='\0'; } -void panic(char *s, int n) + +void +panic(char *s, int n) { pfmt(err, "rc: "); pfmt(err, s, n); diff --git a/rc/trap.c b/rc/trap.c @@ -3,22 +3,25 @@ #include "fns.h" #include "io.h" extern char *Signame[]; -void dotrap(void){ - register int i; - register struct var *trapreq; - register struct word *starval; - starval=vlook("*")->val; - while(ntrap) for(i=0;i!=NSIG;i++) while(trap[i]){ + +void +dotrap(void) +{ + int i; + struct var *trapreq; + struct word *starval; + starval = vlook("*")->val; + while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){ --trap[i]; --ntrap; if(getpid()!=mypid) Exit(getstatus()); - trapreq=vlook(Signame[i]); + trapreq = vlook(Signame[i]); if(trapreq->fn){ start(trapreq->fn, trapreq->pc, (struct var *)0); - runq->local=newvar(strdup("*"), runq->local); - runq->local->val=copywords(starval, (struct word *)0); - runq->local->changed=1; - runq->redir=runq->startredir=0; + runq->local = newvar(strdup("*"), runq->local); + runq->local->val = copywords(starval, (struct word *)0); + runq->local->changed = 1; + runq->redir = runq->startredir = 0; } else if(i==SIGINT || i==SIGQUIT){ /* diff --git a/rc/tree.c b/rc/tree.c @@ -7,108 +7,140 @@ tree *treenodes; * create and clear a new tree node, and add it * to the node list. */ -tree *newtree(void){ - tree *t=new(tree); - t->iskw=0; - t->str=0; - t->child[0]=t->child[1]=t->child[2]=0; - t->next=treenodes; - treenodes=t; + +tree* +newtree(void) +{ + tree *t = new(tree); + t->iskw = 0; + t->str = 0; + t->child[0] = t->child[1] = t->child[2] = 0; + t->next = treenodes; + treenodes = t; return t; } -void freenodes(void){ + +void +freenodes(void) +{ tree *t, *u; - for(t=treenodes;t;t=u){ - u=t->next; - if(t->str) efree(t->str); + for(t = treenodes;t;t = u){ + u = t->next; + if(t->str) + efree(t->str); efree((char *)t); } - treenodes=0; + treenodes = 0; } -tree *tree1(int type, tree *c0) + +tree* +tree1(int type, tree *c0) { return tree3(type, c0, (tree *)0, (tree *)0); } -tree *tree2(int type, tree *c0, tree *c1) + +tree* +tree2(int type, tree *c0, tree *c1) { return tree3(type, c0, c1, (tree *)0); } -tree *tree3(int type, tree *c0, tree *c1, tree *c2) + +tree* +tree3(int type, tree *c0, tree *c1, tree *c2) { tree *t; if(type==';'){ - if(c0==0) return c1; - if(c1==0) return c0; + if(c0==0) + return c1; + if(c1==0) + return c0; } - t=newtree(); - t->type=type; - t->child[0]=c0; - t->child[1]=c1; - t->child[2]=c2; + t = newtree(); + t->type = type; + t->child[0] = c0; + t->child[1] = c1; + t->child[2] = c2; return t; } -tree *mung1(tree *t, tree *c0) + +tree* +mung1(tree *t, tree *c0) { - t->child[0]=c0; + t->child[0] = c0; return t; } -tree *mung2(tree *t, tree *c0, tree *c1) + +tree* +mung2(tree *t, tree *c0, tree *c1) { - t->child[0]=c0; - t->child[1]=c1; + t->child[0] = c0; + t->child[1] = c1; return t; } -tree *mung3(tree *t, tree *c0, tree *c1, tree *c2) + +tree* +mung3(tree *t, tree *c0, tree *c1, tree *c2) { - t->child[0]=c0; - t->child[1]=c1; - t->child[2]=c2; + t->child[0] = c0; + t->child[1] = c1; + t->child[2] = c2; return t; } -tree *epimung(tree *comp, tree *epi) + +tree* +epimung(tree *comp, tree *epi) { tree *p; - if(epi==0) return comp; - for(p=epi;p->child[1];p=p->child[1]); - p->child[1]=comp; + if(epi==0) + return comp; + for(p = epi;p->child[1];p = p->child[1]); + p->child[1] = comp; return epi; } /* * Add a SIMPLE node at the root of t and percolate all the redirections * up to the root. */ -tree *simplemung(tree *t) + +tree* +simplemung(tree *t) { tree *u; struct io *s; - t=tree1(SIMPLE, t); - s=openstr(); + t = tree1(SIMPLE, t); + s = openstr(); pfmt(s, "%t", t); - t->str=strdup(s->strp); + t->str = strdup(s->strp); closeio(s); - for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){ + for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){ if(u->child[1]->type==DUP || u->child[1]->type==REDIR){ - u->child[1]->child[1]=t; - t=u->child[1]; - u->child[1]=0; + u->child[1]->child[1] = t; + t = u->child[1]; + u->child[1] = 0; } } return t; } -tree *token(char *str, int type) + +tree* +token(char *str, int type) { - tree *t=newtree(); - t->type=type; - t->str=strdup(str); + tree *t = newtree(); + t->type = type; + t->str = strdup(str); return t; } -void freetree(tree *p) + +void +freetree(tree *p) { - if(p==0) return; + if(p==0) + return; freetree(p->child[0]); freetree(p->child[1]); freetree(p->child[2]); - if(p->str) efree(p->str); + if(p->str) + efree(p->str); efree((char *)p); } diff --git a/rc/unixcrap.c b/rc/unixcrap.c @@ -2,6 +2,8 @@ #include <sys/time.h> #include <sys/stat.h> #include <sys/resource.h> +#include <errno.h> +#include <fcntl.h> #include <libc.h> #include "rc.h" #include "exec.h" @@ -209,3 +211,26 @@ out: poplist(); flush(err); } + +/* + * Cope with non-blocking read. + */ +long +readnb(int fd, char *buf, long cnt) +{ + int n, didreset; + int flgs; + + didreset = 0; + while((n = read(fd, buf, cnt)) == -1) + if(!didreset && errno == EAGAIN){ + if((flgs = fcntl(fd, F_GETFL, 0)) == -1) + return -1; + flgs &= ~O_NONBLOCK; + if(fcntl(fd, F_SETFL, flgs) == -1) + return -1; + didreset = 1; + } + + return n; +} diff --git a/rc/var.c b/rc/var.c @@ -1,9 +1,11 @@ #include "rc.h" #include "exec.h" #include "fns.h" -int hash(char *s, int n) + +int +hash(char *s, int n) { - register int h=0, i=1; + int h = 0, i = 1; while(*s) h+=*s++*i++; h%=n; return h<0?h+n:h; @@ -14,16 +16,21 @@ struct kw{ int type; struct kw *next; }*kw[NKW]; -void kenter(int type, char *name) + +void +kenter(int type, char *name) { - register int h=hash(name, NKW); - register struct kw *p=new(struct kw); - p->type=type; - p->name=name; - p->next=kw[h]; - kw[h]=p; + int h = hash(name, NKW); + struct kw *p = new(struct kw); + p->type = type; + p->name = name; + p->next = kw[h]; + kw[h] = p; } -void kinit(void){ + +void +kinit(void) +{ kenter(FOR, "for"); kenter(IN, "in"); kenter(WHILE, "while"); @@ -35,47 +42,59 @@ void kinit(void){ kenter(SWITCH, "switch"); kenter(FN, "fn"); } -tree *klook(char *name) + +tree* +klook(char *name) { struct kw *p; - tree *t=token(name, WORD); - for(p=kw[hash(name, NKW)];p;p=p->next) + tree *t = token(name, WORD); + for(p = kw[hash(name, NKW)];p;p = p->next) if(strcmp(p->name, name)==0){ - t->type=p->type; - t->iskw=1; + t->type = p->type; + t->iskw = 1; break; } return t; } -var *gvlook(char *name) + +var* +gvlook(char *name) { - int h=hash(name, NVAR); + int h = hash(name, NVAR); var *v; - for(v=gvar[h];v;v=v->next) if(strcmp(v->name, name)==0) return v; - return gvar[h]=newvar(strdup(name), gvar[h]); + for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v; + return gvar[h] = newvar(strdup(name), gvar[h]); } -var *vlook(char *name) + +var* +vlook(char *name) { var *v; if(runq) - for(v=runq->local;v;v=v->next) + for(v = runq->local;v;v = v->next) if(strcmp(v->name, name)==0) return v; return gvlook(name); } -void _setvar(char *name, word *val, int callfn) + +void +_setvar(char *name, word *val, int callfn) { - register struct var *v=vlook(name); + struct var *v = vlook(name); freewords(v->val); v->val=val; v->changed=1; if(callfn && v->changefn) v->changefn(v); } -void setvar(char *name, word *val) + +void +setvar(char *name, word *val) { _setvar(name, val, 1); } -void bigpath(var *v) + +void +bigpath(var *v) { /* convert $PATH to $path */ char *p, *q; @@ -107,19 +126,42 @@ void bigpath(var *v) } _setvar("path", w, 0); } -void littlepath(var *v) + +char* +list2strcolon(word *words) +{ + char *value, *s, *t; + int len = 0; + word *ap; + for(ap = words;ap;ap = ap->next) + len+=1+strlen(ap->word); + value = emalloc(len+1); + s = value; + for(ap = words;ap;ap = ap->next){ + for(t = ap->word;*t;) *s++=*t++; + *s++=':'; + } + if(s==value) + *s='\0'; + else s[-1]='\0'; + return value; +} +void +littlepath(var *v) { /* convert $path to $PATH */ char *p; word *w; - p = _list2str(v->val, ':'); + p = list2strcolon(v->val); w = new(word); w->word = p; w->next = nil; _setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */ } -void pathinit(void) + +void +pathinit(void) { var *v; diff --git a/sed/sed.1 b/sed/sed.1 @@ -4,10 +4,7 @@ sed \- stream editor .SH SYNOPSIS .B sed [ -.B -n -] -[ -.B -g +.B -gln ] [ .B -e @@ -44,6 +41,11 @@ option suppresses the default output; .B -g causes all substitutions to be global, as if suffixed .BR g . +The +.B -l +option causes +.I sed +to flush its output buffer after every newline. .PP A script consists of editing commands, one per line, of the following form: diff --git a/sed/sed.c b/sed/sed.c @@ -16,7 +16,7 @@ enum { LBSIZE = 8192, /* input line size */ LABSIZE = 50, /* max label name size */ MAXSUB = 10, /* max number of sub reg exp */ - MAXFILES = 120, /* max output files */ + MAXFILES = 120 /* max output files */ }; /* An address is a line #, a R.E., "$", a reference to the last * R.E., or nothing. @@ -27,7 +27,7 @@ typedef struct { A_DOL, A_LINE, A_RE, - A_LAST, + A_LAST }type; union { long line; /* Line # */ @@ -137,6 +137,7 @@ Rune *hspend = holdsp; /* End of hold data */ int nflag; /* Command line flags */ int gflag; +int lflag; int dolflag; /* Set when at true EOF */ int sflag; /* Set when substitution done */ @@ -234,6 +235,9 @@ main(int argc, char **argv) case 'g': gflag++; continue; + case 'l': + lflag++; + continue; default: fprint(2, "sed: Unknown flag: %c\n", ARGC()); continue; @@ -990,7 +994,7 @@ match(Reprog *pattern, Rune *buf) return 0; subexp[0].s.rsp = buf; subexp[0].e.rep = 0; - if (rregexec(pattern, linebuf, subexp, MAXSUB)) { + if (rregexec(pattern, linebuf, subexp, MAXSUB) > 0) { loc1 = subexp[0].s.rsp; loc2 = subexp[0].e.rep; return 1; @@ -1315,6 +1319,8 @@ putline(Biobuf *bp, Rune *buf, int n) while (n--) Bputrune(bp, *buf++); Bputc(bp, '\n'); + if(lflag) + Bflush(bp); } int diff --git a/sort/sort.c b/sort/sort.c @@ -34,7 +34,7 @@ enum NSzerofract, NSexp, NSexpsign, - NSexpdigit, + NSexpdigit }; typedef struct Line Line; @@ -243,8 +243,7 @@ notifyf(void *a, char *s) done(0); if(strncmp(s, "sys: write on closed pipe", 25) == 0) done(0); - fprint(2, "sort: note: %s\n", s); - abort(); + noted(NDFLT); } Line* @@ -1583,7 +1582,7 @@ Rune* month[12] = enum { - Threshold = 14, + Threshold = 14 }; void rsort4(Key***, ulong, int); diff --git a/test/test.1 b/test/test.1 @@ -17,7 +17,7 @@ The following primitives are used to construct .TP "\w'\fIn1 \fL-eq \fIn2\fLXX'u" .BI -r " file" True if the file exists (is accessible) and is readable. -.PD +.PD0 .TP .BI -w " file" True if the file exists and is writable. @@ -146,7 +146,7 @@ following operators: .TP "\w'\fL( \fIexpr\fL )XX'u" .B ! unary negation operator -.PD +.PD0 .TP .B -o binary diff --git a/test/test.c b/test/test.c @@ -6,13 +6,15 @@ * Plan 9 additions: * -A file exists and is append-only * -L file exists and is exclusive-use + * -T file exists and is temporary */ #include <u.h> #include <libc.h> -#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0)) -extern int isatty(int); /* <unistd.h> */ +#define isatty plan9_isatty + +#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0)) int ap; int ac; @@ -23,14 +25,21 @@ void synbad(char *, char *); int fsizep(char *); int isdir(char *); int isreg(char *); +int isatty(int); int isint(char *, int *); +int isolder(char *, char *); +int isolderthan(char *, char *); +int isnewerthan(char *, char *); int hasmode(char *, ulong); int tio(char *, int); int e(void), e1(void), e2(void), e3(void); +char *nxtarg(int); void main(int argc, char *argv[]) { + int r; + char *c; ac = argc; av = argv; ap = 1; if(EQ(argv[0],"[")) { @@ -38,8 +47,16 @@ main(int argc, char *argv[]) synbad("] missing",""); } argv[ac] = 0; - if (ac<=1) exits("usage"); - exits(e()?0:"false"); + if (ac<=1) + exits("usage"); + r = e(); + /* + * nice idea but short-circuit -o and -a operators may have + * not consumed their right-hand sides. + */ + if(0 && (c = nxtarg(1)) != nil) + synbad("unexpected operator/operand: ", c); + exits(r?0:"false"); } char * @@ -66,27 +83,32 @@ nxtintarg(int *pans) } int -e(void) { +e(void) +{ int p1; p1 = e1(); - if (EQ(nxtarg(1), "-o")) return(p1 || e()); + if (EQ(nxtarg(1), "-o")) + return(p1 || e()); ap--; return(p1); } int -e1(void) { +e1(void) +{ int p1; p1 = e2(); - if (EQ(nxtarg(1), "-a")) return (p1 && e1()); + if (EQ(nxtarg(1), "-a")) + return (p1 && e1()); ap--; return(p1); } int -e2(void) { +e2(void) +{ if (EQ(nxtarg(0), "!")) return(!e2()); ap--; @@ -94,16 +116,16 @@ e2(void) { } int -e3(void) { - int p1; - char *a; - char *p2; - int int1, int2; +e3(void) +{ + int p1, int1, int2; + char *a, *p2; a = nxtarg(0); if(EQ(a, "(")) { p1 = e(); - if(!EQ(nxtarg(0), ")")) synbad(") expected",""); + if(!EQ(nxtarg(0), ")")) + synbad(") expected",""); return(p1); } @@ -113,6 +135,9 @@ e3(void) { if(EQ(a, "-L")) return(hasmode(nxtarg(0), DMEXCL)); + if(EQ(a, "-T")) + return(hasmode(nxtarg(0), DMTMP)); + if(EQ(a, "-f")) return(isreg(nxtarg(0))); @@ -147,10 +172,12 @@ e3(void) { return(fsizep(nxtarg(0))); if(EQ(a, "-t")) - if(ap>=ac || !nxtintarg(&int1)) + if(ap>=ac) return(isatty(1)); - else + else if(nxtintarg(&int1)) return(isatty(int1)); + else + synbad("not a valid file descriptor number ", ""); if(EQ(a, "-n")) return(!EQ(nxtarg(0), "")); @@ -166,8 +193,17 @@ e3(void) { if(EQ(p2, "!=")) return(!EQ(nxtarg(0), a)); + if(EQ(p2, "-older")) + return(isolder(nxtarg(0), a)); + + if(EQ(p2, "-ot")) + return(isolderthan(nxtarg(0), a)); + + if(EQ(p2, "-nt")) + return(isnewerthan(nxtarg(0), a)); + if(!isint(a, &int1)) - return(!EQ(a,"")); + synbad("unexpected operator/operand: ", p2); if(nxtintarg(&int2)){ if(EQ(p2, "-eq")) @@ -201,9 +237,10 @@ localstat(char *f, Dir *dir) Dir *d; d = dirstat(f); - if(d == 0) + if(d == nil) return(-1); *dir = *d; + free(d); dir->name = 0; dir->uid = 0; dir->gid = 0; @@ -218,9 +255,10 @@ localfstat(int f, Dir *dir) Dir *d; d = dirfstat(f); - if(d == 0) + if(d == nil) return(-1); *dir = *d; + free(d); dir->name = 0; dir->uid = 0; dir->gid = 0; @@ -259,6 +297,18 @@ isreg(char *f) } int +isatty(int fd) +{ + Dir d1, d2; + + if(localfstat(fd, &d1) < 0) + return 0; + if(localstat("/dev/cons", &d2) < 0) + return 0; + return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path; +} + +int fsizep(char *f) { Dir dir; @@ -290,3 +340,72 @@ isint(char *s, int *pans) *pans = strtol(s, &ep, 0); return (*ep == 0); } + +int +isolder(char *pin, char *f) +{ + char *p = pin; + ulong n, m; + Dir dir; + + if(localstat(f,&dir)<0) + return(0); + + /* parse time */ + n = 0; + while(*p){ + m = strtoul(p, &p, 0); + switch(*p){ + case 0: + n = m; + break; + case 'y': + m *= 12; + /* fall through */ + case 'M': + m *= 30; + /* fall through */ + case 'd': + m *= 24; + /* fall through */ + case 'h': + m *= 60; + /* fall through */ + case 'm': + m *= 60; + /* fall through */ + case 's': + n += m; + p++; + break; + default: + synbad("bad time syntax, ", pin); + } + } + + return(dir.mtime+n < time(0)); +} + +int +isolderthan(char *a, char *b) +{ + Dir ad, bd; + + if(localstat(a, &ad)<0) + return(0); + if(localstat(b, &bd)<0) + return(0); + return ad.mtime > bd.mtime; +} + +int +isnewerthan(char *a, char *b) +{ + Dir ad, bd; + + if(localstat(a, &ad)<0) + return(0); + if(localstat(b, &bd)<0) + return(0); + return ad.mtime < bd.mtime; +} diff --git a/touch/touch.c b/touch/touch.c @@ -3,6 +3,7 @@ int touch(int, char *); ulong now; +int tflag; void usage(void) @@ -20,6 +21,7 @@ main(int argc, char **argv) now = time(0); ARGBEGIN{ case 't': + tflag = 1; now = strtoul(EARGF(usage()), 0, 0); break; case 'c': @@ -52,11 +54,15 @@ touch(int nocreate, char *name) fprint(2, "touch: %s: cannot wstat: %r\n", name); return 1; } - if ((fd = create(name, OREAD, 0666)) < 0) { + if((fd = create(name, OREAD, 0666)) < 0) { fprint(2, "touch: %s: cannot create: %r\n", name); return 1; } - dirfwstat(fd, &stbuff); + if(tflag && dirfwstat(fd, &stbuff) < 0){ + fprint(2, "touch: %s: cannot wstat: %r\n", name); + close(fd); + return 1; + } close(fd); return 0; } diff --git a/yacc/yacc.c b/yacc/yacc.c @@ -98,7 +98,7 @@ enum EMPTY = 1, WHOKNOWS = 0, OK = 1, - NOMORE = -1000, + NOMORE = -1000 }; /* macros for getting associativity and precedence levels */ @@ -1223,7 +1223,7 @@ setup(int argc, char *argv[]) openup(stemc, dflag, vflag, ytab, ytabc); fout = dflag?fdefine:ftable; if(yyarg){ - Bprint(fdefine, "#define\tYYARG\t1\n\n"); + Bprint(ftable, "#define\tYYARG\t1\n\n"); } if((fd = mkstemp(ttempname)) >= 0){ tempname = ttempname;