upgraded 9base to p9p 20090731 - 9base - revived minimalist port of Plan 9 user… | |
git clone git://git.suckless.org/9base | |
Log | |
Files | |
Refs | |
README | |
LICENSE | |
--- | |
commit abc072187111c9098f80518e9c8d0b81ae1577d0 | |
parent 89cb321008eab13102fa98bd1b28caadc2c5218e | |
Author: Anselm R Garbe <[email protected]> | |
Date: Fri, 31 Jul 2009 21:02:58 +0100 | |
upgraded 9base to p9p 20090731 | |
Diffstat: | |
M Makefile | 2 +- | |
A awk/README | 13 +++++++++++++ | |
M awk/awk.h | 1 + | |
M awk/awkgram.y | 1 + | |
M awk/lex.c | 3 ++- | |
M awk/lib.c | 27 +++++++++++++++++++++++++++ | |
M awk/main.c | 3 ++- | |
M awk/maketab.c | 1 + | |
M awk/parse.c | 1 + | |
M awk/proto.h | 3 +++ | |
M awk/re.c | 18 +++++++++--------- | |
M awk/run.c | 25 ++++++++++++++++--------- | |
M awk/tran.c | 1 + | |
M bc/bc.1 | 2 +- | |
M bc/bc.y | 181 ++++++++++++++++-------------… | |
M config.mk | 4 +++- | |
M dc/dc.c | 31 ++++++++---------------------… | |
M grep/comp.c | 6 +++--- | |
M grep/main.c | 14 +++++++++----- | |
M grep/sub.c | 2 +- | |
M lib9/Makefile | 199 +++++++++++++++++++++++++++++… | |
M lib9/_exits.c | 6 +++--- | |
M lib9/_p9dialparse.c | 5 ++--- | |
M lib9/_p9dir.c | 144 ++++++++++++++++-------------… | |
M lib9/atexit.c | 4 +++- | |
M lib9/bio.h | 21 +++------------------ | |
M lib9/bio/bbuffered.c | 1 - | |
M lib9/bio/bflush.c | 1 - | |
M lib9/bio/bgetc.c | 1 - | |
M lib9/bio/bgetd.c | 1 - | |
M lib9/bio/binit.c | 7 ++----- | |
M lib9/bio/boffset.c | 5 ++--- | |
M lib9/bio/brdline.c | 1 - | |
M lib9/bio/brdstr.c | 2 -- | |
M lib9/bio/bread.c | 1 - | |
M lib9/bio/bseek.c | 11 ++++------- | |
M lib9/bio/bvprint.c | 7 +++---- | |
M lib9/bio/bwrite.c | 1 - | |
M lib9/bio/lib9.std.h | 8 +++++++- | |
M lib9/convD2M.c | 61 +++++++++++++++++++++++++----… | |
M lib9/convM2D.c | 50 ++++++++++++++++++++++++++---… | |
M lib9/convM2S.c | 17 ++++++++++++++++- | |
M lib9/convS2M.c | 28 +++++++++++++++++++++++++--- | |
A lib9/crypt.c | 68 +++++++++++++++++++++++++++++… | |
M lib9/ctime.c | 157 +++++++++++++++++++++++++++--… | |
M lib9/debugmalloc.c | 16 ++++++++-------- | |
M lib9/dial.c | 21 ++++++++++++++------- | |
M lib9/dirfwstat.c | 6 +++++- | |
M lib9/dirread.c | 10 ++++++++-- | |
M lib9/dirwstat.c | 24 ++++++++++++++++++------ | |
M lib9/encodefmt.c | 11 ++--------- | |
M lib9/errstr.c | 2 +- | |
A lib9/exitcode.c | 9 +++++++++ | |
M lib9/fcallfmt.c | 4 ++-- | |
M lib9/fmt.h | 17 ++++++++++++++++- | |
M lib9/fmt/LICENSE | 19 +++++++++++-------- | |
C lib9/fmt/LICENSE -> lib9/fmt/NOTICE | 0 | |
C lib9/fmt/LICENSE -> lib9/fmt/README | 0 | |
M lib9/fmt/charstod.c | 14 +------------- | |
M lib9/fmt/dofmt.c | 128 +++++++++++++++++++++++------… | |
M lib9/fmt/dorfmt.c | 25 +++++++------------------ | |
M lib9/fmt/errfmt.c | 14 +------------- | |
M lib9/fmt/fltfmt.c | 748 +++++++++++++++++++++--------… | |
M lib9/fmt/fmt.c | 17 +++-------------- | |
M lib9/fmt/fmtdef.h | 27 ++++++++------------------- | |
M lib9/fmt/fmtfd.c | 18 ++++-------------- | |
M lib9/fmt/fmtfdflush.c | 16 ++-------------- | |
A lib9/fmt/fmtlocale.c | 55 +++++++++++++++++++++++++++++… | |
M lib9/fmt/fmtlock.c | 14 +------------- | |
A lib9/fmt/fmtnull.c | 33 +++++++++++++++++++++++++++++… | |
M lib9/fmt/fmtprint.c | 14 +------------- | |
M lib9/fmt/fmtquote.c | 25 ++++++++++--------------- | |
M lib9/fmt/fmtrune.c | 14 +------------- | |
M lib9/fmt/fmtstr.c | 15 ++------------- | |
M lib9/fmt/fmtvprint.c | 14 +------------- | |
M lib9/fmt/fprint.c | 14 +------------- | |
A lib9/fmt/nan.h | 4 ++++ | |
M lib9/fmt/nan64.c | 59 ++++++++++++++++++-----------… | |
M lib9/fmt/plan9.h | 5 +++++ | |
M lib9/fmt/pow10.c | 14 +------------- | |
M lib9/fmt/print.c | 14 +------------- | |
M lib9/fmt/runefmtstr.c | 15 ++------------- | |
M lib9/fmt/runeseprint.c | 14 +------------- | |
M lib9/fmt/runesmprint.c | 14 +------------- | |
M lib9/fmt/runesnprint.c | 14 +------------- | |
M lib9/fmt/runesprint.c | 14 +------------- | |
M lib9/fmt/runevseprint.c | 15 ++------------- | |
M lib9/fmt/runevsmprint.c | 21 +++++---------------- | |
M lib9/fmt/runevsnprint.c | 15 ++------------- | |
M lib9/fmt/seprint.c | 14 +------------- | |
M lib9/fmt/smprint.c | 14 +------------- | |
M lib9/fmt/snprint.c | 14 +------------- | |
M lib9/fmt/sprint.c | 21 ++++++--------------- | |
M lib9/fmt/strtod.c | 20 ++++---------------- | |
M lib9/fmt/test.c | 35 +++++++++++++++++++----------… | |
M lib9/fmt/vfprint.c | 14 +------------- | |
M lib9/fmt/vseprint.c | 15 ++------------- | |
M lib9/fmt/vsmprint.c | 21 +++++---------------- | |
M lib9/fmt/vsnprint.c | 15 ++------------- | |
A lib9/getcallerpc-arm.c | 8 ++++++++ | |
M lib9/getnetconn.c | 4 ++-- | |
M lib9/getns.c | 25 ++++++++++++++++++++++++- | |
M lib9/lib9.h | 19 ++----------------- | |
M lib9/libc.h | 17 ++++++++++++----- | |
M lib9/malloctag.c | 4 ---- | |
M lib9/nan.c | 2 +- | |
A lib9/netcrypt.c | 18 ++++++++++++++++++ | |
M lib9/netmkaddr.c | 38 +++++++++++++++++++----------… | |
M lib9/notify.c | 9 +++++---- | |
M lib9/nrand.c | 2 -- | |
M lib9/nulldir.c | 2 +- | |
M lib9/opentemp.c | 13 +++++++++---- | |
A lib9/pin.c | 11 +++++++++++ | |
M lib9/portdate | 85 ++++++++++++++++++++---------… | |
M lib9/post9p.c | 93 +++++++++++++++++++++--------… | |
M lib9/rand.c | 3 --- | |
M lib9/readn.c | 1 - | |
M lib9/regex/regcomp.c | 10 +++++----- | |
M lib9/regex/regexec.c | 2 +- | |
M lib9/regex/rregexec.c | 19 +++++++++---------- | |
M lib9/rfork.c | 10 +++++++--- | |
M lib9/sendfd.c | 5 ++++- | |
M lib9/sleep.c | 12 ++++++++++++ | |
M lib9/sysfatal.c | 5 ----- | |
A lib9/test.c | 8 ++++++++ | |
A lib9/testfltfmt.c | 183 +++++++++++++++++++++++++++++… | |
A lib9/testfmt.c | 148 +++++++++++++++++++++++++++++… | |
A lib9/testprint.c | 14 ++++++++++++++ | |
A lib9/tm2sec.c | 110 +++++++++++++++++++++++++++++… | |
M lib9/truerand.c | 2 +- | |
M lib9/u.h | 23 ++++++++++++++++++++--- | |
M lib9/utf.h | 2 +- | |
A lib9/utf/NOTICE | 13 +++++++++++++ | |
A lib9/utf/README | 13 +++++++++++++ | |
C lib9/lib9.h -> lib9/utf/lib9.h | 0 | |
M lib9/utf/rune.c | 2 +- | |
M lib9/utf/utfecpy.c | 1 + | |
A lib9/write.c | 23 +++++++++++++++++++++++ | |
A lib9/zoneinfo.c | 215 +++++++++++++++++++++++++++++… | |
A lib9/zoneinfo.h | 19 +++++++++++++++++++ | |
M ls/ls.c | 11 +++++------ | |
D mk/Makefile | 37 -----------------------------… | |
D mk/NOTICE | 27 --------------------------- | |
D mk/README | 7 ------- | |
D mk/arc.c | 52 -----------------------------… | |
D mk/archive.c | 253 -----------------------------… | |
D mk/bufblock.c | 88 -----------------------------… | |
D mk/env.c | 149 -----------------------------… | |
D mk/file.c | 90 -----------------------------… | |
D mk/fns.h | 88 -----------------------------… | |
D mk/graph.c | 279 -----------------------------… | |
D mk/job.c | 33 -----------------------------… | |
D mk/lex.c | 146 -----------------------------… | |
D mk/main.c | 287 -----------------------------… | |
D mk/match.c | 49 -----------------------------… | |
D mk/mk.1 | 691 -----------------------------… | |
D mk/mk.c | 234 -----------------------------… | |
D mk/mk.h | 182 -----------------------------… | |
D mk/parse.c | 318 -----------------------------… | |
D mk/rc.c | 194 ------------------------------ | |
D mk/recipe.c | 117 -----------------------------… | |
D mk/rule.c | 110 -----------------------------… | |
D mk/run.c | 296 -----------------------------… | |
D mk/sh.c | 206 -----------------------------… | |
D mk/shell.c | 80 -----------------------------… | |
D mk/shprint.c | 125 -----------------------------… | |
D mk/symtab.c | 97 ------------------------------ | |
D mk/sys.h | 5 ----- | |
D mk/sys.std.h | 22 ---------------------- | |
D mk/unix.c | 341 -----------------------------… | |
D mk/var.c | 41 -----------------------------… | |
D mk/varsub.c | 256 -----------------------------… | |
D mk/word.c | 180 -----------------------------… | |
M rc/Makefile | 3 ++- | |
M rc/code.c | 226 +++++++++++++++++++----------… | |
M rc/exec.c | 1031 ++++++++++++++++-------------… | |
M rc/exec.h | 10 +++++++--- | |
M rc/fns.h | 14 ++++++++++---- | |
M rc/getflags.c | 171 ++++++++++++++++++-----------… | |
M rc/glob.c | 165 +++++++++++++++++++----------… | |
M rc/havefork.c | 53 +++++++++++++++++++++++++----… | |
M rc/here.c | 97 ++++++++++++++++++-----------… | |
M rc/io.c | 231 +++++++++++++++++++++--------… | |
M rc/io.h | 6 +++--- | |
M rc/lex.c | 280 ++++++++++++++++++-----------… | |
M rc/pcmd.c | 107 +++++++++++++++++++++--------… | |
M rc/pfnc.c | 16 ++++++++++------ | |
M rc/plan9ish.c | 71 +++++++++++++++++++++++++++--… | |
M rc/rc.1 | 5 +++++ | |
M rc/rc.h | 3 ++- | |
M rc/simple.c | 331 ++++++++++++++++++-----------… | |
M rc/subr.c | 48 +++++++++++++++++++++--------… | |
M rc/trap.c | 25 ++++++++++++++----------- | |
M rc/tree.c | 132 +++++++++++++++++++----------… | |
M rc/unixcrap.c | 25 +++++++++++++++++++++++++ | |
M rc/var.c | 98 ++++++++++++++++++++++-------… | |
M sed/sed.1 | 10 ++++++---- | |
M sed/sed.c | 12 +++++++++--- | |
M sort/sort.c | 7 +++---- | |
M test/test.1 | 4 ++-- | |
M test/test.c | 159 +++++++++++++++++++++++++++--… | |
M touch/touch.c | 10 ++++++++-- | |
M yacc/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 t… | |
+Lucent Public License version 1.02 [http://www.opensource.org/licenses/lucent1… | |
+ | |
+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 a… | |
} | |
} | |
} | |
+ | |
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'] [-Ffie… | |
+ fprintf(stderr, "Usage: %s [-F fieldsep] [-mf n] [-mr n] [-v v… | |
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 … | |
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 pa… | |
recbld(); | |
return(x); | |
} | |
- if (notlegal(a->nobj)) /* probably a Cell* but too risk… | |
+ nobj = a->nobj; | |
+ if (notlegal(nobj)) /* probably a Cell* but too risky t… | |
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) … | |
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.… | |
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) /* ha… | |
*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 … | |
*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. -D… | |
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 *ph… | |
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… | |
/* 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… | |
/* 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… | |
#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.… | |
- | |
- 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 per… | |
-#define OTRUNC 16 /* or'ed in (except for exec), truncate… | |
-#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 o… | |
-#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 … | |
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__) || defi… | |
/* 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__) || de… | |
+#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. V… | |
+ * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in P… | |
+ * \x00: repeat previous indefinitely | |
+ * \x**: count that many | |
+ */ | |
+ char *grouping; /* descriptor of separator place… | |
}; | |
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 … | |
- * 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 PURP… | |
+ */ | |
This is a Unix port of the Plan 9 formatted I/O package. | |
-Please send comments about the packaging | |
-to Russ Cox <[email protected]>. | |
+Please send comments about the packaging to Russ Cox <[email protected]>. | |
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 bu… | |
- * 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 FmtWidt… | |
*/ | |
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 … | |
+ 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 z… | |
+ * (if the value and precision are both 0, a single 0 is print… | |
+ */ | |
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & Fm… | |
+ *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 u… | |
+ * decimal is known to be 9s or we wouldn't | |
+ * have gotten this far. (e.g., 10000-1 => 09… | |
+ */ | |
+ *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, newndigi… | |
+ /* | |
+ * 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, n… | |
+ /* | |
+ * 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.0… | |
+ 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] … | |
+ 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; av… | |
}; | |
-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 … | |
- * 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, i… | |
@@ -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 strin… | |
+ if(group == 0xFF || group == 0x7f || group == 0x00) | |
+ return 0; | |
+ if(*ndig > group){ | |
+ /* if we're at end of string, continue with this grouping; els… | |
+ 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… | |
/* 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.nb… | |
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nb… | |
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, 3333333333333L… | |
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333L… | |
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 11234… | |
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 = (u… | |
+# 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 addr… | |
+ 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, (c… | |
+ 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… | |
+ verify(smprint("e: %e %e %e", 3.14159, 3.14159e10, 3.14159e-10), "e: 3… | |
+ verify(smprint("f: %f %f %f", 3.14159, 3.14159e10, 3.14159e-10), "f: 3… | |
+ 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.000000000000000000000000000000000000… | |
+ verify(smprint("%.100g", 1.0), "1"); | |
+ verify(smprint("%0100f", 1.0), "00000000000000000000000000000000000000… | |
+ 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 0002… | |
+ verify(smprint("%3$Zd %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "11… | |
+ verify(smprint("%3$d %4$*5$06d %2$d %1$d", 444, 333, 111, 222, 20), "1… | |
+ verify(smprint("%3$hd %4$*5$06d %2$d %1$d", 444, 333, (short)111, 222,… | |
+ verify(smprint("%3$\xe2\x98\xba""d %5$06d %2$d %1$d", 444, 333, 555, 1… | |
+ | |
+ /* 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,0… | |
+#ifdef PLAN9PORT | |
+ verify(smprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111… | |
+#else | |
+ verify(smprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:11… | |
+#endif | |
+ verify(smprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL)… | |
+ verify(smprint("%'019lld %'019lld %'019lld", 1LL, 222222222LL, 3333333… | |
+#ifdef PLAN9PORT | |
+ verify(smprint("%'llux %'lluX %'llub", 0x111111111111LL, 0xabcd1234567… | |
+#else | |
+ verify(smprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL… | |
+#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""… | |
+#ifdef PLAN9PORT | |
+ verify(mysmprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "11… | |
+#else | |
+ verify(mysmprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:… | |
+#endif | |
+ verify(mysmprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333L… | |
+ verify(mysmprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678… | |
+ 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 … | |
+ 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 tran… | |
+ */ | |
+ if (ti->t+ti->tzoff > secs) | |
+ if (zonetinfo(&ti1, i-1)!=-1) | |
+ ti = &ti1; | |
+ } else | |
+ /* | |
+ * west of GMT; check next local time transiti… | |
+ */ | |
+ 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… | |
+ 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); … | |
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… | |
+# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5… | |
/* 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__ ((wea… | |
+# undef AUTOFRAMEWORK | |
+# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attri… | |
# else | |
# undef AUTOLIB | |
# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute_… | |
+# undef AUTOFRAMEWORK | |
+# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x … | |
# 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 U… | |
Runeself = 0x80, /* rune and UTF sequences are t… | |
- 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 … | |
+ * 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 … | |
+ * 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 abb… | |
+ | |
+ 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->tzo… | |
+ 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, … | |
+ 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 %*u… | |
+ "%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 ([email protected]). All … | |
-Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved. | |
-Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com… | |
- | |
-Under a licence agreement with Lucent Technologies Inc. effective 1st March 20… | |
-Vita Nuova Holdings Limited has the right to determine (within a specified sco… | |
-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… | |
-of any warranty: for this software, note that includes this NOTICE file in par… | |
- | |
-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 <[email protected]> | |
- | |
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 archiv… | |
- 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… | |
- Bprint(&bout, "%s doesn't exist: assuming it w… | |
- 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®EXP) | |
- 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®EXP) && 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 cac… | |
- 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 || … | |
- 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, "",… | |
- 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 || … | |
- if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR)) | |
- continue; | |
- if(r->attr®EXP){ | |
- 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)) con… | |
- } | |
- 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®EXP) | |
- regsub(w->s, buf, sizeof buf, rmatch, … | |
- else | |
- subst(stem, w->s, buf); | |
- a->next = newarc(applyrules(buf, cnt), r, stem… | |
- 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->nam… | |
- 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 %… | |
- 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, … | |
-{ | |
- 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' nprere… | |
- wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wt… | |
- 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 new… | |
- 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… | |
- 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]]… | |
- 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, nod… | |
- if(node->flags&BEINGMADE) | |
- return(did); | |
- if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p,… | |
- if(explain) | |
- fprint(1, "unpretending %s(%ld) because %s is out of d… | |
- 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", n… | |
- 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|CANPR… | |
- && 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->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 b… | |
- a->n->name, node->name, ra->n? ra->n->name : "… | |
- | |
- unpretend(a->n); | |
- did = work(a->n, node, a) || did; | |
- ready = 0; | |
- } | |
- if(ready == 0) /* try later unless nothing has happened for -k'… | |
- 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, n… | |
-} | |
- | |
-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->n… | |
- 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… | |
- 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 … | |
- 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 assignmen… | |
- int iws; /* inter-word separator in envi… | |
- char *(*charin)(char*, char*); /* search for unescaped c… | |
- char *(*expandquote)(char*, Rune, Bufblock*); /* extract… | |
- int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* inp… | |
- char *(*copyq)(char*, Rune, Bufblock*); /* check for quo… | |
- 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|BEIN… | |
-#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… | |
-#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r… | |
-#define NAMEBLOCK 1000 | |
-#define BIGBLOCK 20000 | |
- | |
-#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n')) | |
-#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^… | |
- | |
-#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 f… | |
- } 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 f… | |
- } 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 assig… | |
- 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®EXP)){ | |
- 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… | |
- if (pp && *pp == '=') { | |
- while (p != pp) { | |
- n = chartorune(&r, p); | |
- switch(r) | |
- { | |
- default: | |
- SYNERR(-1); | |
- fprint(2, "unknown attribute '%c'\n",*… | |
- 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 quote… | |
- * 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", no… | |
- } | |
- return(did); | |
- } | |
- /* | |
- build the node list | |
- */ | |
- node->next = 0; | |
- head.next = 0; | |
- ww = &head; | |
- ahead.next = 0; | |
- aw = &ahead; | |
- if(r->attr®EXP){ | |
- 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 interest… | |
- 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… | |
- } | |
- } 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, ' '),… | |
- run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.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, … | |
-{ | |
- 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®EXP) || shellt->charin(head, "%&")){ | |
- r->attr |= META; | |
- if(reuse) | |
- return; | |
- if(attr®EXP){ | |
- 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 a… | |
- r, r->file, r->line, r->attr, r->next, r->chain, wtos(… | |
- 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->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->she… | |
- usage(); | |
- nrunning++; | |
- if(DEBUG(D_EXEC)) | |
- fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '),… | |
- } | |
-} | |
- | |
-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",… | |
- 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*s… | |
- 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 convent… | |
- */ | |
- | |
- | |
-/* | |
- * 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 quote… | |
- * 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 strin… | |
- } | |
- 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 strin… | |
- } | |
- } | |
- 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) == … | |
- 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->va… | |
- 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",… | |
- 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 *shellcm… | |
-{ | |
- 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 … | |
- ; | |
- *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 o… | |
- */ | |
- 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=… | |
-#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=… | |
-#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=… | |
+#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f … | |
+#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i … | |
+#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s … | |
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 == whi… | |
+ if(q==codep) | |
+ emitf(Xsettrue); /* empty condition == while(tr… | |
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, efla… | |
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 outp… | |
* 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->ne… | |
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(vo… | |
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(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… | |
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void); | |
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(… | |
@@ -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 th… | |
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 … | |
-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 … | |
+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… | |
+ count = 0; | |
+ while('0'<=*f && *f<='9') count = count*10+*f+… | |
+ } | |
+ else | |
+ count = 0; | |
+ if(*f=='['){ | |
+ do{ | |
+ f++; | |
+ if(*f=='\0'){ reason = FLAGSYN; return… | |
+ }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 astac… | |
* 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 strin… | |
+ 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; /* synta… | |
- lo=unicode(p); | |
- p=nextutf(p); | |
- if(*p!='-') hi=lo; | |
+ if(*p=='\0') | |
+ return 0; /* syntax err… | |
+ lo = unicode(p); | |
+ p = nextutf(p); | |
+ if(*p!='-') | |
+ hi = lo; | |
else{ | |
p++; | |
- if(*p=='\0') return 0; /* synta… | |
- hi=unicode(p); | |
- p=nextutf(p); | |
- if(hi<lo){ t=lo; lo=hi; hi=t; } | |
+ if(*p=='\0') | |
+ return 0; /* syntax err… | |
+ 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+*… | |
+ n = 0; | |
+ for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*… | |
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; /*unportab… | |
- 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 com… | |
+ 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 = 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 termin… | |
-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 unq… | |
* WORD then we alter the meaning of what follows. If the next charac… | |
@@ -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 … | |
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 bourn… | |
#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 … | |
- 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]]?"":"fl… | |
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->n… | |
+ for(path = searchpath(a->word);path;path = pat… | |
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 f… | |
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 pr… | |
} | |
-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 ex… | |
- 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… | |
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; |