commit abc072187111c9098f80518e9c8d0b81ae1577d0
parent 89cb321008eab13102fa98bd1b28caadc2c5218e
Author: Anselm R Garbe <anselm@garbe.us>
Date: Fri, 31 Jul 2009 21:02:58 +0100
upgraded 9base to p9p 20090731
Diffstat:
203 files changed, 4891 insertions(+), 7638 deletions(-)
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@
include config.mk
SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \
- mk rc read sed seq sleep sort tee test touch tr uniq
+ rc read sed seq sleep sort tee test touch tr uniq
all:
@echo 9base build options:
diff --git a/awk/README b/awk/README
@@ -0,0 +1,13 @@
+This 'awk' source is directly downloaded from the Plan 9 source
+
+http://cm.bell-labs.com/sources/plan9/sys/src/cmd/awk/
+
+as such, it's copyright is held by Lucent Technologies and distributed under the
+Lucent Public License version 1.02 [http://www.opensource.org/licenses/lucent1.02.php].
+
+Modifications were made by Jeff Sickel in order to build using Plan 9 from User
+Space [http://swtch.com/plan9port/] to the following files:
+
+ mkfile
+ re.c
+
diff --git a/awk/awk.h b/awk/awk.h
@@ -182,3 +182,4 @@ extern int pairstack[], paircnt;
#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR )
#include "proto.h"
+
diff --git a/awk/awkgram.y b/awk/awkgram.y
@@ -486,3 +486,4 @@ void checkdup(Node *vl, Cell *cp) /* check if name already in list */
}
}
}
+
diff --git a/awk/lex.c b/awk/lex.c
@@ -86,8 +86,8 @@ Keyword keywords[] ={ /* keep sorted: binary searched */
{ "system", FSYSTEM, BLTIN },
{ "tolower", FTOLOWER, BLTIN },
{ "toupper", FTOUPPER, BLTIN },
- { "while", WHILE, WHILE },
{ "utf", FUTF, BLTIN },
+ { "while", WHILE, WHILE },
};
#define DEBUG
@@ -567,3 +567,4 @@ void unputstr(char *s) /* put a string back on input */
for (i = strlen(s)-1; i >= 0; i--)
unput(s[i]);
}
+
diff --git a/awk/lib.c b/awk/lib.c
@@ -673,6 +673,32 @@ int is_number(char *s)
{
double r;
char *ep;
+
+ /*
+ * fast could-it-be-a-number check before calling strtod,
+ * which takes a surprisingly long time to reject non-numbers.
+ */
+ switch (*s) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ case '-':
+ case '+':
+ case '.':
+ case 'n': /* nans */
+ case 'N':
+ case 'i': /* infs */
+ case 'I':
+ break;
+ default:
+ return 0; /* can't be a number */
+ }
+
errno = 0;
r = strtod(s, &ep);
if (ep == s || r == HUGE_VAL || errno == ERANGE)
@@ -684,3 +710,4 @@ int is_number(char *s)
else
return 0;
}
+
diff --git a/awk/main.c b/awk/main.c
@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
cmdname = argv[0];
if (argc == 1) {
- fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffieldsep] [-v var=value] [files]\n", cmdname);
+ fprintf(stderr, "Usage: %s [-F fieldsep] [-mf n] [-mr n] [-v var=value] [-f programfile | 'program'] [file ...]\n", cmdname);
exit(1);
}
signal(SIGFPE, fpecatch);
@@ -195,3 +195,4 @@ char *cursource(void) /* current source file name */
else
return NULL;
}
+
diff --git a/awk/maketab.c b/awk/maketab.c
@@ -166,3 +166,4 @@ int main(int argc, char *argv[])
printf("}\n");
return 0;
}
+
diff --git a/awk/parse.c b/awk/parse.c
@@ -269,3 +269,4 @@ Node *itonp(int i) /* and vice versa */
{
return (Node *) (long) i;
}
+
diff --git a/awk/proto.h b/awk/proto.h
@@ -22,6 +22,8 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
****************************************************************/
+#define getline p9getline
+
extern int yywrap(void);
extern void setfname(Cell *);
extern int constnode(Node *);
@@ -175,3 +177,4 @@ extern Cell *gsub(Node **, int);
extern FILE *popen(const char *, const char *);
extern int pclose(FILE *);
+
diff --git a/awk/re.c b/awk/re.c
@@ -25,15 +25,13 @@ THIS SOFTWARE.
#define DEBUG
#include <stdio.h>
+#include <u.h>
+#include <libc.h>
#include <ctype.h>
-#include <setjmp.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
+#include <bio.h>
+#include <regexp.h>
#include "awk.h"
#include "y.tab.h"
-#include "regexp.h"
/* This file provides the interface between the main body of
* awk and the pattern matching package. It preprocesses
@@ -187,7 +185,7 @@ void
/* T/F match indication - matched string not exported */
int
-match(void *p, char *s, char *q)
+match(void *p, char *s, char *start)
{
return regexec((Reprog *) p, (char *) s, 0, 0);
}
@@ -222,10 +220,11 @@ nematch(void *p, char *s, char *start)
}
/* in the parsing of regular expressions, metacharacters like . have */
/* to be seen literally; \056 is not a metacharacter. */
-int
+
+int
hexstr(char **pp) /* find and eval hex string at pp, return new p */
{
- int c;
+ char c;
int n = 0;
int i;
@@ -323,3 +322,4 @@ overflow(void)
{
FATAL("%s", "regular expression too big");
}
+
diff --git a/awk/run.c b/awk/run.c
@@ -133,6 +133,7 @@ void run(Node *a) /* execution of parse tree starts here */
Cell *execute(Node *u) /* execute a node of the parse tree */
{
+ int nobj;
Cell *(*proc)(Node **, int);
Cell *x;
Node *a;
@@ -149,10 +150,11 @@ Cell *execute(Node *u) /* execute a node of the parse tree */
recbld();
return(x);
}
- if (notlegal(a->nobj)) /* probably a Cell* but too risky to print */
+ nobj = a->nobj;
+ if (notlegal(nobj)) /* probably a Cell* but too risky to print */
FATAL("illegal statement");
- proc = proctab[a->nobj-FIRSTTOKEN];
- x = (*proc)(a->narg, a->nobj);
+ proc = proctab[nobj-FIRSTTOKEN];
+ x = (*proc)(a->narg, nobj);
if (isfld(x) && !donefld)
fldbld();
else if (isrec(x) && !donerec)
@@ -901,8 +903,10 @@ int format(char **pbuf, int *pbufsize, char *s, Node *a) /* printf-like conversi
if (isnum(x)) {
if (getfval(x))
sprintf(p, fmt, (int) getfval(x));
- else
+ else{
*p++ = '\0';
+ *p = '\0';
+ }
} else
sprintf(p, fmt, getsval(x)[0]);
break;
@@ -1540,6 +1544,7 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis
Cell *printstat(Node **a, int n) /* print a[0] */
{
+ int r;
Node *x;
Cell *y;
FILE *fp;
@@ -1553,14 +1558,15 @@ Cell *printstat(Node **a, int n) /* print a[0] */
fputs(getsval(y), fp);
tempfree(y);
if (x->nnext == NULL)
- fputs(*ORS, fp);
+ r = fputs(*ORS, fp);
else
- fputs(*OFS, fp);
+ r = fputs(*OFS, fp);
+ if (r == EOF)
+ FATAL("write error on %s", filename(fp));
}
if (a[1] != 0)
- fflush(fp);
- if (ferror(fp))
- FATAL("write error on %s", filename(fp));
+ if (fflush(fp) == EOF)
+ FATAL("write error on %s", filename(fp));
return(True);
}
@@ -1890,3 +1896,4 @@ void backsub(char **pb_ptr, char **sptr_ptr) /* handle \\& variations */
*pb_ptr = pb;
*sptr_ptr = sptr;
}
+
diff --git a/awk/tran.c b/awk/tran.c
@@ -432,3 +432,4 @@ char *qstring(char *s, int delim) /* collect string up to next delim */
*bp++ = 0;
return buf;
}
+
diff --git a/bc/bc.1 b/bc/bc.1
@@ -159,7 +159,7 @@ Function definitions
.B ,
.I L
.B ){
-.PD
+.PD0
.br
.B auto
.I L
diff --git a/bc/bc.y b/bc/bc.y
@@ -6,10 +6,8 @@
#define bsp_max 5000
Biobuf *in;
- #define stdin bstdin
- #define stdout bstdout
- Biobuf stdin;
- Biobuf stdout;
+ Biobuf bstdin;
+ Biobuf bstdout;
char cary[1000];
char* cp = { cary };
char string[1000];
@@ -19,7 +17,7 @@
int bindx = 0;
int lev = 0;
int ln;
- int* ttp;
+ char* ttp;
char* ss = "";
int bstack[10] = { 0 };
char* numb[15] =
@@ -28,8 +26,8 @@
" 6", " 7", " 8", " 9", " 10", " 11",
" 12", " 13", " 14"
};
- int* pre;
- int* post;
+ char* pre;
+ char* post;
long peekc = -1;
int sargc;
@@ -61,40 +59,39 @@
"u","v","w","x","y","z"
};
char* dot = { "." };
- int bspace[bsp_max];
- int* bsp_nxt = { bspace };
+ char* bspace[bsp_max];
+ char** bsp_nxt = bspace;
int bdebug = 0;
int lflag;
int cflag;
int sflag;
- int* bundle(int, ...);
- void conout(int*, char*);
+ char* bundle(int, ...);
+ void conout(char*, char*);
int cpeek(int, int, int);
int getch(void);
- int* geta(char*);
- int* getf(char*);
+ char* geta(char*);
+ char* getf(char*);
void getout(void);
- void output(int*);
+ void output(char*);
void pp(char*);
- void routput(int*);
+ void routput(char*);
void tp(char*);
void yyerror(char*, ...);
int yyparse(void);
typedef void* pointer;
-/* #pragma varargck type "lx" pointer */
+ #pragma varargck type "lx" pointer
%}
%union
{
- int* iptr;
char* cptr;
int cc;
}
-%type <iptr> pstat stat stat1 def slist dlets e ase nase
-%type <iptr> slist re fprefix cargs eora cons constant lora
+%type <cptr> pstat stat stat1 def slist dlets e ase nase
+%type <cptr> slist re fprefix cargs eora cons constant lora
%type <cptr> crs
%token <cptr> LETTER EQOP _AUTO DOT
@@ -124,7 +121,7 @@ stuff:
ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
conout(ttp, (char*)$1);
rcrs = crs;
- output((int*)""); /* this is horse puk!! */
+ output("");
lev = bindx = 0;
}
@@ -550,8 +547,8 @@ def:
_DEFINE LETTER '('
{
$$ = getf($2);
- pre = (int*)"";
- post = (int*)"";
+ pre = (char*)"";
+ post = (char*)"";
lev = 1;
bindx = 0;
bstack[bindx] = 0;
@@ -789,76 +786,85 @@ loop:
peekc = -1;
if(ch >= 0)
return ch;
+
ifile++;
- if(ifile > sargc) {
- if(ifile >= sargc+2)
+ if(ifile >= sargc) {
+ if(ifile >= sargc+1)
getout();
- in = &stdin;
+ in = &bstdin;
Binit(in, 0, OREAD);
ln = 0;
goto loop;
}
- Bterm(in);
+ if(in)
+ Bterm(in);
if((in = Bopen(sargv[ifile], OREAD)) != 0){
ln = 0;
ss = sargv[ifile];
goto loop;
}
+ fprint(2, "open %s: %r\n", sargv[ifile]);
yyerror("cannot open input file");
return 0; /* shut up ken */
}
-int*
+char*
bundle(int a, ...)
{
- int i, *p, *q;
-
- p = &a;
- i = *p++;
+ int i;
+ char **q;
+ va_list arg;
+
+ i = a;
+ va_start(arg, a);
q = bsp_nxt;
if(bdebug)
fprint(2, "bundle %d elements at %lx\n", i, q);
while(i-- > 0) {
if(bsp_nxt >= &bspace[bsp_max])
yyerror("bundling space exceeded");
- *bsp_nxt++ = *p++;
+ *bsp_nxt++ = va_arg(arg, char*);
}
*bsp_nxt++ = 0;
- yyval.iptr = q;
- return q;
+ va_end(arg);
+ yyval.cptr = (char*)q;
+ return (char*)q;
}
void
-routput(int *p)
+routput(char *p)
{
+ char **pp;
+
if(bdebug)
fprint(2, "routput(%lx)\n", p);
- if(p >= &bspace[0] && p < &bspace[bsp_max]) {
+ if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
/* part of a bundle */
- while(*p != 0)
- routput((int*)(*p++));
+ pp = (char**)p;
+ while(*pp != 0)
+ routput(*pp++);
} else
- Bprint(&stdout, (char*)p); /* character string */
+ Bprint(&bstdout, p); /* character string */
}
void
-output(int *p)
+output(char *p)
{
routput(p);
bsp_nxt = &bspace[0];
- Bprint(&stdout, "\n");
- Bflush(&stdout);
+ Bprint(&bstdout, "\n");
+ Bflush(&bstdout);
cp = cary;
crs = rcrs;
}
void
-conout(int *p, char *s)
+conout(char *p, char *s)
{
- Bprint(&stdout, "[");
+ Bprint(&bstdout, "[");
routput(p);
- Bprint(&stdout, "]s%s\n", s);
- Bflush(&stdout);
+ Bprint(&bstdout, "]s%s\n", s);
+ Bflush(&bstdout);
lev--;
}
@@ -867,8 +873,8 @@ yyerror(char *s, ...)
{
if(ifile > sargc)
ss = "teletype";
- Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
- Bflush(&stdout);
+ Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss);
+ Bflush(&bstdout);
cp = cary;
crs = rcrs;
bindx = 0;
@@ -881,9 +887,9 @@ pp(char *s)
{
/* puts the relevant stuff on pre and post for the letter s */
bundle(3, "S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
}
void
@@ -891,45 +897,45 @@ tp(char *s)
{
/* same as pp, but for temps */
bundle(3, "0S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
}
void
yyinit(int argc, char **argv)
{
- Binit(&stdout, 1, OWRITE);
+ Binit(&bstdout, 1, OWRITE);
sargv = argv;
- sargc = argc - 1;
+ sargc = argc;
if(sargc == 0) {
- in = &stdin;
+ in = &bstdin;
Binit(in, 0, OREAD);
- } else if((in = Bopen(sargv[1], OREAD)) == 0)
+ } else if((in = Bopen(sargv[0], OREAD)) == 0)
yyerror("cannot open input file");
- ifile = 1;
+ ifile = 0;
ln = 0;
- ss = sargv[1];
+ ss = sargv[0];
}
void
getout(void)
{
- Bprint(&stdout, "q");
- Bflush(&stdout);
+ Bprint(&bstdout, "q");
+ Bflush(&bstdout);
exits(0);
}
-int*
+char*
getf(char *p)
{
- return (int*)funtab[*p - 'a'];
+ return funtab[*p - 'a'];
}
-int*
+char*
geta(char *p)
{
- return (int*)atab[*p - 'a'];
+ return atab[*p - 'a'];
}
void
@@ -937,37 +943,34 @@ main(int argc, char **argv)
{
int p[2];
- while(argc > 1 && *argv[1] == '-') {
- switch(argv[1][1]) {
- case 'd':
- bdebug++;
- break;
- case 'c':
- cflag++;
- break;
- case 'l':
- lflag++;
- break;
- case 's':
- sflag++;
- break;
- default:
- fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
- exits("usage");
- }
- argc--;
- argv++;
- }
+ ARGBEGIN{
+ case 'd':
+ bdebug++;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ default:
+ fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
+ exits("usage");
+ }ARGEND
+
if(lflag) {
- argv--;
argc++;
- argv[1] = unsharp("#9/lib/bclib");
+ argv--;
+ *argv = unsharp("#9/lib/bclib");
}
if(cflag) {
yyinit(argc, argv);
for(;;)
yyparse();
- /* exits(0); */
+ exits(0);
}
pipe(p);
if(fork() == 0) {
@@ -981,5 +984,5 @@ main(int argc, char **argv)
dup(p[0], 0);
close(p[0]);
close(p[1]);
- execlp("dc", "dc", (char*)0);
+ execl(unsharp("#9/bin/dc"), "dc", nil);
}
diff --git a/config.mk b/config.mk
@@ -4,7 +4,9 @@
PREFIX = /usr/local/9
MANPREFIX = ${PREFIX}/share/man
-VERSION = 20060209
+VERSION = 200907
+# 386, arm, etc31
+OBJTYPE = x86_64
# Linux/BSD
CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. -DPREFIX="\"${PREFIX}\""
diff --git a/dc/dc.c b/dc/dc.c
@@ -165,7 +165,6 @@ void release(Blk *p);
Blk* dcgetwd(Blk *p);
void putwd(Blk *p, Blk *c);
Blk* lookwd(Blk *p);
-char* nalloc(char *p, unsigned nbytes);
int getstk(void);
/********debug only**/
@@ -1222,7 +1221,7 @@ init(int argc, char *argv[])
readptr = &readstk[0];
k=0;
sp = sptr = &symlst[0];
- while(sptr < &symlst[TBLSZ]) {
+ while(sptr < &symlst[TBLSZ-1]) {
sptr->next = ++sp;
sptr++;
}
@@ -2103,14 +2102,13 @@ copy(Blk *hptr, int size)
if(size > maxsize)
maxsize = size;
sz = length(hptr);
- ptr = nalloc(hptr->beg, size);
+ ptr = malloc(size);
if(ptr == 0) {
- garbage("copy");
- if((ptr = nalloc(hptr->beg, size)) == 0) {
- Bprint(&bout,"copy size %d\n",size);
- ospace("copy");
- }
+ Bprint(&bout,"copy size %d\n",size);
+ ospace("copy");
}
+ memmove(ptr, hptr->beg, sz);
+ memset(ptr+sz, 0, size-sz);
if((hdr = hfree) == 0)
hdr = morehd();
hfree = (Blk *)hdr->rd;
@@ -2149,7 +2147,7 @@ seekc(Blk *hptr, int n)
lbytes += nn - hptr->last;
if(n > longest)
longest = n;
-/* free(hptr->beg); *//**/
+/* free(hptr->beg); */
p = realloc(hptr->beg, n);
if(p == 0) {
/* hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg);
@@ -2194,7 +2192,7 @@ more(Blk *hptr)
longest = size;
lbytes += size/2;
lmore++;
-/* free(hptr->beg);*//**/
+/* free(hptr->beg);*/
p = realloc(hptr->beg, size);
if(p == 0) {
@@ -2269,19 +2267,6 @@ lookwd(Blk *p)
return(*wp->rdw);
}
-char*
-nalloc(char *p, unsigned nbytes)
-{
- char *q, *r;
-
- q = r = malloc(nbytes);
- if(q==0)
- return(0);
- while(nbytes--)
- *q++ = *p++;
- return(r);
-}
-
int
getstk(void)
{
diff --git a/grep/comp.c b/grep/comp.c
@@ -128,12 +128,12 @@ loop:
Rune tab1[] =
{
0x007f,
- 0x07ff,
+ 0x07ff
};
Rune tab2[] =
{
0x003f,
- 0x0fff,
+ 0x0fff
};
Re2
@@ -144,7 +144,7 @@ rclass(Rune p0, Rune p1)
Re2 x;
if(p0 > p1)
- return re2char(0xff, 0xff); // no match
+ return re2char(0xff, 0xff); /* no match */
/*
* bust range into same length
diff --git a/grep/main.c b/grep/main.c
@@ -21,6 +21,10 @@ main(int argc, char *argv[])
flags[ARGC()]++;
break;
+ case 'q': /* gnu grep -q means plan 9 grep -s */
+ flags['s']++;
+ break;
+
case 'E': /* ignore, turns gnu grep into egrep */
break;
@@ -170,11 +174,11 @@ loop:
increment(s, c);
goto loop;
}
-// if(flags['2'])
-// if(s->match)
-// print("%d: %.2x**\n", s, c);
-// else
-// print("%d: %.2x\n", s, c);
+/* if(flags['2']) */
+/* if(s->match) */
+/* print("%d: %.2x**\n", s, c); */
+/* else */
+/* print("%d: %.2x\n", s, c); */
lp++;
s = ns;
if(c == '\n') {
diff --git a/grep/sub.c b/grep/sub.c
@@ -30,7 +30,7 @@ sal(int n)
State *s;
s = mal(sizeof(*s));
-// s->next = mal(256*sizeof(*s->next));
+/* s->next = mal(256*sizeof(*s->next)); */
s->count = n;
s->re = mal(n*sizeof(*state0->re));
return s;
diff --git a/lib9/Makefile b/lib9/Makefile
@@ -15,16 +15,203 @@ include ../config.mk
LIB=lib9.a
TARG=lib9
+O=o
# following objects are not compiled for several reasons
-# crypt.o
-# netcrypt.o
-# convD2M.o
-# convM2D.o
-# convM2S.o
-# convS2M.o
+# crypt.$(O)
+# netcrypt.$(O)
+# convD2M.$(O)
+# convM2D.$(O)
+# convM2S.$(O)
+# convS2M.$(O)
+
+NUM=\
+ fmt/charstod.$(O)\
+ fmt/pow10.$(O)\
+
+FMTOFILES=\
+ fmt/dofmt.$(O)\
+ fmt/fltfmt.$(O)\
+ fmt/fmt.$(O)\
+ fmt/fmtfd.$(O)\
+ fmt/fmtfdflush.$(O)\
+ fmt/fmtlocale.$(O)\
+ fmtlock2.$(O)\
+ fmt/fmtnull.$(O)\
+ fmt/fmtprint.$(O)\
+ fmt/fmtquote.$(O)\
+ fmt/fmtrune.$(O)\
+ fmt/fmtstr.$(O)\
+ fmt/fmtvprint.$(O)\
+ fmt/fprint.$(O)\
+ fmt/nan64.$(O)\
+ fmt/print.$(O)\
+ fmt/runefmtstr.$(O)\
+ fmt/runeseprint.$(O)\
+ fmt/runesmprint.$(O)\
+ fmt/runesnprint.$(O)\
+ fmt/runesprint.$(O)\
+ fmt/runevseprint.$(O)\
+ fmt/runevsmprint.$(O)\
+ fmt/runevsnprint.$(O)\
+ fmt/seprint.$(O)\
+ fmt/smprint.$(O)\
+ fmt/snprint.$(O)\
+ fmt/sprint.$(O)\
+ fmt/strtod.$(O)\
+ fmt/vfprint.$(O)\
+ fmt/vseprint.$(O)\
+ fmt/vsmprint.$(O)\
+ fmt/vsnprint.$(O)\
+ $(NUM)\
+
+UTFOFILES=\
+ utf/rune.$(O)\
+ utf/runestrcat.$(O)\
+ utf/runestrchr.$(O)\
+ utf/runestrcmp.$(O)\
+ utf/runestrcpy.$(O)\
+ utf/runestrdup.$(O)\
+ utf/runestrlen.$(O)\
+ utf/runestrecpy.$(O)\
+ utf/runestrncat.$(O)\
+ utf/runestrncmp.$(O)\
+ utf/runestrncpy.$(O)\
+ utf/runestrrchr.$(O)\
+ utf/runestrstr.$(O)\
+ utf/runetype.$(O)\
+ utf/utfecpy.$(O)\
+ utf/utflen.$(O)\
+ utf/utfnlen.$(O)\
+ utf/utfrrune.$(O)\
+ utf/utfrune.$(O)\
+ utf/utfutf.$(O)\
+
+BIOFILES=\
+ bio/bbuffered.$(O)\
+ bio/bfildes.$(O)\
+ bio/bflush.$(O)\
+ bio/bgetc.$(O)\
+ bio/bgetrune.$(O)\
+ bio/bgetd.$(O)\
+ bio/binit.$(O)\
+ bio/boffset.$(O)\
+ bio/bprint.$(O)\
+ bio/bputc.$(O)\
+ bio/bputrune.$(O)\
+ bio/brdline.$(O)\
+ bio/brdstr.$(O)\
+ bio/bread.$(O)\
+ bio/bseek.$(O)\
+ bio/bvprint.$(O)\
+ bio/bwrite.$(O)\
+
+REGEXFILES=\
+ regex/regcomp.$(O)\
+ regex/regerror.$(O)\
+ regex/regexec.$(O)\
+ regex/regsub.$(O)\
+ regex/regaux.$(O)\
+ regex/rregexec.$(O)\
+ regex/rregsub.$(O)\
+
+LIB9OFILES=\
+ _exits.$(O)\
+ _p9dialparse.$(O)\
+ _p9dir.$(O)\
+ announce.$(O)\
+ argv0.$(O)\
+ atexit.$(O)\
+ atoi.$(O)\
+ atol.$(O)\
+ atoll.$(O)\
+ atnotify.$(O)\
+ await.$(O)\
+ cistrcmp.$(O)\
+ cistrncmp.$(O)\
+ cistrstr.$(O)\
+ cleanname.$(O)\
+ create.$(O)\
+ ctime.$(O)\
+ dial.$(O)\
+ dirfstat.$(O)\
+ dirfwstat.$(O)\
+ dirmodefmt.$(O)\
+ dirread.$(O)\
+ dirstat.$(O)\
+ dirwstat.$(O)\
+ dup.$(O)\
+ encodefmt.$(O)\
+ errstr.$(O)\
+ exec.$(O)\
+ execl.$(O)\
+ exitcode.$(O)\
+ fcallfmt.$(O)\
+ get9root.$(O)\
+ getcallerpc-$(OBJTYPE).$(O)\
+ getenv.$(O)\
+ getfields.$(O)\
+ getnetconn.$(O)\
+ getns.$(O)\
+ getuser.$(O)\
+ getwd.$(O)\
+ jmp.$(O)\
+ lrand.$(O)\
+ lnrand.$(O)\
+ main.$(O)\
+ malloc.$(O)\
+ malloctag.$(O)\
+ mallocz.$(O)\
+ nan.$(O)\
+ needsrcquote.$(O)\
+ needstack.$(O)\
+ netmkaddr.$(O)\
+ notify.$(O)\
+ nrand.$(O)\
+ nulldir.$(O)\
+ open.$(O)\
+ opentemp.$(O)\
+ pin.$(O)\
+ pipe.$(O)\
+ post9p.$(O)\
+ postnote.$(O)\
+ qlock.$(O)\
+ quote.$(O)\
+ rand.$(O)\
+ read9pmsg.$(O)\
+ readcons.$(O)\
+ readn.$(O)\
+ rfork.$(O)\
+ searchpath.$(O)\
+ seek.$(O)\
+ sendfd.$(O)\
+ sleep.$(O)\
+ strdup.$(O)\
+ strecpy.$(O)\
+ sysfatal.$(O)\
+ syslog.$(O)\
+ sysname.$(O)\
+ time.$(O)\
+ tm2sec.$(O)\
+ tokenize.$(O)\
+ truerand.$(O)\
+ u16.$(O)\
+ u32.$(O)\
+ u64.$(O)\
+ unsharp.$(O)\
+ wait.$(O)\
+ waitpid.$(O)\
+ write.$(O)\
+ zoneinfo.$(O)\
OFILES=\
+ $(FMTOFILES)\
+ $(UTFOFILES)\
+ $(BIOFILES)\
+ $(REGEXFILES)\
+ $(LIB9OFILES)
+
+OFILESOLD=\
fmt/dofmt.o\
fmt/fltfmt.o\
fmt/fmt.o\
diff --git a/lib9/_exits.c b/lib9/_exits.c
@@ -4,7 +4,7 @@
void
_exits(char *s)
{
- if(s && *s)
- _exit(1);
- _exit(0);
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(exitcode(s));
}
diff --git a/lib9/_p9dialparse.c b/lib9/_p9dialparse.c
@@ -26,6 +26,8 @@ static struct {
"tcp", "venti", 17034,
"tcp", "wiki", 17035,
"tcp", "secstore", 5356,
+ "udp", "dns", 53,
+ "tcp", "dns", 53,
};
static int
@@ -82,9 +84,6 @@ p9dialparse(char *addr, char **pnet, char **punix, u32int *phost, int *pport)
struct hostent *he;
struct sockaddr_un *sockun;
- if(strncmp(addr, "/net/", 5) == 0)
- addr += 5;
-
*punix = nil;
net = addr;
if((host = strchr(net, '!')) == nil){
diff --git a/lib9/_p9dir.c b/lib9/_p9dir.c
@@ -7,50 +7,67 @@
#include <pwd.h>
#include <grp.h>
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__APPLE__)
+#define _HAVESTGEN
+#include <sys/disk.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ u64int bc;
+ u32int bs;
+
+ bs = 0;
+ bc = 0;
+ ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
+ ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
+ if(bs >0 && bc > 0)
+ return bc*bs;
+ return 0;
+}
+
+#elif defined(__FreeBSD__)
+#define _HAVESTGEN
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ off_t mediasize;
+
+ if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+ return mediasize;
+ return 0;
+}
+
+#elif defined(__OpenBSD__)
+#define _HAVESTGEN
#include <sys/disklabel.h>
#include <sys/ioctl.h>
-static int diskdev[] = {
- 151, /* aacd */
- 116, /* ad */
- 157, /* ar */
- 118, /* afd */
- 133, /* amrd */
- 13, /* da */
- 102, /* fla */
- 109, /* idad */
- 95, /* md */
- 131, /* mlxd */
- 168, /* pst */
- 147, /* twed */
- 43, /* vn */
- 3, /* wd */
- 87, /* wfd */
-};
-static int
-isdisk(struct stat *st)
+static vlong
+disksize(int fd, struct stat *st)
{
- int i, dev;
+ struct disklabel lab;
+ int n;
if(!S_ISCHR(st->st_mode))
return 0;
- dev = major(st->st_rdev);
- for(i=0; i<nelem(diskdev); i++)
- if(diskdev[i] == dev)
- return 1;
- return 0;
+ if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+ return 0;
+ n = minor(st->st_rdev)&7;
+ if(n >= lab.d_npartitions)
+ return 0;
+ return (vlong)lab.d_partitions[n].p_size * lab.d_secsize;
}
-#define _HAVEDISKLABEL
-#endif
-#if defined(__linux__)
+#elif defined(__linux__)
#include <linux/hdreg.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#undef major
#define major(dev) ((int)(((dev) >> 8) & 0xff))
static vlong
-disksize(int fd, int dev)
+disksize(int fd, struct stat *st)
{
u64int u64;
long l;
@@ -64,18 +81,21 @@ disksize(int fd, int dev)
return u64;
#endif
if(ioctl(fd, BLKGETSIZE, &l) >= 0)
- return (vlong)l*512;
+ return l*512;
if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
return 0;
}
-#define _HAVEDISKSIZE
-#endif
-#if !defined(__linux__) && !defined(__sun__)
-#define _HAVESTGEN
+#else
+static vlong
+disksize(int fd, struct stat *st)
+{
+ return 0;
+}
#endif
+int _p9usepwlibrary = 1;
/*
* Caching the last group and passwd looked up is
* a significant win (stupidly enough) on most systems.
@@ -122,11 +142,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
/* user */
if(p && st->st_uid == uid && p->pw_uid == uid)
;
- else{
+ else if(_p9usepwlibrary){
p = getpwuid(st->st_uid);
uid = st->st_uid;
}
- if(p == nil){
+ if(p == nil || st->st_uid != uid || p->pw_uid != uid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
s = tmp;
}else
@@ -145,11 +165,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
/* group */
if(g && st->st_gid == gid && g->gr_gid == gid)
;
- else{
+ else if(_p9usepwlibrary){
g = getgrgid(st->st_gid);
gid = st->st_gid;
}
- if(g == nil){
+ if(g == nil || st->st_gid != gid || g->gr_gid != gid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
s = tmp;
}else
@@ -173,57 +193,41 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *
#ifdef _HAVESTGEN
d->qid.vers = st->st_gen;
#endif
+ if(d->qid.vers == 0)
+ d->qid.vers = st->st_mtime + st->st_ctime;
d->mode = st->st_mode&0777;
d->atime = st->st_atime;
d->mtime = st->st_mtime;
d->length = st->st_size;
- if(S_ISDIR(st->st_mode)){
+ if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */
+ d->mode |= DMSYMLINK;
+ d->length = lst->st_size;
+ }
+ else if(S_ISDIR(st->st_mode)){
d->length = 0;
d->mode |= DMDIR;
d->qid.type = QTDIR;
}
- if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
- d->mode |= DMSYMLINK;
- if(S_ISFIFO(st->st_mode))
+ else if(S_ISFIFO(st->st_mode))
d->mode |= DMNAMEDPIPE;
- if(S_ISSOCK(st->st_mode))
+ else if(S_ISSOCK(st->st_mode))
d->mode |= DMSOCKET;
- if(S_ISBLK(st->st_mode)){
+ else if(S_ISBLK(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('b'<<16)|st->st_rdev;
}
- if(S_ISCHR(st->st_mode)){
+ else if(S_ISCHR(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('c'<<16)|st->st_rdev;
}
/* fetch real size for disks */
-#ifdef _HAVEDISKSIZE
- if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
- d->length = disksize(fd, major(st->st_dev));
- close(fd);
- }
-#endif
-#ifdef _HAVEDISKLABEL
- if(isdisk(st)){
- int fd, n;
- struct disklabel lab;
-
- if((fd = open(name, O_RDONLY)) < 0)
- goto nosize;
- if(ioctl(fd, DIOCGDINFO, &lab) < 0)
- goto nosize;
- n = minor(st->st_rdev)&7;
- if(n >= lab.d_npartitions)
- goto nosize;
-
- d->length = (vlong)(lab.d_partitions[n].p_size) * lab.d_secsize;
-
- nosize:
- if(fd >= 0)
+ if(S_ISBLK(lst->st_mode) || S_ISCHR(lst->st_mode)){
+ if((fd = open(name, O_RDONLY)) >= 0){
+ d->length = disksize(fd, st);
close(fd);
+ }
}
-#endif
}
return sz;
diff --git a/lib9/atexit.c b/lib9/atexit.c
@@ -50,5 +50,7 @@ exits(char *s)
onex[i].f = 0;
(*f)();
}
- exit(s && *s ? 1 : 0);
+ if(s == 0 || *s == 0)
+ exit(0);
+ exit(exitcode(s));
}
diff --git a/lib9/bio.h b/lib9/bio.h
@@ -8,23 +8,8 @@ extern "C" {
AUTOLIB(bio)
#endif
-#include <sys/types.h> /* for off_t */
-#include <stdarg.h>
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
-#define OREAD 0 /* open for read */
-#define OWRITE 1 /* write */
-#define ORDWR 2 /* read and write */
-#define OEXEC 3 /* execute, == read but check execute permission */
-#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
-#define OCEXEC 32 /* or'ed in, close on exec */
-#define ORCLOSE 64 /* or'ed in, remove on close */
-#define ODIRECT 128 /* or'ed in, direct access */
-#define ONONBLOCK 256 /* or'ed in, non-blocking call */
-#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
-#define OLOCK 0x2000 /* or'ed in, lock after opening */
-#define OAPPEND 0x4000 /* or'ed in, append only */
-
typedef struct Biobuf Biobuf;
enum
@@ -52,7 +37,7 @@ struct Biobuf
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
- off_t offset; /* offset of buffer in file */
+ long long offset; /* offset of buffer in file */
int bsize; /* size of buffer */
unsigned char* bbuf; /* pointer to beginning of buffer */
unsigned char* ebuf; /* pointer to end of buffer */
@@ -85,7 +70,7 @@ long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, unsigned char*, int);
int Blinelen(Biobuf*);
-off_t Boffset(Biobuf*);
+long long Boffset(Biobuf*);
Biobuf* Bopen(char*, int);
int Bprint(Biobuf*, char*, ...);
int Bputc(Biobuf*, int);
@@ -93,7 +78,7 @@ int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
-off_t Bseek(Biobuf*, off_t, int);
+long long Bseek(Biobuf*, long long, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
diff --git a/lib9/bio/bbuffered.c b/lib9/bio/bbuffered.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
int
Bbuffered(Biobuf *bp)
diff --git a/lib9/bio/bflush.c b/lib9/bio/bflush.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
int
Bflush(Biobuf *bp)
diff --git a/lib9/bio/bgetc.c b/lib9/bio/bgetc.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
int
Bgetc(Biobuf *bp)
diff --git a/lib9/bio/bgetd.c b/lib9/bio/bgetd.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
struct bgetd
{
diff --git a/lib9/bio/binit.c b/lib9/bio/binit.c
@@ -1,8 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-#include <stdlib.h>
-#include <unistd.h>
enum
{
@@ -125,13 +122,13 @@ Bopen(char *name, int mode)
return 0;
case OREAD:
- f = open(name, OREAD);
+ f = open(name, mode);
if(f < 0)
return 0;
break;
case OWRITE:
- f = creat(name, 0666);
+ f = create(name, mode, 0666);
if(f < 0)
return 0;
}
diff --git a/lib9/bio/boffset.c b/lib9/bio/boffset.c
@@ -1,11 +1,10 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-off_t
+vlong
Boffset(Biobuf *bp)
{
- off_t n;
+ vlong n;
switch(bp->state) {
default:
diff --git a/lib9/bio/brdline.c b/lib9/bio/brdline.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
void*
Brdline(Biobuf *bp, int delim)
diff --git a/lib9/bio/brdstr.c b/lib9/bio/brdstr.c
@@ -1,7 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <stdlib.h>
-#include <unistd.h>
static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
diff --git a/lib9/bio/bread.c b/lib9/bio/bread.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
long
Bread(Biobuf *bp, void *ap, long count)
diff --git a/lib9/bio/bseek.c b/lib9/bio/bseek.c
@@ -1,13 +1,10 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-#include <sys/types.h>
-#include <unistd.h>
-off_t
-Bseek(Biobuf *bp, off_t offset, int base)
+long long
+Bseek(Biobuf *bp, long long offset, int base)
{
- long long n, d;
+ vlong n, d;
int bufsz;
switch(bp->state) {
@@ -55,7 +52,7 @@ Bseek(Biobuf *bp, off_t offset, int base)
case Bwactive:
Bflush(bp);
- n = lseek(bp->fid, offset, base);
+ n = seek(bp->fid, offset, base);
break;
}
bp->offset = n;
diff --git a/lib9/bio/bvprint.c b/lib9/bio/bvprint.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
static int
fmtBflush(Fmt *f)
@@ -30,10 +29,10 @@ Bvprint(Biobuf *bp, char *fmt, va_list arg)
f.flush = fmtBflush;
f.farg = bp;
f.nfmt = 0;
+ fmtlocaleinit(&f, nil, nil, nil);
n = fmtvprint(&f, fmt, arg);
bp->ocount = (char*)f.to - (char*)f.stop;
+ if(n == 0)
+ n = f.nfmt;
return n;
}
-
-
-
diff --git a/lib9/bio/bwrite.c b/lib9/bio/bwrite.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
long
Bwrite(Biobuf *bp, void *ap, long count)
diff --git a/lib9/bio/lib9.std.h b/lib9/bio/lib9.std.h
@@ -1,3 +1,6 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+
#include <utf.h>
#include <fmt.h>
@@ -13,8 +16,11 @@
#define ORCLOSE 0
#define OTRUNC 0
-
#define nil ((void*)0)
typedef long long vlong;
typedef unsigned long long uvlong;
+
+#define seek(fd, offset, whence) lseek(fd, offset, whence)
+#define create(name, mode, perm) creat(name, perm)
+
diff --git a/lib9/convD2M.c b/lib9/convD2M.c
@@ -3,30 +3,44 @@
#include <fcall.h>
uint
-sizeD2M(Dir *d)
+sizeD2Mu(Dir *d, int dotu)
{
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr, fixlen;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
-
+
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
ns = 0;
- for(i = 0; i < 4; i++)
+ for(i = 0; i < nstr; i++)
if(sv[i])
ns += strlen(sv[i]);
- return STATFIXLEN + ns;
+ return fixlen + ns;
}
uint
-convD2M(Dir *d, uchar *buf, uint nbuf)
+sizeD2M(Dir *d)
+{
+ return sizeD2Mu(d, 0);
+}
+
+uint
+convD2Mu(Dir *d, uchar *buf, uint nbuf, int dotu)
{
uchar *p, *ebuf;
- char *sv[4];
- int i, ns, nsv[4], ss;
+ char *sv[5];
+ int i, ns, nsv[5], ss, nstr, fixlen;
if(nbuf < BIT16SZ)
return 0;
@@ -39,8 +53,16 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
sv[2] = d->gid;
sv[3] = d->muid;
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
ns = 0;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
if(sv[i])
nsv[i] = strlen(sv[i]);
else
@@ -48,7 +70,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
ns += nsv[i];
}
- ss = STATFIXLEN + ns;
+ ss = fixlen + ns;
/* set size befor erroring, so user can know how much is needed */
/* note that length excludes count field itself */
@@ -77,7 +99,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
PBIT64(p, d->length);
p += BIT64SZ;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
ns = nsv[i];
if(p + ns + BIT16SZ > ebuf)
return 0;
@@ -87,9 +109,24 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
memmove(p, sv[i], ns);
p += ns;
}
+
+ if(dotu){
+ PBIT32(p, d->uidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->gidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->muidnum);
+ p += BIT32SZ;
+ }
if(ss != p - buf)
return 0;
return p - buf;
}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ return convD2Mu(d, buf, nbuf, 0);
+}
diff --git a/lib9/convM2D.c b/lib9/convM2D.c
@@ -3,10 +3,10 @@
#include <fcall.h>
int
-statcheck(uchar *buf, uint nbuf)
+statchecku(uchar *buf, uint nbuf, int dotu)
{
uchar *ebuf;
- int i;
+ int i, nstr;
ebuf = buf + nbuf;
@@ -15,26 +15,38 @@ statcheck(uchar *buf, uint nbuf)
buf += STATFIXLEN - 4 * BIT16SZ;
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
if(buf + BIT16SZ > ebuf)
return -1;
buf += BIT16SZ + GBIT16(buf);
}
+ if(dotu)
+ buf += 3*BIT32SZ;
+
if(buf != ebuf)
return -1;
return 0;
}
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ return statchecku(buf, nbuf, 0);
+}
+
static char nullstring[] = "";
uint
-convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+convM2Du(uchar *buf, uint nbuf, Dir *d, char *strs, int dotu)
{
uchar *p, *ebuf;
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr;
if(nbuf < STATFIXLEN)
return 0;
@@ -62,7 +74,10 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
d->length = GBIT64(p);
p += BIT64SZ;
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
if(p + BIT16SZ > ebuf)
return 0;
ns = GBIT16(p);
@@ -78,17 +93,38 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
p += ns;
}
+ if(dotu){
+ if(p + BIT32SZ*3 > ebuf)
+ return 0;
+ d->uidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->gidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->muidnum = GBIT32(p);
+ p += BIT32SZ;
+ }
+
if(strs){
d->name = sv[0];
d->uid = sv[1];
d->gid = sv[2];
d->muid = sv[3];
+ d->ext = nullstring;
+ if(dotu)
+ d->ext = sv[4];
}else{
d->name = nullstring;
d->uid = nullstring;
d->gid = nullstring;
d->muid = nullstring;
+ d->ext = nullstring;
}
return p - buf;
}
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ return convM2Du(buf, nbuf, d, strs, 0);
+}
diff --git a/lib9/convM2S.c b/lib9/convM2S.c
@@ -48,7 +48,7 @@ gqid(uchar *p, uchar *ep, Qid *q)
* to test at end of routine.
*/
uint
-convM2S(uchar *ap, uint nap, Fcall *f)
+convM2Su(uchar *ap, uint nap, Fcall *f, int dotu)
{
uchar *p, *ep;
uint i, size;
@@ -161,6 +161,8 @@ convM2S(uchar *ap, uint nap, Fcall *f)
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
+ if(dotu)
+ p = gstring(p, ep, &f->extension);
break;
case Tread:
@@ -229,6 +231,13 @@ convM2S(uchar *ap, uint nap, Fcall *f)
case Rerror:
p = gstring(p, ep, &f->ename);
+ f->errornum = 0;
+ if(dotu){
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->errornum = GBIT16(p);
+ p += BIT16SZ;
+ }
break;
case Rflush:
@@ -321,3 +330,9 @@ convM2S(uchar *ap, uint nap, Fcall *f)
return size;
return 0;
}
+
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ return convM2Su(ap, nap, f, 0);
+}
diff --git a/lib9/convS2M.c b/lib9/convS2M.c
@@ -46,7 +46,7 @@ stringsz(char *s)
}
uint
-sizeS2M(Fcall *f)
+sizeS2Mu(Fcall *f, int dotu)
{
uint n;
int i;
@@ -102,6 +102,8 @@ sizeS2M(Fcall *f)
n += stringsz(f->name);
n += BIT32SZ;
n += BIT8SZ;
+ if(dotu)
+ n += stringsz(f->extension);
break;
case Tread:
@@ -141,6 +143,8 @@ sizeS2M(Fcall *f)
case Rerror:
n += stringsz(f->ename);
+ if(dotu)
+ n += BIT16SZ;
break;
case Rflush:
@@ -198,12 +202,18 @@ sizeS2M(Fcall *f)
}
uint
-convS2M(Fcall *f, uchar *ap, uint nap)
+sizeS2M(Fcall *f)
+{
+ return sizeS2Mu(f, 0);
+}
+
+uint
+convS2Mu(Fcall *f, uchar *ap, uint nap, int dotu)
{
uchar *p;
uint i, size;
- size = sizeS2M(f);
+ size = sizeS2Mu(f, dotu);
if(size == 0)
return 0;
if(size > nap)
@@ -279,6 +289,8 @@ convS2M(Fcall *f, uchar *ap, uint nap)
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
+ if(dotu)
+ p = pstring(p, f->extension);
break;
case Tread:
@@ -331,6 +343,10 @@ convS2M(Fcall *f, uchar *ap, uint nap)
case Rerror:
p = pstring(p, f->ename);
+ if(dotu){
+ PBIT16(p, f->errornum);
+ p += BIT16SZ;
+ }
break;
case Rflush:
@@ -397,3 +413,9 @@ convS2M(Fcall *f, uchar *ap, uint nap)
return 0;
return size;
}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ return convS2Mu(f, ap, nap, 0);
+}
diff --git a/lib9/crypt.c b/lib9/crypt.c
@@ -0,0 +1,68 @@
+/*
+ * Data Encryption Standard
+ * D.P.Mitchell 83/06/08.
+ *
+ * block_cipher(key, block, decrypting)
+ *
+ * these routines use the non-standard 7 byte format
+ * for DES keys.
+ */
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <libsec.h>
+
+/*
+ * destructively encrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+encrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[32];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ for(i = 0; i < n; i++){
+ block_cipher(ekey, buf, 0);
+ buf += 7;
+ }
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 0);
+ return 1;
+}
+
+/*
+ * destructively decrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+decrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[128];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ buf += n * 7;
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 1);
+ for(i = 0; i < n; i++){
+ buf -= 7;
+ block_cipher(ekey, buf, 1);
+ }
+ return 1;
+}
diff --git a/lib9/ctime.c b/lib9/ctime.c
@@ -1,21 +1,135 @@
+/*
+ * This routine converts time as follows.
+ * The epoch is 0000 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * The localtime(t) entry returns a pointer to an array
+ * containing
+ *
+ * seconds (0-59)
+ * minutes (0-59)
+ * hours (0-23)
+ * day of month (1-31)
+ * month (0-11)
+ * year-1970
+ * weekday (0-6, Sun is 0)
+ * day of the year
+ * daylight savings flag
+ *
+ * The routine gets the daylight savings time from the environment.
+ *
+ * asctime(tvec))
+ * where tvec is produced by localtime
+ * returns a ptr to a character string
+ * that has the ascii time in the form
+ *
+ * \\
+ * Thu Jan 01 00:00:00 GMT 1970n0
+ * 012345678901234567890123456789
+ * 0 1 2
+ *
+ * ctime(t) just calls localtime, then asctime.
+ */
+
#include <u.h>
#include <libc.h>
-static
-void
-ct_numb(char *cp, int n)
+#include "zoneinfo.h"
+
+static char dmsize[12] =
{
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
- cp[0] = ' ';
- if(n >= 10)
- cp[0] = (n/10)%10 + '0';
- cp[1] = n%10 + '0';
+#define dysize ctimedysize
+static int dysize(int);
+static void ct_numb(char*, int);
+
+char*
+ctime(long t)
+{
+ return asctime(localtime(t));
+}
+
+Tm*
+localtime(long tim)
+{
+ Tinfo ti;
+ Tm *ct;
+
+ if (zonelookuptinfo(&ti, tim)!=-1) {
+ ct = gmtime(tim+ti.tzoff);
+ strncpy(ct->zone, ti.zone, sizeof ct->zone);
+ ct->zone[sizeof ct->zone-1] = 0;
+ ct->tzoff = ti.tzoff;
+ return ct;
+ }
+ return gmtime(tim);
+}
+
+Tm*
+gmtime(long tim)
+{
+ int d0, d1;
+ long hms, day;
+ static Tm xtime;
+
+ /*
+ * break initial number into days
+ */
+ hms = tim % 86400L;
+ day = tim / 86400L;
+ if(hms < 0) {
+ hms += 86400L;
+ day -= 1;
+ }
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ xtime.sec = hms % 60;
+ d1 = hms / 60;
+ xtime.min = d1 % 60;
+ d1 /= 60;
+ xtime.hour = d1;
+
+ /*
+ * day is the day number.
+ * generate day of the week.
+ * The addend is 4 mod 7 (1/1/1970 was Thursday)
+ */
+
+ xtime.wday = (day + 7340036L) % 7;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d1 = 1970; day >= dysize(d1); d1++)
+ day -= dysize(d1);
+ else
+ for (d1 = 1970; day < 0; d1--)
+ day += dysize(d1-1);
+ xtime.year = d1-1900;
+ xtime.yday = d0 = day;
+
+ /*
+ * generate month
+ */
+
+ if(dysize(d1) == 366)
+ dmsize[1] = 29;
+ for(d1 = 0; d0 >= dmsize[d1]; d1++)
+ d0 -= dmsize[d1];
+ dmsize[1] = 28;
+ xtime.mday = d0 + 1;
+ xtime.mon = d1;
+ strcpy(xtime.zone, "GMT");
+ return &xtime;
}
char*
asctime(Tm *t)
{
- int i;
char *ncp;
static char cbuf[30];
@@ -33,12 +147,6 @@ asctime(Tm *t)
ct_numb(cbuf+14, t->min+100);
ct_numb(cbuf+17, t->sec+100);
ncp = t->zone;
- for(i=0; i<3; i++)
- if(ncp[i] == 0)
- break;
- for(; i<3; i++)
- ncp[i] = '?';
- ncp = t->zone;
cbuf[20] = *ncp++;
cbuf[21] = *ncp++;
cbuf[22] = *ncp;
@@ -50,9 +158,24 @@ asctime(Tm *t)
return cbuf;
}
-char*
-ctime(long t)
+static
+int
+dysize(int y)
{
- return asctime(localtime(t));
+
+ if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
+ return 366;
+ return 365;
+}
+
+static
+void
+ct_numb(char *cp, int n)
+{
+
+ cp[0] = ' ';
+ if(n >= 10)
+ cp[0] = (n/10)%10 + '0';
+ cp[1] = n%10 + '0';
}
diff --git a/lib9/debugmalloc.c b/lib9/debugmalloc.c
@@ -111,13 +111,13 @@ p9malloc(ulong n)
void *v;
if(n == 0)
n++;
-//fprint(2, "%s %d malloc\n", argv0, getpid());
+/*fprint(2, "%s %d malloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = malloc(n+Overhead);
v = mark(v, getcallerpc(&n), n, MallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donemalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */
return v;
}
@@ -127,13 +127,13 @@ p9free(void *v)
if(v == nil)
return;
-//fprint(2, "%s %d free\n", argv0, getpid());
+/*fprint(2, "%s %d free\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, FreeMagic);
free(v);
unlock(&malloclock);
-//fprint(2, "%s %d donefree\n", argv0, getpid());
+/*fprint(2, "%s %d donefree\n", argv0, getpid()); */
}
void*
@@ -141,26 +141,26 @@ p9calloc(ulong a, ulong b)
{
void *v;
-//fprint(2, "%s %d calloc\n", argv0, getpid());
+/*fprint(2, "%s %d calloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = calloc(a*b+Overhead, 1);
v = mark(v, getcallerpc(&a), a*b, CallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donecalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */
return v;
}
void*
p9realloc(void *v, ulong n)
{
-//fprint(2, "%s %d realloc\n", argv0, getpid());
+/*fprint(2, "%s %d realloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, CheckMagic);
v = realloc(v, n+Overhead);
v = mark(v, getcallerpc(&v), n, ReallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donerealloc\n", argv0, getpid());
+/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */
return v;
}
diff --git a/lib9/dial.c b/lib9/dial.c
@@ -60,10 +60,6 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
}
free(buf);
- memset(&sa, 0, sizeof sa);
- memmove(&sa.sin_addr, &host, 4);
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
if((s = socket(AF_INET, proto, 0)) < 0)
return -1;
@@ -98,9 +94,17 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
free(buf);
}
- if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
- close(s);
- return -1;
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
+ if(host != 0){
+ memset(&sa, 0, sizeof sa);
+ memmove(&sa.sin_addr, &host, 4);
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
+ close(s);
+ return -1;
+ }
}
if(proto == SOCK_STREAM){
int one = 1;
@@ -114,6 +118,9 @@ Unix:
free(buf);
return -1;
}
+ /* Allow regular files in addition to Unix sockets. */
+ if((s = open(unix, ORDWR)) >= 0)
+ return s;
memset(&su, 0, sizeof su);
su.sun_family = AF_UNIX;
if(strlen(unix)+1 > sizeof su.sun_path){
diff --git a/lib9/dirfwstat.c b/lib9/dirfwstat.c
@@ -4,7 +4,7 @@
#include <sys/time.h>
#include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__)
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
/* do nothing -- futimes exists and is fine */
#elif defined(__SunOS5_9__)
@@ -48,6 +48,10 @@ dirfwstat(int fd, Dir *dir)
if(futimes(fd, tv) < 0)
ret = -1;
}
+ if(~dir->length != 0){
+ if(ftruncate(fd, dir->length) < 0)
+ ret = -1;
+ }
return ret;
}
diff --git a/lib9/dirread.c b/lib9/dirread.c
@@ -18,19 +18,25 @@ mygetdents(int fd, struct dirent *buf, int n)
nn = getdirentries(fd, (void*)buf, n, &off);
return nn;
}
-#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || defined(__NetBSD__)
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
static int
mygetdents(int fd, struct dirent *buf, int n)
{
long off;
return getdirentries(fd, (void*)buf, n, &off);
}
-#elif defined(__sun__)
+#elif defined(__sun__) || defined(__NetBSD__)
static int
mygetdents(int fd, struct dirent *buf, int n)
{
return getdents(fd, (void*)buf, n);
}
+#elif defined(__AIX__)
+static int
+mygetdents(int fd, struct dirent *buf, int n)
+{
+ return getdirent(fd, (void*)buf, n);
+}
#endif
static int
diff --git a/lib9/dirwstat.c b/lib9/dirwstat.c
@@ -3,17 +3,29 @@
#include <libc.h>
#include <sys/time.h>
#include <utime.h>
+#include <sys/stat.h>
int
dirwstat(char *file, Dir *dir)
{
+ int ret;
struct utimbuf ub;
/* BUG handle more */
- if(~dir->mtime == 0)
- return 0;
-
- ub.actime = dir->mtime;
- ub.modtime = dir->mtime;
- return utime(file, &ub);
+ ret = 0;
+ if(~dir->mode != 0){
+ if(chmod(file, dir->mode) < 0)
+ ret = -1;
+ }
+ if(~dir->mtime != 0){
+ ub.actime = dir->mtime;
+ ub.modtime = dir->mtime;
+ if(utime(file, &ub) < 0)
+ ret = -1;
+ }
+ if(~dir->length != 0){
+ if(truncate(file, dir->length) < 0)
+ ret = -1;
+ }
+ return ret;
}
diff --git a/lib9/encodefmt.c b/lib9/encodefmt.c
@@ -1,11 +1,4 @@
#include <lib9.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "fmt.h"
-
-extern int enc64(char*, int, uchar*, int);
-extern int enc32(char*, int, uchar*, int);
-extern int enc16(char*, int, uchar*, int);
int
encodefmt(Fmt *f)
@@ -16,7 +9,7 @@ encodefmt(Fmt *f)
int ilen;
int rv;
uchar *b;
- char obuf[64]; // rsc optimization
+ char obuf[64]; /* rsc optimization */
b = va_arg(f->args, uchar*);
if(b == 0)
@@ -51,7 +44,7 @@ encodefmt(Fmt *f)
} else
buf = obuf;
- // convert
+ /* convert */
out = buf;
switch(f->r){
case '<':
diff --git a/lib9/errstr.c b/lib9/errstr.c
@@ -12,7 +12,7 @@
enum
{
- EPLAN9 = 0x19283745,
+ EPLAN9 = 0x19283745
};
char *(*_syserrstr)(void);
diff --git a/lib9/exitcode.c b/lib9/exitcode.c
@@ -0,0 +1,9 @@
+#include <u.h>
+#include <libc.h>
+
+int
+exitcode(char *s)
+{
+ return 1;
+}
+
diff --git a/lib9/fcallfmt.c b/lib9/fcallfmt.c
@@ -124,7 +124,7 @@ fcallfmt(Fmt *fmt)
break;
case Rstat:
p = seprint(buf, e, "Rstat tag %ud ", tag);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
@@ -135,7 +135,7 @@ fcallfmt(Fmt *fmt)
break;
case Twstat: /* 126 */
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
diff --git a/lib9/fmt.h b/lib9/fmt.h
@@ -34,6 +34,18 @@ struct Fmt{
int width;
int prec;
unsigned long flags;
+ char *decimal; /* decimal point; cannot be "" */
+
+ /* For %'d */
+ char *thousands; /* separator for thousands */
+
+ /*
+ * Each char is an integer indicating #digits before next separator. Values:
+ * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
+ * \x00: repeat previous indefinitely
+ * \x**: count that many
+ */
+ char *grouping; /* descriptor of separator placement */
};
enum{
@@ -43,7 +55,8 @@ enum{
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
- FmtZero = FmtSign << 1,
+ FmtApost = FmtSign << 1,
+ FmtZero = FmtApost << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
@@ -64,6 +77,8 @@ double fmtcharstod(int(*f)(void*), void *vp);
int fmtfdflush(Fmt *f);
int fmtfdinit(Fmt *f, int fd, char *buf, int size);
int fmtinstall(int c, int (*f)(Fmt*));
+int fmtnullinit(Fmt*);
+void fmtlocaleinit(Fmt*, char*, char*, char*);
int fmtprint(Fmt *f, char *fmt, ...);
int fmtrune(Fmt *f, int r);
int fmtrunestrcpy(Fmt *f, Rune *s);
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/LICENSE
@@ -1,19 +1,22 @@
/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-*/
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
This is a Unix port of the Plan 9 formatted I/O package.
-Please send comments about the packaging
-to Russ Cox <rsc@post.harvard.edu>.
+Please send comments about the packaging to Russ Cox <rsc@swtch.com>.
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/NOTICE
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/README
diff --git a/lib9/fmt/charstod.c b/lib9/fmt/charstod.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/dofmt.c b/lib9/fmt/dofmt.c
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -97,7 +87,7 @@ __fmtflush(Fmt *f, void *t, int len)
/*
* put a formatted block of memory sz bytes long of n runes into the output buffer,
- * left/right justified in a field of at least f->width charactes
+ * left/right justified in a field of at least f->width characters (if FmtWidth is set)
*/
int
__fmtpad(Fmt *f, int n)
@@ -139,8 +129,10 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
m = (char*)vm;
me = m + sz;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
@@ -194,8 +186,10 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
int w;
m = (Rune*)vm;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
@@ -252,15 +246,23 @@ int
fmtstrcpy(Fmt *f, char *s)
{
int i, j;
- Rune r;
if(!s)
return __fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+ Rune r;
i = 0;
for(j=0; j<f->prec && s[i]; j++)
i += chartorune(&r, s+i);
+#else
+ /* ANSI requires precision in bytes, not Runes */
+ for(i=0; i<f->prec; i++)
+ if(s[i] == 0)
+ break;
+ j = utfnlen(s, i); /* won't print partial at end */
+#endif
return __fmtcpy(f, s, j, i);
}
return __fmtcpy(f, s, utflen(s), strlen(s));
@@ -324,10 +326,14 @@ __percentfmt(Fmt *f)
int
__ifmt(Fmt *f)
{
- char buf[70], *p, *conv;
+ char buf[140], *p, *conv;
+ /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
uvlong vu;
ulong u;
int neg, base, i, n, fl, w, isv;
+ int ndig, len, excess, bytelen;
+ char *grouping;
+ char *thousands;
neg = 0;
fl = f->flags;
@@ -339,11 +345,11 @@ __ifmt(Fmt *f)
* Unsigned verbs for ANSI C
*/
switch(f->r){
- case 'x':
- case 'X':
case 'o':
- case 'u':
case 'p':
+ case 'u':
+ case 'x':
+ case 'X':
fl |= FmtUnsigned;
fl &= ~(FmtSign|FmtSpace);
break;
@@ -381,21 +387,25 @@ __ifmt(Fmt *f)
u = va_arg(f->args, int);
}
conv = "0123456789abcdef";
+ grouping = "\4"; /* for hex, octal etc. (undefined by spec but nice) */
+ thousands = f->thousands;
switch(f->r){
case 'd':
case 'i':
case 'u':
base = 10;
- break;
- case 'x':
- base = 16;
+ grouping = f->grouping;
break;
case 'X':
- base = 16;
conv = "0123456789ABCDEF";
+ /* fall through */
+ case 'x':
+ base = 16;
+ thousands = ":";
break;
case 'b':
base = 2;
+ thousands = ":";
break;
case 'o':
base = 8;
@@ -413,7 +423,11 @@ __ifmt(Fmt *f)
}
}
p = buf + sizeof buf - 1;
- n = 0;
+ n = 0; /* in runes */
+ excess = 0; /* number of bytes > number runes */
+ ndig = 0;
+ len = utflen(thousands);
+ bytelen = strlen(thousands);
if(isv){
while(vu){
i = vu % base;
@@ -422,6 +436,12 @@ __ifmt(Fmt *f)
*p-- = ',';
n++;
}
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = conv[i];
n++;
}
@@ -433,16 +453,47 @@ __ifmt(Fmt *f)
*p-- = ',';
n++;
}
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = conv[i];
n++;
}
}
if(n == 0){
- *p-- = '0';
- n = 1;
+ /*
+ * "The result of converting a zero value with
+ * a precision of zero is no characters." - ANSI
+ *
+ * "For o conversion, # increases the precision, if and only if
+ * necessary, to force the first digit of the result to be a zero
+ * (if the value and precision are both 0, a single 0 is printed)." - ANSI
+ */
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & FmtSharp))){
+ *p-- = '0';
+ n = 1;
+ if(fl & FmtApost)
+ __needsep(&ndig, &grouping);
+ }
+
+ /*
+ * Zero values don't get 0x.
+ */
+ if(f->r == 'x' || f->r == 'X')
+ fl &= ~FmtSharp;
}
- for(w = f->prec; n < w && p > buf+3; n++)
+ for(w = f->prec; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = '0';
+ }
if(neg || (fl & (FmtSign|FmtSpace)))
n++;
if(fl & FmtSharp){
@@ -456,9 +507,19 @@ __ifmt(Fmt *f)
}
}
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
- for(w = f->width; n < w && p > buf+3; n++)
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ for(; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = '0';
- f->width = 0;
+ }
+ f->flags &= ~FmtWidth;
}
if(fl & FmtSharp){
if(base == 16)
@@ -473,7 +534,7 @@ __ifmt(Fmt *f)
else if(fl & FmtSpace)
*p-- = ' ';
f->flags &= ~FmtPrec;
- return __fmtcpy(f, p + 1, n, n);
+ return __fmtcpy(f, p + 1, n, n + excess);
}
int
@@ -514,6 +575,9 @@ __flagfmt(Fmt *f)
case '#':
f->flags |= FmtSharp;
break;
+ case '\'':
+ f->flags |= FmtApost;
+ break;
case ' ':
f->flags |= FmtSpace;
break;
diff --git a/lib9/fmt/dorfmt.c b/lib9/fmt/dorfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -19,6 +7,7 @@
/* format the output into f->to and return the number of characters fmted */
+/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
int
dorfmt(Fmt *f, const Rune *fmt)
{
@@ -30,8 +19,8 @@ dorfmt(Fmt *f, const Rune *fmt)
nfmt = f->nfmt;
for(;;){
if(f->runes){
- rt = f->to;
- rs = f->stop;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRCHAR(f, rt, rs, r);
}
@@ -41,8 +30,8 @@ dorfmt(Fmt *f, const Rune *fmt)
return f->nfmt - nfmt;
f->stop = rs;
}else{
- t = f->to;
- s = f->stop;
+ t = (char*)f->to;
+ s = (char*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRUNE(f, t, f->stop, r);
}
@@ -53,7 +42,7 @@ dorfmt(Fmt *f, const Rune *fmt)
f->stop = s;
}
- fmt = __fmtdispatch(f, (Rune*)fmt, 1);
+ fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
if(fmt == nil)
return -1;
}
diff --git a/lib9/fmt/errfmt.c b/lib9/fmt/errfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <errno.h>
#include <string.h>
diff --git a/lib9/fmt/fltfmt.c b/lib9/fmt/fltfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdio.h>
#include <math.h>
#include <float.h>
@@ -18,11 +6,12 @@
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <ctype.h>
#include <fmt.h>
+#include <assert.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
+#include "nan.h"
enum
{
@@ -54,8 +43,8 @@ static double pows10[] =
1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
};
-
-#define pow10(x) fmtpow10(x)
+#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#define pow10(x) fmtpow10(x)
static double
pow10(int n)
@@ -65,330 +54,615 @@ pow10(int n)
neg = 0;
if(n < 0){
- if(n < DBL_MIN_10_EXP){
- return 0.;
- }
neg = 1;
n = -n;
- }else if(n > DBL_MAX_10_EXP){
- return HUGE_VAL;
}
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
+
+ if(n < npows10)
d = pows10[n];
else{
- d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d = pows10[npows10-1];
for(;;){
- n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
+ n -= npows10 - 1;
+ if(n < npows10){
d *= pows10[n];
break;
}
- d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d *= pows10[npows10 - 1];
}
}
- if(neg){
+ if(neg)
return 1./d;
- }
return d;
}
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
static int
-xadd(char *a, int n, int v)
+xadd1(char *a, int n)
{
char *b;
int c;
- if(n < 0 || n >= NSIGNIF)
+ if(n < 0 || n > NSIGNIF)
return 0;
- for(b = a+n; b >= a; b--) {
- c = *b + v;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b + 1;
if(c <= '9') {
*b = c;
return 0;
}
*b = '0';
- v = 1;
}
- *a = '1'; /* overflow adding */
+ /*
+ * need to overflow adding digit.
+ * shift number down and insert 1 at beginning.
+ * decimal is known to be 0s or we wouldn't
+ * have gotten this far. (e.g., 99999+1 => 00000)
+ */
+ a[0] = '1';
return 1;
}
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point. this way, xsub1 is inverse of xadd1.
+ */
static int
-xsub(char *a, int n, int v)
+xsub1(char *a, int n)
{
char *b;
int c;
- for(b = a+n; b >= a; b--) {
- c = *b - v;
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b - 1;
if(c >= '0') {
+ if(c == '0' && b == a) {
+ /*
+ * just zeroed the top digit; shift everyone up.
+ * decimal is known to be 9s or we wouldn't
+ * have gotten this far. (e.g., 10000-1 => 09999)
+ */
+ *b = '9';
+ return 1;
+ }
*b = c;
return 0;
}
*b = '9';
- v = 1;
}
- *a = '9'; /* underflow subtracting */
- return 1;
+ /*
+ * can't get here. the number a is always normalized
+ * so that it has a nonzero first digit.
+ */
+ abort();
}
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
static void
-xdtoa(Fmt *fmt, char *s2, double f)
+xfmtexp(char *p, int e, int ucase)
{
- char s1[NSIGNIF+10];
- double g, h;
- int e, d, i, n;
- int c1, c2, c3, c4, ucase, sign, chr, prec;
+ char se[9];
+ int i;
- prec = FDEFLT;
- if(fmt->flags & FmtPrec)
- prec = fmt->prec;
- if(prec > FDIGIT)
- prec = FDIGIT;
- if(__isNaN(f)) {
- strcpy(s2, "NaN");
- return;
- }
- if(__isInf(f, 1)) {
- strcpy(s2, "+Inf");
- return;
- }
- if(__isInf(f, -1)) {
- strcpy(s2, "-Inf");
- return;
+ *p++ = ucase ? 'E' : 'e';
+ if(e < 0) {
+ *p++ = '-';
+ e = -e;
+ } else
+ *p++ = '+';
+ i = 0;
+ while(e) {
+ se[i++] = e % 10 + '0';
+ e /= 10;
}
- sign = 0;
+ while(i < 2)
+ se[i++] = '0';
+ while(i > 0)
+ *p++ = se[--i];
+ *p++ = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ * f = m*10^exp
+ * m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+ int c, d, e2, e, ee, i, ndigit, oerrno;
+ char tmp[NSIGNIF+10];
+ double g;
+
+ oerrno = errno; /* in case strtod smashes errno */
+
+ /*
+ * make f non-negative.
+ */
+ *neg = 0;
if(f < 0) {
f = -f;
- sign++;
- }
- ucase = 0;
- chr = fmt->r;
- if(isupper(chr)) {
- ucase = 1;
- chr = tolower(chr);
+ *neg = 1;
}
- e = 0;
- g = f;
- if(g != 0) {
- frexp(f, &e);
- e = e * .301029995664;
- if(e >= -150 && e <= +150) {
- d = 0;
- h = f;
- } else {
- d = e/2;
- h = f * pow10(-d);
- }
- g = h * pow10(d-e);
- while(g < 1) {
- e--;
- g = h * pow10(d-e);
- }
- while(g >= 10) {
- e++;
- g = h * pow10(d-e);
- }
+ /*
+ * must handle zero specially.
+ */
+ if(f == 0){
+ *exp = 0;
+ s[0] = '0';
+ s[1] = '\0';
+ *ns = 1;
+ return;
+ }
+
+ /*
+ * find g,e such that f = g*10^e.
+ * guess 10-exponent using 2-exponent, then fine tune.
+ */
+ frexp(f, &e2);
+ e = (int)(e2 * .301029995664);
+ g = f * pow10(-e);
+ while(g < 1) {
+ e--;
+ g = f * pow10(-e);
+ }
+ while(g >= 10) {
+ e++;
+ g = f * pow10(-e);
}
/*
- * convert NSIGNIF digits and convert
- * back to get accuracy.
+ * convert NSIGNIF digits as a first approximation.
*/
for(i=0; i<NSIGNIF; i++) {
- d = g;
- s1[i] = d + '0';
- g = (g - d) * 10;
+ d = (int)g;
+ s[i] = d+'0';
+ g = (g-d) * 10;
}
- s1[i] = 0;
+ s[i] = 0;
/*
- * try decimal rounding to eliminate 9s
+ * adjust e because s is 314159... not 3.14159...
*/
- c2 = prec + 1;
- if(chr == 'f')
- c2 += e;
- if(c2 >= NSIGNIF-2) {
- strcpy(s2, s1);
- d = e;
- s1[NSIGNIF-2] = '0';
- s1[NSIGNIF-1] = '0';
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- if(xadd(s1, NSIGNIF-3, 1)) {
- e++;
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- }
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- strcpy(s1, s2);
- e = d;
- }
+ e -= NSIGNIF-1;
+ xfmtexp(s+NSIGNIF, e, 0);
/*
- * convert back so s1 gets exact answer
+ * adjust conversion until strtod(s) == f exactly.
*/
- for(;;) {
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
+ for(i=0; i<10; i++) {
+ g = fmtstrtod(s, nil);
if(f > g) {
- if(xadd(s1, NSIGNIF-1, 1))
+ if(xadd1(s, NSIGNIF)) {
+ /* gained a digit */
e--;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
continue;
}
if(f < g) {
- if(xsub(s1, NSIGNIF-1, 1))
+ if(xsub1(s, NSIGNIF)) {
+ /* lost a digit */
e++;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
continue;
}
break;
}
-found:
/*
- * sign
+ * play with the decimal to try to simplify.
*/
- d = 0;
- i = 0;
- if(sign)
- s2[d++] = '-';
- else if(fmt->flags & FmtSign)
- s2[d++] = '+';
- else if(fmt->flags & FmtSpace)
- s2[d++] = ' ';
/*
- * copy into final place
- * c1 digits of leading '0'
- * c2 digits from conversion
- * c3 digits of trailing '0'
- * c4 digits after '.'
+ * bump last few digits up to 9 if we can
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '9') {
+ s[i] = '9';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add 1 in hopes of turning 9s to 0s
+ */
+ if(s[NSIGNIF-1] == '9') {
+ strcpy(tmp, s);
+ ee = e;
+ if(xadd1(tmp, NSIGNIF)) {
+ ee--;
+ xfmtexp(tmp+NSIGNIF, ee, 0);
+ }
+ g = fmtstrtod(tmp, nil);
+ if(g == f) {
+ strcpy(s, tmp);
+ e = ee;
+ }
+ }
+
+ /*
+ * bump last few digits down to 0 as we can.
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '0') {
+ s[i] = '0';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * remove trailing zeros.
+ */
+ ndigit = NSIGNIF;
+ while(ndigit > 1 && s[ndigit-1] == '0'){
+ e++;
+ --ndigit;
+ }
+ s[ndigit] = 0;
+ *exp = e;
+ *ns = ndigit;
+ errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+ char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+ double f;
+ int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
+ int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+ Rune r, *rs, *rt;
+
+ if(fmt->flags&FmtLong)
+ f = va_arg(fmt->args, long double);
+ else
+ f = va_arg(fmt->args, double);
+
+ /*
+ * extract formatting flags
*/
- c1 = 0;
- c2 = prec + 1;
- c3 = 0;
- c4 = prec;
+ fl = fmt->flags;
+ fmt->flags = 0;
+ prec = FDEFLT;
+ if(fl & FmtPrec)
+ prec = fmt->prec;
+ chr = fmt->r;
+ ucase = 0;
switch(chr) {
- default:
- if(xadd(s1, c2, 5))
- e++;
+ case 'A':
+ case 'E':
+ case 'F':
+ case 'G':
+ chr += 'a'-'A';
+ ucase = 1;
break;
+ }
+
+ /*
+ * pick off special numbers.
+ */
+ if(__isNaN(f)) {
+ s = special[0+ucase];
+ special:
+ fmt->flags = fl & (FmtWidth|FmtLeft);
+ return __fmtcpy(fmt, s, strlen(s), strlen(s));
+ }
+ if(__isInf(f, 1)) {
+ s = special[2+ucase];
+ goto special;
+ }
+ if(__isInf(f, -1)) {
+ s = special[4+ucase];
+ goto special;
+ }
+
+ /*
+ * get exact representation.
+ */
+ digits = buf;
+ xdtoa(f, digits, &exp, &neg, &ndigits);
+
+ /*
+ * get locale's decimal point.
+ */
+ dot = fmt->decimal;
+ if(dot == nil)
+ dot = ".";
+ dotwid = utflen(dot);
+
+ /*
+ * now the formatting fun begins.
+ * compute parameters for actual fmt:
+ *
+ * pad: number of spaces to insert before/after field.
+ * z1: number of zeros to insert before digits
+ * z2: number of zeros to insert after digits
+ * point: number of digits to print before decimal point
+ * ndigits: number of digits to use from digits[]
+ * suf: trailing suffix, like "e-5"
+ */
+ realchr = chr;
+ switch(chr){
case 'g':
/*
- * decide on 'e' of 'f' style convers
+ * convert to at most prec significant digits. (prec=0 means 1)
+ */
+ if(prec == 0)
+ prec = 1;
+ if(ndigits > prec) {
+ if(digits[prec] >= '5' && xadd1(digits, prec))
+ exp++;
+ exp += ndigits-prec;
+ ndigits = prec;
+ }
+
+ /*
+ * extra rules for %g (implemented below):
+ * trailing zeros removed after decimal unless FmtSharp.
+ * decimal point only if digit follows.
+ */
+
+ /* fall through to %e */
+ default:
+ case 'e':
+ /*
+ * one significant digit before decimal, no leading zeros.
+ */
+ point = 1;
+ z1 = 0;
+
+ /*
+ * decimal point is after ndigits digits right now.
+ * slide to be after first.
+ */
+ e = exp + (ndigits-1);
+
+ /*
+ * if this is %g, check exponent and convert prec
*/
- if(xadd(s1, c2, 5))
- e++;
- if(e >= -5 && e <= prec) {
- c1 = -e - 1;
- c4 = prec - e;
- chr = 'h'; // flag for 'f' style
+ if(realchr == 'g') {
+ if(-4 <= e && e < prec)
+ goto casef;
+ prec--; /* one digit before decimal; rest after */
+ }
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(1+prec >= ndigits)
+ z2 = 1+prec - ndigits;
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = 1+prec;
+ if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * had 999e4, now have 100e5
+ */
+ e++;
+ }
+ ndigits = newndigits;
+ z2 = 0;
}
+ xfmtexp(suf, e, ucase);
+ sufwid = strlen(suf);
break;
+
+ casef:
case 'f':
- if(xadd(s1, c2+e, 5))
- e++;
- c1 = -e;
- if(c1 > prec)
- c1 = c2;
- c2 += e;
+ /*
+ * determine where digits go with respect to decimal point
+ */
+ if(ndigits+exp > 0) {
+ point = ndigits+exp;
+ z1 = 0;
+ } else {
+ point = 1;
+ z1 = 1 + -(ndigits+exp);
+ }
+
+ /*
+ * %g specifies prec = number of significant digits
+ * convert to number of digits after decimal point
+ */
+ if(realchr == 'g')
+ prec += z1 - point;
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(point+prec >= z1+ndigits)
+ z2 = point+prec - (z1+ndigits);
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = point+prec - z1;
+ if(newndigits < 0) {
+ z1 += newndigits;
+ newndigits = 0;
+ } else if(newndigits == 0) {
+ /* perhaps round up */
+ if(digits[0] >= '5'){
+ digits[0] = '1';
+ newndigits = 1;
+ goto newdigit;
+ }
+ } else if(digits[newndigits] >= '5' && xadd1(digits, newndigits)) {
+ /*
+ * digits was 999, is now 100; make it 1000
+ */
+ digits[newndigits++] = '0';
+ newdigit:
+ /*
+ * account for new digit
+ */
+ if(z1) /* 0.099 => 0.100 or 0.99 => 1.00*/
+ z1--;
+ else /* 9.99 => 10.00 */
+ point++;
+ }
+ z2 = 0;
+ ndigits = newndigits;
+ }
+ sufwid = 0;
break;
}
-
+
/*
- * clean up c1 c2 and c3
+ * if %g is given without FmtSharp, remove trailing zeros.
+ * must do after truncation, so that e.g. print %.3g 1.001
+ * produces 1, not 1.00. sorry, but them's the rules.
*/
- if(c1 < 0)
- c1 = 0;
- if(c2 < 0)
- c2 = 0;
- if(c2 > NSIGNIF) {
- c3 = c2-NSIGNIF;
- c2 = NSIGNIF;
+ if(realchr == 'g' && !(fl & FmtSharp)) {
+ if(z1+ndigits+z2 >= point) {
+ if(z1+ndigits < point)
+ z2 = point - (z1+ndigits);
+ else{
+ z2 = 0;
+ while(z1+ndigits > point && digits[ndigits-1] == '0')
+ ndigits--;
+ }
+ }
}
/*
- * copy digits
+ * compute width of all digits and decimal point and suffix if any
*/
- while(c1 > 0) {
- if(c1+c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c1--;
- }
- while(c2 > 0) {
- if(c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = s1[i++];
- c2--;
+ wid = z1+ndigits+z2;
+ if(wid > point)
+ wid += dotwid;
+ else if(wid == point){
+ if(fl & FmtSharp)
+ wid += dotwid;
+ else
+ point++; /* do not print any decimal point */
}
- while(c3 > 0) {
- if(c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c3--;
+ wid += sufwid;
+
+ /*
+ * determine sign
+ */
+ sign = 0;
+ if(neg)
+ sign = '-';
+ else if(fl & FmtSign)
+ sign = '+';
+ else if(fl & FmtSpace)
+ sign = ' ';
+ if(sign)
+ wid++;
+
+ /*
+ * compute padding
+ */
+ pad = 0;
+ if((fl & FmtWidth) && fmt->width > wid)
+ pad = fmt->width - wid;
+ if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+ z1 += pad;
+ point += pad;
+ pad = 0;
}
/*
- * strip trailing '0' on g conv
+ * format the actual field. too bad about doing this twice.
*/
- if(fmt->flags & FmtSharp) {
- if(0 == c4)
- s2[d++] = '.';
- } else
- if(chr == 'g' || chr == 'h') {
- for(n=d-1; n>=0; n--)
- if(s2[n] != '0')
- break;
- for(i=n; i>=0; i--)
- if(s2[i] == '.') {
- d = n;
- if(i != n)
- d++;
- break;
+ if(fmt->runes){
+ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ rt = (Rune*)fmt->to;
+ rs = (Rune*)fmt->stop;
+ if(sign)
+ FMTRCHAR(fmt, rt, rs, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
}
- }
- if(chr == 'e' || chr == 'g') {
- if(ucase)
- s2[d++] = 'E';
- else
- s2[d++] = 'e';
- c1 = e;
- if(c1 < 0) {
- s2[d++] = '-';
- c1 = -c1;
- } else
- s2[d++] = '+';
- if(c1 >= 100) {
- s2[d++] = c1/100 + '0';
- c1 = c1%100;
+ FMTRCHAR(fmt, rt, rs, c);
+ if(--point == 0) {
+ for(p = dot; *p; ){
+ p += chartorune(&r, p);
+ FMTRCHAR(fmt, rt, rs, r);
+ }
+ }
+ }
+ fmt->nfmt += rt - (Rune*)fmt->to;
+ fmt->to = rt;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ }else{
+ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ t = (char*)fmt->to;
+ s = (char*)fmt->stop;
+ if(sign)
+ FMTCHAR(fmt, t, s, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTCHAR(fmt, t, s, c);
+ if(--point == 0)
+ for(p=dot; *p; p++)
+ FMTCHAR(fmt, t, s, *p);
}
- s2[d++] = c1/10 + '0';
- s2[d++] = c1%10 + '0';
+ fmt->nfmt += t - (char*)fmt->to;
+ fmt->to = t;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
}
- s2[d] = 0;
-}
-
-static int
-floatfmt(Fmt *fmt, double f)
-{
- char s[FDIGIT+10];
-
- xdtoa(fmt, s, f);
- fmt->flags &= FmtWidth|FmtLeft;
- __fmtcpy(fmt, s, strlen(s), strlen(s));
return 0;
}
-int
-__efgfmt(Fmt *f)
-{
- double d;
-
- d = va_arg(f->args, double);
- return floatfmt(f, d);
-}
diff --git a/lib9/fmt/fmt.c b/lib9/fmt/fmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -29,7 +17,7 @@ struct Convfmt
volatile Fmts fmt; /* for spin lock in fmtfmt; avoids race due to write order */
};
-struct
+static struct
{
/* lock by calling __fmtlock, __fmtunlock */
int nfmt;
@@ -40,6 +28,7 @@ static Convfmt knownfmt[] = {
' ', __flagfmt,
'#', __flagfmt,
'%', __percentfmt,
+ '\'', __flagfmt,
'+', __flagfmt,
',', __flagfmt,
'-', __flagfmt,
diff --git a/lib9/fmt/fmtdef.h b/lib9/fmt/fmtdef.h
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* dofmt -- format to a buffer
@@ -53,6 +41,7 @@ void __fmtunlock(void);
int __ifmt(Fmt *f);
int __isInf(double d, int sign);
int __isNaN(double d);
+int __needsep(int*, char**);
int __needsquotes(char *s, int *quotelenp);
int __percentfmt(Fmt *f);
void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int runesout);
@@ -66,9 +55,9 @@ int __strfmt(Fmt *f);
#define FMTCHAR(f, t, s, c)\
do{\
if(t + 1 > (char*)s){\
- t = __fmtflush(f, t, 1);\
+ t = (char*)__fmtflush(f, t, 1);\
if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
else\
return -1;\
}\
@@ -78,9 +67,9 @@ int __strfmt(Fmt *f);
#define FMTRCHAR(f, t, s, c)\
do{\
if(t + 1 > (Rune*)s){\
- t = __fmtflush(f, t, sizeof(Rune));\
+ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
if(t != nil)\
- s = f->stop;\
+ s = (Rune*)f->stop;\
else\
return -1;\
}\
@@ -92,9 +81,9 @@ int __strfmt(Fmt *f);
Rune _rune;\
int _runelen;\
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
- t = __fmtflush(f, t, _runelen);\
+ t = (char*)__fmtflush(f, t, _runelen);\
if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
else\
return -1;\
}\
diff --git a/lib9/fmt/fmtfd.c b/lib9/fmt/fmtfd.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -40,7 +28,9 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size)
f->to = buf;
f->stop = buf + size;
f->flush = __fmtFdFlush;
- f->farg = (void*)fd;
+ f->farg = (void*)(uintptr_t)fd;
+ f->flags = 0;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/fmtfdflush.c b/lib9/fmt/fmtfdflush.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <unistd.h>
#include "plan9.h"
@@ -27,7 +15,7 @@ __fmtFdFlush(Fmt *f)
int n;
n = (char*)f->to - (char*)f->start;
- if(n && write((int)f->farg, f->start, n) != n)
+ if(n && write((uintptr)f->farg, f->start, n) != n)
return 0;
f->to = f->start;
return 1;
diff --git a/lib9/fmt/fmtlocale.c b/lib9/fmt/fmtlocale.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ * decimal is a period
+ * thousands separator is a comma
+ * thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+ if(decimal == nil || decimal[0] == '\0')
+ decimal = ".";
+ if(thousands == nil)
+ thousands = ",";
+ if(grouping == nil)
+ grouping = "\3";
+ f->decimal = decimal;
+ f->thousands = thousands;
+ f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d. If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator. Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+ int group;
+
+ (*ndig)++;
+ group = *(unsigned char*)*grouping;
+ /* CHAR_MAX means no further grouping. \0 means we got the empty string */
+ if(group == 0xFF || group == 0x7f || group == 0x00)
+ return 0;
+ if(*ndig > group){
+ /* if we're at end of string, continue with this grouping; else advance */
+ if((*grouping)[1] != '\0')
+ (*grouping)++;
+ *ndig = 1;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/lib9/fmt/fmtlock.c b/lib9/fmt/fmtlock.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/fmtnull.c b/lib9/fmt/fmtnull.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+ f->to = nullbuf;
+ f->nfmt = 0;
+ return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+ memset(f, 0, sizeof *f);
+ f->runes = 1;
+ f->start = nullbuf;
+ f->to = nullbuf;
+ f->stop = nullbuf+nelem(nullbuf);
+ f->flush = __fmtnullflush;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
diff --git a/lib9/fmt/fmtprint.c b/lib9/fmt/fmtprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fmtquote.c b/lib9/fmt/fmtquote.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -103,6 +91,11 @@ __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, int sharp, int r
/* advance output */
q->nbytesout += w;
q->nrunesout++;
+
+#ifndef PLAN9PORT
+ /* ANSI requires precision in bytes, not Runes. */
+ nin-= w-1; /* and then n-- in the loop */
+#endif
}
}
@@ -120,8 +113,10 @@ qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
rm = rin;
rme = rm + q->nrunesin;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if(f->runes){
if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
return -1;
@@ -209,7 +204,7 @@ __quotestrfmt(int runesin, Fmt *f)
outlen = (char*)f->stop - (char*)f->to;
__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
-//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout);
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nbytesout, q.nrunesin, q.nrunesout); */
if(runesin){
if(!q.quoted)
diff --git a/lib9/fmt/fmtrune.c b/lib9/fmt/fmtrune.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fmtstr.c b/lib9/fmt/fmtstr.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
@@ -23,5 +11,6 @@ fmtstrflush(Fmt *f)
if(f->start == nil)
return nil;
*(char*)f->to = '\0';
+ f->to = f->start;
return (char*)f->start;
}
diff --git a/lib9/fmt/fmtvprint.c b/lib9/fmt/fmtvprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fprint.c b/lib9/fmt/fprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/nan.h b/lib9/fmt/nan.h
@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern int __isNaN(double);
+extern int __isInf(double, int);
diff --git a/lib9/fmt/nan64.c b/lib9/fmt/nan64.c
@@ -6,58 +6,67 @@
*/
#include "plan9.h"
+#include <assert.h>
#include "fmt.h"
#include "fmtdef.h"
-#if defined (__APPLE__) || (__powerpc__)
-#define _NEEDLL
-#endif
-
static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.d = d;
+ return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.v = v;
+ return u.d;
+}
+
double
__NaN(void)
{
- uvlong *p;
-
- /* gcc complains about "return *(double*)&uvnan;" */
- p = &uvnan;
- return *(double*)p;
+ return u2d(uvnan);
}
int
__isNaN(double d)
{
uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
- return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
+
+ x = d2u(d);
+ /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+ return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
}
double
__Inf(int sign)
{
- uvlong *p;
-
- if(sign < 0)
- p = &uvinf;
- else
- p = &uvneginf;
- return *(double*)p;
+ return u2d(sign < 0 ? uvneginf : uvinf);
}
int
__isInf(double d, int sign)
{
uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
+
+ x = d2u(d);
if(sign == 0)
return x==uvinf || x==uvneginf;
else if(sign > 0)
diff --git a/lib9/fmt/plan9.h b/lib9/fmt/plan9.h
@@ -1,3 +1,5 @@
+#include <inttypes.h>
+
/*
* compiler directive on Plan 9
*/
@@ -14,12 +16,15 @@
#define ulong _fmtulong
#define vlong _fmtvlong
#define uvlong _fmtuvlong
+#define uintptr _fmtuintptr
+
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long uvlong;
typedef long long vlong;
+typedef uintptr_t uintptr;
/*
* nil cannot be ((void*)0) on ANSI C,
diff --git a/lib9/fmt/pow10.c b/lib9/fmt/pow10.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/print.c b/lib9/fmt/print.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/runefmtstr.c b/lib9/fmt/runefmtstr.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <stdlib.h>
#include "plan9.h"
@@ -23,5 +11,6 @@ runefmtstrflush(Fmt *f)
if(f->start == nil)
return nil;
*(Rune*)f->to = '\0';
+ f->to = f->start;
return f->start;
}
diff --git a/lib9/fmt/runeseprint.c b/lib9/fmt/runeseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesmprint.c b/lib9/fmt/runesmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesnprint.c b/lib9/fmt/runesnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesprint.c b/lib9/fmt/runesprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runevseprint.c b/lib9/fmt/runevseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
diff --git a/lib9/fmt/runevsmprint.c b/lib9/fmt/runevsmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@ runeFmtStrFlush(Fmt *f)
if(f->start == nil)
return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
n *= 2;
s = (Rune*)f->start;
f->start = realloc(s, sizeof(Rune)*n);
@@ -47,7 +35,7 @@ runeFmtStrFlush(Fmt *f)
free(s);
return 0;
}
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->to = (Rune*)f->start + ((Rune*)f->to - s);
f->stop = (Rune*)f->start + n - 1;
return 1;
@@ -67,8 +55,9 @@ runefmtstrinit(Fmt *f)
f->to = f->start;
f->stop = (Rune*)f->start + n - 1;
f->flush = runeFmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/runevsnprint.c b/lib9/fmt/runevsnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ runevsnprint(Rune *buf, int len, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
diff --git a/lib9/fmt/seprint.c b/lib9/fmt/seprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/smprint.c b/lib9/fmt/smprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/snprint.c b/lib9/fmt/snprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/sprint.c b/lib9/fmt/sprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <fmt.h>
#include "plan9.h"
@@ -28,9 +16,12 @@ sprint(char *buf, char *fmt, ...)
/*
* on PowerPC, the stack is near the top of memory, so
* we must be sure not to overflow a 32-bit pointer.
+ *
+ * careful! gcc-4.2 assumes buf+len < buf can never be true and
+ * optimizes the test away. casting to uintptr works around this bug.
*/
- if(buf+len < buf)
- len = -(uint)buf-1;
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uintptr)buf-1;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
diff --git a/lib9/fmt/strtod.c b/lib9/fmt/strtod.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
@@ -67,7 +55,7 @@ enum
S4, /* _+#.# #S4 eS5 */
S5, /* _+#.#e +S6 #S7 */
S6, /* _+#.#e+ #S7 */
- S7, /* _+#.#e+# #S7 */
+ S7 /* _+#.#e+# #S7 */
};
static int xcmp(char*, char*);
@@ -239,7 +227,7 @@ fmtstrtod(const char *as, char **aas)
/* close approx by naive conversion */
mid[0] = 0;
mid[1] = 1;
- for(i=0; c=a[i]; i++) {
+ for(i=0; (c=a[i]) != '\0'; i++) {
mid[0] = mid[0]*10 + (c-'0');
mid[1] = mid[1]*10;
if(i >= 8)
@@ -521,7 +509,7 @@ xcmp(char *a, char *b)
{
int c1, c2;
- while(c1 = *b++) {
+ while((c1 = *b++) != '\0') {
c2 = *a++;
if(isupper(c2))
c2 = tolower(c2);
diff --git a/lib9/fmt/test.c b/lib9/fmt/test.c
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
#include <stdio.h>
#include <stdarg.h>
#include <utf.h>
@@ -40,5 +30,24 @@ main(int argc, char *argv[])
print("%d\n", 23);
print("%i\n", 23);
print("%0.10d\n", 12345);
+
+ /* test %4$d formats */
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+ print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+ print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+ /* test %'d formats */
+ print("%'d %'d %'d\n", 1, 2222, 33333333);
+ print("%'019d\n", 0);
+ print("%08d %08d %08d\n", 1, 2222, 33333333);
+ print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+ print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+ print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 112342345LL);
return 0;
}
diff --git a/lib9/fmt/vfprint.c b/lib9/fmt/vfprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/vseprint.c b/lib9/fmt/vseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
@@ -31,6 +19,7 @@ vseprint(char *buf, char *e, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
diff --git a/lib9/fmt/vsmprint.c b/lib9/fmt/vsmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@ fmtStrFlush(Fmt *f)
if(f->start == nil)
return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
n *= 2;
s = (char*)f->start;
f->start = realloc(s, n);
@@ -47,7 +35,7 @@ fmtStrFlush(Fmt *f)
free(s);
return 0;
}
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->to = (char*)f->start + ((char*)f->to - s);
f->stop = (char*)f->start + n - 1;
return 1;
@@ -67,8 +55,9 @@ fmtstrinit(Fmt *f)
f->to = f->start;
f->stop = (char*)f->start + n - 1;
f->flush = fmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/vsnprint.c b/lib9/fmt/vsnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ vsnprint(char *buf, int len, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
diff --git a/lib9/getcallerpc-arm.c b/lib9/getcallerpc-arm.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+ return ((ulong*)x)[-2];
+}
+
diff --git a/lib9/getnetconn.c b/lib9/getnetconn.c
@@ -91,12 +91,12 @@ getnetconninfo(char *dir, int fd)
nci->spec = unknown;
if(nci->dir == nil || nci->root == nil)
goto err;
- sn = sizeof sn;
+ sn = sizeof u;
if(getsockname(fd, &u.sa, &sn) < 0)
goto err;
if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0)
goto err;
- sn = sizeof sn;
+ sn = sizeof u;
if(getpeername(fd, &u.sa, &sn) < 0)
goto err;
if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0)
diff --git a/lib9/getns.c b/lib9/getns.c
@@ -2,6 +2,17 @@
#include <libc.h>
#include <ctype.h>
+static int
+isme(char *uid)
+{
+ int n;
+ char *p;
+
+ n = strtol(uid, &p, 10);
+ if(*p == 0 && p > uid)
+ return n == getuid();
+ return strcmp(getuser(), uid) == 0;
+}
/*
* Absent other hints, it works reasonably well to use
* the X11 display name as the name space identifier.
@@ -18,8 +29,15 @@ nsfromdisplay(void)
char *disp, *p;
if((disp = getenv("DISPLAY")) == nil){
+#ifdef __APPLE__
+ // Might be running native GUI on OS X.
+ disp = strdup(":0.0");
+ if(disp == nil)
+ return nil;
+#else
werrstr("$DISPLAY not set");
return nil;
+#endif
}
/* canonicalize: xxx:0.0 => xxx:0 */
@@ -31,6 +49,11 @@ nsfromdisplay(void)
if(strcmp(p, ".0") == 0)
*p = 0;
}
+
+ /* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */
+ for(p=disp; *p; p++)
+ if(*p == '/')
+ *p = '_';
p = smprint("/tmp/ns.%s.%s", getuser(), disp);
free(disp);
@@ -48,7 +71,7 @@ nsfromdisplay(void)
free(p);
return nil;
}
- if((d->mode&0777) != 0700 || strcmp(d->uid, getuser()) != 0){
+ if((d->mode&0777) != 0700 || !isme(d->uid)){
werrstr("bad name space dir %s", p);
free(p);
free(d);
diff --git a/lib9/lib9.h b/lib9/lib9.h
@@ -1,17 +1,2 @@
-#include <string.h>
-#include "utf.h"
-
-#define nil ((void*)0)
-
-#define uchar _fmtuchar
-#define ushort _fmtushort
-#define uint _fmtuint
-#define ulong _fmtulong
-#define vlong _fmtvlong
-#define uvlong _fmtuvlong
-
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-
+#include <u.h>
+#include <libc.h>
diff --git a/lib9/libc.h b/lib9/libc.h
@@ -349,7 +349,7 @@ extern vlong p9nsec(void);
enum
{
PNPROC = 1,
- PNGROUP = 2,
+ PNGROUP = 2
};
/* extern int abs(int); <stdlib.h> */
@@ -376,6 +376,7 @@ extern int dec16(uchar*, int, char*, int);
extern int enc16(char*, int, uchar*, int);
extern int encodefmt(Fmt*);
extern int dirmodefmt(Fmt*);
+extern int exitcode(char*);
extern void exits(char*);
extern double frexp(double, int*);
extern ulong getcallerpc(void*);
@@ -390,7 +391,7 @@ extern int iounit(int);
/* extern double ldexp(double, int); <math.h> */
extern void p9longjmp(p9jmp_buf, int);
extern char* mktemp(char*);
-extern int opentemp(char*);
+extern int opentemp(char*, int);
/* extern double modf(double, double*); <math.h> */
extern void p9notejmp(void*, p9jmp_buf, int);
extern void perror(const char*);
@@ -416,6 +417,9 @@ extern long p9time(long*);
extern void needstack(int);
extern char* readcons(char*, char*, int);
+extern void (*_pin)(void);
+extern void (*_unpin)(void);
+
#ifndef NOPLAN9DEFINES
#define atexit p9atexit
#define atexitdont p9atexitdont
@@ -670,7 +674,7 @@ enum
RFNOWAIT = (1<<6),
RFCNAMEG = (1<<10),
RFCENVG = (1<<11),
- RFCFDG = (1<<12),
+ RFCFDG = (1<<12)
/* RFREND = (1<<13), */
/* RFNOMNT = (1<<14) */
};
@@ -789,6 +793,7 @@ extern int p9waitpid(void);
extern long write(int, void*, long);
extern long writev(int, IOchunk*, int);
*/
+extern long p9write(int, void*, long);
/* extern int wstat(char*, uchar*, int); give up */
extern ulong rendezvous(ulong, ulong);
@@ -809,6 +814,7 @@ extern ulong rendezvous(ulong, ulong);
#define open p9open
#define pipe p9pipe
#define waitfor p9waitfor
+#define write p9write
#endif
extern Dir* dirstat(char*);
@@ -828,7 +834,8 @@ extern char* get9root(void);
extern char* unsharp(char*);
extern int sendfd(int, int);
extern int recvfd(int);
-extern int post9pservice(int, char*);
+extern int post9pservice(int, char*, char*);
+extern int chattyfuse;
/* external names that we don't want to step on */
#ifndef NOPLAN9DEFINES
@@ -900,7 +907,7 @@ extern int post9pservice(int, char*);
#ifdef __GNUC__
# if __GNUC__ >= 3
# undef USED
-# define USED(x) { ulong __y __attribute__ ((unused)); __y = (ulong)(x); }
+# define USED(x) ((void)(x))
# endif
#endif
diff --git a/lib9/malloctag.c b/lib9/malloctag.c
@@ -1,9 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define USED(x) if(x){}else{}
-#define lrand p9lrand
-
void
setmalloctag(void *v, ulong t)
{
diff --git a/lib9/nan.c b/lib9/nan.c
@@ -1,6 +1,6 @@
#include <u.h>
#include <libc.h>
-#include "nan.h"
+#include "fmt/nan.h"
double
NaN(void)
diff --git a/lib9/netcrypt.c b/lib9/netcrypt.c
@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+
+int
+netcrypt(void *key, void *chal)
+{
+ uchar buf[8], *p;
+
+ strncpy((char*)buf, chal, 7);
+ buf[7] = '\0';
+ for(p = buf; *p && *p != '\n'; p++)
+ ;
+ *p = '\0';
+ encrypt(key, buf, 8);
+ sprint(chal, "%.2ux%.2ux%.2ux%.2ux", buf[0], buf[1], buf[2], buf[3]);
+ return 1;
+}
diff --git a/lib9/netmkaddr.c b/lib9/netmkaddr.c
@@ -16,21 +16,25 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
*/
cp = strchr(linear, '!');
if(cp == 0){
- if(defnet==0){
- if(defsrv)
- snprint(addr, sizeof(addr), "net!%s!%s",
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "net!%s", linear);
+ if(defnet == 0)
+ defnet = "net";
+ /* allow unix sockets to omit unix! prefix */
+ if(access(linear, 0) >= 0){
+ snprint(addr, sizeof(addr), "unix!%s", linear);
+ return addr;
}
- else {
- if(defsrv)
- snprint(addr, sizeof(addr), "%s!%s!%s", defnet,
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "%s!%s", defnet,
- linear);
+ /* allow host:service in deference to Unix convention */
+ if((cp = strchr(linear, ':')) != nil){
+ snprint(addr, sizeof(addr), "%s!%.*s!%s",
+ defnet, utfnlen(linear, cp-linear),
+ linear, cp+1);
+ return addr;
}
+ if(defsrv)
+ snprint(addr, sizeof(addr), "%s!%s!%s",
+ defnet, linear, defsrv);
+ else
+ snprint(addr, sizeof(addr), "%s!%s", defnet, linear);
return addr;
}
@@ -42,11 +46,17 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
return linear;
/*
+ * if the network is unix, no service
+ */
+ if(strncmp(linear, "unix!", 5) == 0)
+ return linear;
+
+ /*
* add default service
*/
if(defsrv == 0)
return linear;
- snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
+ snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
return addr;
}
diff --git a/lib9/notify.c b/lib9/notify.c
@@ -38,6 +38,7 @@ enum
{
Restart = 1<<0,
Ignore = 1<<1,
+ NoNotify = 1<<2,
};
static Sig sigs[] = {
@@ -58,7 +59,7 @@ static Sig sigs[] = {
SIGPIPE, Ignore,
SIGALRM, 0,
SIGTERM, 0,
- SIGTSTP, Restart|Ignore,
+ SIGTSTP, Restart|Ignore|NoNotify,
/* SIGTTIN, Restart|Ignore, */
/* SIGTTOU, Restart|Ignore, */
SIGXCPU, 0,
@@ -67,10 +68,10 @@ static Sig sigs[] = {
SIGUSR1, 0,
SIGUSR2, 0,
#ifdef SIGWINCH
- SIGWINCH, Restart|Ignore,
+ SIGWINCH, Restart|Ignore|NoNotify,
#endif
#ifdef SIGINFO
- SIGINFO, Restart|Ignore,
+ SIGINFO, Restart|Ignore|NoNotify,
#endif
};
@@ -266,7 +267,7 @@ noteinit(void)
*/
if(handler(sig->sig) != SIG_DFL)
continue;
- notifyseton(sig->sig, 1);
+ notifyseton(sig->sig, !(sig->flags&NoNotify));
}
}
diff --git a/lib9/nrand.c b/lib9/nrand.c
@@ -1,7 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define lrand p9lrand
#define MASK 0x7fffffffL
int
diff --git a/lib9/nulldir.c b/lib9/nulldir.c
@@ -5,5 +5,5 @@ void
nulldir(Dir *d)
{
memset(d, ~0, sizeof(Dir));
- d->name = d->uid = d->gid = d->muid = "";
+ d->name = d->uid = d->gid = d->muid = d->ext = "";
}
diff --git a/lib9/opentemp.c b/lib9/opentemp.c
@@ -2,14 +2,19 @@
#include <libc.h>
int
-opentemp(char *template)
+opentemp(char *template, int mode)
{
- int fd;
+ int fd, fd1;
fd = mkstemp(template);
if(fd < 0)
return -1;
- remove(template);
- return fd;
+ if((fd1 = open(template, mode)) < 0){
+ remove(template);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return fd1;
}
diff --git a/lib9/pin.c b/lib9/pin.c
@@ -0,0 +1,11 @@
+#include <u.h>
+#include <libc.h>
+
+static void
+nop(void)
+{
+}
+
+void (*_pin)(void) = nop;
+void (*_unpin)(void) = nop;
+
diff --git a/lib9/portdate b/lib9/portdate
@@ -1,30 +1,55 @@
-dofmt.c 2004/1225
-dorfmt.c 2004/1225
-errfmt.c 2004/1225
-fltfmt.c 2004/1225
-fmt.c 2004/1225
-fmtfd.c 2004/1225
-fmtlock.c 2004/1225
-fmtprint.c 2004/1225
-fmtquote.c 2004/1225
-fmtrune.c 2004/1225
-fmtstr.c 2004/1225
-fmtvprint.c 2004/1225
-fprint.c 2004/1225
-print.c 2004/1225
-runefmtstr.c 2004/1225
-runeseprint.c 2004/1225
-runesmprint.c 2004/1225
-runesnprint.c 2004/1225
-runesprint.c 2004/1225
-runevseprint.c 2004/1225
-runevsmprint.c 2004/1225
-runevsnprint.c 2004/1225
-seprint.c 2004/1225
-smprint.c 2004/1225
-snprint.c 2004/1225
-sprint.c 2004/1225
-vfprint.c 2004/1225
-vseprint.c 2004/1225
-vsmprint.c 2004/1225
-vsnprint.c 2004/1225
+announce.c 2004/1225
+atexit.c 2004/1225
+atnotify.c 2004/1225
+atol.c 2004/1225
+atoll.c 2004/1225
+cistrcmp.c 2004/1225
+cistrncmp.c 2004/1225
+cistrstr.c 2004/1225
+cleanname.c 2004/1225
+convD2M.c 2004/1225
+convM2D.c 2004/1225
+convM2S.c 2004/1225
+convS2M.c 2004/1225
+ctime.c 2004/1225
+dial.c 2004/1225
+dirfstat.c 2004/1225
+dirfwstat.c 2004/1225
+dirmodefmt.c 2004/1225
+dirread.c 2004/1225
+dirstat.c 2004/1225
+dirwstat.c 2004/1225
+encodefmt.c 2004/1225
+fcallfmt.c 2004/1225
+fork.c 2004/1225
+getenv.c 2004/1225
+getfields.c 2004/1225
+getuser.c 2004/1225
+getwd.c 2004/1225
+lnrand.c 2004/1225
+lock.c 2004/1225
+lrand.c 2004/1225
+malloc.c 2004/1225
+nan.c 2004/1225
+needsrcquote.c 2004/1225
+netmkaddr.c 2004/1225
+nrand.c 2004/1225
+nulldir.c 2004/1225
+postnote.c 2004/1225
+qlock.c 2004/1225
+quote.c 2004/1225
+rand.c 2004/1225
+read9pmsg.c 2004/1225
+readn.c 2004/1225
+strdup.c 2004/1225
+strecpy.c 2004/1225
+sysfatal.c 2004/1225
+sysname.c 2004/1225
+time.c 2004/1225
+tokenize.c 2004/1225
+truerand.c 2004/1225
+u16.c 2004/1225
+u32.c 2004/1225
+u64.c 2004/1225
+wait.c 2004/1225
+waitpid.c 2004/1225
diff --git a/lib9/post9p.c b/lib9/post9p.c
@@ -1,46 +1,83 @@
#include <u.h>
#include <libc.h>
+int chattyfuse;
+
int
-post9pservice(int fd, char *name)
+post9pservice(int fd, char *name, char *mtpt)
{
- int i;
- char *ns, *s;
+ int i, pid;
+ char *ns, *addr;
Waitmsg *w;
- if(strchr(name, '!')) /* assume is already network address */
- s = strdup(name);
- else{
- if((ns = getns()) == nil)
- return -1;
- s = smprint("unix!%s/%s", ns, name);
- free(ns);
- }
- if(s == nil)
- return -1;
- switch(fork()){
- case -1:
+ if(name == nil && mtpt == nil){
+ close(fd);
+ werrstr("nothing to do");
return -1;
- case 0:
- dup(fd, 0);
- dup(fd, 1);
- for(i=3; i<20; i++)
- close(i);
- execlp("9pserve", "9pserve", "-u", s, (char*)0);
- fprint(2, "exec 9pserve: %r\n");
- _exits("exec");
- default:
- w = wait();
- if(w == nil)
+ }
+
+ if(name){
+ if(strchr(name, '!')) /* assume is already network address */
+ addr = strdup(name);
+ else{
+ if((ns = getns()) == nil)
+ return -1;
+ addr = smprint("unix!%s/%s", ns, name);
+ free(ns);
+ }
+ if(addr == nil)
+ return -1;
+ switch(pid = fork()){
+ case -1:
return -1;
+ case 0:
+ dup(fd, 0);
+ dup(fd, 1);
+ for(i=3; i<20; i++)
+ close(i);
+ execlp("9pserve", "9pserve", "-u", addr, (char*)0);
+ fprint(2, "exec 9pserve: %r\n");
+ _exits("exec");
+ }
close(fd);
- free(s);
+ w = waitfor(pid);
+ if(w == nil)
+ return -1;
if(w->msg && w->msg[0]){
free(w);
werrstr("9pserve failed");
return -1;
}
free(w);
- return 0;
+ if(mtpt){
+ /* reopen */
+ if((fd = dial(addr, nil, nil, nil)) < 0){
+ werrstr("cannot reopen for mount: %r");
+ return -1;
+ }
+ }
+ free(addr);
+ }
+ if(mtpt){
+ switch(pid = rfork(RFFDG|RFPROC|RFNOWAIT)){
+ case -1:
+ return -1;
+ case 0:
+ dup(fd, 0);
+ for(i=3; i<20; i++)
+ close(i);
+
+ /* Try v9fs on Linux, which will mount 9P directly. */
+ execlp("mount9p", "mount9p", "-", mtpt, (char*)0);
+
+ if(chattyfuse)
+ execlp("9pfuse", "9pfuse", "-D", "-", mtpt, (char*)0);
+ else
+ execlp("9pfuse", "9pfuse", "-", mtpt, (char*)0);
+ fprint(2, "exec 9pfuse: %r\n");
+ _exits("exec");
+ }
+ close(fd);
}
+ return 0;
}
diff --git a/lib9/rand.c b/lib9/rand.c
@@ -1,8 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define lrand p9lrand
-
int
p9rand(void)
{
diff --git a/lib9/readn.c b/lib9/readn.c
@@ -1,5 +1,4 @@
#include <lib9.h>
-#include <unistd.h>
long
readn(int f, void *av, long n)
diff --git a/lib9/regex/regcomp.c b/lib9/regex/regcomp.c
@@ -261,18 +261,18 @@ optimize(Reprog *pp)
case STAR:
case PLUS:
case QUEST:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
break;
case CCLASS:
case NCCLASS:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
cl = inst->u1.cp;
- *(char **)&cl->end += diff;
+ cl->end = (void*)((char*)cl->end + diff);
break;
}
- *(char **)&inst->u2.left += diff;
+ inst->u2.left = (void*)((char*)inst->u2.left + diff);
}
- *(char **)&npp->startinst += diff;
+ npp->startinst = (void*)((char*)npp->startinst + diff);
return npp;
}
diff --git a/lib9/regex/regexec.c b/lib9/regex/regexec.c
@@ -58,7 +58,7 @@ regexec1(Reprog *progp, /* program to run */
p = utfrune(s, '\n');
if(p == 0 || s == j->eol)
return match;
- s = p;
+ s = p+1;
break;
}
}
diff --git a/lib9/regex/rregexec.c b/lib9/regex/rregexec.c
@@ -25,6 +25,7 @@ rregexec1(Reprog *progp, /* program to run */
Relist* tle; /* ends of this and next list */
Relist* nle;
int match;
+ Rune *p;
match = 0;
checkstart = j->startchar;
@@ -44,20 +45,18 @@ rregexec1(Reprog *progp, /* program to run */
if(checkstart) {
switch(j->starttype) {
case RUNE:
- while(*s != j->startchar) {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, j->startchar);
+ if(p == 0 || p == j->reol)
+ return match;
+ s = p;
break;
case BOL:
if(s == bol)
break;
- while(*s != '\n') {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, '\n');
+ if(p == 0 || s == j->reol)
+ return match;
+ s = p+1;
break;
}
}
diff --git a/lib9/rfork.c b/lib9/rfork.c
@@ -17,11 +17,12 @@ p9rfork(int flags)
int p[2];
int n;
char buf[128], *q;
+ extern char **environ;
if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
/* check other flags before we commit */
- flags &= ~(RFPROC|RFFDG);
- n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
if(n){
werrstr("unknown flags %08ux in rfork", n);
return -1;
@@ -99,9 +100,12 @@ p9rfork(int flags)
}
if(pid != 0)
return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
}
if(flags&RFPROC){
- werrstr("cannot use rfork for shared memory -- use ffork");
+ werrstr("cannot use rfork for shared memory -- use libthread");
return -1;
}
if(flags&RFNAMEG){
diff --git a/lib9/sendfd.c b/lib9/sendfd.c
@@ -78,7 +78,10 @@ recvfd(int s)
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
-
+ if(n == 0){
+ werrstr("unexpected EOF");
+ return -1;
+ }
cmsg = CMSG_FIRSTHDR(&msg);
fd = *(int*)CMSG_DATA(cmsg);
return fd;
diff --git a/lib9/sleep.c b/lib9/sleep.c
@@ -1,9 +1,21 @@
#include <u.h>
#define NOPLAN9DEFINES
+#include <sys/param.h>
#include <sys/time.h>
#include <sched.h>
#include <libc.h>
+#if defined(__NetBSD__) || (defined(__OpenBSD__) && OpenBSD <= 200611)
+#if !defined(sched_yield)
+# define sched_yield() \
+ do{ struct timespec ts; \
+ ts.tv_sec = 0; \
+ ts.tv_nsec = 0; \
+ nanosleep(&ts, 0); \
+ }while(0)
+#endif
+#endif
+
int
p9sleep(long milli)
{
diff --git a/lib9/sysfatal.c b/lib9/sysfatal.c
@@ -1,10 +1,5 @@
#include <lib9.h>
-#include <stdarg.h>
-#include "fmt.h"
-extern char *argv0;
-extern void __fixargv0(void);
-extern void exits(char*);
void (*_sysfatal)(char*, ...);
void
diff --git a/lib9/test.c b/lib9/test.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+int
+main(int argc, char **argv)
+{
+ werrstr("hello world");
+ print("%r\n");
+}
diff --git a/lib9/testfltfmt.c b/lib9/testfltfmt.c
@@ -0,0 +1,183 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+/*
+ * try all combination of flags and float conversions
+ * with some different widths & precisions
+ */
+
+#define Njust 2
+#define Nplus 3
+#define Nalt 2
+#define Nzero 2
+#define Nspec 5
+#define Nwidth 5
+#define Nprec 5
+
+static double fmtvals[] = {
+ 3.1415925535897932e15,
+ 3.1415925535897932e14,
+ 3.1415925535897932e13,
+ 3.1415925535897932e12,
+ 3.1415925535897932e11,
+ 3.1415925535897932e10,
+ 3.1415925535897932e9,
+ 3.1415925535897932e8,
+ 3.1415925535897932e7,
+ 3.1415925535897932e6,
+ 3.1415925535897932e5,
+ 3.1415925535897932e4,
+ 3.1415925535897932e3,
+ 3.1415925535897932e2,
+ 3.1415925535897932e1,
+ 3.1415925535897932e0,
+ 3.1415925535897932e-1,
+ 3.1415925535897932e-2,
+ 3.1415925535897932e-3,
+ 3.1415925535897932e-4,
+ 3.1415925535897932e-5,
+ 3.1415925535897932e-6,
+ 3.1415925535897932e-7,
+ 3.1415925535897932e-8,
+ 3.1415925535897932e-9,
+ 3.1415925535897932e-10,
+ 3.1415925535897932e-11,
+ 3.1415925535897932e-12,
+ 3.1415925535897932e-13,
+ 3.1415925535897932e-14,
+ 3.1415925535897932e-15,
+};
+
+/*
+ * are the numbers close?
+ * used to compare long numbers where the last few digits are garbage
+ * due to precision problems
+ */
+static int
+numclose(char *num1, char *num2)
+{
+ int ndig;
+ double d1, d2;
+ enum { MAXDIG = 15 };
+
+ d1 = fmtstrtod(num1, 0);
+ d2 = fmtstrtod(num2, 0);
+ if(d1 != d2)
+ return 0;
+
+ ndig = 0;
+ while (*num1) {
+ if (*num1 >= '0' && *num1 <= '9') {
+ ndig++;
+ if (ndig > MAXDIG) {
+ if (!(*num2 >= '0' && *num2 <= '9')) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ } else if (*num1 == 'e' || *num1 == 'E') {
+ ndig = 0;
+ }
+ num1++;
+ num2++;
+ }
+ if (*num1 || !num2)
+ return 0;
+ return 1;
+}
+
+static void
+doit(int just, int plus, int alt, int zero, int width, int prec, int spec)
+{
+ char format[256];
+ char *p;
+ const char *s;
+ int i;
+
+ p = format;
+ *p++ = '%';
+ if (just > 0)
+ *p++ = "-"[just - 1];
+ if (plus > 0)
+ *p++ = "+ "[plus - 1];
+ if (alt > 0)
+ *p++ = "#"[alt - 1];
+ if (zero > 0)
+ *p++ = "0"[zero - 1];
+
+ s = "";
+ switch (width) {
+ case 1: s = "1"; break;
+ case 2: s = "5"; break;
+ case 3: s = "10"; break;
+ case 4: s = "15"; break;
+ }
+ strcpy(p, s);
+
+ s = "";
+ switch (prec) {
+ case 1: s = ".0"; break;
+ case 2: s = ".2"; break;
+ case 3: s = ".5"; break;
+ case 4: s = ".15"; break;
+ }
+ strcat(p, s);
+
+ p = strchr(p, '\0');
+ *p++ = "efgEG"[spec];
+ *p = '\0';
+
+ for (i = 0; i < sizeof(fmtvals) / sizeof(fmtvals[0]); i++) {
+ char ref[1024], buf[1024];
+ Rune rbuf[1024];
+ double d1, d2;
+
+ sprintf(ref, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), format, fmtvals[i]);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)",
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)");
+ // exits("oops");
+ }
+
+ /* Check again with output to rune string */
+ runesnprint(rbuf, 1024, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), "%S", rbuf);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)",
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)");
+ // exits("oops");
+ }
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ int just, plus, alt, zero, width, prec, spec;
+
+ for (just = 0; just < Njust; just++)
+ for (plus = 0; plus < Nplus; plus++)
+ for (alt = 0; alt < Nalt; alt++)
+ for (zero = 0; zero < Nzero; zero++)
+ for (width = 0; width < Nwidth; width++)
+ for (prec = 0; prec < Nprec; prec++)
+ for (spec = 0; spec < Nspec; spec++)
+ doit(just, plus, alt, zero, width, prec, spec);
+
+ exits(0);
+}
diff --git a/lib9/testfmt.c b/lib9/testfmt.c
@@ -0,0 +1,148 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+int failed;
+
+/* Consume argument and ignore it */
+int
+Zflag(Fmt* f)
+{
+ if(va_arg(f->args, int))
+ ;
+ return 1; /* it's a flag */
+}
+
+void
+verify(char *s, char *t)
+{
+ if(strcmp(s, t) != 0){
+ failed = 1;
+ fprintf(stderr, "error: (%s) != (%s)\n", s, t);
+ }
+ free(s);
+}
+
+Rune lightsmiley = 0x263a;
+Rune darksmiley = 0x263b;
+
+/* Test printer that loads unusual decimal point and separator */
+char*
+mysmprint(char *fmt, ...)
+{
+ Fmt f;
+
+ if(fmtstrinit(&f) < 0)
+ return 0;
+ va_start(f.args, fmt);
+ f.decimal = smprint("%C", lightsmiley);
+ f.thousands = smprint("%C", darksmiley);
+ f.grouping = "\1\2\3\4";
+ if(dofmt(&f, fmt) < 0)
+ return 0;
+ va_end(f.args);
+ return fmtstrflush(&f);
+}
+
+double near1[] = {
+ 0.5,
+ 0.95,
+ 0.995,
+ 0.9995,
+ 0.99995,
+ 0.999995,
+ 0.9999995,
+ 0.99999995,
+ 0.999999995,
+};
+
+void
+main(int argc, char **argv)
+{
+ int i, j;
+
+ quotefmtinstall();
+ fmtinstall('Z', Zflag);
+ fmtinstall(L'\x263a', Zflag);
+#ifdef PLAN9PORT
+{ extern int __ifmt(Fmt*);
+ fmtinstall('i', __ifmt);
+}
+#endif
+
+ verify(smprint("hello world"), "hello world");
+#ifdef PLAN9PORT
+ verify(smprint("x: %ux", 0x87654321), "x: 87654321");
+#else
+ verify(smprint("x: %x", 0x87654321), "x: 87654321");
+#endif
+ verify(smprint("d: %d", 0x87654321), "d: -2023406815");
+ verify(smprint("s: %s", "hi there"), "s: hi there");
+ verify(smprint("q: %q", "hi i'm here"), "q: 'hi i''m here'");
+ verify(smprint("c: %c", '!'), "c: !");
+ verify(smprint("g: %g %g %g", 3.14159, 3.14159e10, 3.14159e-10), "g: 3.14159 3.14159e+10 3.14159e-10");
+ verify(smprint("e: %e %e %e", 3.14159, 3.14159e10, 3.14159e-10), "e: 3.141590e+00 3.141590e+10 3.141590e-10");
+ verify(smprint("f: %f %f %f", 3.14159, 3.14159e10, 3.14159e-10), "f: 3.141590 31415900000.000000 0.000000");
+ verify(smprint("smiley: %C", (Rune)0x263a), "smiley: \xe2\x98\xba");
+ verify(smprint("%g %.18g", 2e25, 2e25), "2e+25 2e+25");
+ verify(smprint("%2.18g", 1.0), " 1");
+ verify(smprint("%f", 3.1415927/4), "0.785398");
+ verify(smprint("%d", 23), "23");
+ verify(smprint("%i", 23), "23");
+ verify(smprint("%Zi", 1234, 23), "23");
+
+ /* ANSI and their wacky corner cases */
+ verify(smprint("%.0d", 0), "");
+ verify(smprint("%.0o", 0), "");
+ verify(smprint("%.0x", 0), "");
+ verify(smprint("%#.0o", 0), "0");
+ verify(smprint("%#.0x", 0), "");
+
+ /* difficult floating point tests that many libraries get wrong */
+ verify(smprint("%.100f", 1.0), "1.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000");
+ verify(smprint("%.100g", 1.0), "1");
+ verify(smprint("%0100f", 1.0), "000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000001.000000");
+ for(i=1; i<9; i++)
+ for(j=0; j<=i; j++)
+ verify(smprint("%.*g", j, near1[i]), "1");
+
+ /* test $ reorderings */
+ verify(smprint("%3$d %4$06d %2$d %1$d", 444, 333, 111, 222), "111 000222 333 444");
+ verify(smprint("%3$Zd %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444");
+ verify(smprint("%3$d %4$*5$06d %2$d %1$d", 444, 333, 111, 222, 20), "111 000222 333 444");
+ verify(smprint("%3$hd %4$*5$06d %2$d %1$d", 444, 333, (short)111, 222, 20), "111 000222 333 444");
+ verify(smprint("%3$\xe2\x98\xba""d %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "111 000222 333 444");
+
+ /* test %'d formats */
+ verify(smprint("%'d %'d %'d", 1, 2222, 33333333), "1 2,222 33,333,333");
+ verify(smprint("%'019d", 0), "000,000,000,000,000");
+ verify(smprint("%'08d %'08d %'08d", 1, 2222, 33333333), "0,000,001 0,002,222 33,333,333");
+#ifdef PLAN9PORT
+ verify(smprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#else
+ verify(smprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#endif
+ verify(smprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222,222,222 3,333,333,333,333");
+ verify(smprint("%'019lld %'019lld %'019lld", 1LL, 222222222LL, 3333333333333LL), "000,000,000,000,001 000,000,222,222,222 003,333,333,333,333");
+#ifdef PLAN9PORT
+ verify(smprint("%'llux %'lluX %'llub", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+#else
+ verify(smprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+#endif
+
+ /* test %'d with custom (utf-8!) separators */
+ /* x and b still use : */
+ verify(mysmprint("%'d %'d %'d", 1, 2222, 33333333), "1 2\xe2\x98\xbb""22\xe2\x98\xbb""2 33\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3");
+#ifdef PLAN9PORT
+ verify(mysmprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#else
+ verify(mysmprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:1111 ABCD:1234 11:0000:0011:1001");
+#endif
+ verify(mysmprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL), "1 222\xe2\x98\xbb""222\xe2\x98\xbb""22\xe2\x98\xbb""2 333\xe2\x98\xbb""3333\xe2\x98\xbb""333\xe2\x98\xbb""33\xe2\x98\xbb""3");
+ verify(mysmprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL, 112342345LL), "1111:1111:1111 ABCD:1234:5678 110:1011:0010:0011:0101:0100:1001");
+ verify(mysmprint("%.4f", 3.14159), "3\xe2\x98\xba""1416");
+
+ if(failed)
+ sysfatal("tests failed");
+ exits(0);
+}
diff --git a/lib9/testprint.c b/lib9/testprint.c
@@ -0,0 +1,14 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(int argc, char **argv)
+{
+ char c;
+
+ c = argv[1][strlen(argv[1])-1];
+ if(c == 'f' || c == 'e' || c == 'g' || c == 'F' || c == 'E' || c == 'G')
+ print(argv[1], atof(argv[2]));
+ else if(c == 'x' || c == 'u' || c == 'd' || c == 'c' || c == 'C' || c == 'X')
+ print(argv[1], atoi(argv[2]));
+}
diff --git a/lib9/tm2sec.c b/lib9/tm2sec.c
@@ -0,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+
+#include "zoneinfo.h"
+
+#define SEC2MIN 60L
+#define SEC2HOUR (60L*SEC2MIN)
+#define SEC2DAY (24L*SEC2HOUR)
+
+/*
+ * days per month plus days/year
+ */
+static int dmsize[] =
+{
+ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+static int ldmsize[] =
+{
+ 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * return the days/month for the given year
+ */
+static int *
+yrsize(int y)
+{
+ if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
+ return ldmsize;
+ else
+ return dmsize;
+}
+
+/*
+ * compute seconds since Jan 1 1970 GMT
+ * and convert to our timezone.
+ */
+long
+tm2sec(Tm *tm)
+{
+ Tinfo ti0, ti1, *ti;
+ long secs;
+ int i, yday, year, *d2m;
+
+ secs = 0;
+
+ /*
+ * seconds per year
+ */
+ year = tm->year + 1900;
+ for(i = 1970; i < year; i++){
+ d2m = yrsize(i);
+ secs += d2m[0] * SEC2DAY;
+ }
+
+ /*
+ * if mday is set, use mon and mday to compute yday
+ */
+ if(tm->mday){
+ yday = 0;
+ d2m = yrsize(year);
+ for(i=0; i<tm->mon; i++)
+ yday += d2m[i+1];
+ yday += tm->mday-1;
+ }else{
+ yday = tm->yday;
+ }
+ secs += yday * SEC2DAY;
+
+ /*
+ * hours, minutes, seconds
+ */
+ secs += tm->hour * SEC2HOUR;
+ secs += tm->min * SEC2MIN;
+ secs += tm->sec;
+
+ /*
+ * Assume the local time zone if zone is not GMT
+ */
+ if(strcmp(tm->zone, "GMT") != 0) {
+ i = zonelookuptinfo(&ti0, secs);
+ ti = &ti0;
+ if (i != -1)
+ if (ti->tzoff!=0) {
+ /*
+ * to what local time period `secs' belongs?
+ */
+ if (ti->tzoff>0) {
+ /*
+ * east of GMT; check previous local time transition
+ */
+ if (ti->t+ti->tzoff > secs)
+ if (zonetinfo(&ti1, i-1)!=-1)
+ ti = &ti1;
+ } else
+ /*
+ * west of GMT; check next local time transition
+ */
+ if (zonetinfo(&ti1, i+1))
+ if (ti1.t+ti->tzoff < secs)
+ ti = &ti1;
+// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff, (long)secs);
+ secs -= ti->tzoff;
+ }
+ }
+
+ if(secs < 0)
+ secs = 0;
+ return secs;
+}
diff --git a/lib9/truerand.c b/lib9/truerand.c
@@ -15,7 +15,7 @@ truerand(void)
if(randfd < 0 || read(randfd, buf, 1) != 1)
randfd = open(randfile="/dev/srandom", OREAD); /* OpenBSD */
if(randfd < 0)
- sysfatal("can't open /dev/random: %r");
+ sysfatal("can't open %s: %r", randfile);
fcntl(randfd, F_SETFD, FD_CLOEXEC);
}
for(i=0; i<sizeof(buf); i += n)
diff --git a/lib9/u.h b/lib9/u.h
@@ -7,9 +7,10 @@ extern "C" {
#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
#if defined(__sun__)
# define __EXTENSIONS__ 1 /* SunOS */
-# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__)
+# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)
/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
# else
+ /* What's left? */
# define __MAKECONTEXT_V2_SOURCE 1
# endif
#endif
@@ -20,6 +21,17 @@ extern "C" {
# define _XOPEN_SOURCE 1000
# define _XOPEN_SOURCE_EXTENDED 1
#endif
+#if defined(__FreeBSD__)
+# include <sys/cdefs.h>
+ /* for strtoll */
+# undef __ISO_C_VISIBLE
+# define __ISO_C_VISIBLE 1999
+# undef __LONG_LONG_SUPPORTED
+# define __LONG_LONG_SUPPORTED
+#endif
+#if defined(__AIX__)
+# define _XOPEN_SOURCE 1
+#endif
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
@@ -33,8 +45,6 @@ extern "C" {
#include <assert.h>
#include <setjmp.h>
#include <stddef.h>
-#include <utf.h>
-#include <fmt.h>
#include <math.h>
#include <ctype.h> /* for tolower */
@@ -138,6 +148,7 @@ typedef int8_t s8int;
typedef uint16_t u16int;
typedef int16_t s16int;
typedef uintptr_t uintptr;
+typedef intptr_t intptr;
typedef uint32_t u32int;
typedef int32_t s32int;
@@ -150,17 +161,23 @@ typedef int32_t s32int;
* Funny-named symbols to tip off 9l to autolink.
*/
#define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
+#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
/*
* Gcc is too smart for its own good.
*/
#if defined(__GNUC__)
+# undef strcmp /* causes way too many warnings */
# if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__))
# undef AUTOLIB
# define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
# else
# undef AUTOLIB
# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
# endif
#endif
diff --git a/lib9/utf.h b/lib9/utf.h
@@ -11,7 +11,7 @@ enum
UTFmax = 3, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
- Runeerror = 0xFFFD, /* decoding error in UTF */
+ Runeerror = 0xFFFD /* decoding error in UTF */
};
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
diff --git a/lib9/utf/NOTICE b/lib9/utf/NOTICE
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff --git a/lib9/utf/README b/lib9/utf/README
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE ANY
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff --git a/lib9/lib9.h b/lib9/utf/lib9.h
diff --git a/lib9/utf/rune.c b/lib9/utf/rune.c
@@ -37,7 +37,7 @@ enum
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
- Bad = Runeerror,
+ Bad = Runeerror
};
int
diff --git a/lib9/utf/utfecpy.c b/lib9/utf/utfecpy.c
@@ -11,6 +11,7 @@
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
+#define _BSD_SOURCE 1 /* memccpy */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/write.c b/lib9/write.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+long
+p9write(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = write(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/lib9/zoneinfo.c b/lib9/zoneinfo.c
@@ -0,0 +1,215 @@
+#include <u.h>
+#include <libc.h>
+
+/*
+ * Access local time entries of zoneinfo files.
+ * Formats 0 and 2 are supported, and 4-byte timestamps
+ *
+ * Copyright © 2008 M. Teichgräber
+ * Contributed under the terms of the Lucent Public License 1.02.
+ */
+#include "zoneinfo.h"
+
+static
+struct Zoneinfo
+{
+ int timecnt; /* # of transition times */
+ int typecnt; /* # of local time types */
+ int charcnt; /* # of characters of time zone abbreviation strings */
+
+ uchar *ptime;
+ uchar *ptype;
+ uchar *ptt;
+ uchar *pzone;
+} z;
+
+static uchar *tzdata;
+
+static
+uchar*
+readtzfile(char *file)
+{
+ uchar *p;
+ int fd;
+ Dir *d;
+
+ fd = open(file, OREAD);
+ if (fd<0)
+ return nil;
+ d = dirfstat(fd);
+ if (d==nil)
+ return nil;
+ p = malloc(d->length);
+ if (p!=nil)
+ readn(fd, p, d->length);
+ free(d);
+ close(fd);
+ return p;
+}
+static char *zonefile;
+void
+tzfile(char *f)
+{
+ if (tzdata!=nil) {
+ free(tzdata);
+ tzdata = nil;
+ }
+ z.timecnt = 0;
+ zonefile = f;
+}
+
+static
+long
+get4(uchar *p)
+{
+ return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
+}
+
+enum {
+ TTinfosz = 4+1+1,
+};
+
+static
+int
+parsehead(void)
+{
+ uchar *p;
+ int ver;
+
+ ver = tzdata[4];
+ if (ver!=0)
+ if (ver!='2')
+ return -1;
+
+ p = tzdata + 4 + 1 + 15;
+
+ z.timecnt = get4(p+3*4);
+ z.typecnt = get4(p+4*4);
+ if (z.typecnt==0)
+ return -1;
+ z.charcnt = get4(p+5*4);
+ z.ptime = p+6*4;
+ z.ptype = z.ptime + z.timecnt*4;
+ z.ptt = z.ptype + z.timecnt;
+ z.pzone = z.ptt + z.typecnt*TTinfosz;
+ return 0;
+}
+
+static
+void
+ttinfo(Tinfo *ti, int tti)
+{
+ uchar *p;
+ int i;
+
+ i = z.ptype[tti];
+ assert(i<z.typecnt);
+ p = z.ptt + i*TTinfosz;
+ ti->tzoff = get4(p);
+ ti->dlflag = p[4];
+ assert(p[5]<z.charcnt);
+ ti->zone = (char*)z.pzone + p[5];
+}
+
+static
+void
+readtimezone(void)
+{
+ char *tmp;
+
+ z.timecnt = 0;
+ switch (zonefile==nil) {
+ default:
+ if ((tmp=getenv("timezone"))!=nil) {
+ tzdata = readtzfile(tmp);
+ free(tmp);
+ break;
+ }
+ zonefile = "/etc/localtime";
+ /* fall through */
+ case 0:
+ tzdata = readtzfile(zonefile);
+ }
+ if (tzdata==nil)
+ return;
+
+ if (strncmp("TZif", (char*)tzdata, 4)!=0)
+ goto errfree;
+
+ if (parsehead()==-1) {
+ errfree:
+ free(tzdata);
+ tzdata = nil;
+ z.timecnt = 0;
+ return;
+ }
+}
+
+static
+tlong
+gett4(uchar *p)
+{
+ long l;
+
+ l = get4(p);
+ if (l<0)
+ return 0;
+ return l;
+}
+int
+zonetinfo(Tinfo *ti, int i)
+{
+ if (tzdata==nil)
+ readtimezone();
+ if (i<0 || i>=z.timecnt)
+ return -1;
+ ti->t = gett4(z.ptime + 4*i);
+ ttinfo(ti, i);
+ return i;
+}
+
+int
+zonelookuptinfo(Tinfo *ti, tlong t)
+{
+ uchar *p;
+ int i;
+ tlong oldtt, tt;
+
+ if (tzdata==nil)
+ readtimezone();
+ oldtt = 0;
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ tt = gett4(p);
+ if (t<tt)
+ break;
+ oldtt = tt;
+ p += 4;
+ }
+ if (i>0) {
+ ttinfo(ti, i-1);
+ ti->t = oldtt;
+// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzoff, ti->dlflag, ti->zone);
+ return i-1;
+ }
+ return -1;
+}
+
+void
+zonedump(int fd)
+{
+ int i;
+ uchar *p;
+ tlong t;
+ Tinfo ti;
+
+ if (tzdata==nil)
+ readtimezone();
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ t = gett4(p);
+ ttinfo(&ti, i);
+ fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, ti.zone);
+ p += 4;
+ }
+}
diff --git a/lib9/zoneinfo.h b/lib9/zoneinfo.h
@@ -0,0 +1,19 @@
+#define zonetinfo _p9zonetinfo
+#define zonedump _p9zonedump
+#define zonelookuptinfo _p9zonelookuptinfo
+
+typedef long tlong;
+
+typedef
+struct Tinfo
+{
+ long t;
+ int tzoff;
+ int dlflag;
+ char *zone;
+} Tinfo;
+
+extern int zonelookuptinfo(Tinfo*, tlong);
+extern int zonetinfo(Tinfo*, int);
+extern void zonedump(int fd);
+
diff --git a/ls/ls.c b/ls/ls.c
@@ -227,17 +227,16 @@ format(Dir *db, char *name)
db->qid.type);
if(lflag)
Bprint(&bin,
- Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*ud %*s %s %*llud %s %q\n",
+ "%M %C %*ud %*s %s %*llud %s ",
db->mode, db->type,
vwidth, db->dev,
-uwidth, db->uid,
db->gid,
(int)(glwidth-strlen(db->gid)), db->length,
- asciitime(uflag? db->atime : db->mtime), name);
- else
- Bprint(&bin,
- Qflag? "%s%s\n" : "%q%s\n",
- name, fileflag(db));
+ asciitime(uflag? db->atime : db->mtime));
+ Bprint(&bin,
+ Qflag? "%s%s\n" : "%q%s\n",
+ name, fileflag(db));
}
void
diff --git a/mk/Makefile b/mk/Makefile
@@ -1,37 +0,0 @@
-# basename - basename unix port from plan9
-# Depends on ../lib9
-
-TARG = mk
-OFILES = arc.o archive.o bufblock.o env.o file.o graph.o job.o\
- lex.o main.o match.o mk.o parse.o recipe.o rc.o rule.o\
- run.o sh.o shell.o shprint.o symtab.o var.o varsub.o\
- word.o unix.o
-MANFILES = ${TARG}.1
-
-include ../config.mk
-
-all: ${TARG}
- @echo built ${TARG}
-
-install: ${TARG}
- @mkdir -p ${DESTDIR}${PREFIX}/bin
- @cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
- @chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
- @mkdir -p ${DESTDIR}${MANPREFIX}/man1
- @cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
- @chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
-
-uninstall:
- rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
- rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
-
-.c.o:
- @echo CC $*.c
- @${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
-
-clean:
- rm -f ${OFILES} ${TARG}
-
-${TARG}: ${OFILES}
- @echo LD ${TARG}
- @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
diff --git a/mk/NOTICE b/mk/NOTICE
@@ -1,27 +0,0 @@
-Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-Portions Copyright © 1995-1997 C H Forsyth (forsyth@caldo.demon.co.uk). All rights reserved.
-Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved.
-Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com). All rights reserved.
-
-Under a licence agreement with Lucent Technologies Inc. effective 1st March 2000,
-Vita Nuova Holdings Limited has the right to determine (within a specified scope)
-the form and content of sublicences for this software.
-
-Vita Nuova Holdings Limited now makes this software available as Free
-Software under the terms of the `GNU General Public LIcense, Version 2'
-(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for
-the full terms and conditions). One of the conditions of that licence
-is that you must keep intact all notices that refer to that licence and to the absence of
-of any warranty: for this software, note that includes this NOTICE file in particular.
-
-This suite of programs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-`GNU General Public License' for more details.
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices above.
diff --git a/mk/README b/mk/README
@@ -1,7 +0,0 @@
-This is a Unix port of mk,
-originally done for the Inferno operating system.
-
-Russ Cox repackaged this to build as a standalone
-Unix program. Send comments about packaging to
-Russ Cox <rsc@post.harvard.edu>
-
diff --git a/mk/arc.c b/mk/arc.c
@@ -1,52 +0,0 @@
-#include "mk.h"
-
-Arc *
-newarc(Node *n, Rule *r, char *stem, Resub *match)
-{
- Arc *a;
-
- a = (Arc *)Malloc(sizeof(Arc));
- a->n = n;
- a->r = r;
- a->stem = strdup(stem);
- rcopy(a->match, match, NREGEXP);
- a->next = 0;
- a->flag = 0;
- a->prog = r->prog;
- return(a);
-}
-
-void
-dumpa(char *s, Arc *a)
-{
- char buf[1024];
-
- Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'",
- s, a, a->n, a->r, a->flag, a->stem);
- if(a->prog)
- Bprint(&bout, " prog='%s'", a->prog);
- Bprint(&bout, "\n");
-
- if(a->n){
- snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:"");
- dumpn(buf, a->n);
- }
-}
-
-void
-nrep(void)
-{
- Symtab *sym;
- Word *w;
-
- sym = symlook("NREP", S_VAR, 0);
- if(sym){
- w = (Word *) sym->value;
- if (w && w->s && *w->s)
- nreps = atoi(w->s);
- }
- if(nreps < 1)
- nreps = 1;
- if(DEBUG(D_GRAPH))
- Bprint(&bout, "nreps = %d\n", nreps);
-}
diff --git a/mk/archive.c b/mk/archive.c
@@ -1,253 +0,0 @@
-#include "mk.h"
-#define ARMAG "!<arch>\n"
-#define SARMAG 8
-
-#define ARFMAG "`\n"
-#define SARNAME 16
-
-struct ar_hdr
-{
- char name[SARNAME];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char fmag[2];
-};
-#define SAR_HDR (SARNAME+44)
-
-static int dolong = 1;
-
-static void atimes(char *);
-static char *split(char*, char**);
-
-long
-readn(int f, void *av, long n)
-{
- char *a;
- long m, t;
-
- a = av;
- t = 0;
- while(t < n){
- m = read(f, a+t, n-t);
- if(m <= 0){
- if(t == 0)
- return m;
- break;
- }
- t += m;
- }
- return t;
-}
-long
-atimeof(int force, char *name)
-{
- Symtab *sym;
- long t;
- char *archive, *member, buf[512];
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- t = mtime(archive);
- sym = symlook(archive, S_AGG, 0);
- if(sym){
- if(force || (t > (long)sym->value)){
- atimes(archive);
- sym->value = (void *)t;
- }
- }
- else{
- atimes(archive);
- /* mark the aggegate as having been done */
- symlook(strdup(archive), S_AGG, "")->value = (void *)t;
- }
- /* truncate long member name to sizeof of name field in archive header */
- if(dolong)
- snprint(buf, sizeof(buf), "%s(%s)", archive, member);
- else
- snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member);
- sym = symlook(buf, S_TIME, 0);
- if (sym)
- return (long)sym->value; /* uggh */
- return 0;
-}
-
-void
-atouch(char *name)
-{
- char *archive, *member;
- int fd, i;
- struct ar_hdr h;
- long t;
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- fd = open(archive, ORDWR);
- if(fd < 0){
- fd = create(archive, OWRITE, 0666);
- if(fd < 0){
- fprint(2, "create %s: %r\n", archive);
- Exit();
- }
- write(fd, ARMAG, SARMAG);
- }
- if(symlook(name, S_TIME, 0)){
- /* hoon off and change it in situ */
- LSEEK(fd, SARMAG, 0);
- while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
- ;
- h.name[i+1]=0;
- if(strcmp(member, h.name) == 0){
- t = SARNAME-sizeof(h); /* ughgghh */
- LSEEK(fd, t, 1);
- fprint(fd, "%-12ld", time(0));
- break;
- }
- t = atol(h.size);
- if(t&01) t++;
- LSEEK(fd, t, 1);
- }
- }
- close(fd);
-}
-
-static void
-atimes(char *ar)
-{
- struct ar_hdr h;
- long t;
- int fd, i, namelen;
- char buf[2048], *p, *strings;
- char name[1024];
- Symtab *sym;
-
- strings = nil;
- fd = open(ar, OREAD);
- if(fd < 0)
- return;
-
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return;
- }
- while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- t = atol(h.date);
- if(t == 0) /* as it sometimes happens; thanks ken */
- t = 1;
- namelen = 0;
- if(memcmp(h.name, "#1/", 3) == 0){ /* BSD */
- namelen = atoi(h.name+3);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- if(readn(fd, name, namelen) != namelen)
- break;
- name[namelen] = 0;
- }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
- /* date, uid, gid, mode all ' ' */
- for(i=2; i<16+12+6+6+8; i++)
- if(h.name[i] != ' ')
- goto skip;
- t = atol(h.size);
- if(t&01)
- t++;
- free(strings);
- strings = malloc(t+1);
- if(strings){
- if(readn(fd, strings, t) != t){
- free(strings);
- strings = nil;
- break;
- }
- strings[t] = 0;
- continue;
- }
- goto skip;
- }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1])){
- i = strtol(h.name+1, &p, 10);
- if(*p != ' ' || i >= strlen(strings))
- goto skip;
- p = strings+i;
- for(; *p && *p != '/'; p++)
- ;
- namelen = p-(strings+i);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- memmove(name, strings+i, namelen);
- name[namelen] = 0;
- namelen = 0;
- }else{
- strncpy(name, h.name, sizeof(h.name));
- for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
- ;
- if(name[i] == '/') /* system V bug */
- i--;
- name[i+1]=0;
- }
- snprint(buf, sizeof buf, "%s(%s)", ar, name);
- sym = symlook(strdup(buf), S_TIME, (void *)t);
- sym->value = (void *)t;
- skip:
- t = atol(h.size);
- if(t&01) t++;
- t -= namelen;
- LSEEK(fd, t, 1);
- }
- close(fd);
- free(strings);
-}
-
-static int
-type(char *file)
-{
- int fd;
- char buf[SARMAG];
-
- fd = open(file, OREAD);
- if(fd < 0){
- if(symlook(file, S_BITCH, 0) == 0){
- if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a") != 0)
- Bprint(&bout, "%s doesn't exist: assuming it will be an archive\n", file);
- symlook(file, S_BITCH, (void *)file);
- }
- return 1;
- }
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return 0;
- }
- close(fd);
- return !strncmp(ARMAG, buf, SARMAG);
-}
-
-static char*
-split(char *name, char **member)
-{
- char *p, *q;
-
- p = strdup(name);
- q = utfrune(p, '(');
- if(q){
- *q++ = 0;
- if(member)
- *member = q;
- q = utfrune(q, ')');
- if (q)
- *q = 0;
- if(type(p))
- return p;
- free(p);
- fprint(2, "mk: '%s' is not an archive\n", name);
- }
- return 0;
-}
diff --git a/mk/bufblock.c b/mk/bufblock.c
@@ -1,88 +0,0 @@
-#include "mk.h"
-
-static Bufblock *freelist;
-#define QUANTA 4096
-
-Bufblock *
-newbuf(void)
-{
- Bufblock *p;
-
- if (freelist) {
- p = freelist;
- freelist = freelist->next;
- } else {
- p = (Bufblock *) Malloc(sizeof(Bufblock));
- p->start = Malloc(QUANTA*sizeof(*p->start));
- p->end = p->start+QUANTA;
- }
- p->current = p->start;
- *p->start = 0;
- p->next = 0;
- return p;
-}
-
-void
-freebuf(Bufblock *p)
-{
- p->next = freelist;
- freelist = p;
-}
-
-void
-growbuf(Bufblock *p)
-{
- int n;
- Bufblock *f;
- char *cp;
-
- n = p->end-p->start+QUANTA;
- /* search the free list for a big buffer */
- for (f = freelist; f; f = f->next) {
- if (f->end-f->start >= n) {
- memcpy(f->start, p->start, p->end-p->start);
- cp = f->start;
- f->start = p->start;
- p->start = cp;
- cp = f->end;
- f->end = p->end;
- p->end = cp;
- f->current = f->start;
- break;
- }
- }
- if (!f) { /* not found - grow it */
- p->start = Realloc(p->start, n);
- p->end = p->start+n;
- }
- p->current = p->start+n-QUANTA;
-}
-
-void
-bufcpy(Bufblock *buf, char *cp, int n)
-{
-
- while (n--)
- insert(buf, *cp++);
-}
-
-void
-insert(Bufblock *buf, int c)
-{
-
- if (buf->current >= buf->end)
- growbuf(buf);
- *buf->current++ = c;
-}
-
-void
-rinsert(Bufblock *buf, Rune r)
-{
- int n;
-
- n = runelen(r);
- if (buf->current+n > buf->end)
- growbuf(buf);
- runetochar(buf->current, &r);
- buf->current += n;
-}
diff --git a/mk/env.c b/mk/env.c
@@ -1,149 +0,0 @@
-#include "mk.h"
-
-enum {
- ENVQUANTA=10
-};
-
-Envy *envy;
-static int nextv;
-
-static char *myenv[] =
-{
- "target",
- "stem",
- "prereq",
- "pid",
- "nproc",
- "newprereq",
- "alltarget",
- "newmember",
- "stem0", /* must be in order from here */
- "stem1",
- "stem2",
- "stem3",
- "stem4",
- "stem5",
- "stem6",
- "stem7",
- "stem8",
- "stem9",
- 0,
-};
-
-void
-initenv(void)
-{
- char **p;
-
- for(p = myenv; *p; p++)
- symlook(*p, S_INTERNAL, (void *)"");
- readenv(); /* o.s. dependent */
-}
-
-static void
-envinsert(char *name, Word *value)
-{
- static int envsize;
-
- if (nextv >= envsize) {
- envsize += ENVQUANTA;
- envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy));
- }
- envy[nextv].name = name;
- envy[nextv++].values = value;
-}
-
-static void
-envupd(char *name, Word *value)
-{
- Envy *e;
-
- for(e = envy; e->name; e++)
- if(strcmp(name, e->name) == 0){
- delword(e->values);
- e->values = value;
- return;
- }
- e->name = name;
- e->values = value;
- envinsert(0,0);
-}
-
-static void
-ecopy(Symtab *s)
-{
- char **p;
-
- if(symlook(s->name, S_NOEXPORT, 0))
- return;
- for(p = myenv; *p; p++)
- if(strcmp(*p, s->name) == 0)
- return;
- envinsert(s->name, (Word *) s->value);
-}
-
-void
-execinit(void)
-{
- char **p;
-
- nextv = 0;
- for(p = myenv; *p; p++)
- envinsert(*p, stow(""));
-
- symtraverse(S_VAR, ecopy);
- envinsert(0, 0);
-}
-
-Envy*
-buildenv(Job *j, int slot)
-{
- char **p, *cp, *qp;
- Word *w, *v, **l;
- int i;
- char buf[256];
-
- envupd("target", wdup(j->t));
- if(j->r->attr®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 cache */
- return t;
-}
-
-void
-touch(char *name)
-{
- Bprint(&bout, "touch(%s)\n", name);
- if(nflag)
- return;
-
- if(utfrune(name, '('))
- atouch(name); /* archive */
- else if(chgtime(name) < 0) {
- fprint(2, "%s: %r\n", name);
- Exit();
- }
-}
-
-void
-delete(char *name)
-{
- if(utfrune(name, '(') == 0) { /* file */
- if(remove(name) < 0)
- fprint(2, "remove %s: %r\n", name);
- } else
- fprint(2, "hoon off; mk can'tdelete archive members\n");
-}
-
-void
-timeinit(char *s)
-{
- long t;
- char *cp;
- Rune r;
- int c, n;
-
- t = time(0);
- while (*s) {
- cp = s;
- do{
- n = chartorune(&r, s);
- if (r == ' ' || r == ',' || r == '\n')
- break;
- s += n;
- } while(*s);
- c = *s;
- *s = 0;
- symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t;
- if (c)
- *s++ = c;
- while(*s){
- n = chartorune(&r, s);
- if(r != ' ' && r != ',' && r != '\n')
- break;
- s += n;
- }
- }
-}
diff --git a/mk/fns.h b/mk/fns.h
@@ -1,88 +0,0 @@
-#undef waitfor
-#define waitfor mkwaitfor
-
-void addrule(char*, Word*, char*, Word*, int, int, char*);
-void addrules(Word*, Word*, char*, int, int, char*);
-void addw(Word*, char*);
-void assert(char*, int);
-int assline(Biobuf *, Bufblock *);
-long atimeof(int,char*);
-void atouch(char*);
-void bufcpy(Bufblock *, char *, int);
-Envy *buildenv(Job*, int);
-void catchnotes(void);
-int chgtime(char*);
-void clrmade(Node*);
-void delete(char*);
-void delword(Word*);
-int dorecipe(Node*);
-void dumpa(char*, Arc*);
-void dumpj(char*, Job*, int);
-void dumpn(char*, Node*);
-void dumpr(char*, Rule*);
-void dumpv(char*);
-void dumpw(char*, Word*);
-void execinit(void);
-int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*);
-void Exit(void);
-void expunge(int, char*);
-void freebuf(Bufblock*);
-void front(char*);
-Node *graph(char*);
-void growbuf(Bufblock *);
-void initenv(void);
-void initshell(void);
-void insert(Bufblock *, int);
-void ipop(void);
-void ipush(void);
-void killchildren(char*);
-void *Malloc(int);
-char *maketmp(int*);
-int match(char*, char*, char*, Shell*);
-char *membername(char*, int, char*);
-void mk(char*);
-unsigned long mkmtime(char*);
-long mtime(char*);
-Arc *newarc(Node*, Rule*, char*, Resub*);
-Bufblock *newbuf(void);
-Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*);
-Word *newword(char*);
-int nextrune(Biobuf*, int);
-int nextslot(void);
-void nproc(void);
-void nrep(void);
-int outofdate(Node*, Arc*, int);
-void parse(char*, int, int);
-int pipecmd(char*, Envy*, int*, Shell*, Word*);
-void popshell(void);
-void prusage(void);
-void pushshell(void);
-void rcopy(char**, Resub*, int);
-void readenv(void);
-void *Realloc(void*, int);
-void rinsert(Bufblock *, Rune);
-char *rulecnt(void);
-void run(Job*);
-char *setshell(Word*);
-void setvar(char*, void*);
-int shargv(Word*, int, char***);
-char *shname(char*);
-void shprint(char*, Envy*, Bufblock*, Shell*);
-Word *stow(char*);
-void subst(char*, char*, char*);
-void symdel(char*, int);
-void syminit(void);
-Symtab *symlook(char*, int, void*);
-void symstat(void);
-void symtraverse(int, void(*)(Symtab*));
-void timeinit(char*);
-long timeof(char*, int);
-void touch(char*);
-void update(int, Node*);
-void usage(void);
-Word *varsub(char**);
-int waitfor(char*);
-int waitup(int, int*);
-Word *wdup(Word*);
-int work(Node*, Node*, Arc*);
-char *wtos(Word*, int);
diff --git a/mk/graph.c b/mk/graph.c
@@ -1,279 +0,0 @@
-#include "mk.h"
-
-static Node *applyrules(char *, char *);
-static void togo(Node *);
-static int vacuous(Node *);
-static Node *newnode(char *);
-static void trace(char *, Arc *);
-static void cyclechk(Node *);
-static void ambiguous(Node *);
-static void attribute(Node *);
-
-Node *
-graph(char *target)
-{
- Node *node;
- char *cnt;
-
- cnt = rulecnt();
- node = applyrules(target, cnt);
- free(cnt);
- cyclechk(node);
- node->flags |= PROBABLE; /* make sure it doesn't get deleted */
- vacuous(node);
- ambiguous(node);
- attribute(node);
- return(node);
-}
-
-static Node *
-applyrules(char *target, char *cnt)
-{
- Symtab *sym;
- Node *node;
- Rule *r;
- Arc head, *a = &head;
- Word *w;
- char stem[NAMEBLOCK], buf[NAMEBLOCK];
- Resub rmatch[NREGEXP];
-
-/* print("applyrules(%lux='%s')\n", target, target);*//**/
- sym = symlook(target, S_NODE, 0);
- if(sym)
- return (Node *)(sym->value);
- target = strdup(target);
- node = newnode(target);
- head.n = 0;
- head.next = 0;
- sym = symlook(target, S_TARGET, 0);
- memset((char*)rmatch, 0, sizeof(rmatch));
- for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){
- if(r->attr&META) continue;
- if(strcmp(target, r->target)) continue;
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
- node->flags |= PROBABLE;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, "", rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- a->next = newarc(applyrules(w->s, cnt), r, "", rmatch);
- a = a->next;
- }
- cnt[r->rule]--;
- head.n = node;
- }
- for(r = metarules; r; r = r->next){
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || !*r->tail->s)) continue; /* no effect; ignore */
- if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
- continue;
- if(r->attr®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)) continue;
- }
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
-
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, stem, rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- if(r->attr®EXP)
- regsub(w->s, buf, sizeof buf, rmatch, NREGEXP);
- else
- subst(stem, w->s, buf);
- a->next = newarc(applyrules(buf, cnt), r, stem, rmatch);
- a = a->next;
- }
- cnt[r->rule]--;
- }
- a->next = node->prereqs;
- node->prereqs = head.next;
- return(node);
-}
-
-static void
-togo(Node *node)
-{
- Arc *la, *a;
-
- /* delete them now */
- la = 0;
- for(a = node->prereqs; a; la = a, a = a->next)
- if(a->flag&TOGO){
- if(a == node->prereqs)
- node->prereqs = a->next;
- else
- la->next = a->next, a = la;
- }
-}
-
-static int
-vacuous(Node *node)
-{
- Arc *la, *a;
- int vac = !(node->flags&PROBABLE);
-
- if(node->flags&READY)
- return(node->flags&VACUOUS);
- node->flags |= READY;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && vacuous(a->n) && (a->r->attr&META))
- a->flag |= TOGO;
- else
- vac = 0;
- /* if a rule generated arcs that DON'T go; no others from that rule go */
- for(a = node->prereqs; a; a = a->next)
- if((a->flag&TOGO) == 0)
- for(la = node->prereqs; la; la = la->next)
- if((la->flag&TOGO) && (la->r == a->r)){
- la->flag &= ~TOGO;
- }
- togo(node);
- if(vac)
- node->flags |= VACUOUS;
- return(vac);
-}
-
-static Node *
-newnode(char *name)
-{
- register Node *node;
-
- node = (Node *)Malloc(sizeof(Node));
- symlook(name, S_NODE, (void *)node);
- node->name = name;
- node->time = timeof(name, 0);
- node->prereqs = 0;
- node->flags = node->time? PROBABLE : 0;
- node->next = 0;
- return(node);
-}
-
-void
-dumpn(char *s, Node *n)
-{
- char buf[1024];
- Arc *a;
-
- snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:"");
- Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n",
- s, n->name, n, n->time, n->flags, n->next);
- for(a = n->prereqs; a; a = a->next)
- dumpa(buf, a);
-}
-
-static void
-trace(char *s, Arc *a)
-{
- fprint(2, "\t%s", s);
- while(a){
- fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
- a->n? a->n->name:"");
- if(a->n){
- for(a = a->n->prereqs; a; a = a->next)
- if(*a->r->recipe) break;
- } else
- a = 0;
- }
- fprint(2, "\n");
-}
-
-static void
-cyclechk(Node *n)
-{
- Arc *a;
-
- if((n->flags&CYCLE) && n->prereqs){
- fprint(2, "mk: cycle in graph detected at target %s\n", n->name);
- Exit();
- }
- n->flags |= CYCLE;
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- cyclechk(a->n);
- n->flags &= ~CYCLE;
-}
-
-static void
-ambiguous(Node *n)
-{
- Arc *a;
- Rule *r = 0;
- Arc *la;
- int bad = 0;
-
- la = 0;
- for(a = n->prereqs; a; a = a->next){
- if(a->n)
- ambiguous(a->n);
- if(*a->r->recipe == 0) continue;
- if(r == 0)
- r = a->r, la = a;
- else{
- if(r->recipe != a->r->recipe){
- if((r->attr&META) && !(a->r->attr&META)){
- la->flag |= TOGO;
- r = a->r, la = a;
- } else if(!(r->attr&META) && (a->r->attr&META)){
- a->flag |= TOGO;
- continue;
- }
- }
- if(r->recipe != a->r->recipe){
- if(bad == 0){
- fprint(2, "mk: ambiguous recipes for %s:\n", n->name);
- bad = 1;
- trace(n->name, la);
- }
- trace(n->name, a);
- }
- }
- }
- if(bad)
- Exit();
- togo(n);
-}
-
-static void
-attribute(Node *n)
-{
- register Arc *a;
-
- for(a = n->prereqs; a; a = a->next){
- if(a->r->attr&VIR)
- n->flags |= VIRTUAL;
- if(a->r->attr&NOREC)
- n->flags |= NORECIPE;
- if(a->r->attr&DEL)
- n->flags |= DELETE;
- if(a->n)
- attribute(a->n);
- }
- if(n->flags&VIRTUAL)
- n->time = 0;
-}
diff --git a/mk/job.c b/mk/job.c
@@ -1,33 +0,0 @@
-#include "mk.h"
-
-Job *
-newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, Word *tar, Word *atar)
-{
- register Job *j;
-
- j = (Job *)Malloc(sizeof(Job));
- j->r = r;
- j->n = nlist;
- j->stem = stem;
- j->match = match;
- j->p = pre;
- j->np = npre;
- j->t = tar;
- j->at = atar;
- j->nproc = -1;
- j->next = 0;
- return(j);
-}
-
-void
-dumpj(char *s, Job *j, int all)
-{
- Bprint(&bout, "%s\n", s);
- while(j){
- Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n",
- j, j->r, j->n, j->stem, j->nproc);
- Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprereq='%s'\n",
- wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wtos(j->np, ' '));
- j = all? j->next : 0;
- }
-}
diff --git a/mk/lex.c b/mk/lex.c
@@ -1,146 +0,0 @@
-#include "mk.h"
-
-static int bquote(Biobuf*, Bufblock*);
-
-/*
- * Assemble a line skipping blank lines, comments, and eliding
- * escaped newlines
- */
-int
-assline(Biobuf *bp, Bufblock *buf)
-{
- int c;
- int lastc;
-
- buf->current=buf->start;
- while ((c = nextrune(bp, 1)) >= 0){
- switch(c)
- {
- case '\r': /* consumes CRs for Win95 */
- continue;
- case '\n':
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break; /* skip empty lines */
- case '\\':
- case '\'':
- case '"':
- rinsert(buf, c);
- if (shellt->escapetoken(bp, buf, 1, c) == 0)
- Exit();
- break;
- case '`':
- if (bquote(bp, buf) == 0)
- Exit();
- break;
- case '#':
- lastc = '#';
- while ((c = Bgetc(bp)) != '\n') {
- if (c < 0)
- goto eof;
- if(c != '\r')
- lastc = c;
- }
- mkinline++;
- if (lastc == '\\')
- break; /* propagate escaped newlines??*/
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break;
- default:
- rinsert(buf, c);
- break;
- }
- }
-eof:
- insert(buf, 0);
- return *buf->start != 0;
-}
-
-/*
- * assemble a back-quoted shell command into a buffer
- */
-static int
-bquote(Biobuf *bp, Bufblock *buf)
-{
- int c, line, term;
- int start;
-
- line = mkinline;
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- if(c == '{'){
- term = '}'; /* rc style */
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- } else
- term = '`'; /* sh style */
-
- start = buf->current-buf->start;
- for(;c > 0; c = nextrune(bp, 0)){
- if(c == term){
- insert(buf, '\n');
- insert(buf,0);
- buf->current = buf->start+start;
- execinit();
- execsh(0, buf->current, buf, envy, shellt, shellcmd);
- return 1;
- }
- if(c == '\n')
- break;
- if(c == '\'' || c == '"' || c == '\\'){
- insert(buf, c);
- if(!shellt->escapetoken(bp, buf, 1, c))
- return 0;
- continue;
- }
- rinsert(buf, c);
- }
- SYNERR(line);
- fprint(2, "missing closing %c after `\n", term);
- return 0;
-}
-
-/*
- * get next character stripping escaped newlines
- * the flag specifies whether escaped newlines are to be elided or
- * replaced with a blank.
- */
-int
-nextrune(Biobuf *bp, int elide)
-{
- int c, c2;
- static int savec;
-
- if(savec){
- c = savec;
- savec = 0;
- return c;
- }
-
- for (;;) {
- c = Bgetrune(bp);
- if (c == '\\') {
- c2 = Bgetrune(bp);
- if(c2 == '\r'){
- savec = c2;
- c2 = Bgetrune(bp);
- }
- if (c2 == '\n') {
- savec = 0;
- mkinline++;
- if (elide)
- continue;
- return ' ';
- }
- Bungetrune(bp);
- }
- if (c == '\n')
- mkinline++;
- return c;
- }
-}
diff --git a/mk/main.c b/mk/main.c
@@ -1,287 +0,0 @@
-#include "mk.h"
-
-#define MKFILE "mkfile"
-
-int debug;
-Rule *rules, *metarules;
-int nflag = 0;
-int tflag = 0;
-int iflag = 0;
-int kflag = 0;
-int aflag = 0;
-int uflag = 0;
-char *explain = 0;
-Word *target1;
-int nreps = 1;
-Job *jobs;
-Biobuf bout;
-Rule *patrule;
-void badusage(void);
-#ifdef PROF
-short buf[10000];
-#endif
-
-int
-main(int argc, char **argv)
-{
- Word *w;
- char *s, *temp;
- char *files[256], **f = files, **ff;
- int sflag = 0;
- int i;
- int tfd = -1;
- Biobuf tb;
- Bufblock *buf;
- Bufblock *whatif;
-
- /*
- * start with a copy of the current environment variables
- * instead of sharing them
- */
-
- Binit(&bout, 1, OWRITE);
- buf = newbuf();
- whatif = 0;
- USED(argc);
- for(argv++; *argv && (**argv == '-'); argv++)
- {
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- switch(argv[0][1])
- {
- case 'a':
- aflag = 1;
- break;
- case 'd':
- if(*(s = &argv[0][2]))
- while(*s) switch(*s++)
- {
- case 'p': debug |= D_PARSE; break;
- case 'g': debug |= D_GRAPH; break;
- case 'e': debug |= D_EXEC; break;
- }
- else
- debug = 0xFFFF;
- break;
- case 'e':
- explain = &argv[0][2];
- break;
- case 'f':
- if(*++argv == 0)
- badusage();
- *f++ = *argv;
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- break;
- case 'i':
- iflag = 1;
- break;
- case 'k':
- kflag = 1;
- break;
- case 'n':
- nflag = 1;
- break;
- case 's':
- sflag = 1;
- break;
- case 't':
- tflag = 1;
- break;
- case 'u':
- uflag = 1;
- break;
- case 'w':
- if(whatif == 0)
- whatif = newbuf();
- else
- insert(whatif, ' ');
- if(argv[0][2])
- bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]));
- else {
- if(*++argv == 0)
- badusage();
- bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]));
- }
- break;
- default:
- badusage();
- }
- }
-#ifdef PROF
- {
- extern etext();
- monitor(main, etext, buf, sizeof buf, 300);
- }
-#endif
-
- if(aflag)
- iflag = 1;
- usage();
- syminit();
- initshell();
- initenv();
- usage();
-
- /*
- assignment args become null strings
- */
- temp = 0;
- for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
- bufcpy(buf, argv[i], strlen(argv[i]));
- insert(buf, ' ');
- if(tfd < 0){
- temp = maketmp(&tfd);
- if(temp == 0) {
- fprint(2, "temp file: %r\n");
- Exit();
- }
- Binit(&tb, tfd, OWRITE);
- }
- Bprint(&tb, "%s\n", argv[i]);
- *argv[i] = 0;
- }
- if(tfd >= 0){
- Bflush(&tb);
- LSEEK(tfd, 0L, 0);
- parse("command line args", tfd, 1);
- remove(temp);
- }
-
- if (buf->current != buf->start) {
- buf->current--;
- insert(buf, 0);
- }
- symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
- buf->current = buf->start;
- for(i = 0; argv[i]; i++){
- if(*argv[i] == 0) continue;
- if(i)
- insert(buf, ' ');
- bufcpy(buf, argv[i], strlen(argv[i]));
- }
- insert(buf, 0);
- symlook("MKARGS", S_VAR, (void *) stow(buf->start));
- freebuf(buf);
-
- if(f == files){
- if(access(MKFILE, 4) == 0)
- parse(MKFILE, open(MKFILE, 0), 0);
- } else
- for(ff = files; ff < f; ff++)
- parse(*ff, open(*ff, 0), 0);
- if(DEBUG(D_PARSE)){
- dumpw("default targets", target1);
- dumpr("rules", rules);
- dumpr("metarules", metarules);
- dumpv("variables");
- }
- if(whatif){
- insert(whatif, 0);
- timeinit(whatif->start);
- freebuf(whatif);
- }
- execinit();
- /* skip assignment args */
- while(*argv && (**argv == 0))
- argv++;
-
- catchnotes();
- if(*argv == 0){
- if(target1)
- for(w = target1; w; w = w->next)
- mk(w->s);
- else {
- fprint(2, "mk: nothing to mk\n");
- Exit();
- }
- } else {
- if(sflag){
- for(; *argv; argv++)
- if(**argv)
- mk(*argv);
- } else {
- Word *head, *tail, *t;
-
- /* fake a new rule with all the args as prereqs */
- tail = 0;
- t = 0;
- for(; *argv; argv++)
- if(**argv){
- if(tail == 0)
- tail = t = newword(*argv);
- else {
- t->next = newword(*argv);
- t = t->next;
- }
- }
- if(tail->next == 0)
- mk(tail->s);
- else {
- head = newword("command line arguments");
- addrules(head, tail, strdup(""), VIR, mkinline, 0);
- mk(head->s);
- }
- }
- }
- if(uflag)
- prusage();
- exits(0);
- return 0;
-}
-
-void
-badusage(void)
-{
-
- fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]] [targets ...]\n");
- Exit();
-}
-
-void *
-Malloc(int n)
-{
- register void *s;
-
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void *
-Realloc(void *s, int n)
-{
- if(s)
- s = realloc(s, n);
- else
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void
-assert(char *s, int n)
-{
- if(!n){
- fprint(2, "mk: Assertion ``%s'' failed.\n", s);
- Exit();
- }
-}
-
-void
-regerror(char *s)
-{
- if(patrule)
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- patrule->file, patrule->line, s);
- else
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- infile, mkinline, s);
- Exit();
-}
diff --git a/mk/match.c b/mk/match.c
@@ -1,49 +0,0 @@
-#include "mk.h"
-
-int
-match(char *name, char *template, char *stem, Shell *sh)
-{
- Rune r;
- int n;
-
- while(*name && *template){
- n = chartorune(&r, template);
- if (PERCENT(r))
- break;
- while (n--)
- if(*name++ != *template++)
- return 0;
- }
- if(!PERCENT(*template))
- return 0;
- n = strlen(name)-strlen(template+1);
- if (n < 0)
- return 0;
- if (strcmp(template+1, name+n))
- return 0;
- strncpy(stem, name, n);
- stem[n] = 0;
- if(*template == '&')
- return !sh->charin(stem, "./");
- return 1;
-}
-
-void
-subst(char *stem, char *template, char *dest)
-{
- Rune r;
- char *s;
- int n;
-
- while(*template){
- n = chartorune(&r, template);
- if (PERCENT(r)) {
- template += n;
- for (s = stem; *s; s++)
- *dest++ = *s;
- } else
- while (n--)
- *dest++ = *template++;
- }
- *dest = 0;
-}
diff --git a/mk/mk.1 b/mk/mk.1
@@ -1,691 +0,0 @@
-.TH MK 1
-.SH NAME
-mk \- maintain (make) related files
-.SH SYNOPSIS
-.B mk
-[
-.B -f
-.I mkfile
-] ...
-[
-.I option ...
-]
-[
-.I target ...
-]
-.SH DESCRIPTION
-.I Mk
-uses the dependency rules specified in
-.I mkfile
-to control the update (usually by compilation) of
-.I targets
-(usually files)
-from the source files upon which they depend.
-The
-.I mkfile
-(default
-.LR mkfile )
-contains a
-.I rule
-for each target that identifies the files and other
-targets upon which it depends and an
-.IR sh (1)
-script, a
-.IR recipe ,
-to update the target.
-The script is run if the target does not exist
-or if it is older than any of the files it depends on.
-.I Mkfile
-may also contain
-.I meta-rules
-that define actions for updating implicit targets.
-If no
-.I target
-is specified, the target of the first rule (not meta-rule) in
-.I mkfile
-is updated.
-.PP
-The environment variable
-.B $NPROC
-determines how many targets may be updated simultaneously;
-Some operating systems, e.g., Plan 9, set
-.B $NPROC
-automatically to the number of CPUs on the current machine.
-.PP
-Options are:
-.TP \w'\fL-d[egp]\ 'u
-.B -a
-Assume all targets to be out of date.
-Thus, everything is updated.
-.PD 0
-.TP
-.BR -d [ egp ]
-Produce debugging output
-.RB ( p
-is for parsing,
-.B g
-for graph building,
-.B e
-for execution).
-.TP
-.B -e
-Explain why each target is made.
-.TP
-.B -i
-Force any missing intermediate targets to be made.
-.TP
-.B -k
-Do as much work as possible in the face of errors.
-.TP
-.B -n
-Print, but do not execute, the commands
-needed to update the targets.
-.TP
-.B -s
-Make the command line arguments sequentially rather than in parallel.
-.TP
-.B -t
-Touch (update the modified date of) file targets, without
-executing any recipes.
-.TP
-.BI -w target1 , target2,...
-Pretend the modify time for each
-.I target
-is the current time; useful in conjunction with
-.B -n
-to learn what updates would be triggered by
-modifying the
-.IR targets .
-.PD
-.SS The \fLmkfile\fP
-A
-.I mkfile
-consists of
-.I assignments
-(described under `Environment') and
-.IR rules .
-A rule contains
-.I targets
-and a
-.IR tail .
-A target is a literal string
-and is normally a file name.
-The tail contains zero or more
-.I prerequisites
-and an optional
-.IR recipe ,
-which is an
-.B shell
-script.
-Each line of the recipe must begin with white space.
-A rule takes the form
-.IP
-.EX
-target: prereq1 prereq2
- \f2recipe using\fP prereq1, prereq2 \f2to build\fP target
-.EE
-.PP
-When the recipe is executed,
-the first character on every line is elided.
-.PP
-After the colon on the target line, a rule may specify
-.IR attributes ,
-described below.
-.PP
-A
-.I meta-rule
-has a target of the form
-.IB A % B
-where
-.I A
-and
-.I B
-are (possibly empty) strings.
-A meta-rule acts as a rule for any potential target whose
-name matches
-.IB A % B
-with
-.B %
-replaced by an arbitrary string, called the
-.IR stem .
-In interpreting a meta-rule,
-the stem is substituted for all occurrences of
-.B %
-in the prerequisite names.
-In the recipe of a meta-rule, the environment variable
-.B $stem
-contains the string matched by the
-.BR % .
-For example, a meta-rule to compile a C program using
-.IR 9c (1)
-might be:
-.IP
-.EX
-%: %.c
- 9c -c $stem.c
- 9l -o $stem $stem.o
-.EE
-.PP
-Meta-rules may contain an ampersand
-.B &
-rather than a percent sign
-.BR % .
-A
-.B %
-matches a maximal length string of any characters;
-an
-.B &
-matches a maximal length string of any characters except period
-or slash.
-.PP
-The text of the
-.I mkfile
-is processed as follows.
-Lines beginning with
-.B <
-followed by a file name are replaced by the contents of the named
-file.
-Lines beginning with
-.B "<|"
-followed by a file name are replaced by the output
-of the execution of the named
-file.
-Blank lines and comments, which run from unquoted
-.B #
-characters to the following newline, are deleted.
-The character sequence backslash-newline is deleted,
-so long lines in
-.I mkfile
-may be folded.
-Non-recipe lines are processed by substituting for
-.BI `{ command }
-the output of the
-.I command
-when run by
-.IR sh .
-References to variables are replaced by the variables' values.
-Special characters may be quoted using single quotes
-.BR \&''
-as in
-.IR sh (1).
-.PP
-Assignments and rules are distinguished by
-the first unquoted occurrence of
-.B :
-(rule)
-or
-.B =
-(assignment).
-.PP
-A later rule may modify or override an existing rule under the
-following conditions:
-.TP
-\-
-If the targets of the rules exactly match and one rule
-contains only a prerequisite clause and no recipe, the
-clause is added to the prerequisites of the other rule.
-If either or both targets are virtual, the recipe is
-always executed.
-.TP
-\-
-If the targets of the rules match exactly and the
-prerequisites do not match and both rules
-contain recipes,
-.I mk
-reports an ``ambiguous recipe'' error.
-.TP
-\-
-If the target and prerequisites of both rules match exactly,
-the second rule overrides the first.
-.SS Environment
-Rules may make use of
-shell
-environment variables.
-A legal reference of the form
-.B $OBJ
-or
-.B ${name}
-is expanded as in
-.IR sh (1).
-A reference of the form
-.BI ${name: A % B = C\fL%\fID\fL}\fR,
-where
-.I A, B, C, D
-are (possibly empty) strings,
-has the value formed by expanding
-.B $name
-and substituting
-.I C
-for
-.I A
-and
-.I D
-for
-.I B
-in each word in
-.B $name
-that matches pattern
-.IB A % B\f1.
-.PP
-Variables can be set by
-assignments of the form
-.I
- var\fL=\fR[\fIattr\fL=\fR]\fIvalue\fR
-.br
-Blanks in the
-.I value
-break it into words.
-Such variables are exported
-to the environment of
-recipes as they are executed, unless
-.BR U ,
-the only legal attribute
-.IR attr ,
-is present.
-The initial value of a variable is
-taken from (in increasing order of precedence)
-the default values below,
-.I mk's
-environment, the
-.IR mkfiles ,
-and any command line assignment as an argument to
-.IR mk .
-A variable assignment argument overrides the first (but not any subsequent)
-assignment to that variable.
-.PP
-The variable
-.B MKFLAGS
-contains all the option arguments (arguments starting with
-.L -
-or containing
-.LR = )
-and
-.B MKARGS
-contains all the targets in the call to
-.IR mk .
-.PP
-The variable
-.B MKSHELL
-contains the shell command line
-.I mk
-uses to run recipes.
-If the first word of the command ends in
-.B rc
-or
-.BR rcsh ,
-.I mk
-uses
-.IR rc (1)'s
-quoting rules; otherwise it uses
-.IR sh (1)'s.
-The
-.B MKSHELL
-variable is consulted when the mkfile is read, not when it is executed,
-so that different shells can be used within a single mkfile:
-.IP
-.EX
-MKSHELL=$PLAN9/bin/rc
-use-rc:V:
- for(i in a b c) echo $i
-
-MKSHELL=sh
-use-sh:V:
- for i in a b c; do echo $i; done
-.EE
-.LP
-Mkfiles included via
-.B <
-or
-.B <|
-.RI ( q.v. )
-see their own private copy of
-.BR MKSHELL ,
-which always starts set to
-.B sh .
-.PP
-Dynamic information may be included in the mkfile by using a line of the form
-.IP
-\fR<|\fIcommand\fR \fIargs\fR
-.LP
-This runs the command
-.I command
-with the given arguments
-.I args
-and pipes its standard output to
-.I mk
-to be included as part of the mkfile. For instance, the Inferno kernels
-use this technique
-to run a shell command with an awk script and a configuration
-file as arguments in order for
-the
-.I awk
-script to process the file and output a set of variables and their values.
-.SS Execution
-.PP
-During execution,
-.I mk
-determines which targets must be updated, and in what order,
-to build the
-.I names
-specified on the command line.
-It then runs the associated recipes.
-.PP
-A target is considered up to date if it has no prerequisites or
-if all its prerequisites are up to date and it is newer
-than all its prerequisites.
-Once the recipe for a target has executed, the target is
-considered up to date.
-.PP
-The date stamp
-used to determine if a target is up to date is computed
-differently for different types of targets.
-If a target is
-.I virtual
-(the target of a rule with the
-.B V
-attribute),
-its date stamp is initially zero; when the target is
-updated the date stamp is set to
-the most recent date stamp of its prerequisites.
-Otherwise, if a target does not exist as a file,
-its date stamp is set to the most recent date stamp of its prerequisites,
-or zero if it has no prerequisites.
-Otherwise, the target is the name of a file and
-the target's date stamp is always that file's modification date.
-The date stamp is computed when the target is needed in
-the execution of a rule; it is not a static value.
-.PP
-Nonexistent targets that have prerequisites
-and are themselves prerequisites are treated specially.
-Such a target
-.I t
-is given the date stamp of its most recent prerequisite
-and if this causes all the targets which have
-.I t
-as a prerequisite to be up to date,
-.I t
-is considered up to date.
-Otherwise,
-.I t
-is made in the normal fashion.
-The
-.B -i
-flag overrides this special treatment.
-.PP
-Files may be made in any order that respects
-the preceding restrictions.
-.PP
-A recipe is executed by supplying the recipe as standard input to
-the command
-.BR /bin/sh .
-(Note that unlike
-.IR make ,
-.I mk
-feeds the entire recipe to the shell rather than running each line
-of the recipe separately.)
-The environment is augmented by the following variables:
-.TP 14
-.B $alltarget
-all the targets of this rule.
-.TP
-.B $newprereq
-the prerequisites that caused this rule to execute.
-.TP
-.B $newmember
-the prerequisites that are members of an aggregate
-that caused this rule to execute.
-When the prerequisites of a rule are members of an
-aggregate,
-.B $newprereq
-contains the name of the aggregate and out of date
-members, while
-.B $newmember
-contains only the name of the members.
-.TP
-.B $nproc
-the process slot for this recipe.
-It satisfies
-.RB 0≤ $nproc < $NPROC .
-.TP
-.B $pid
-the process id for the
-.I mk
-executing the recipe.
-.TP
-.B $prereq
-all the prerequisites for this rule.
-.TP
-.B $stem
-if this is a meta-rule,
-.B $stem
-is the string that matched
-.B %
-or
-.BR & .
-Otherwise, it is empty.
-For regular expression meta-rules (see below), the variables
-.LR stem0 ", ...,"
-.L stem9
-are set to the corresponding subexpressions.
-.TP
-.B $target
-the targets for this rule that need to be remade.
-.PP
-These variables are available only during the execution of a recipe,
-not while evaluating the
-.IR mkfile .
-.PP
-Unless the rule has the
-.B Q
-attribute,
-the recipe is printed prior to execution
-with recognizable environment variables expanded.
-Commands returning error status
-cause
-.I mk
-to terminate.
-.PP
-Recipes and backquoted
-.B rc
-commands in places such as assignments
-execute in a copy of
-.I mk's
-environment; changes they make to
-environment variables are not visible from
-.IR mk .
-.PP
-Variable substitution in a rule is done when
-the rule is read; variable substitution in the recipe is done
-when the recipe is executed. For example:
-.IP
-.EX
-bar=a.c
-foo: $bar
- $CC -o foo $bar
-bar=b.c
-.EE
-.PP
-will compile
-.B b.c
-into
-.BR foo ,
-if
-.B a.c
-is newer than
-.BR foo .
-.SS Aggregates
-Names of the form
-.IR a ( b )
-refer to member
-.I b
-of the aggregate
-.IR a .
-Currently, the only aggregates supported are
-.I 9ar
-(see
-.IR 9c (1))
-archives.
-.SS Attributes
-The colon separating the target from the prerequisites
-may be
-immediately followed by
-.I attributes
-and another colon.
-The attributes are:
-.TP
-.B D
-If the recipe exits with a non-null status, the target is deleted.
-.TP
-.B E
-Continue execution if the recipe draws errors.
-.TP
-.B N
-If there is no recipe, the target has its time updated.
-.TP
-.B n
-The rule is a meta-rule that cannot be a target of a virtual rule.
-Only files match the pattern in the target.
-.TP
-.B P
-The characters after the
-.B P
-until the terminating
-.B :
-are taken as a program name.
-It will be invoked as
-.B "sh -c prog 'arg1' 'arg2'"
-and should return a zero exit status
-if and only if arg1 is up to date with respect to arg2.
-Date stamps are still propagated in the normal way.
-.TP
-.B Q
-The recipe is not printed prior to execution.
-.TP
-.B R
-The rule is a meta-rule using regular expressions.
-In the rule,
-.B %
-has no special meaning.
-The target is interpreted as a regular expression as defined in
-.IR regexp (7).
-The prerequisites may contain references
-to subexpressions in form
-.BI \e n\f1,
-as in the substitute command of
-.IR sed (1).
-.TP
-.B U
-The targets are considered to have been updated
-even if the recipe did not do so.
-.TP
-.B V
-The targets of this rule are marked as virtual.
-They are distinct from files of the same name.
-.PD
-.SH EXAMPLES
-A simple mkfile to compile a program:
-.IP
-.EX
-.ta 8n +8n +8n +8n +8n +8n +8n
-</$objtype/mkfile
-
-prog: a.$O b.$O c.$O
- $LD $LDFLAGS -o $target $prereq
-
-%.$O: %.c
- $CC $CFLAGS $stem.c
-.EE
-.PP
-Override flag settings in the mkfile:
-.IP
-.EX
-% mk target 'CFLAGS=-S -w'
-.EE
-.PP
-Maintain a library:
-.IP
-.EX
-libc.a(%.$O):N: %.$O
-libc.a: libc.a(abs.$O) libc.a(access.$O) libc.a(alarm.$O) ...
- ar r libc.a $newmember
-.EE
-.PP
-String expression variables to derive names from a master list:
-.IP
-.EX
-NAMES=alloc arc bquote builtins expand main match mk var word
-OBJ=${NAMES:%=%.$O}
-.EE
-.PP
-Regular expression meta-rules:
-.IP
-.EX
-([^/]*)/(.*)\e.$O:R: \e1/\e2.c
- cd $stem1; $CC $CFLAGS $stem2.c
-.EE
-.PP
-A correct way to deal with
-.IR yacc (1)
-grammars.
-The file
-.B lex.c
-includes the file
-.B x.tab.h
-rather than
-.B y.tab.h
-in order to reflect changes in content, not just modification time.
-.IP
-.EX
-lex.$O: x.tab.h
-x.tab.h: y.tab.h
- cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
-y.tab.c y.tab.h: gram.y
- $YACC -d gram.y
-.EE
-.PP
-The above example could also use the
-.B P
-attribute for the
-.B x.tab.h
-rule:
-.IP
-.EX
-x.tab.h:Pcmp -s: y.tab.h
- cp y.tab.h x.tab.h
-.EE
-.SH SOURCE
-.B \*9/src/cmd/mk
-.SH SEE ALSO
-.IR sh (1),
-.IR regexp (7)
-.PP
-A. Hume,
-``Mk: a Successor to Make''
-(Tenth Edition Research Unix Manuals).
-.PP
-Andrew G. Hume and Bob Flandrena,
-``Maintaining Files on Plan 9 with Mk''.
-DOCPREFIX/doc/mk.pdf
-.SH HISTORY
-Andrew Hume wrote
-.I mk
-for Tenth Edition Research Unix.
-It was later ported to Plan 9.
-This software is a port of the Plan 9 version back to Unix.
-.SH BUGS
-Identical recipes for regular expression meta-rules only have one target.
-.PP
-Seemingly appropriate input like
-.B CFLAGS=-DHZ=60
-is parsed as an erroneous attribute; correct it by inserting
-a space after the first
-.LR = .
-.PP
-The recipes printed by
-.I mk
-before being passed to
-the shell
-for execution are sometimes erroneously expanded
-for printing. Don't trust what's printed; rely
-on what the shell
-does.
diff --git a/mk/mk.c b/mk/mk.c
@@ -1,234 +0,0 @@
-#include "mk.h"
-
-int runerrs;
-
-void
-mk(char *target)
-{
- Node *node;
- int did = 0;
-
- nproc(); /* it can be updated dynamically */
- nrep(); /* it can be updated dynamically */
- runerrs = 0;
- node = graph(target);
- if(DEBUG(D_GRAPH)){
- dumpn("new target\n", node);
- Bflush(&bout);
- }
- clrmade(node);
- while(node->flags&NOTMADE){
- if(work(node, (Node *)0, (Arc *)0))
- did = 1; /* found something to do */
- else {
- if(waitup(1, (int *)0) > 0){
- if(node->flags&(NOTMADE|BEINGMADE)){
- assert("must be run errors", runerrs);
- break; /* nothing more waiting */
- }
- }
- }
- }
- if(node->flags&BEINGMADE)
- waitup(-1, (int *)0);
- while(jobs)
- waitup(-2, (int *)0);
- assert("target didn't get done", runerrs || (node->flags&MADE));
- if(did == 0)
- Bprint(&bout, "mk: '%s' is up to date\n", node->name);
-}
-
-void
-clrmade(Node *n)
-{
- Arc *a;
-
- n->flags &= ~(CANPRETEND|PRETENDING);
- if(strchr(n->name, '(') ==0 || n->time)
- n->flags |= CANPRETEND;
- MADESET(n, NOTMADE);
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- clrmade(a->n);
-}
-
-static void
-unpretend(Node *n)
-{
- MADESET(n, NOTMADE);
- n->flags &= ~(CANPRETEND|PRETENDING);
- n->time = 0;
-}
-
-static char*
-dir(void)
-{
- static char buf[1024];
-
- return getcwd(buf, sizeof buf);
-}
-
-int
-work(Node *node, Node *p, Arc *parc)
-{
- Arc *a, *ra;
- int weoutofdate;
- int ready;
- int did = 0;
-
- /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, node->time);*//**/
- if(node->flags&BEINGMADE)
- return(did);
- if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p, parc, 0)){
- if(explain)
- fprint(1, "unpretending %s(%ld) because %s is out of date(%ld)\n",
- node->name, node->time, p->name, p->time);
- unpretend(node);
- }
- /*
- have a look if we are pretending in case
- someone has been unpretended out from underneath us
- */
- if(node->flags&MADE){
- if(node->flags&PRETENDING){
- node->time = 0;
- }else
- return(did);
- }
- /* consider no prerequsite case */
- if(node->prereqs == 0){
- if(node->time == 0){
- fprint(2, "mk: don't know how to make '%s' in %s\n", node->name, dir());
- if(kflag){
- node->flags |= BEINGMADE;
- runerrs++;
- } else
- Exit();
- } else
- MADESET(node, MADE);
- return(did);
- }
- /*
- now see if we are out of date or what
- */
- ready = 1;
- weoutofdate = aflag;
- ra = 0;
- for(a = node->prereqs; a; a = a->next)
- if(a->n){
- did = work(a->n, node, a) || did;
- if(a->n->flags&(NOTMADE|BEINGMADE))
- ready = 0;
- if(outofdate(node, a, 0)){
- weoutofdate = 1;
- if((ra == 0) || (ra->n == 0)
- || (ra->n->time < a->n->time))
- ra = a;
- }
- } else {
- if(node->time == 0){
- if(ra == 0)
- ra = a;
- weoutofdate = 1;
- }
- }
- if(ready == 0) /* can't do anything now */
- return(did);
- if(weoutofdate == 0){
- MADESET(node, MADE);
- return(did);
- }
- /*
- can we pretend to be made?
- */
- if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPRETEND))
- && p && ra->n && !outofdate(p, ra, 0)){
- node->flags &= ~CANPRETEND;
- MADESET(node, MADE);
- if(explain && ((node->flags&PRETENDING) == 0))
- fprint(1, "pretending %s has time %ld\n", node->name, node->time);
- node->flags |= PRETENDING;
- return(did);
- }
- /*
- node is out of date and we REALLY do have to do something.
- quickly rescan for pretenders
- */
- for(a = node->prereqs; a; a = a->next)
- if(a->n && (a->n->flags&PRETENDING)){
- if(explain)
- Bprint(&bout, "unpretending %s because of %s because of %s\n",
- a->n->name, node->name, ra->n? ra->n->name : "rule with no prerequisites");
-
- unpretend(a->n);
- did = work(a->n, node, a) || did;
- ready = 0;
- }
- if(ready == 0) /* try later unless nothing has happened for -k's sake */
- return(did || work(node, p, parc));
- did = dorecipe(node) || did;
- return(did);
-}
-
-void
-update(int fake, Node *node)
-{
- Arc *a;
-
- MADESET(node, fake? BEINGMADE : MADE);
- if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
- node->time = timeof(node->name, 1);
- node->flags &= ~(CANPRETEND|PRETENDING);
- for(a = node->prereqs; a; a = a->next)
- if(a->prog)
- outofdate(node, a, 1);
- } else {
- node->time = 1;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && outofdate(node, a, 1))
- node->time = a->n->time;
- }
-/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, node->flags);*//**/
-}
-
-static int
-pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd)
-{
- char buf[3*NAMEBLOCK];
- int pid;
-
- Bflush(&bout);
- snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
- pid = pipecmd(buf, 0, 0, sh, shcmd);
- while(waitup(-3, &pid) >= 0)
- ;
- return(pid? 2:1);
-}
-
-int
-outofdate(Node *node, Arc *arc, int eval)
-{
- char buf[3*NAMEBLOCK], *str;
- Symtab *sym;
- int ret;
-
- str = 0;
- if(arc->prog){
- snprint(buf, sizeof buf, "%s%c%s", node->name, 0377, arc->n->name);
- sym = symlook(buf, S_OUTOFDATE, 0);
- if(sym == 0 || eval){
- if(sym == 0)
- str = strdup(buf);
- ret = pcmp(arc->prog, node->name, arc->n->name, arc->r->shellt, arc->r->shellcmd);
- if(sym)
- sym->value = (void *)ret;
- else
- symlook(str, S_OUTOFDATE, (void *)ret);
- } else
- ret = (int)sym->value;
- return(ret-1);
- } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing archive member */
- return 1;
- else
- return node->time <= arc->n->time;
-}
diff --git a/mk/mk.h b/mk/mk.h
@@ -1,182 +0,0 @@
-#include "sys.h"
-
-#undef assert
-#define assert mkassert
-extern Biobuf bout;
-
-typedef struct Bufblock
-{
- struct Bufblock *next;
- char *start;
- char *end;
- char *current;
-} Bufblock;
-
-typedef struct Word
-{
- char *s;
- struct Word *next;
-} Word;
-
-typedef struct Envy
-{
- char *name;
- Word *values;
-} Envy;
-
-extern Envy *envy;
-
-typedef struct Shell
-{
- char *name;
- char *termchars; /* used in parse.c to isolate assignment attribute */
- int iws; /* inter-word separator in environment */
- char *(*charin)(char*, char*); /* search for unescaped characters */
- char *(*expandquote)(char*, Rune, Bufblock*); /* extract escaped token */
- int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* input escaped token */
- char *(*copyq)(char*, Rune, Bufblock*); /* check for quoted strings */
- int (*matchname)(char*); /* does name match */
-} Shell;
-
-typedef struct Rule
-{
- char *target; /* one target */
- Word *tail; /* constituents of targets */
- char *recipe; /* do it ! */
- short attr; /* attributes */
- short line; /* source line */
- char *file; /* source file */
- Word *alltargets; /* all the targets */
- int rule; /* rule number */
- Reprog *pat; /* reg exp goo */
- char *prog; /* to use in out of date */
- struct Rule *chain; /* hashed per target */
- struct Rule *next;
- Shell *shellt; /* shell to use with this rule */
- Word *shellcmd;
-} Rule;
-
-extern Rule *rules, *metarules, *patrule;
-
-/* Rule.attr */
-#define META 0x0001
-#define UNUSED 0x0002
-#define UPD 0x0004
-#define QUIET 0x0008
-#define VIR 0x0010
-#define REGEXP 0x0020
-#define NOREC 0x0040
-#define DEL 0x0080
-#define NOVIRT 0x0100
-
-#define NREGEXP 10
-
-typedef struct Arc
-{
- short flag;
- struct Node *n;
- Rule *r;
- char *stem;
- char *prog;
- char *match[NREGEXP];
- struct Arc *next;
-} Arc;
-
- /* Arc.flag */
-#define TOGO 1
-
-typedef struct Node
-{
- char *name;
- long time;
- unsigned short flags;
- Arc *prereqs;
- struct Node *next; /* list for a rule */
-} Node;
-
- /* Node.flags */
-#define VIRTUAL 0x0001
-#define CYCLE 0x0002
-#define READY 0x0004
-#define CANPRETEND 0x0008
-#define PRETENDING 0x0010
-#define NOTMADE 0x0020
-#define BEINGMADE 0x0040
-#define MADE 0x0080
-#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEINGMADE|MADE))|(m)
-#define PROBABLE 0x0100
-#define VACUOUS 0x0200
-#define NORECIPE 0x0400
-#define DELETE 0x0800
-#define NOMINUSE 0x1000
-
-typedef struct Job
-{
- Rule *r; /* master rule for job */
- Node *n; /* list of node targets */
- char *stem;
- char **match;
- Word *p; /* prerequistes */
- Word *np; /* new prerequistes */
- Word *t; /* targets */
- Word *at; /* all targets */
- int nproc; /* slot number */
- struct Job *next;
-} Job;
-extern Job *jobs;
-
-typedef struct Symtab
-{
- short space;
- char *name;
- void *value;
- struct Symtab *next;
-} Symtab;
-
-enum {
- S_VAR, /* variable -> value */
- S_TARGET, /* target -> rule */
- S_TIME, /* file -> time */
- S_PID, /* pid -> products */
- S_NODE, /* target name -> node */
- S_AGG, /* aggregate -> time */
- S_BITCH, /* bitched about aggregate not there */
- S_NOEXPORT, /* var -> noexport */
- S_OVERRIDE, /* can't override */
- S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */
- S_MAKEFILE, /* target -> node */
- S_MAKEVAR, /* dumpable mk variable */
- S_EXPORTED, /* var -> current exported value */
- S_WESET, /* variable; we set in the mkfile */
- S_INTERNAL /* an internal mk variable (e.g., stem, target) */
-};
-
-extern int debug;
-extern int nflag, tflag, iflag, kflag, aflag, mflag;
-extern int mkinline;
-extern char *infile;
-extern int nreps;
-extern char *explain;
-extern Shell *shellt;
-extern Word *shellcmd;
-
-extern Shell shshell, rcshell;
-
-#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile, ((l)>=0)?(l):mkinline))
-#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r)->file, (r)->line))
-#define NAMEBLOCK 1000
-#define BIGBLOCK 20000
-
-#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
-#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^`{|}~", (r)))
-
-#define DEBUG(x) (debug&(x))
-#define D_PARSE 0x01
-#define D_GRAPH 0x02
-#define D_EXEC 0x04
-
-#define LSEEK(f,o,p) seek(f,o,p)
-
-#define PERCENT(ch) (((ch) == '%') || ((ch) == '&'))
-
-#include "fns.h"
diff --git a/mk/parse.c b/mk/parse.c
@@ -1,318 +0,0 @@
-#include "mk.h"
-
-char *infile;
-int mkinline;
-static int rhead(char *, Word **, Word **, int *, char **);
-static char *rbody(Biobuf*);
-extern Word *target1;
-
-void
-parse(char *f, int fd, int varoverride)
-{
- int hline;
- char *body;
- Word *head, *tail;
- int attr, set, pid;
- char *prog, *p;
- int newfd;
- Biobuf in;
- Bufblock *buf;
- char *err;
-
- if(fd < 0){
- fprint(2, "open %s: %r\n", f);
- Exit();
- }
- pushshell();
- ipush();
- infile = strdup(f);
- mkinline = 1;
- Binit(&in, fd, OREAD);
- buf = newbuf();
- while(assline(&in, buf)){
- hline = mkinline;
- switch(rhead(buf->start, &head, &tail, &attr, &prog))
- {
- case '<':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include file name\n");
- Exit();
- }
- newfd = open(p, OREAD);
- if(newfd < 0){
- fprint(2, "warning: skipping missing include file %s: %r\n", p);
- } else
- parse(p, newfd, 0);
- break;
- case '|':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include program name\n");
- Exit();
- }
- execinit();
- pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
- if(newfd < 0){
- fprint(2, "warning: skipping missing program file %s: %r\n", p);
- } else
- parse(p, newfd, 0);
- while(waitup(-3, &pid) >= 0)
- ;
- if(pid != 0){
- fprint(2, "bad include program status\n");
- Exit();
- }
- break;
- case ':':
- body = rbody(&in);
- addrules(head, tail, body, attr, hline, prog);
- break;
- case '=':
- if(head->next){
- SYNERR(-1);
- fprint(2, "multiple vars on left side of assignment\n");
- Exit();
- }
- if(symlook(head->s, S_OVERRIDE, 0)){
- set = varoverride;
- } else {
- set = 1;
- if(varoverride)
- symlook(head->s, S_OVERRIDE, (void *)"");
- }
- if(set){
-/*
-char *cp;
-dumpw("tail", tail);
-cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
-*/
- setvar(head->s, (void *) tail);
- symlook(head->s, S_WESET, (void *)"");
- if(strcmp(head->s, "MKSHELL") == 0){
- if((err = setshell(tail)) != nil){
- SYNERR(hline);
- fprint(2, "%s\n", err);
- Exit();
- break;
- }
- }
- }
- if(attr)
- symlook(head->s, S_NOEXPORT, (void *)"");
- break;
- default:
- SYNERR(hline);
- fprint(2, "expected one of :<=\n");
- Exit();
- break;
- }
- }
- close(fd);
- freebuf(buf);
- ipop();
- popshell();
-}
-
-void
-addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
-{
- Word *w;
-
- assert("addrules args", head && body);
- /* tuck away first non-meta rule as default target*/
- if(target1 == 0 && !(attr®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 is shell-dependent */
- if (pp && *pp == '=') {
- while (p != pp) {
- n = chartorune(&r, p);
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n",*p);
- Exit();
- case 'U':
- *attr = 1;
- break;
- }
- p += n;
- }
- p++; /* skip trailing '=' */
- }
- }
- if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
- while (*p) {
- n = chartorune(&r, p);
- if (r == ':')
- break;
- p += n;
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n", p[-1]);
- Exit();
- case 'D':
- *attr |= DEL;
- break;
- case 'E':
- *attr |= NOMINUSE;
- break;
- case 'n':
- *attr |= NOVIRT;
- break;
- case 'N':
- *attr |= NOREC;
- break;
- case 'P':
- pp = utfrune(p, ':');
- if (pp == 0 || *pp == 0)
- goto eos;
- *pp = 0;
- *prog = strdup(p);
- *pp = ':';
- p = pp;
- break;
- case 'Q':
- *attr |= QUIET;
- break;
- case 'R':
- *attr |= REGEXP;
- break;
- case 'U':
- *attr |= UPD;
- break;
- case 'V':
- *attr |= VIR;
- break;
- }
- }
- if (*p++ != ':') {
- eos:
- SYNERR(-1);
- fprint(2, "missing trailing :\n");
- Exit();
- }
- }
- *h = w = stow(line);
- if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
- SYNERR(mkinline-1);
- fprint(2, "no var on left side of assignment/rule\n");
- Exit();
- }
- *t = stow(p);
- return(sep);
-}
-
-static char *
-rbody(Biobuf *in)
-{
- Bufblock *buf;
- int r, lastr;
- char *p;
-
- lastr = '\n';
- buf = newbuf();
- for(;;){
- r = Bgetrune(in);
- if (r < 0)
- break;
- if (lastr == '\n') {
- if (r == '#')
- rinsert(buf, r);
- else if (r != ' ' && r != '\t') {
- Bungetrune(in);
- break;
- }
- } else
- rinsert(buf, r);
- lastr = r;
- if (r == '\n')
- mkinline++;
- }
- insert(buf, 0);
- p = strdup(buf->start);
- freebuf(buf);
- return p;
-}
-
-struct input
-{
- char *file;
- int line;
- struct input *next;
-};
-static struct input *inputs = 0;
-
-void
-ipush(void)
-{
- struct input *in, *me;
-
- me = (struct input *)Malloc(sizeof(*me));
- me->file = infile;
- me->line = mkinline;
- me->next = 0;
- if(inputs == 0)
- inputs = me;
- else {
- for(in = inputs; in->next; )
- in = in->next;
- in->next = me;
- }
-}
-
-void
-ipop(void)
-{
- struct input *in, *me;
-
- assert("pop input list", inputs != 0);
- if(inputs->next == 0){
- me = inputs;
- inputs = 0;
- } else {
- for(in = inputs; in->next->next; )
- in = in->next;
- me = in->next;
- in->next = 0;
- }
- infile = me->file;
- mkinline = me->line;
- free((char *)me);
-}
diff --git a/mk/rc.c b/mk/rc.c
@@ -1,194 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on rc's syntax. Most
- * of the routines extract strings observing rc's escape conventions
- */
-
-
-/*
- * skip a token in single quotes.
- */
-static char *
-squote(char *cp)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == '\'') {
- n += chartorune(&r, cp+n);
- if(r != '\'')
- return(cp);
- }
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-
-/*
- * search a string for characters in a pattern set
- * characters in quotes and variable generators are escaped
- */
-char *
-rccharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\'': /* skip quoted string */
- cp = squote(cp+1); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash. Only the first is valid for rc. the
- * others are just inserted into the receiving buffer.
- */
-char*
-rcexpandquote(char *s, Rune r, Bufblock *b)
-{
- if (r != '\'') {
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == '\'') {
- if(*s == '\'')
- s++;
- else
- return s;
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash. Only the first is a valid escape for
- * rc; the others are just inserted into the receiving buffer.
- */
-int
-rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc != '\'')
- return 1;
-
- line = mkinline;
- while((c = nextrune(bp, 0)) > 0){
- if(c == '\''){
- if(preserve)
- rinsert(buf, c);
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if(c != '\''){
- Bungetrune(bp);
- return 1;
- }
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a single-quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == '\'')
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quotes above.
- * s points to char after opening quote, q.
- */
-char *
-rccopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'') /* copy quoted string */
- return copysingle(s, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '}')
- break;
- if(q == '\'')
- s = copysingle(s, buf); /* copy quoted string */
- }
- return s;
-}
-
-static int
-rcmatchname(char *name)
-{
- char *p;
-
- if((p = strchr(name, '/')) != nil)
- name = p+1;
- if(name[0] == 'r' && name[1] == 'c')
- return 1;
- return 0;
-}
-
-Shell rcshell = {
- "rc",
- "'= \t",
- '\1',
- rccharin,
- rcexpandquote,
- rcescapetoken,
- rccopyq,
- rcmatchname,
-};
diff --git a/mk/recipe.c b/mk/recipe.c
@@ -1,117 +0,0 @@
-#include "mk.h"
-
-int
-dorecipe(Node *node)
-{
- char buf[BIGBLOCK];
- register Node *n;
- Rule *r = 0;
- Arc *a, *aa;
- Word head, ahead, lp, ln, *w, *ww, *aw;
- Symtab *s;
- int did = 0;
-
- aa = 0;
- /*
- pick up the rule
- */
- for(a = node->prereqs; a; a = a->next)
- if(*a->r->recipe)
- r = (aa = a)->r;
- /*
- no recipe? go to buggery!
- */
- if(r == 0){
- if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){
- fprint(2, "mk: no recipe to make '%s'\n", node->name);
- Exit();
- }
- if(strchr(node->name, '(') && node->time == 0)
- MADESET(node, MADE);
- else
- update(0, node);
- if(tflag){
- if(!(node->flags&VIRTUAL))
- touch(node->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s'\n", node->name);
- }
- return(did);
- }
- /*
- build the node list
- */
- node->next = 0;
- head.next = 0;
- ww = &head;
- ahead.next = 0;
- aw = &ahead;
- if(r->attr®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 interested in */
- n = (Node *)s->value;
- if(aflag == 0 && n->time) {
- for(a = n->prereqs; a; a = a->next)
- if(a->n && outofdate(n, a, 0))
- break;
- if(a == 0)
- continue;
- }
- ww->next = newword(buf);
- ww = ww->next;
- if(n == node) continue;
- n->next = node->next;
- node->next = n;
- }
- }
- for(n = node; n; n = n->next)
- if((n->flags&READY) == 0)
- return(did);
- /*
- gather the params for the job
- */
- lp.next = ln.next = 0;
- for(n = node; n; n = n->next){
- for(a = n->prereqs; a; a = a->next){
- if(a->n){
- addw(&lp, a->n->name);
- if(outofdate(n, a, 0)){
- addw(&ln, a->n->name);
- if(explain)
- fprint(1, "%s(%ld) < %s(%ld)\n",
- n->name, n->time, a->n->name, a->n->time);
- }
- } else {
- if(explain)
- fprint(1, "%s has no prerequisites\n",
- n->name);
- }
- }
- MADESET(n, BEINGMADE);
- }
- /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),wtos(lp.next, ' '));*//**/
- run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, ahead.next));
- return(1);
-}
-
-void
-addw(Word *w, char *s)
-{
- Word *lw;
-
- for(lw = w; w = w->next; lw = w){
- if(strcmp(s, w->s) == 0)
- return;
- }
- lw->next = newword(s);
-}
diff --git a/mk/rule.c b/mk/rule.c
@@ -1,110 +0,0 @@
-#include "mk.h"
-
-static Rule *lr, *lmr;
-static int rcmp(Rule *r, char *target, Word *tail);
-static int nrules = 0;
-
-void
-addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, char *prog)
-{
- Rule *r;
- Rule *rr;
- Symtab *sym;
- int reuse;
-
- r = 0;
- reuse = 0;
- if(sym = symlook(head, S_TARGET, 0)){
- for(r = (Rule *)sym->value; r; r = r->chain)
- if(rcmp(r, head, tail) == 0){
- reuse = 1;
- break;
- }
- }
- if(r == 0)
- r = (Rule *)Malloc(sizeof(Rule));
- r->shellt = shellt;
- r->shellcmd = shellcmd;
- r->target = head;
- r->tail = tail;
- r->recipe = body;
- r->line = hline;
- r->file = infile;
- r->attr = attr;
- r->alltargets = ahead;
- r->prog = prog;
- r->rule = nrules++;
- if(!reuse){
- rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value;
- if(rr != r){
- r->chain = rr->chain;
- rr->chain = r;
- } else
- r->chain = 0;
- }
- if(!reuse)
- r->next = 0;
- if((attr®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 alltarget='%s'",
- r, r->file, r->line, r->attr, r->next, r->chain, wtos(r->alltargets, ' '));
- if(r->prog)
- Bprint(&bout, " prog='%s'", r->prog);
- Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, ' '));
- Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe);
- }
-}
-
-static int
-rcmp(Rule *r, char *target, Word *tail)
-{
- Word *w;
-
- if(strcmp(r->target, target))
- return 1;
- for(w = r->tail; w && tail; w = w->next, tail = tail->next)
- if(strcmp(w->s, tail->s))
- return 1;
- return(w || tail);
-}
-
-char *
-rulecnt(void)
-{
- char *s;
-
- s = Malloc(nrules);
- memset(s, 0, nrules);
- return(s);
-}
diff --git a/mk/run.c b/mk/run.c
@@ -1,296 +0,0 @@
-#include "mk.h"
-
-typedef struct Event
-{
- int pid;
- Job *job;
-} Event;
-static Event *events;
-static int nevents, nrunning, nproclimit;
-
-typedef struct Process
-{
- int pid;
- int status;
- struct Process *b, *f;
-} Process;
-static Process *phead, *pfree;
-static void sched(void);
-static void pnew(int, int), pdelete(Process *);
-
-int pidslot(int);
-
-void
-run(Job *j)
-{
- Job *jj;
-
- if(jobs){
- for(jj = jobs; jj->next; jj = jj->next)
- ;
- jj->next = j;
- } else
- jobs = j;
- j->next = 0;
- /* this code also in waitup after parse redirect */
- if(nrunning < nproclimit)
- sched();
-}
-
-static void
-sched(void)
-{
- char *flags;
- Job *j;
- Bufblock *buf;
- int slot;
- Node *n;
- Envy *e;
-
- if(jobs == 0){
- usage();
- return;
- }
- j = jobs;
- jobs = j->next;
- if(DEBUG(D_EXEC))
- fprint(1, "firing up job for target %s\n", wtos(j->t, ' '));
- slot = nextslot();
- events[slot].job = j;
- buf = newbuf();
- e = buildenv(j, slot);
- shprint(j->r->recipe, e, buf, j->r->shellt);
- if(!tflag && (nflag || !(j->r->attr&QUIET)))
- Bwrite(&bout, buf->start, (long)strlen(buf->start));
- freebuf(buf);
- if(nflag||tflag){
- for(n = j->n; n; n = n->next){
- if(tflag){
- if(!(n->flags&VIRTUAL))
- touch(n->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s'\n", n->name);
- }
- n->time = time((long *)0);
- MADESET(n, MADE);
- }
- } else {
- if(DEBUG(D_EXEC))
- fprint(1, "recipe='%s'", j->r->recipe);/**/
- Bflush(&bout);
- if(j->r->attr&NOMINUSE)
- flags = 0;
- else
- flags = "-e";
- events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->shellt, j->r->shellcmd);
- usage();
- nrunning++;
- if(DEBUG(D_EXEC))
- fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '), events[slot].pid);
- }
-}
-
-int
-waitup(int echildok, int *retstatus)
-{
- Envy *e;
- int pid;
- int slot;
- Symtab *s;
- Word *w;
- Job *j;
- char buf[ERRMAX];
- Bufblock *bp;
- int uarg = 0;
- int done;
- Node *n;
- Process *p;
- extern int runerrs;
-
- /* first check against the proces slist */
- if(retstatus)
- for(p = phead; p; p = p->f)
- if(p->pid == *retstatus){
- *retstatus = p->status;
- pdelete(p);
- return(-1);
- }
-again: /* rogue processes */
- pid = waitfor(buf);
- if(pid == -1){
- if(echildok > 0)
- return(1);
- else {
- fprint(2, "mk: (waitup %d): %r\n", echildok);
- Exit();
- }
- }
- if(DEBUG(D_EXEC))
- fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf);
- if(retstatus && pid == *retstatus){
- *retstatus = buf[0]? 1:0;
- return(-1);
- }
- slot = pidslot(pid);
- if(slot < 0){
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n", pid);
- pnew(pid, buf[0]? 1:0);
- goto again;
- }
- j = events[slot].job;
- usage();
- nrunning--;
- events[slot].pid = -1;
- if(buf[0]){
- e = buildenv(j, slot);
- bp = newbuf();
- shprint(j->r->recipe, e, bp, j->r->shellt);
- front(bp->start);
- fprint(2, "mk: %s: exit status=%s", bp->start, buf);
- freebuf(bp);
- for(n = j->n, done = 0; n; n = n->next)
- if(n->flags&DELETE){
- if(done++ == 0)
- fprint(2, ", deleting");
- fprint(2, " '%s'", n->name);
- delete(n->name);
- }
- fprint(2, "\n");
- if(kflag){
- runerrs++;
- uarg = 1;
- } else {
- jobs = 0;
- Exit();
- }
- }
- for(w = j->t; w; w = w->next){
- if((s = symlook(w->s, S_NODE, 0)) == 0)
- continue; /* not interested in this node */
- update(uarg, (Node *)s->value);
- }
- if(nrunning < nproclimit)
- sched();
- return(0);
-}
-
-void
-nproc(void)
-{
- Symtab *sym;
- Word *w;
-
- if(sym = symlook("NPROC", S_VAR, 0)) {
- w = (Word *) sym->value;
- if (w && w->s && w->s[0])
- nproclimit = atoi(w->s);
- }
- if(nproclimit < 1)
- nproclimit = 1;
- if(DEBUG(D_EXEC))
- fprint(1, "nprocs = %d\n", nproclimit);
- if(nproclimit > nevents){
- if(nevents)
- events = (Event *)Realloc((char *)events, nproclimit*sizeof(Event));
- else
- events = (Event *)Malloc(nproclimit*sizeof(Event));
- while(nevents < nproclimit)
- events[nevents++].pid = 0;
- }
-}
-
-int
-nextslot(void)
-{
- int i;
-
- for(i = 0; i < nproclimit; i++)
- if(events[i].pid <= 0) return i;
- assert("out of slots!!", 0);
- return 0; /* cyntax */
-}
-
-int
-pidslot(int pid)
-{
- int i;
-
- for(i = 0; i < nevents; i++)
- if(events[i].pid == pid) return(i);
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n", pid);
- return(-1);
-}
-
-
-static void
-pnew(int pid, int status)
-{
- Process *p;
-
- if(pfree){
- p = pfree;
- pfree = p->f;
- } else
- p = (Process *)Malloc(sizeof(Process));
- p->pid = pid;
- p->status = status;
- p->f = phead;
- phead = p;
- if(p->f)
- p->f->b = p;
- p->b = 0;
-}
-
-static void
-pdelete(Process *p)
-{
- if(p->f)
- p->f->b = p->b;
- if(p->b)
- p->b->f = p->f;
- else
- phead = p->f;
- p->f = pfree;
- pfree = p;
-}
-
-void
-killchildren(char *msg)
-{
- Process *p;
-
- kflag = 1; /* to make sure waitup doesn't exit */
- jobs = 0; /* make sure no more get scheduled */
- for(p = phead; p; p = p->f)
- expunge(p->pid, msg);
- while(waitup(1, (int *)0) == 0)
- ;
- Bprint(&bout, "mk: %s\n", msg);
- Exit();
-}
-
-static long tslot[1000];
-static long tick;
-
-void
-usage(void)
-{
- long t;
-
- time(&t);
- if(tick)
- tslot[nrunning] += (t-tick);
- tick = t;
-}
-
-void
-prusage(void)
-{
- int i;
-
- usage();
- for(i = 0; i <= nevents; i++)
- fprint(1, "%d: %ld\n", i, tslot[i]);
-}
diff --git a/mk/sh.c b/mk/sh.c
@@ -1,206 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on the shell's syntax. Most
- * of the routines extract strings observing the shell's escape conventions.
- */
-
-
-/*
- * skip a token in quotes.
- */
-static char *
-squote(char *cp, int c)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == c)
- return cp;
- if(r == '\\')
- n += chartorune(&r, cp+n);
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-/*
- * search a string for unescaped characters in a pattern set
- */
-static char *
-shcharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\\': /* skip escaped char */
- cp += n;
- n = chartorune(&r, cp);
- break;
- case '\'': /* skip quoted string */
- case '"':
- cp = squote(cp+1, r); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash.
- */
-static char*
-shexpandquote(char *s, Rune esc, Bufblock *b)
-{
- Rune r;
-
- if (esc == '\\') {
- s += chartorune(&r, s);
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == esc)
- return s;
- if (r == '\\') {
- rinsert(b, r);
- s += chartorune(&r, s);
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash.
- */
-static int
-shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc == '\\') {
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c == '\n')
- mkinline++;
- rinsert(buf, c);
- return 1;
- }
-
- line = mkinline;
- while((c = nextrune(bp, 0)) >= 0){
- if(c == esc){
- if(preserve)
- rinsert(buf, c);
- return 1;
- }
- if(c == '\\') {
- rinsert(buf, c);
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if (c == '\n')
- mkinline++;
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Rune q, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == q)
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quotes above.
- * s points to char after opening quote, q.
- */
-static char *
-shcopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'' || q == '"') /* copy quoted string */
- return copysingle(s, q, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '`')
- break;
- if(q == '\'' || q == '"')
- s = copysingle(s, q, buf); /* copy quoted string */
- }
- return s;
-}
-
-static int
-shmatchname(char *name)
-{
- USED(name);
-
- return 1;
-}
-
-
-Shell shshell = {
- "sh",
- "\"'= \t", /*used in parse.c to isolate assignment attribute*/
- ' ', /* inter-word separator in env */
- shcharin,
- shexpandquote,
- shescapetoken,
- shcopyq,
- shmatchname,
-};
-
diff --git a/mk/shell.c b/mk/shell.c
@@ -1,80 +0,0 @@
-#include "mk.h"
-
-static Shell *shells[] = {
- &rcshell,
- &shshell,
-};
-
-Shell *shelldefault = &shshell;
-
-Shell *shellt;
-Word *shellcmd;
-
-typedef struct Shellstack Shellstack;
-struct Shellstack
-{
- Shell *t;
- Word *w;
- Shellstack *next;
-};
-
-Shellstack *shellstack;
-
-char*
-setshell(Word *w)
-{
- int i;
-
- if(w->s == nil)
- return "shell name not found on line";
-
- for(i=0; i<nelem(shells); i++)
- if(shells[i]->matchname(w->s))
- break;
- if(i == nelem(shells))
- return "cannot determine shell type";
- shellt = shells[i];
- shellcmd = w;
- return nil;
-}
-
-void
-initshell(void)
-{
- shellcmd = stow(shelldefault->name);
- shellt = shelldefault;
- setvar("MKSHELL", shellcmd);
-}
-
-void
-pushshell(void)
-{
- Shellstack *s;
-
- /* save */
- s = Malloc(sizeof *s);
- s->t = shellt;
- s->w = shellcmd;
- s->next = shellstack;
- shellstack = s;
-
- initshell(); /* reset to defaults */
-}
-
-void
-popshell(void)
-{
- Shellstack *s;
-
- if(shellstack == nil){
- fprint(2, "internal shellstack error\n");
- Exit();
- }
-
- s = shellstack;
- shellstack = s->next;
- shellt = s->t;
- shellcmd = s->w;
- setvar("MKSHELL", shellcmd);
- free(s);
-}
diff --git a/mk/shprint.c b/mk/shprint.c
@@ -1,125 +0,0 @@
-#include "mk.h"
-
-static char *vexpand(char*, Envy*, Bufblock*);
-
-#define getfields mkgetfields
-
-static int
-getfields(char *str, char **args, int max, int mflag, char *set)
-{
- Rune r;
- int nr, intok, narg;
-
- if(max <= 0)
- return 0;
-
- narg = 0;
- args[narg] = str;
- if(!mflag)
- narg++;
- intok = 0;
- for(;; str += nr) {
- nr = chartorune(&r, str);
- if(r == 0)
- break;
- if(utfrune(set, r)) {
- if(narg >= max)
- break;
- *str = 0;
- intok = 0;
- args[narg] = str + nr;
- if(!mflag)
- narg++;
- } else {
- if(!intok && mflag)
- narg++;
- intok = 1;
- }
- }
- return narg;
-}
-
-void
-shprint(char *s, Envy *env, Bufblock *buf, Shell *sh)
-{
- int n;
- Rune r;
-
- while(*s) {
- n = chartorune(&r, s);
- if (r == '$')
- s = vexpand(s, env, buf);
- else {
- rinsert(buf, r);
- s += n;
- s = sh->copyq(s, r, buf); /*handle quoted strings*/
- }
- }
- insert(buf, 0);
-}
-
-static char *
-mygetenv(char *name, Envy *env)
-{
- if (!env)
- return 0;
- if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == 0)
- return 0;
- /* only resolve internal variables and variables we've set */
- for(; env->name; env++){
- if (strcmp(env->name, name) == 0)
- return wtos(env->values, ' ');
- }
- return 0;
-}
-
-static char *
-vexpand(char *w, Envy *env, Bufblock *buf)
-{
- char *s, carry, *p, *q;
-
- assert("vexpand no $", *w == '$');
- p = w+1; /* skip dollar sign */
- if(*p == '{') {
- p++;
- q = utfrune(p, '}');
- if (!q)
- q = strchr(p, 0);
- } else
- q = shname(p);
- carry = *q;
- *q = 0;
- s = mygetenv(p, env);
- *q = carry;
- if (carry == '}')
- q++;
- if (s) {
- bufcpy(buf, s, strlen(s));
- free(s);
- } else /* copy name intact*/
- bufcpy(buf, w, q-w);
- return(q);
-}
-
-void
-front(char *s)
-{
- char *t, *q;
- int i, j;
- char *flds[512];
-
- q = strdup(s);
- i = getfields(q, flds, 512, 0, " \t\n");
- if(i > 5){
- flds[4] = flds[i-1];
- flds[3] = "...";
- i = 5;
- }
- t = s;
- for(j = 0; j < i; j++){
- for(s = flds[j]; *s; *t++ = *s++);
- *t++ = ' ';
- }
- *t = 0;
- free(q);
-}
diff --git a/mk/symtab.c b/mk/symtab.c
@@ -1,97 +0,0 @@
-#include "mk.h"
-
-#define NHASH 4099
-#define HASHMUL 79L /* this is a good value */
-static Symtab *hash[NHASH];
-
-void
-syminit(void)
-{
- Symtab **s, *ss, *next;
-
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s; ss; ss = next){
- next = ss->next;
- free((char *)ss);
- }
- *s = 0;
- }
-}
-
-Symtab *
-symlook(char *sym, int space, void *install)
-{
- long h;
- char *p;
- Symtab *s;
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h]; s; s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0))
- return(s);
- if(install == 0)
- return(0);
- s = (Symtab *)Malloc(sizeof(Symtab));
- s->space = space;
- s->name = sym;
- s->value = install;
- s->next = hash[h];
- hash[h] = s;
- return(s);
-}
-
-void
-symdel(char *sym, int space)
-{
- long h;
- char *p;
- Symtab *s, *ls;
-
- /* multiple memory leaks */
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h], ls = 0; s; ls = s, s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0)){
- if(ls)
- ls->next = s->next;
- else
- hash[h] = s->next;
- free((char *)s);
- }
-}
-
-void
-symtraverse(int space, void (*fn)(Symtab*))
-{
- Symtab **s, *ss;
-
- for(s = hash; s < &hash[NHASH]; s++)
- for(ss = *s; ss; ss = ss->next)
- if(ss->space == space)
- (*fn)(ss);
-}
-
-void
-symstat(void)
-{
- Symtab **s, *ss;
- int n;
- int l[1000];
-
- memset((char *)l, 0, sizeof(l));
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s, n = 0; ss; ss = ss->next)
- n++;
- l[n]++;
- }
- for(n = 0; n < 1000; n++)
- if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n);
-}
diff --git a/mk/sys.h b/mk/sys.h
@@ -1,5 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <regexp.h>
-
diff --git a/mk/sys.std.h b/mk/sys.std.h
@@ -1,22 +0,0 @@
-#include <utf.h>
-#include <fmt.h>
-#include <bio.h>
-#include <regexp9.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#define OREAD O_RDONLY
-#define OWRITE O_WRONLY
-#define ORDWR O_RDWR
-#define nil 0
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define seek lseek
-#define remove unlink
-#define exits(x) exit(x && *(char*)x ? 1 : 0)
-#define USED(x) if(x){}else
-#define create(name, mode, perm) open(name, mode|O_CREAT, perm)
-#define ERRMAX 256
diff --git a/mk/unix.c b/mk/unix.c
@@ -1,341 +0,0 @@
-#define NOPLAN9DEFINES
-#include "mk.h"
-#include <sys/wait.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-char *shell = "/bin/sh";
-char *shellname = "sh";
-
-extern char **environ;
-
-static void
-mkperror(char *s)
-{
- fprint(2, "%s: %r\n", s);
-}
-
-void
-readenv(void)
-{
- char **p, *s;
- Word *w;
-
- for(p = environ; *p; p++){
-/* rsc 5/5/2004 -- This misparses fn#cd={whatever}
- s = shname(*p);
- if(*s == '=') {
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
-*/
- s = strchr(*p, '=');
- if(s){
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
- if (symlook(*p, S_INTERNAL, 0))
- continue;
- s = strdup(*p);
- setvar(s, (void *)w);
- symlook(s, S_EXPORTED, (void*)"")->value = (void*)"";
- }
-}
-
-/*
- * done on child side of fork, so parent's env is not affected
- * and we don't care about freeing memory because we're going
- * to exec immediately after this.
- */
-void
-exportenv(Envy *e, Shell *sh)
-{
- int i;
- char **p;
- static char buf[16384];
-
- p = 0;
- for(i = 0; e->name; e++, i++) {
- p = (char**) Realloc(p, (i+2)*sizeof(char*));
- if(e->values)
- snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->values, sh->iws));
- else
- snprint(buf, sizeof buf, "%s=", e->name);
- p[i] = strdup(buf);
- }
- p[i] = 0;
- environ = p;
-}
-
-int
-waitfor(char *msg)
-{
- int status;
- int pid;
-
- *msg = 0;
- pid = wait(&status);
- if(pid > 0) {
- if(status&0x7f) {
- if(status&0x80)
- snprint(msg, ERRMAX, "signal %d, core dumped", status&0x7f);
- else
- snprint(msg, ERRMAX, "signal %d", status&0x7f);
- } else if(status&0xff00)
- snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff);
- }
- return pid;
-}
-
-void
-expunge(int pid, char *msg)
-{
- if(strcmp(msg, "interrupt"))
- kill(pid, SIGINT);
- else
- kill(pid, SIGHUP);
-}
-
-int mypid;
-
-int
-shargv(Word *cmd, int extra, char ***pargv)
-{
- char **argv;
- int i, n;
- Word *w;
-
- n = 0;
- for(w=cmd; w; w=w->next)
- n++;
-
- argv = Malloc((n+extra+1)*sizeof(argv[0]));
- i = 0;
- for(w=cmd; w; w=w->next)
- argv[i++] = w->s;
- argv[n] = 0;
- *pargv = argv;
- return n;
-}
-
-int
-execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcmd)
-{
- char *p, **argv;
- int tot, n, pid, in[2], out[2];
-
- if(buf && pipe(out) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- mypid = getpid();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(buf)
- close(out[0]);
- if(pipe(in) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid != 0){
- dup2(in[0], 0);
- if(buf){
- dup2(out[1], 1);
- close(out[1]);
- }
- close(in[0]);
- close(in[1]);
- if (e)
- exportenv(e, sh);
- n = shargv(shellcmd, 1, &argv);
- argv[n++] = args;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- close(out[1]);
- close(in[0]);
- if(DEBUG(D_EXEC))
- fprint(1, "starting: %s\n", cmd);
- p = cmd+strlen(cmd);
- while(cmd < p){
- n = write(in[1], cmd, p-cmd);
- if(n < 0)
- break;
- cmd += n;
- }
- close(in[1]);
- _exit(0);
- }
- if(buf){
- close(out[1]);
- tot = 0;
- for(;;){
- if (buf->current >= buf->end)
- growbuf(buf);
- n = read(out[0], buf->current, buf->end-buf->current);
- if(n <= 0)
- break;
- buf->current += n;
- tot += n;
- }
- if (tot && buf->current[-1] == '\n')
- buf->current--;
- close(out[0]);
- }
- return pid;
-}
-
-int
-pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd)
-{
- int pid, pfd[2];
- int n;
- char **argv;
-
- if(DEBUG(D_EXEC))
- fprint(1, "pipecmd='%s'\n", cmd);/**/
-
- if(fd && pipe(pfd) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(fd){
- close(pfd[0]);
- dup2(pfd[1], 1);
- close(pfd[1]);
- }
- if(e)
- exportenv(e, sh);
- n = shargv(shellcmd, 2, &argv);
- argv[n++] = "-c";
- argv[n++] = cmd;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- if(fd){
- close(pfd[1]);
- *fd = pfd[0];
- }
- return pid;
-}
-
-void
-Exit(void)
-{
- while(wait(0) >= 0)
- ;
- exits("error");
-}
-
-static struct
-{
- int sig;
- char *msg;
-} sigmsgs[] =
-{
- SIGALRM, "alarm",
- SIGFPE, "sys: fp: fptrap",
- SIGPIPE, "sys: write on closed pipe",
- SIGILL, "sys: trap: illegal instruction",
-// SIGSEGV, "sys: segmentation violation",
- 0, 0
-};
-
-static void
-notifyf(int sig)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- if(sigmsgs[i].sig == sig)
- killchildren(sigmsgs[i].msg);
-
- /* should never happen */
- signal(sig, SIG_DFL);
- kill(getpid(), sig);
-}
-
-void
-catchnotes(void)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- signal(sigmsgs[i].sig, notifyf);
-}
-
-char*
-maketmp(int *pfd)
-{
- static char temp[] = "/tmp/mkargXXXXXX";
- static char buf[100];
- int fd;
-
- strcpy(buf, temp);
- fd = mkstemp(buf);
- if(fd < 0)
- return 0;
- *pfd = fd;
- return buf;
-}
-
-int
-chgtime(char *name)
-{
- if(access(name, 0) >= 0)
- return utimes(name, 0);
- return close(creat(name, 0666));
-}
-
-void
-rcopy(char **to, Resub *match, int n)
-{
- int c;
- char *p;
-
- *to = match->s.sp; /* stem0 matches complete target */
- for(to++, match++; --n > 0; to++, match++){
- if(match->s.sp && match->e.ep){
- p = match->e.ep;
- c = *p;
- *p = 0;
- *to = strdup(match->s.sp);
- *p = c;
- }
- else
- *to = 0;
- }
-}
-
-unsigned long
-mkmtime(char *name)
-{
- struct stat st;
-
- if(stat(name, &st) < 0)
- return 0;
-
- return st.st_mtime;
-}
diff --git a/mk/var.c b/mk/var.c
@@ -1,41 +0,0 @@
-#include "mk.h"
-
-void
-setvar(char *name, void *value)
-{
- symlook(name, S_VAR, value)->value = value;
- symlook(name, S_MAKEVAR, (void*)"");
-}
-
-static void
-print1(Symtab *s)
-{
- Word *w;
-
- Bprint(&bout, "\t%s=", s->name);
- for (w = (Word *) s->value; w; w = w->next)
- Bprint(&bout, "'%s'", w->s);
- Bprint(&bout, "\n");
-}
-
-void
-dumpv(char *s)
-{
- Bprint(&bout, "%s:\n", s);
- symtraverse(S_VAR, print1);
-}
-
-char *
-shname(char *a)
-{
- Rune r;
- int n;
-
- while (*a) {
- n = chartorune(&r, a);
- if (!WORDCHR(r))
- break;
- a += n;
- }
- return a;
-}
diff --git a/mk/varsub.c b/mk/varsub.c
@@ -1,256 +0,0 @@
-#include "mk.h"
-
-static Word *subsub(Word*, char*, char*);
-static Word *expandvar(char**);
-static Bufblock *varname(char**);
-static Word *extractpat(char*, char**, char*, char*);
-static int submatch(char*, Word*, Word*, int*, char**);
-static Word *varmatch(char *, char**);
-
-Word *
-varsub(char **s)
-{
- Bufblock *b;
- Word *w;
-
- if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
- return expandvar(s);
-
- b = varname(s);
- if(b == 0)
- return 0;
-
- w = varmatch(b->start, s);
- freebuf(b);
- return w;
-}
-
-/*
- * extract a variable name
- */
-static Bufblock*
-varname(char **s)
-{
- Bufblock *b;
- char *cp;
- Rune r;
- int n;
-
- b = newbuf();
- cp = *s;
- for(;;){
- n = chartorune(&r, cp);
- if (!WORDCHR(r))
- break;
- rinsert(b, r);
- cp += n;
- }
- if (b->current == b->start){
- SYNERR(-1);
- fprint(2, "missing variable name <%s>\n", *s);
- freebuf(b);
- return 0;
- }
- *s = cp;
- insert(b, 0);
- return b;
-}
-
-static Word*
-varmatch(char *name, char **s)
-{
- Word *w;
- Symtab *sym;
- char *cp;
-
- sym = symlook(name, S_VAR, 0);
- if(sym){
- /* check for at least one non-NULL value */
- for (w = (Word*)sym->value; w; w = w->next)
- if(w->s && *w->s)
- return wdup(w);
- }
- for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing whitespace */
- ;
- *s = cp;
- return 0;
-}
-
-static Word*
-expandvar(char **s)
-{
- Word *w;
- Bufblock *buf;
- Symtab *sym;
- char *cp, *begin, *end;
-
- begin = *s;
- (*s)++; /* skip the '{' */
- buf = varname(s);
- if (buf == 0)
- return 0;
- cp = *s;
- if (*cp == '}') { /* ${name} variant*/
- (*s)++; /* skip the '}' */
- w = varmatch(buf->start, s);
- freebuf(buf);
- return w;
- }
- if (*cp != ':') {
- SYNERR(-1);
- fprint(2, "bad variable name <%s>\n", buf->start);
- freebuf(buf);
- return 0;
- }
- cp++;
- end = shellt->charin(cp , "}");
- if(end == 0){
- SYNERR(-1);
- fprint(2, "missing '}': %s\n", begin);
- Exit();
- }
- *end = 0;
- *s = end+1;
-
- sym = symlook(buf->start, S_VAR, 0);
- if(sym == 0 || sym->value == 0)
- w = newword(buf->start);
- else
- w = subsub((Word*) sym->value, cp, end);
- freebuf(buf);
- return w;
-}
-
-static Word*
-extractpat(char *s, char **r, char *term, char *end)
-{
- int save;
- char *cp;
- Word *w;
-
- cp = shellt->charin(s, term);
- if(cp){
- *r = cp;
- if(cp == s)
- return 0;
- save = *cp;
- *cp = 0;
- w = stow(s);
- *cp = save;
- } else {
- *r = end;
- w = stow(s);
- }
- return w;
-}
-
-static Word*
-subsub(Word *v, char *s, char *end)
-{
- int nmid;
- Word *head, *tail, *w, *h;
- Word *a, *b, *c, *d;
- Bufblock *buf;
- char *cp, *enda;
-
- a = extractpat(s, &cp, "=%&", end);
- b = c = d = 0;
- if(PERCENT(*cp))
- b = extractpat(cp+1, &cp, "=", end);
- if(*cp == '=')
- c = extractpat(cp+1, &cp, "&%", end);
- if(PERCENT(*cp))
- d = stow(cp+1);
- else if(*cp)
- d = stow(cp);
-
- head = tail = 0;
- buf = newbuf();
- for(; v; v = v->next){
- h = w = 0;
- if(submatch(v->s, a, b, &nmid, &enda)){
- /* enda points to end of A match in source;
- * nmid = number of chars between end of A and start of B
- */
- if(c){
- h = w = wdup(c);
- while(w->next)
- w = w->next;
- }
- if(PERCENT(*cp) && nmid > 0){
- if(w){
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- } else {
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- h = w = newword(buf->start);
- }
- buf->current = buf->start;
- }
- if(d && *d->s){
- if(w){
-
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, d->s, strlen(d->s));
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- w->next = wdup(d->next);
- while(w->next)
- w = w->next;
- buf->current = buf->start;
- } else
- h = w = wdup(d);
- }
- }
- if(w == 0)
- h = w = newword(v->s);
-
- if(head == 0)
- head = h;
- else
- tail->next = h;
- tail = w;
- }
- freebuf(buf);
- delword(a);
- delword(b);
- delword(c);
- delword(d);
- return head;
-}
-
-static int
-submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
-{
- Word *w;
- int n;
- char *end;
-
- n = 0;
- for(w = a; w; w = w->next){
- n = strlen(w->s);
- if(strncmp(s, w->s, n) == 0)
- break;
- }
- if(a && w == 0) /* a == NULL matches everything*/
- return 0;
-
- *enda = s+n; /* pointer to end a A part match */
- *nmid = strlen(s)-n; /* size of remainder of source */
- end = *enda+*nmid;
- for(w = b; w; w = w->next){
- n = strlen(w->s);
- if(strcmp(w->s, end-n) == 0){
- *nmid -= n;
- break;
- }
- }
- if(b && w == 0) /* b == NULL matches everything */
- return 0;
- return 1;
-}
diff --git a/mk/word.c b/mk/word.c
@@ -1,180 +0,0 @@
-#include "mk.h"
-
-static Word *nextword(char**);
-
-Word*
-newword(char *s)
-{
- Word *w;
-
- w = (Word *)Malloc(sizeof(Word));
- w->s = strdup(s);
- w->next = 0;
- return(w);
-}
-
-Word *
-stow(char *s)
-{
- Word *head, *w, *new;
-
- w = head = 0;
- while(*s){
- new = nextword(&s);
- if(new == 0)
- break;
- if (w)
- w->next = new;
- else
- head = w = new;
- while(w->next)
- w = w->next;
-
- }
- if (!head)
- head = newword("");
- return(head);
-}
-
-char *
-wtos(Word *w, int sep)
-{
- Bufblock *buf;
- char *cp;
-
- buf = newbuf();
- for(; w; w = w->next){
- for(cp = w->s; *cp; cp++)
- insert(buf, *cp);
- if(w->next)
- insert(buf, sep);
- }
- insert(buf, 0);
- cp = strdup(buf->start);
- freebuf(buf);
- return(cp);
-}
-
-Word*
-wdup(Word *w)
-{
- Word *v, *new, *base;
-
- v = base = 0;
- while(w){
- new = newword(w->s);
- if(v)
- v->next = new;
- else
- base = new;
- v = new;
- w = w->next;
- }
- return base;
-}
-
-void
-delword(Word *w)
-{
- Word *v;
-
- while(v = w){
- w = w->next;
- if(v->s)
- free(v->s);
- free(v);
- }
-}
-
-/*
- * break out a word from a string handling quotes, executions,
- * and variable expansions.
- */
-static Word*
-nextword(char **s)
-{
- Bufblock *b;
- Word *head, *tail, *w;
- Rune r;
- char *cp;
-
- cp = *s;
- b = newbuf();
- head = tail = 0;
- while(*cp == ' ' || *cp == '\t') /* leading white space */
- cp++;
- while(*cp){
- cp += chartorune(&r, cp);
- switch(r)
- {
- case ' ':
- case '\t':
- case '\n':
- goto out;
- case '\\':
- case '\'':
- case '"':
- cp = shellt->expandquote(cp, r, b);
- if(cp == 0){
- fprint(2, "missing closing quote: %s\n", *s);
- Exit();
- }
- break;
- case '$':
- w = varsub(&cp);
- if(w == 0)
- break;
- if(b->current != b->start){
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(w->s);
- w->s = strdup(b->start);
- b->current = b->start;
- }
- if(head){
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(b->start);
- tail->next = w->next;
- free(w->s);
- free(w);
- b->current = b->start;
- } else
- tail = head = w;
- while(tail->next)
- tail = tail->next;
- break;
- default:
- rinsert(b, r);
- break;
- }
- }
-out:
- *s = cp;
- if(b->current != b->start){
- if(head){
- cp = b->current;
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, b->start, cp-b->start);
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(cp);
- } else {
- insert(b, 0);
- head = newword(b->start);
- }
- }
- freebuf(b);
- return head;
-}
-
-void
-dumpw(char *s, Word *w)
-{
- Bprint(&bout, "%s", s);
- for(; w; w = w->next)
- Bprint(&bout, " '%s'", w->s);
- Bputc(&bout, '\n');
-}
diff --git a/rc/Makefile b/rc/Makefile
@@ -4,7 +4,7 @@
TARG = rc
OFILES = code.o exec.o getflags.o glob.o here.o io.o lex.o \
pcmd.o pfnc.o simple.o subr.o trap.o tree.o unixcrap.o \
- var.o y.tab.o plan9ish.o
+ var.o y.tab.o plan9ish.o havefork.o
YFILES = syn.y
MANFILES = rc.1
@@ -23,6 +23,7 @@ all:
depend:
@echo YACC ${YFILES}
@${YACC} -d ${YFILES}
+ @cp y.tab.h x.tab.h
install: ${TARG}
@mkdir -p ${DESTDIR}${PREFIX}/bin
diff --git a/rc/code.c b/rc/code.c
@@ -7,9 +7,9 @@
#define c1 t->child[1]
#define c2 t->child[2]
int codep, ncode;
-#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=(x), codep++)
-#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=(x), codep++)
-#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=(x), codep++)
+#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
+#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
+#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
void stuffdot(int);
char *fnstr(tree*);
void outcode(tree*, int);
@@ -17,22 +17,33 @@ void codeswitch(tree*, int);
int iscase(tree*);
code *codecopy(code*);
void codefree(code*);
-int morecode(void){
+
+int
+morecode(void)
+{
ncode+=100;
- codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
- if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
+ codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
ncode*sizeof codebuf[0]);
+ memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
return 0;
}
-void stuffdot(int a){
- if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
- codebuf[a].i=codep;
+
+void
+stuffdot(int a)
+{
+ if(a<0 || codep<=a)
+ panic("Bad address %d in stuffdot", a);
+ codebuf[a].i = codep;
}
-int compile(tree *t)
+
+int
+compile(tree *t)
{
- ncode=100;
- codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
- codep=0;
+ ncode = 100;
+ codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+ codep = 0;
emiti(0); /* reference count */
outcode(t, flag['e']?1:0);
if(nerror){
@@ -44,31 +55,39 @@ int compile(tree *t)
emitf(0);
return 1;
}
-void cleanhere(char *f)
+
+void
+cleanhere(char *f)
{
emitf(Xdelhere);
emits(strdup(f));
}
-char *fnstr(tree *t)
+
+char*
+fnstr(tree *t)
{
- io *f=openstr();
+ io *f = openstr();
char *v;
extern char nl;
- char svnl=nl;
+ char svnl = nl;
nl=';';
pfmt(f, "%t", t);
- nl=svnl;
- v=f->strp;
- f->strp=0;
+ nl = svnl;
+ v = f->strp;
+ f->strp = 0;
closeio(f);
return v;
}
-void outcode(tree *t, int eflag)
+
+void
+outcode(tree *t, int eflag)
{
int p, q;
tree *tt;
- if(t==0) return;
- if(t->type!=NOT && t->type!=';') runq->iflast=0;
+ if(t==0)
+ return;
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast = 0;
switch(t->type){
default:
pfmt(err, "bad type %d in outcode\n", t->type);
@@ -92,10 +111,13 @@ void outcode(tree *t, int eflag)
break;
case '&':
emitf(Xasync);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
case ';':
outcode(c0, eflag);
@@ -110,15 +132,18 @@ void outcode(tree *t, int eflag)
break;
case '`':
emitf(Xbackq);
- p=emiti(0);
- outcode(c0, 0);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
case ANDAND:
outcode(c0, 0);
emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
@@ -144,7 +169,7 @@ void outcode(tree *t, int eflag)
outcode(c0, eflag);
if(c1){
emitf(Xfn);
- p=emiti(0);
+ p = emiti(0);
emits(fnstr(c1));
outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
@@ -157,22 +182,23 @@ void outcode(tree *t, int eflag)
case IF:
outcode(c0, 0);
emitf(Xif);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
emitf(Xwastrue);
stuffdot(p);
break;
case NOT:
- if(!runq->iflast) yyerror("`if not' does not follow `if(...)'");
+ if(!runq->iflast)
+ yyerror("`if not' does not follow `if(...)'");
emitf(Xifnot);
- p=emiti(0);
+ p = emiti(0);
outcode(c0, eflag);
stuffdot(p);
break;
case OROR:
outcode(c0, 0);
emitf(Xfalse);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
@@ -183,15 +209,20 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xsimple);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
break;
case SUBSHELL:
emitf(Xsubshell);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- if(eflag) emitf(Xeflag);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
+ if(eflag)
+ emitf(Xeflag);
break;
case SWITCH:
codeswitch(t, eflag);
@@ -202,14 +233,16 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xmatch);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
break;
case WHILE:
- q=codep;
+ q = codep;
outcode(c0, 0);
- if(q==codep) emitf(Xsettrue); /* empty condition == while(true) */
+ if(q==codep)
+ emitf(Xsettrue); /* empty condition == while(true) */
emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
emitf(Xjump);
emiti(q);
@@ -235,8 +268,8 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
- p=emitf(Xfor);
- q=emiti(0);
+ p = emitf(Xfor);
+ q = emiti(0);
outcode(c2, eflag);
emitf(Xjump);
emiti(p);
@@ -263,10 +296,14 @@ void outcode(tree *t, int eflag)
case PIPEFD:
emitf(Xpipefd);
emiti(t->rtype);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
break;
case REDIR:
emitf(Xmark);
@@ -283,28 +320,31 @@ void outcode(tree *t, int eflag)
case HERE:
emitf(Xread);
break;
+ case RDWR:
+ emitf(Xrdwr);
+ break;
}
emiti(t->fd0);
outcode(c1, eflag);
emitf(Xpopredir);
break;
case '=':
- tt=t;
- for(;t && t->type=='=';t=c2);
+ tt = t;
+ for(;t && t->type=='=';t = c2);
if(t){
- for(t=tt;t->type=='=';t=c2){
+ for(t = tt;t->type=='=';t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
}
- t=tt;
- outcode(c2, eflag);
- for(;t->type=='=';t=c2) emitf(Xunlocal);
+ outcode(t, eflag);
+ for(t = tt; t->type=='='; t = c2)
+ emitf(Xunlocal);
}
else{
- for(t=tt;t;t=c2){
+ for(t = tt;t;t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
@@ -312,17 +352,22 @@ void outcode(tree *t, int eflag)
emitf(Xassign);
}
}
- t=tt; /* so tests below will work */
+ t = tt; /* so tests below will work */
break;
case PIPE:
emitf(Xpipe);
emiti(t->fd0);
emiti(t->fd1);
- p=emiti(0);
- q=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ q = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ q = emiti(0);
+ }
outcode(c1, eflag);
emitf(Xreturn);
stuffdot(q);
@@ -330,8 +375,8 @@ void outcode(tree *t, int eflag)
break;
}
if(t->type!=NOT && t->type!=';')
- runq->iflast=t->type==IF;
- else if(c0) runq->iflast=c0->type==IF;
+ runq->iflast = t->type==IF;
+ else if(c0) runq->iflast = c0->type==IF;
}
/*
* switch code looks like this:
@@ -353,7 +398,9 @@ void outcode(tree *t, int eflag)
* leave:
* Xpopm
*/
-void codeswitch(tree *t, int eflag)
+
+void
+codeswitch(tree *t, int eflag)
{
int leave; /* patch jump address to leave switch */
int out; /* jump here to leave switch */
@@ -368,23 +415,23 @@ void codeswitch(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xjump);
- nextcase=emiti(0);
- out=emitf(Xjump);
- leave=emiti(0);
+ nextcase = emiti(0);
+ out = emitf(Xjump);
+ leave = emiti(0);
stuffdot(nextcase);
- t=c1->child[0];
+ t = c1->child[0];
while(t->type==';'){
- tt=c1;
+ tt = c1;
emitf(Xmark);
- for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
+ for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
emitf(Xcase);
- nextcase=emiti(0);
- t=tt;
+ nextcase = emiti(0);
+ t = tt;
for(;;){
if(t->type==';'){
if(iscase(c0)) break;
outcode(c0, eflag);
- t=c1;
+ t = c1;
}
else{
if(!iscase(t)) outcode(t, eflag);
@@ -398,23 +445,32 @@ void codeswitch(tree *t, int eflag)
stuffdot(leave);
emitf(Xpopm);
}
-int iscase(tree *t)
+
+int
+iscase(tree *t)
{
- if(t->type!=SIMPLE) return 0;
- do t=c0; while(t->type==ARGLIST);
+ if(t->type!=SIMPLE)
+ return 0;
+ do t = c0; while(t->type==ARGLIST);
return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
}
-code *codecopy(code *cp)
+
+code*
+codecopy(code *cp)
{
cp[0].i++;
return cp;
}
-void codefree(code *cp)
+
+void
+codefree(code *cp)
{
code *p;
- if(--cp[0].i!=0) return;
- for(p=cp+1;p->f;p++){
+ if(--cp[0].i!=0)
+ return;
+ for(p = cp+1;p->f;p++){
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+ || p->f==Xrdwr
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|| p->f==Xfor || p->f==Xjump
|| p->f==Xsubshell || p->f==Xtrue) p++;
diff --git a/rc/exec.c b/rc/exec.c
@@ -1,12 +1,3 @@
-#include <u.h>
-#include <signal.h>
-#if defined(PLAN9PORT) && defined(__sun__)
-# define BSD_COMP /* sigh. for TIOCNOTTY */
-#endif
-#ifdef __sun__
-#include <sys/termios.h>
-#endif
-#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
@@ -16,90 +7,118 @@
* Start executing the given code at the given pc with the given redirection
*/
char *argv0="rc";
-void start(code *c, int pc, var *local)
-{
- struct thread *p=new(struct thread);
- p->code=codecopy(c);
- p->pc=pc;
- p->argv=0;
- p->redir=p->startredir=runq?runq->redir:0;
- p->local=local;
- p->cmdfile=0;
- p->cmdfd=0;
- p->eof=0;
- p->iflag=0;
- p->lineno=1;
- p->pid=-1;
- p->ret=runq;
- runq=p;
-}
-word *newword(char *wd, word *next)
-{
- word *p=new(word);
- p->word=strdup(wd);
- p->next=next;
+
+void
+start(code *c, int pc, var *local)
+{
+ struct thread *p = new(struct thread);
+
+ p->code = codecopy(c);
+ p->pc = pc;
+ p->argv = 0;
+ p->redir = p->startredir = runq?runq->redir:0;
+ p->local = local;
+ p->cmdfile = 0;
+ p->cmdfd = 0;
+ p->eof = 0;
+ p->iflag = 0;
+ p->lineno = 1;
+ p->ret = runq;
+ runq = p;
+}
+
+word*
+newword(char *wd, word *next)
+{
+ word *p = new(word);
+ p->word = strdup(wd);
+ p->next = next;
return p;
}
-void pushword(char *wd)
+
+void
+pushword(char *wd)
{
- if(runq->argv==0) panic("pushword but no argv!", 0);
- runq->argv->words=newword(wd, runq->argv->words);
+ if(runq->argv==0)
+ panic("pushword but no argv!", 0);
+ runq->argv->words = newword(wd, runq->argv->words);
}
-void popword(void){
+
+void
+popword(void)
+{
word *p;
- if(runq->argv==0) panic("popword but no argv!", 0);
- p=runq->argv->words;
- if(p==0) panic("popword but no word!", 0);
- runq->argv->words=p->next;
+ if(runq->argv==0)
+ panic("popword but no argv!", 0);
+ p = runq->argv->words;
+ if(p==0)
+ panic("popword but no word!", 0);
+ runq->argv->words = p->next;
efree(p->word);
efree((char *)p);
}
-void freelist(word *w)
+
+void
+freelist(word *w)
{
word *nw;
while(w){
- nw=w->next;
+ nw = w->next;
efree(w->word);
efree((char *)w);
- w=nw;
+ w = nw;
}
}
-void pushlist(void){
- list *p=new(list);
- p->next=runq->argv;
- p->words=0;
- runq->argv=p;
-}
-void poplist(void){
- list *p=runq->argv;
- if(p==0) panic("poplist but no argv", 0);
+
+void
+pushlist(void)
+{
+ list *p = new(list);
+ p->next = runq->argv;
+ p->words = 0;
+ runq->argv = p;
+}
+
+void
+poplist(void)
+{
+ list *p = runq->argv;
+ if(p==0)
+ panic("poplist but no argv", 0);
freelist(p->words);
- runq->argv=p->next;
+ runq->argv = p->next;
efree((char *)p);
}
-int count(word *w)
+
+int
+count(word *w)
{
int n;
- for(n=0;w;n++) w=w->next;
+ for(n = 0;w;n++) w = w->next;
return n;
}
-void pushredir(int type, int from, int to){
- redir * rp=new(redir);
- rp->type=type;
- rp->from=from;
- rp->to=to;
- rp->next=runq->redir;
- runq->redir=rp;
-}
-var *newvar(char *name, var *next)
-{
- var *v=new(var);
- v->name=name;
- v->val=0;
- v->fn=0;
- v->changed=0;
- v->fnchanged=0;
- v->next=next;
+
+void
+pushredir(int type, int from, int to)
+{
+ redir * rp = new(redir);
+ rp->type = type;
+ rp->from = from;
+ rp->to = to;
+ rp->next = runq->redir;
+ runq->redir = rp;
+}
+
+var*
+newvar(char *name, var *next)
+{
+ var *v = new(var);
+ v->name = name;
+ v->val = 0;
+ v->fn = 0;
+ v->changed = 0;
+ v->fnchanged = 0;
+ v->next = next;
v->changefn = 0;
return v;
}
@@ -117,52 +136,59 @@ main(int argc, char *argv[])
char num[12], *rcmain;
int i;
- argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
- if(argc==-1) usage("[file [arg ...]]");
- if(argv[0][0]=='-') flag['l']=flagset;
- if(flag['I']) flag['i'] = 0;
+ /* needed for rcmain later */
+ putenv("PLAN9", unsharp("#9"));
+
+ argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
+ if(argc==-1)
+ usage("[file [arg ...]]");
+ if(argv[0][0]=='-')
+ flag['l'] = flagset;
+ if(flag['I'])
+ flag['i'] = 0;
else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
- rcmain=flag['m']?flag['m'][0]:Rcmain();
- err=openfd(2);
+ rcmain = flag['m'] ? flag['m'][0] : Rcmain();
+ err = openfd(2);
kinit();
Trapinit();
Vinit();
- itoa(num, mypid=getpid());
+ inttoascii(num, mypid = getpid());
pathinit();
setvar("pid", newword(num, (word *)0));
setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
:(word *)0);
setvar("rcname", newword(argv[0], (word *)0));
- i=0;
- bootstrap[i++].i=1;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xword;
+ i = 0;
+ bootstrap[i++].i = 1;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s="*";
- bootstrap[i++].f=Xassign;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xword;
+ bootstrap[i++].f = Xassign;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s="*";
- bootstrap[i++].f=Xdol;
- bootstrap[i++].f=Xword;
- bootstrap[i++].s=rcmain;
- bootstrap[i++].f=Xword;
+ bootstrap[i++].f = Xdol;
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s = rcmain;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s=".";
- bootstrap[i++].f=Xsimple;
- bootstrap[i++].f=Xexit;
- bootstrap[i].i=0;
+ bootstrap[i++].f = Xsimple;
+ bootstrap[i++].f = Xexit;
+ bootstrap[i].i = 0;
start(bootstrap, 1, (var *)0);
/* prime bootstrap argv */
pushlist();
argv0 = strdup(argv[0]);
- for(i=argc-1;i!=0;--i) pushword(argv[i]);
+ for(i = argc-1;i!=0;--i) pushword(argv[i]);
for(;;){
- if(flag['r']) pfnc(err, runq);
+ if(flag['r'])
+ pfnc(err, runq);
runq->pc++;
(*runq->code[runq->pc-1].f)();
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
}
- return 0;
}
/*
* Opcode routines
@@ -198,6 +224,7 @@ main(int argc, char *argv[])
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or output,
* depending on type), push /dev/fd/??
* Xpopm(value) pop value from stack
+ * Xrdwr(file)[fd] open file for reading and writing
* Xread(file)[fd] open file to read
* Xsettraps(names){... Xreturn} define trap functions
* Xshowtraps print trap list
@@ -209,16 +236,24 @@ main(int argc, char *argv[])
* Xword[string] push string
* Xwrite(file)[fd] open file to write
*/
-void Xappend(void){
+
+void
+Xappend(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1(">> requires singleton"); return;
- case 0: Xerror1(">> requires file"); return;
- case 1: break;
+ default:
+ Xerror1(">> requires singleton");
+ return;
+ case 0:
+ Xerror1(">> requires file");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=open(file, 1))<0 && (f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 1))<0 && (f = Creat(file))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -228,126 +263,114 @@ void Xappend(void){
runq->pc++;
poplist();
}
-void Xasync(void){
- int null=open("/dev/null", 0);
- int tty;
- int pid;
- char npid[10];
- if(null<0){
- Xerror("Can't open /dev/null\n");
- return;
- }
- switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
- case -1:
- close(null);
- Xerror("try again");
- break;
- case 0:
- /*
- * I don't know what the right thing to do here is,
- * so this is all experimentally determined.
- * If we just dup /dev/null onto 0, then running
- * ssh foo & will reopen /dev/tty, try to read a password,
- * get a signal, and repeat, in a tight loop, forever.
- * Arguably this is a bug in ssh (it behaves the same
- * way under bash as under rc) but I'm fixing it here
- * anyway. If we dissociate the process from the tty,
- * then it won't be able to open /dev/tty ever again.
- * The SIG_IGN on SIGTTOU makes writing the tty
- * (via fd 1 or 2, for example) succeed even though
- * our pgrp is not the terminal's controlling pgrp.
- */
- if((tty=open("/dev/tty", OREAD)) >= 0){
- /*
- * Should make reads of tty fail, writes succeed.
- */
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- ioctl(tty, TIOCNOTTY);
- close(tty);
- }
- if(isatty(0))
- pushredir(ROPEN, null, 0);
- else
- close(null);
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- close(null);
- runq->pc=runq->code[runq->pc].i;
- itoa(npid, pid);
- setvar("apid", newword(npid, (word *)0));
- break;
- }
-}
-void Xsettrue(void){
+
+void
+Xsettrue(void)
+{
setstatus("");
}
-void Xbang(void){
+
+void
+Xbang(void)
+{
setstatus(truestatus()?"false":"");
}
-void Xclose(void){
+
+void
+Xclose(void)
+{
pushredir(RCLOSE, runq->code[runq->pc].i, 0);
runq->pc++;
}
-void Xdup(void){
+
+void
+Xdup(void)
+{
pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
runq->pc+=2;
}
-void Xeflag(void){
+
+void
+Xeflag(void)
+{
if(eflagok && !truestatus()) Xexit();
}
-void Xexit(void){
+
+void
+Xexit(void)
+{
struct var *trapreq;
struct word *starval;
- static int beenhere=0;
+ static int beenhere = 0;
if(getpid()==mypid && !beenhere){
- trapreq=vlook("sigexit");
+ trapreq = vlook("sigexit");
if(trapreq->fn){
- beenhere=1;
+ beenhere = 1;
--runq->pc;
- starval=vlook("*")->val;
+ starval = vlook("*")->val;
start(trapreq->fn, trapreq->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=copywords(starval, (struct word *)0);
- runq->local->changed=1;
- runq->redir=runq->startredir=0;
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = copywords(starval, (struct word *)0);
+ runq->local->changed = 1;
+ runq->redir = runq->startredir = 0;
return;
}
}
Exit(getstatus());
}
-void Xfalse(void){
- if(truestatus()) runq->pc=runq->code[runq->pc].i;
+
+void
+Xfalse(void)
+{
+ if(truestatus()) runq->pc = runq->code[runq->pc].i;
else runq->pc++;
}
int ifnot; /* dynamic if not flag */
-void Xifnot(void){
+
+void
+Xifnot(void)
+{
if(ifnot)
runq->pc++;
else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
}
-void Xjump(void){
- runq->pc=runq->code[runq->pc].i;
+
+void
+Xjump(void)
+{
+ runq->pc = runq->code[runq->pc].i;
}
-void Xmark(void){
+
+void
+Xmark(void)
+{
pushlist();
}
-void Xpopm(void){
+
+void
+Xpopm(void)
+{
poplist();
}
-void Xread(void){
+
+void
+Xread(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1("< requires singleton\n"); return;
- case 0: Xerror1("< requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("< requires singleton\n");
+ return;
+ case 0:
+ Xerror1("< requires file\n");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=open(file, 0))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 0))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -356,51 +379,110 @@ void Xread(void){
runq->pc++;
poplist();
}
-void turfredir(void){
+
+void
+Xrdwr(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default:
+ Xerror1("<> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("<> requires file\n");
+ return;
+ case 1:
+ break;
+ }
+ file = runq->argv->words->word;
+ if((f = open(file, ORDWR))<0){
+ pfmt(err, "%s: ", file);
+ Xerror("can't open");
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+turfredir(void)
+{
while(runq->redir!=runq->startredir)
Xpopredir();
}
-void Xpopredir(void){
- struct redir *rp=runq->redir;
- if(rp==0) panic("turfredir null!", 0);
- runq->redir=rp->next;
- if(rp->type==ROPEN) close(rp->from);
+
+void
+Xpopredir(void)
+{
+ struct redir *rp = runq->redir;
+ if(rp==0)
+ panic("turfredir null!", 0);
+ runq->redir = rp->next;
+ if(rp->type==ROPEN)
+ close(rp->from);
efree((char *)rp);
}
-void Xreturn(void){
- struct thread *p=runq;
+
+void
+Xreturn(void)
+{
+ struct thread *p = runq;
turfredir();
while(p->argv) poplist();
codefree(p->code);
- runq=p->ret;
+ runq = p->ret;
efree((char *)p);
- if(runq==0) Exit(getstatus());
+ if(runq==0)
+ Exit(getstatus());
}
-void Xtrue(void){
+
+void
+Xtrue(void)
+{
if(truestatus()) runq->pc++;
- else runq->pc=runq->code[runq->pc].i;
+ else runq->pc = runq->code[runq->pc].i;
}
-void Xif(void){
- ifnot=1;
+
+void
+Xif(void)
+{
+ ifnot = 1;
if(truestatus()) runq->pc++;
- else runq->pc=runq->code[runq->pc].i;
+ else runq->pc = runq->code[runq->pc].i;
}
-void Xwastrue(void){
- ifnot=0;
+
+void
+Xwastrue(void)
+{
+ ifnot = 0;
}
-void Xword(void){
+
+void
+Xword(void)
+{
pushword(runq->code[runq->pc++].s);
}
-void Xwrite(void){
+
+void
+Xwrite(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1("> requires singleton\n"); return;
- case 0: Xerror1("> requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("> requires file\n");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = Creat(file))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -409,31 +491,35 @@ void Xwrite(void){
runq->pc++;
poplist();
}
-char *_list2str(word *words, int c){
+
+char*
+list2str(word *words)
+{
char *value, *s, *t;
- int len=0;
+ int len = 0;
word *ap;
- for(ap=words;ap;ap=ap->next)
+ for(ap = words;ap;ap = ap->next)
len+=1+strlen(ap->word);
- value=emalloc(len+1);
- s=value;
- for(ap=words;ap;ap=ap->next){
- for(t=ap->word;*t;) *s++=*t++;
- *s++=c;
- }
- if(s==value) *s='\0';
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=' ';
+ }
+ if(s==value)
+ *s='\0';
else s[-1]='\0';
return value;
}
-char *list2str(word *words){
- return _list2str(words, ' ');
-}
-void Xmatch(void){
+
+void
+Xmatch(void)
+{
word *p;
char *subject;
- subject=list2str(runq->argv->words);
+ subject = list2str(runq->argv->words);
setstatus("no match");
- for(p=runq->argv->next->words;p;p=p->next)
+ for(p = runq->argv->next->words;p;p = p->next)
if(match(subject, p->word, '\0')){
setstatus("");
break;
@@ -442,14 +528,17 @@ void Xmatch(void){
poplist();
poplist();
}
-void Xcase(void){
+
+void
+Xcase(void)
+{
word *p;
char *s;
- int ok=0;
- s=list2str(runq->argv->next->words);
- for(p=runq->argv->words;p;p=p->next){
+ int ok = 0;
+ s = list2str(runq->argv->next->words);
+ for(p = runq->argv->words;p;p = p->next){
if(match(s, p->word, '\0')){
- ok=1;
+ ok = 1;
break;
}
}
@@ -457,28 +546,33 @@ void Xcase(void){
if(ok)
runq->pc++;
else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
poplist();
}
-word *conclist(word *lp, word *rp, word *tail)
+
+word*
+conclist(word *lp, word *rp, word *tail)
{
char *buf;
word *v;
if(lp->next || rp->next)
- tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
+ tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
tail);
- buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
+ buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
strcpy(buf, lp->word);
strcat(buf, rp->word);
- v=newword(buf, tail);
+ v = newword(buf, tail);
efree(buf);
return v;
}
-void Xconc(void){
- word *lp=runq->argv->words;
- word *rp=runq->argv->next->words;
- word *vp=runq->argv->next->next->words;
- int lc=count(lp), rc=count(rp);
+
+void
+Xconc(void)
+{
+ word *lp = runq->argv->words;
+ word *rp = runq->argv->next->words;
+ word *vp = runq->argv->next->next->words;
+ int lc = count(lp), rc = count(rp);
if(lc!=0 || rc!=0){
if(lc==0 || rc==0){
Xerror1("null list in concatenation");
@@ -488,42 +582,50 @@ void Xconc(void){
Xerror1("mismatched list lengths in concatenation");
return;
}
- vp=conclist(lp, rp, vp);
+ vp = conclist(lp, rp, vp);
}
poplist();
poplist();
- runq->argv->words=vp;
+ runq->argv->words = vp;
}
-void Xassign(void){
+
+void
+Xassign(void)
+{
var *v;
if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!");
return;
}
deglob(runq->argv->words->word);
- v=vlook(runq->argv->words->word);
+ v = vlook(runq->argv->words->word);
poplist();
globlist();
freewords(v->val);
- v->val=runq->argv->words;
- v->changed=1;
+ v->val = runq->argv->words;
+ v->changed = 1;
if(v->changefn)
v->changefn(v);
- runq->argv->words=0;
+ runq->argv->words = 0;
poplist();
}
/*
* copy arglist a, adding the copy to the front of tail
*/
-word *copywords(word *a, word *tail)
+
+word*
+copywords(word *a, word *tail)
{
- word *v=0, **end;
- for(end=&v;a;a=a->next,end=&(*end)->next)
- *end=newword(a->word, 0);
- *end=tail;
+ word *v = 0, **end;
+ for(end=&v;a;a = a->next,end=&(*end)->next)
+ *end = newword(a->word, 0);
+ *end = tail;
return v;
}
-void Xdol(void){
+
+void
+Xdol(void)
+{
word *a, *star;
char *s, *t;
int n;
@@ -531,24 +633,27 @@ void Xdol(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
- a=runq->argv->next->words;
+ n = 0;
+ for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
+ a = runq->argv->next->words;
if(n==0 || *t)
- a=copywords(vlook(s)->val, a);
+ a = copywords(vlook(s)->val, a);
else{
- star=vlook("*")->val;
+ star = vlook("*")->val;
if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
- a=newword(star->word, a);
+ while(--n) star = star->next;
+ a = newword(star->word, a);
}
}
poplist();
- runq->argv->words=a;
+ runq->argv->words = a;
}
-void Xqdol(void){
+
+void
+Xqdol(void)
+{
word *a, *p;
char *s;
int n;
@@ -556,20 +661,20 @@ void Xqdol(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- a=vlook(s)->val;
+ a = vlook(s)->val;
poplist();
- n=count(a);
+ n = count(a);
if(n==0){
pushword("");
return;
}
- for(p=a;p;p=p->next) n+=strlen(p->word);
- s=emalloc(n);
+ for(p = a;p;p = p->next) n+=strlen(p->word);
+ s = emalloc(n);
if(a){
strcpy(s, a->word);
- for(p=a->next;p;p=p->next){
+ for(p = a->next;p;p = p->next){
strcat(s, " ");
strcat(s, p->word);
}
@@ -579,37 +684,77 @@ void Xqdol(void){
pushword(s);
efree(s);
}
-word *subwords(word *val, int len, word *sub, word *a)
+
+word*
+copynwords(word *a, word *tail, int n)
{
- int n;
+ word *v, **end;
+
+ v = 0;
+ end = &v;
+ while(n-- > 0){
+ *end = newword(a->word, 0);
+ end = &(*end)->next;
+ a = a->next;
+ }
+ *end = tail;
+ return v;
+}
+
+word*
+subwords(word *val, int len, word *sub, word *a)
+{
+ int n, m;
char *s;
- if(!sub) return a;
- a=subwords(val, len, sub->next, a);
- s=sub->word;
+ if(!sub)
+ return a;
+ a = subwords(val, len, sub->next, a);
+ s = sub->word;
deglob(s);
- n=0;
- while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
- if(n<1 || len<n) return a;
- for(;n!=1;--n) val=val->next;
- return newword(val->word, a);
-}
-void Xsub(void){
+ m = 0;
+ n = 0;
+ while('0'<=*s && *s<='9')
+ n = n*10+ *s++ -'0';
+ if(*s == '-'){
+ if(*++s == 0)
+ m = len - n;
+ else{
+ while('0'<=*s && *s<='9')
+ m = m*10+ *s++ -'0';
+ m -= n;
+ }
+ }
+ if(n<1 || n>len || m<0)
+ return a;
+ if(n+m>len)
+ m = len-n;
+ while(--n > 0)
+ val = val->next;
+ return copynwords(val, a, m+1);
+}
+
+void
+Xsub(void)
+{
word *a, *v;
char *s;
if(count(runq->argv->next->words)!=1){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->next->words->word;
+ s = runq->argv->next->words->word;
deglob(s);
- a=runq->argv->next->next->words;
- v=vlook(s)->val;
- a=subwords(v, count(v), runq->argv->words, a);
+ a = runq->argv->next->next->words;
+ v = vlook(s)->val;
+ a = subwords(v, count(v), runq->argv->words, a);
poplist();
poplist();
- runq->argv->words=a;
+ runq->argv->words = a;
}
-void Xcount(void){
+
+void
+Xcount(void)
+{
word *a;
char *s, *t;
int n;
@@ -618,112 +763,102 @@ void Xcount(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+ n = 0;
+ for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
if(n==0 || *t){
- a=vlook(s)->val;
- itoa(num, count(a));
+ a = vlook(s)->val;
+ inttoascii(num, count(a));
}
else{
- a=vlook("*")->val;
- itoa(num, a && 1<=n && n<=count(a)?1:0);
+ a = vlook("*")->val;
+ inttoascii(num, a && 1<=n && n<=count(a)?1:0);
}
poplist();
pushword(num);
}
-void Xlocal(void){
+
+void
+Xlocal(void)
+{
if(count(runq->argv->words)!=1){
Xerror1("variable name must be singleton\n");
return;
}
deglob(runq->argv->words->word);
- runq->local=newvar(strdup(runq->argv->words->word), runq->local);
- runq->local->val=copywords(runq->argv->next->words, (word *)0);
- runq->local->changed=1;
+ runq->local = newvar(strdup(runq->argv->words->word), runq->local);
+ runq->local->val = copywords(runq->argv->next->words, (word *)0);
+ runq->local->changed = 1;
poplist();
poplist();
}
-void Xunlocal(void){
- var *v=runq->local, *hid;
- if(v==0) panic("Xunlocal: no locals!", 0);
- runq->local=v->next;
- hid=vlook(v->name);
- hid->changed=1;
+
+void
+Xunlocal(void)
+{
+ var *v = runq->local, *hid;
+ if(v==0)
+ panic("Xunlocal: no locals!", 0);
+ runq->local = v->next;
+ hid = vlook(v->name);
+ hid->changed = 1;
efree(v->name);
freewords(v->val);
efree((char *)v);
}
-void freewords(word *w)
+
+void
+freewords(word *w)
{
word *nw;
while(w){
efree(w->word);
- nw=w->next;
+ nw = w->next;
efree((char *)w);
- w=nw;
+ w = nw;
}
}
-void Xfn(void){
+
+void
+Xfn(void)
+{
var *v;
word *a;
int end;
- end=runq->code[runq->pc].i;
- for(a=runq->argv->words;a;a=a->next){
- v=gvlook(a->word);
- if(v->fn) codefree(v->fn);
- v->fn=codecopy(runq->code);
- v->pc=runq->pc+2;
- v->fnchanged=1;
- }
- runq->pc=end;
+ end = runq->code[runq->pc].i;
+ for(a = runq->argv->words;a;a = a->next){
+ v = gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn = codecopy(runq->code);
+ v->pc = runq->pc+2;
+ v->fnchanged = 1;
+ }
+ runq->pc = end;
poplist();
}
-void Xdelfn(void){
+
+void
+Xdelfn(void)
+{
var *v;
word *a;
- for(a=runq->argv->words;a;a=a->next){
- v=gvlook(a->word);
- if(v->fn) codefree(v->fn);
- v->fn=0;
- v->fnchanged=1;
+ for(a = runq->argv->words;a;a = a->next){
+ v = gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn = 0;
+ v->fnchanged = 1;
}
poplist();
}
-void Xpipe(void){
- struct thread *p=runq;
- int pc=p->pc, forkid;
- int lfd=p->code[pc++].i;
- int rfd=p->code[pc++].i;
- int pfd[2];
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- switch(forkid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- runq->ret=0;
- close(pfd[PRD]);
- pushredir(ROPEN, pfd[PWR], lfd);
- break;
- default:
- start(p->code, p->code[pc].i, runq->local);
- close(pfd[PWR]);
- pushredir(ROPEN, pfd[PRD], rfd);
- p->pc=p->code[pc+1].i;
- p->pid=forkid;
- break;
- }
-}
-char *concstatus(char *s, char *t)
+
+char*
+concstatus(char *s, char *t)
{
static char v[NSTATUS+1];
- int n=strlen(s);
+ int n = strlen(s);
strncpy(v, s, NSTATUS);
if(n<NSTATUS){
v[n]='|';
@@ -732,7 +867,10 @@ char *concstatus(char *s, char *t)
v[NSTATUS]='\0';
return v;
}
-void Xpipewait(void){
+
+void
+Xpipewait(void)
+{
char status[NSTATUS+1];
if(runq->pid==-1)
setstatus(concstatus(runq->status, getstatus()));
@@ -744,31 +882,35 @@ void Xpipewait(void){
setstatus(concstatus(getstatus(), status));
}
}
-void Xrdcmds(void){
- struct thread *p=runq;
+
+void
+Xrdcmds(void)
+{
+ struct thread *p = runq;
word *prompt;
flush(err);
- nerror=0;
+ nerror = 0;
if(flag['s'] && !truestatus())
pfmt(err, "status=%v\n", vlook("status")->val);
if(runq->iflag){
- prompt=vlook("prompt")->val;
+ prompt = vlook("prompt")->val;
if(prompt)
- promptstr=prompt->word;
+ promptstr = prompt->word;
else
promptstr="% ";
}
Noerror();
if(yyparse()){
if(!p->iflag || p->eof && !Eintr()){
- if(p->cmdfile) efree(p->cmdfile);
+ if(p->cmdfile)
+ efree(p->cmdfile);
closeio(p->cmdfd);
Xreturn(); /* should this be omitted? */
}
else{
if(Eintr()){
pchr(err, '\n');
- p->eof=0;
+ p->eof = 0;
}
--p->pc; /* go back for next command */
}
@@ -780,7 +922,9 @@ void Xrdcmds(void){
}
freenodes();
}
-void Xerror(char *s)
+
+void
+Xerror(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s: %r\n", s);
@@ -790,7 +934,9 @@ void Xerror(char *s)
setstatus("error");
while(!runq->iflag) Xreturn();
}
-void Xerror1(char *s)
+
+void
+Xerror1(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s\n", s);
@@ -800,150 +946,55 @@ void Xerror1(char *s)
setstatus("error");
while(!runq->iflag) Xreturn();
}
-void Xbackq(void){
- char wd[8193];
- int c;
- char *s, *ewd=&wd[8192], *stop;
- struct io *f;
- var *ifs=vlook("ifs");
- word *v, *nextv;
- int pfd[2];
- int pid;
- stop=ifs->val?ifs->val->word:"";
- if(pipe(pfd)<0){
- Xerror("can't make pipe");
- return;
- }
- switch(pid=fork()){
- case -1: Xerror("try again");
- close(pfd[PRD]);
- close(pfd[PWR]);
- return;
- case 0:
- close(pfd[PRD]);
- start(runq->code, runq->pc+1, runq->local);
- pushredir(ROPEN, pfd[PWR], 1);
- return;
- default:
- close(pfd[PWR]);
- f=openfd(pfd[PRD]);
- s=wd;
- v=0;
- while((c=rchr(f))!=EOF){
- if(strchr(stop, c) || s==ewd){
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- s=wd;
- }
- }
- else *s++=c;
- }
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- }
- closeio(f);
- Waitfor(pid, 0);
- /* v points to reversed arglist -- reverse it onto argv */
- while(v){
- nextv=v->next;
- v->next=runq->argv->words;
- runq->argv->words=v;
- v=nextv;
- }
- runq->pc=runq->code[runq->pc].i;
- return;
- }
-}
-/*
- * Who should wait for the exit from the fork?
- */
-void Xpipefd(void){
- struct thread *p=runq;
- int pc=p->pc;
- char name[40];
- int pfd[2];
- int sidefd, mainfd;
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- if(p->code[pc].i==READ){
- sidefd=pfd[PWR];
- mainfd=pfd[PRD];
- }
- else{
- sidefd=pfd[PRD];
- mainfd=pfd[PWR];
- }
- switch(fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- close(mainfd);
- pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
- runq->ret=0;
- break;
- default:
- close(sidefd);
- pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
- strcpy(name, Fdprefix);
- itoa(name+strlen(name), mainfd);
- pushword(name);
- p->pc=p->code[pc+1].i;
- break;
- }
-}
-void Xsubshell(void){
- int pid;
- switch(pid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- Waitfor(pid, 1);
- runq->pc=runq->code[runq->pc].i;
- break;
- }
-}
-void setstatus(char *s)
+
+void
+setstatus(char *s)
{
setvar("status", newword(s, (word *)0));
}
-char *getstatus(void){
- var *status=vlook("status");
+
+char*
+getstatus(void)
+{
+ var *status = vlook("status");
return status->val?status->val->word:"";
}
-int truestatus(void){
+
+int
+truestatus(void)
+{
char *s;
- for(s=getstatus();*s;s++)
- if(*s!='|' && *s!='0') return 0;
+ for(s = getstatus();*s;s++)
+ if(*s!='|' && *s!='0')
+ return 0;
return 1;
}
-void Xdelhere(void){
+
+void
+Xdelhere(void)
+{
Unlink(runq->code[runq->pc++].s);
}
-void Xfor(void){
+
+void
+Xfor(void)
+{
if(runq->argv->words==0){
poplist();
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
}
else{
freelist(runq->local->val);
- runq->local->val=runq->argv->words;
- runq->local->changed=1;
- runq->argv->words=runq->argv->words->next;
- runq->local->val->next=0;
+ runq->local->val = runq->argv->words;
+ runq->local->changed = 1;
+ runq->argv->words = runq->argv->words->next;
+ runq->local->val->next = 0;
runq->pc++;
}
}
-void Xglob(void){
+
+void
+Xglob(void)
+{
globlist();
}
diff --git a/rc/exec.h b/rc/exec.h
@@ -5,6 +5,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void)
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void);
extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
+extern void Xrdwr(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
@@ -51,7 +52,6 @@ struct thread{
int iflag; /* interactive? */
int lineno; /* linenumber */
int pid; /* process for Xpipewait to wait for */
- int done; /* have we seen a wait message for this process? */
char status[NSTATUS]; /* status for Xpipewait */
tree *treenodes; /* tree nodes created by this process */
thread *ret; /* who continues when this finishes */
@@ -61,12 +61,16 @@ code *codecopy(code*);
code *codebuf; /* compiler output */
int ntrap; /* number of outstanding traps */
int trap[NSIG]; /* number of outstanding traps per type */
-extern struct builtin{
+struct builtin{
char *name;
void (*fnc)(void);
-}Builtin[];
+};
+extern struct builtin Builtin[];
int eflagok; /* kludge flag so that -e doesn't exit in startup */
+int havefork;
+
void execcd(void), execwhatis(void), execeval(void), execexec(void);
+int execforkexec(void);
void execexit(void), execshift(void);
void execwait(void), execumask(void), execdot(void), execflag(void);
void execfunc(var*), execcmds(io *);
diff --git a/rc/fns.h b/rc/fns.h
@@ -7,13 +7,14 @@ int Eintr(void);
int Executable(char*);
void Execute(word*, word*);
void Exit(char*);
+int ForkExecute(char*, char**, int, int, int);
int Globsize(char*);
int Isatty(int);
void Memcpy(char*, char*, long);
void Noerror(void);
int Opendir(char*);
long Read(int, char*, long);
-int Readdir(int, char*);
+int Readdir(int, char*, int);
long Seek(int, long, long);
void Trapinit(void);
void Unlink(char*);
@@ -21,24 +22,29 @@ void Updenv(void);
void Vinit(void);
int Waitfor(int, int);
long Write(int, char*, long);
+void addwaitpid(int);
int advance(void);
int back(int);
void cleanhere(char*);
void codefree(code*);
int compile(tree*);
char * list2str(word*);
-char * _list2str(word*, int);
int count(word*);
void deglob(char*);
+void delwaitpid(int);
void dotrap(void);
void freenodes(void);
void freewords(word*);
void globlist(void);
+int havewaitpid(int);
int idchr(int);
-void itoa(char*, long);
+void inttoascii(char*, long);
void kinit(void);
+int mapfd(int);
int match(char*, char*, int);
int matchfn(char*, char*);
+char** mkargv(word*);
+void clearwaitpids(void);
void panic(char*, int);
void pathinit(void);
void poplist(void);
@@ -48,9 +54,9 @@ void pushlist(void);
void pushredir(int, int, int);
void pushword(char*);
void readhere(void);
+word* searchpath(char*);
void setstatus(char*);
void setvar(char*, word*);
-void _setvar(char*, word*, int);
void skipnl(void);
void start(code*, int, var*);
int truestatus(void);
diff --git a/rc/getflags.c b/rc/getflags.c
@@ -3,7 +3,7 @@
#include "rc.h"
#include "getflags.h"
#include "fns.h"
-char *flagset[]={"<flag>"};
+char *flagset[] = {"<flag>"};
char **flag[NFLAG];
char cmdline[NCMDLINE+1];
char *cmdname;
@@ -19,105 +19,118 @@ static int reason;
#define FLAGSYN 3
#define BADFLAG 4
static int badflag;
-int getflags(int argc, char *argv[], char *flags, int stop)
+
+int
+getflags(int argc, char *argv[], char *flags, int stop)
{
char *s, *t;
int i, j, c, count;
- flagarg=flags;
- if(cmdname==0) cmdname=argv[0];
- s=cmdline;
- for(i=0;i!=argc;i++){
- for(t=argv[i];*t;t++)
+ flagarg = flags;
+ if(cmdname==0)
+ cmdname = argv[0];
+ s = cmdline;
+ for(i = 0;i!=argc;i++){
+ for(t = argv[i];*t;t++)
if(s!=&cmdline[NCMDLINE])
*s++=*t;
if(i!=argc-1 && s!=&cmdline[NCMDLINE])
*s++=' ';
}
*s='\0';
- i=1;
+ i = 1;
while(i!=argc){
if(argv[i][0]!='-' || argv[i][1]=='\0'){
- if(stop) return argc;
+ if(stop)
+ return argc;
i++;
continue;
}
- s=argv[i]+1;
+ s = argv[i]+1;
while(*s){
c=*s++;
- count=scanflag(c, flags);
- if(count==-1) return -1;
- if(flag[c]){ reason=RESET; badflag=c; return -1; }
+ count = scanflag(c, flags);
+ if(count==-1)
+ return -1;
+ if(flag[c]){ reason = RESET; badflag = c; return -1; }
if(count==0){
- flag[c]=flagset;
+ flag[c] = flagset;
if(*s=='\0'){
- for(j=i+1;j<=argc;j++)
- argv[j-1]=argv[j];
+ for(j = i+1;j<=argc;j++)
+ argv[j-1] = argv[j];
--argc;
}
}
else{
if(*s=='\0'){
- for(j=i+1;j<=argc;j++)
- argv[j-1]=argv[j];
+ for(j = i+1;j<=argc;j++)
+ argv[j-1] = argv[j];
--argc;
- s=argv[i];
+ s = argv[i];
}
if(argc-i<count){
- reason=FEWARGS;
- badflag=c;
+ reason = FEWARGS;
+ badflag = c;
return -1;
}
reverse(argv+i, argv+argc);
reverse(argv+i, argv+argc-count);
reverse(argv+argc-count+1, argv+argc);
argc-=count;
- flag[c]=argv+argc+1;
- flag[c][0]=s;
+ flag[c] = argv+argc+1;
+ flag[c][0] = s;
s="";
}
}
}
return argc;
}
-static void reverse(char **p, char **q)
+
+static void
+reverse(char **p, char **q)
{
char *t;
- for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
+ for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
}
-static int scanflag(int c, char *f)
+
+static int
+scanflag(int c, char *f)
{
int fc, count;
- if(0<=c && c<NFLAG) while(*f){
- if(*f==' '){
- f++;
- continue;
- }
- fc=*f++;
- if(*f==':'){
- f++;
- if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; }
- count=0;
- while('0'<=*f && *f<='9') count=count*10+*f++-'0';
- }
- else
- count=0;
- if(*f=='['){
- do{
+ if(0<=c && c<NFLAG)
+ while(*f){
+ if(*f==' '){
+ f++;
+ continue;
+ }
+ fc=*f++;
+ if(*f==':'){
+ f++;
+ if(*f<'0' || '9'<*f){ reason = FLAGSYN; return -1; }
+ count = 0;
+ while('0'<=*f && *f<='9') count = count*10+*f++-'0';
+ }
+ else
+ count = 0;
+ if(*f=='['){
+ do{
+ f++;
+ if(*f=='\0'){ reason = FLAGSYN; return -1; }
+ }while(*f!=']');
f++;
- if(*f=='\0'){ reason=FLAGSYN; return -1; }
- }while(*f!=']');
- f++;
+ }
+ if(c==fc)
+ return count;
}
- if(c==fc) return count;
- }
- reason=BADFLAG;
- badflag=c;
+ reason = BADFLAG;
+ badflag = c;
return -1;
}
-void usage(char *tail)
+
+void
+usage(char *tail)
{
char *s, *t, c;
- int count, nflag=0;
+ int count, nflag = 0;
switch(reason){
case RESET:
errs("Flag -");
@@ -140,46 +153,52 @@ void usage(char *tail)
}
errs("Usage: ");
errs(cmdname);
- for(s=flagarg;*s;){
+ for(s = flagarg;*s;){
c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
if(*s==':'){
s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
- else count=0;
+ else count = 0;
if(count==0){
- if(nflag==0) errs(" [-");
+ if(nflag==0)
+ errs(" [-");
nflag++;
errc(c);
}
if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
}
- if(nflag) errs("]");
- for(s=flagarg;*s;){
+ if(nflag)
+ errs("]");
+ for(s = flagarg;*s;){
c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
if(*s==':'){
s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
- else count=0;
+ else count = 0;
if(count!=0){
errs(" [-");
errc(c);
if(*s=='['){
s++;
- t=s;
+ t = s;
while(*s!=']' && *s!='\0') s++;
errs(" ");
errn(t, s-t);
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
else
while(count--) errs(" arg");
@@ -188,7 +207,8 @@ void usage(char *tail)
else if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
}
if(tail){
@@ -198,20 +218,27 @@ void usage(char *tail)
errs("\n");
Exit("bad flags");
}
-static void errn(char *s, int count)
+
+static void
+errn(char *s, int count)
{
while(count){ errc(*s++); --count; }
}
-static void errs(char *s)
+
+static void
+errs(char *s)
{
while(*s) errc(*s++);
}
#define NBUF 80
-static char buf[NBUF], *bufp=buf;
-static void errc(int c){
+static char buf[NBUF], *bufp = buf;
+
+static void
+errc(int c)
+{
*bufp++=c;
if(bufp==&buf[NBUF] || c=='\n'){
Write(2, buf, bufp-buf);
- bufp=buf;
+ bufp = buf;
}
}
diff --git a/rc/glob.c b/rc/glob.c
@@ -6,68 +6,77 @@ struct word *globv;
/*
* delete all the GLOB marks from s, in place
*/
-void deglob(char *s)
+
+void
+deglob(char *s)
{
- char *t=s;
+ char *t = s;
do{
- if(*t==GLOB) t++;
+ if(*t==GLOB)
+ t++;
*s++=*t;
}while(*t++);
}
-int globcmp(const void *s, const void *t)
+
+int
+globcmp(const void *s, const void *t)
{
return strcmp(*(char**)s, *(char**)t);
}
-void globsort(word *left, word *right)
+
+void
+globsort(word *left, word *right)
{
char **list;
word *a;
- int n=0;
- for(a=left;a!=right;a=a->next) n++;
- list=(char **)emalloc(n*sizeof(char *));
- for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
- qsort((char *)list, n, sizeof(char *), globcmp);
- for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
+ int n = 0;
+ for(a = left;a!=right;a = a->next) n++;
+ list = (char **)emalloc(n*sizeof(char *));
+ for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
+ qsort((void *)list, n, sizeof(void *), globcmp);
+ for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
efree((char *)list);
}
/*
* Push names prefixed by globname and suffixed by a match of p onto the astack.
* namep points to the end of the prefix in globname.
*/
-void globdir(char *p, char *namep)
+
+void
+globdir(char *p, char *namep)
{
char *t, *newp;
int f;
/* scan the pattern looking for a component with a metacharacter in it */
if(*p=='\0'){
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
return;
}
- t=namep;
- newp=p;
+ t = namep;
+ newp = p;
while(*newp){
if(*newp==GLOB)
break;
*t=*newp++;
if(*t++=='/'){
- namep=t;
- p=newp;
+ namep = t;
+ p = newp;
}
}
/* If we ran out of pattern, append the name if accessible */
if(*newp=='\0'){
*t='\0';
if(access(globname, 0)==0)
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
return;
}
/* read the directory and recur for any entry that matches */
*namep='\0';
- if((f=Opendir(globname[0]?globname:"."))<0) return;
+ if((f = Opendir(globname[0]?globname:"."))<0) return;
while(*newp!='/' && *newp!='\0') newp++;
- while(Readdir(f, namep)){
+ while(Readdir(f, namep, *newp=='/')){
if(matchfn(namep, p)){
- for(t=namep;*t;t++);
+ for(t = namep;*t;t++);
globdir(newp, t);
}
}
@@ -77,22 +86,24 @@ void globdir(char *p, char *namep)
* Push all file names matched by p on the current thread's stack.
* If there are no matches, the list consists of p.
*/
-void glob(char *p)
+
+void
+glob(char *p)
{
- word *svglobv=globv;
- int globlen=Globsize(p);
+ word *svglobv = globv;
+ int globlen = Globsize(p);
if(!globlen){
deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
return;
}
- globname=emalloc(globlen);
+ globname = emalloc(globlen);
globname[0]='\0';
globdir(p, globname);
efree(globname);
if(svglobv==globv){
deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
}
else
globsort(globv, svglobv);
@@ -100,12 +111,18 @@ void glob(char *p)
/*
* Do p and q point at equal utf codes
*/
-int equtf(char *p, char *q){
- if(*p!=*q) return 0;
+
+int
+equtf(char *p, char *q)
+{
+ if(*p!=*q)
+ return 0;
if(twobyte(*p)) return p[1]==q[1];
if(threebyte(*p)){
- if(p[1]!=q[1]) return 0;
- if(p[1]=='\0') return 1; /* broken code at end of string! */
+ if(p[1]!=q[1])
+ return 0;
+ if(p[1]=='\0')
+ return 1; /* broken code at end of string! */
return p[2]==q[2];
}
return 1;
@@ -114,7 +131,10 @@ int equtf(char *p, char *q){
* Return a pointer to the next utf code in the string,
* not jumping past nuls in broken utf codes!
*/
-char *nextutf(char *p){
+
+char*
+nextutf(char *p)
+{
if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
return p+1;
@@ -122,7 +142,10 @@ char *nextutf(char *p){
/*
* Convert the utf code at *p to a unicode value
*/
-int unicode(char *p){
+
+int
+unicode(char *p)
+{
int u=*p&0xff;
if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
@@ -135,77 +158,97 @@ int unicode(char *p){
* ? matches any single character
* [...] matches the enclosed list of characters
*/
-int matchfn(char *s, char *p)
+
+int
+matchfn(char *s, char *p)
{
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
return 0;
return match(s, p, '/');
}
-int match(char *s, char *p, int stop)
+
+int
+match(char *s, char *p, int stop)
{
int compl, hit, lo, hi, t, c;
- for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){
+ for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
if(*p!=GLOB){
if(!equtf(p, s)) return 0;
}
else switch(*++p){
case GLOB:
- if(*s!=GLOB) return 0;
+ if(*s!=GLOB)
+ return 0;
break;
case '*':
for(;;){
if(match(s, nextutf(p), stop)) return 1;
- if(!*s) break;
- s=nextutf(s);
+ if(!*s)
+ break;
+ s = nextutf(s);
}
return 0;
case '?':
- if(*s=='\0') return 0;
+ if(*s=='\0')
+ return 0;
break;
case '[':
- if(*s=='\0') return 0;
- c=unicode(s);
+ if(*s=='\0')
+ return 0;
+ c = unicode(s);
p++;
compl=*p=='~';
- if(compl) p++;
- hit=0;
+ if(compl)
+ p++;
+ hit = 0;
while(*p!=']'){
- if(*p=='\0') return 0; /* syntax error */
- lo=unicode(p);
- p=nextutf(p);
- if(*p!='-') hi=lo;
+ if(*p=='\0')
+ return 0; /* syntax error */
+ lo = unicode(p);
+ p = nextutf(p);
+ if(*p!='-')
+ hi = lo;
else{
p++;
- if(*p=='\0') return 0; /* syntax error */
- hi=unicode(p);
- p=nextutf(p);
- if(hi<lo){ t=lo; lo=hi; hi=t; }
+ if(*p=='\0')
+ return 0; /* syntax error */
+ hi = unicode(p);
+ p = nextutf(p);
+ if(hi<lo){ t = lo; lo = hi; hi = t; }
}
- if(lo<=c && c<=hi) hit=1;
+ if(lo<=c && c<=hi)
+ hit = 1;
}
- if(compl) hit=!hit;
- if(!hit) return 0;
+ if(compl)
+ hit=!hit;
+ if(!hit)
+ return 0;
break;
}
}
return *s=='\0';
}
-void globlist1(word *gl)
+
+void
+globlist1(word *gl)
{
if(gl){
globlist1(gl->next);
glob(gl->word);
}
}
-void globlist(void){
+
+void
+globlist(void)
+{
word *a;
- globv=0;
+ globv = 0;
globlist1(runq->argv->words);
poplist();
pushlist();
if(globv){
- for(a=globv;a->next;a=a->next);
- a->next=runq->argv->words;
- runq->argv->words=globv;
+ for(a = globv;a->next;a = a->next);
+ a->next = runq->argv->words;
+ runq->argv->words = globv;
}
}
diff --git a/rc/havefork.c b/rc/havefork.c
@@ -1,5 +1,9 @@
#include <u.h>
#include <signal.h>
+#if defined(PLAN9PORT) && defined(__sun__)
+# define BSD_COMP /* sigh. for TIOCNOTTY */
+#endif
+#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
@@ -12,10 +16,9 @@ void
Xasync(void)
{
int null = open("/dev/null", 0);
+ int tty;
int pid;
- int tcpgrp, pgrp;
char npid[10];
-
if(null<0){
Xerror("Can't open /dev/null\n");
return;
@@ -26,17 +29,39 @@ Xasync(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
/*
- * Should make reads of tty fail, writes succeed.
+ * I don't know what the right thing to do here is,
+ * so this is all experimentally determined.
+ * If we just dup /dev/null onto 0, then running
+ * ssh foo & will reopen /dev/tty, try to read a password,
+ * get a signal, and repeat, in a tight loop, forever.
+ * Arguably this is a bug in ssh (it behaves the same
+ * way under bash as under rc) but I'm fixing it here
+ * anyway. If we dissociate the process from the tty,
+ * then it won't be able to open /dev/tty ever again.
+ * The SIG_IGN on SIGTTOU makes writing the tty
+ * (via fd 1 or 2, for example) succeed even though
+ * our pgrp is not the terminal's controlling pgrp.
*/
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
- pushredir(ROPEN, null, 0);
+ if((tty = open("/dev/tty", OREAD)) >= 0){
+ /*
+ * Should make reads of tty fail, writes succeed.
+ */
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ ioctl(tty, TIOCNOTTY);
+ close(tty);
+ }
+ if(isatty(0))
+ pushredir(ROPEN, null, 0);
+ else
+ close(null);
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
close(null);
runq->pc = runq->code[runq->pc].i;
inttoascii(npid, pid);
@@ -62,12 +87,14 @@ Xpipe(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(p->code, pc+2, runq->local);
runq->ret = 0;
close(pfd[PRD]);
pushredir(ROPEN, pfd[PWR], lfd);
break;
default:
+ addwaitpid(forkid);
start(p->code, p->code[pc].i, runq->local);
close(pfd[PWR]);
pushredir(ROPEN, pfd[PRD], rfd);
@@ -103,11 +130,13 @@ Xbackq(void)
close(pfd[PWR]);
return;
case 0:
+ clearwaitpids();
close(pfd[PRD]);
start(runq->code, runq->pc+1, runq->local);
pushredir(ROPEN, pfd[PWR], 1);
return;
default:
+ addwaitpid(pid);
close(pfd[PWR]);
f = openfd(pfd[PRD]);
s = wd;
@@ -144,7 +173,7 @@ void
Xpipefd(void)
{
struct thread *p = runq;
- int pc = p->pc;
+ int pc = p->pc, pid;
char name[40];
int pfd[2];
int sidefd, mainfd;
@@ -160,17 +189,19 @@ Xpipefd(void)
sidefd = pfd[PRD];
mainfd = pfd[PWR];
}
- switch(fork()){
+ switch(pid = fork()){
case -1:
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(p->code, pc+2, runq->local);
close(mainfd);
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
close(sidefd);
pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop? */
strcpy(name, Fdprefix);
@@ -190,10 +221,12 @@ Xsubshell(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
Waitfor(pid, 1);
runq->pc = runq->code[runq->pc].i;
break;
@@ -211,6 +244,7 @@ execforkexec(void)
case -1:
return -1;
case 0:
+ clearwaitpids();
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
@@ -218,5 +252,6 @@ execforkexec(void)
errstr(buf+n, ERRMAX-n);
Exit(buf);
}
+ addwaitpid(pid);
return pid;
}
diff --git a/rc/here.c b/rc/here.c
@@ -3,32 +3,37 @@
#include "io.h"
#include "fns.h"
struct here *here, **ehere;
-int ser=0;
+int ser = 0;
char tmp[]="/tmp/here0000.0000";
char hex[]="0123456789abcdef";
void psubst(io*, char*);
void pstrs(io*, word*);
-void hexnum(char *p, int n)
+
+void
+hexnum(char *p, int n)
{
*p++=hex[(n>>12)&0xF];
*p++=hex[(n>>8)&0xF];
*p++=hex[(n>>4)&0xF];
- *p=hex[n&0xF];
+ *p = hex[n&0xF];
}
-tree *heredoc(tree *tag)
+
+tree*
+heredoc(tree *tag)
{
- struct here *h=new(struct here);
- if(tag->type!=WORD) yyerror("Bad here tag");
- h->next=0;
+ struct here *h = new(struct here);
+ if(tag->type!=WORD)
+ yyerror("Bad here tag");
+ h->next = 0;
if(here)
- *ehere=h;
+ *ehere = h;
else
- here=h;
+ here = h;
ehere=&h->next;
- h->tag=tag;
+ h->tag = tag;
hexnum(&tmp[9], getpid());
hexnum(&tmp[14], ser++);
- h->name=strdup(tmp);
+ h->name = strdup(tmp);
return token(tmp, WORD);
}
/*
@@ -36,27 +41,32 @@ tree *heredoc(tree *tag)
* missubstitution, or a misrecognized EOF marker.
*/
#define NLINE 4096
-void readhere(void){
+
+void
+readhere(void)
+{
struct here *h, *nexth;
io *f;
char *s, *tag;
int c, subst;
char line[NLINE+1];
- for(h=here;h;h=nexth){
+ for(h = here;h;h = nexth){
subst=!h->tag->quoted;
- tag=h->tag->str;
- c=Creat(h->name);
- if(c<0) yyerror("can't create here document");
- f=openfd(c);
- s=line;
+ tag = h->tag->str;
+ c = Creat(h->name);
+ if(c<0)
+ yyerror("can't create here document");
+ f = openfd(c);
+ s = line;
pprompt();
- while((c=rchr(runq->cmdfd))!=EOF){
+ while((c = rchr(runq->cmdfd))!=EOF){
if(c=='\n' || s==&line[NLINE]){
*s='\0';
- if(strcmp(line, tag)==0) break;
- if(subst) psubst(f, line);
+ if(tag && strcmp(line, tag)==0) break;
+ if(subst)
+ psubst(f, line);
else pstr(f, line);
- s=line;
+ s = line;
if(c=='\n'){
pprompt();
pchr(f, c);
@@ -68,13 +78,15 @@ void readhere(void){
flush(f);
closeio(f);
cleanhere(h->name);
- nexth=h->next;
+ nexth = h->next;
efree((char *)h);
}
- here=0;
- doprompt=1;
+ here = 0;
+ doprompt = 1;
}
-void psubst(io *f, char *s)
+
+void
+psubst(io *f, char *s)
{
char *t, *u;
int savec, n;
@@ -83,48 +95,55 @@ void psubst(io *f, char *s)
if(*s!='$'){
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
}
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
}
pchr(f, *s++);
}
else{
t=++s;
- if(*t=='$') pchr(f, *t++);
+ if(*t=='$')
+ pchr(f, *t++);
else{
while(*t && idchr(*t)) t++;
savec=*t;
*t='\0';
- n=0;
- for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*u-'0';
+ n = 0;
+ for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
if(n && *u=='\0'){
- star=vlook("*")->val;
+ star = vlook("*")->val;
if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
+ while(--n) star = star->next;
pstr(f, star->word);
}
}
else
pstrs(f, vlook(s)->val);
- *t=savec;
- if(savec=='^') t++;
+ *t = savec;
+ if(savec=='^')
+ t++;
}
- s=t;
+ s = t;
}
}
}
-void pstrs(io *f, word *a)
+
+void
+pstrs(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pstr(f, a->word);
pchr(f, ' ');
- a=a->next;
+ a = a->next;
}
pstr(f, a->word);
}
diff --git a/rc/io.c b/rc/io.c
@@ -2,68 +2,121 @@
#include "exec.h"
#include "io.h"
#include "fns.h"
-int pfmtnest=0;
-void pfmt(io *f, char *fmt, ...){
+int pfmtnest = 0;
+
+void
+pfmt(io *f, char *fmt, ...)
+{
va_list ap;
char err[ERRMAX];
va_start(ap, fmt);
pfmtnest++;
for(;*fmt;fmt++)
- if(*fmt!='%') pchr(f, *fmt);
+ if(*fmt!='%')
+ pchr(f, *fmt);
else switch(*++fmt){
- case '\0': va_end(ap); return;
- case 'c': pchr(f, va_arg(ap, int)); break;
- case 'd': pdec(f, va_arg(ap, int)); break;
- case 'o': poct(f, va_arg(ap, unsigned)); break;
- case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportable*/
- case 'Q': pquo(f, va_arg(ap, char *)); break;
- case 'q': pwrd(f, va_arg(ap, char *)); break;
- case 'r': errstr(err, sizeof err); pstr(f, err); break;
- case 's': pstr(f, va_arg(ap, char *)); break;
- case 't': pcmd(f, va_arg(ap, struct tree *)); break;
- case 'v': pval(f, va_arg(ap, struct word *)); break;
- default: pchr(f, *fmt); break;
+ case '\0':
+ va_end(ap);
+ return;
+ case 'c':
+ pchr(f, va_arg(ap, int));
+ break;
+ case 'd':
+ pdec(f, va_arg(ap, int));
+ break;
+ case 'o':
+ poct(f, va_arg(ap, unsigned));
+ break;
+ case 'p':
+ pptr(f, va_arg(ap, void*));
+ break;
+ case 'Q':
+ pquo(f, va_arg(ap, char *));
+ break;
+ case 'q':
+ pwrd(f, va_arg(ap, char *));
+ break;
+ case 'r':
+ rerrstr(err, sizeof err); pstr(f, err);
+ break;
+ case 's':
+ pstr(f, va_arg(ap, char *));
+ break;
+ case 't':
+ pcmd(f, va_arg(ap, struct tree *));
+ break;
+ case 'v':
+ pval(f, va_arg(ap, struct word *));
+ break;
+ default:
+ pchr(f, *fmt);
+ break;
}
va_end(ap);
- if(--pfmtnest==0) flush(f);
+ if(--pfmtnest==0)
+ flush(f);
}
-void pchr(io *b, int c)
+
+void
+pchr(io *b, int c)
{
- if(b->bufp==b->ebuf) fullbuf(b, c);
+ if(b->bufp==b->ebuf)
+ fullbuf(b, c);
else *b->bufp++=c;
}
-int rchr(io *b)
+
+int
+rchr(io *b)
{
- if(b->bufp==b->ebuf) return emptybuf(b);
+ if(b->bufp==b->ebuf)
+ return emptybuf(b);
return *b->bufp++ & 0xFF;
}
-void pquo(io *f, char *s)
+void
+pquo(io *f, char *s)
{
pchr(f, '\'');
for(;*s;s++)
- if(*s=='\'') pfmt(f, "''");
+ if(*s=='\'')
+ pfmt(f, "''");
else pchr(f, *s);
pchr(f, '\'');
}
-void pwrd(io *f, char *s)
+
+void
+pwrd(io *f, char *s)
{
char *t;
- for(t=s;*t;t++) if(!wordchr(*t)) break;
- if(t==s || *t) pquo(f, s);
+ for(t = s;*t;t++) if(!wordchr(*t)) break;
+ if(t==s || *t)
+ pquo(f, s);
else pstr(f, s);
}
-void phex(io *f, long p)
+
+void
+pptr(io *f, void *v)
{
int n;
- for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+ uintptr p;
+
+ p = (uintptr)v;
+ if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
+ for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+
+ for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
}
-void pstr(io *f, char *s)
+
+void
+pstr(io *f, char *s)
{
- if(s==0) s="(null)";
+ if(s==0)
+ s="(null)";
while(*s) pchr(f, *s++);
}
-void pdec(io *f, long n)
+
+void
+pdec(io *f, int n)
{
if(n<0){
n=-n;
@@ -73,110 +126,136 @@ void pdec(io *f, long n)
return;
}
/* n is two's complement minimum integer */
- n=1-n;
+ n = 1-n;
pchr(f, '-');
pdec(f, n/10);
pchr(f, n%10+'1');
return;
}
- if(n>9) pdec(f, n/10);
+ if(n>9)
+ pdec(f, n/10);
pchr(f, n%10+'0');
}
-void poct(io *f, ulong n)
+
+void
+poct(io *f, unsigned n)
{
- if(n>7) poct(f, n>>3);
+ if(n>7)
+ poct(f, n>>3);
pchr(f, (n&7)+'0');
}
-void pval(io *f, word *a)
+
+void
+pval(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pwrd(f, a->word);
pchr(f, ' ');
- a=a->next;
+ a = a->next;
}
pwrd(f, a->word);
}
}
-int fullbuf(io *f, int c)
+
+int
+fullbuf(io *f, int c)
{
flush(f);
return *f->bufp++=c;
}
-void flush(io *f)
+
+void
+flush(io *f)
{
int n;
char *s;
if(f->strp){
- n=f->ebuf-f->strp;
- f->strp=realloc(f->strp, n+101);
- if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101);
- f->bufp=f->strp+n;
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ n = f->ebuf-f->strp;
+ f->strp = realloc(f->strp, n+101);
+ if(f->strp==0)
+ panic("Can't realloc %d bytes in flush!", n+101);
+ f->bufp = f->strp+n;
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
}
else{
- n=f->bufp-f->buf;
+ n = f->bufp-f->buf;
if(n && Write(f->fd, f->buf, n) < 0){
Write(3, "Write error\n", 12);
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
}
- f->bufp=f->buf;
- f->ebuf=f->buf+NBUF;
+ f->bufp = f->buf;
+ f->ebuf = f->buf+NBUF;
}
}
-io *openfd(int fd){
- io *f;
- f=new(struct io);
- f->fd=fd;
- f->bufp=f->ebuf=f->buf;
- f->strp=0;
+
+io*
+openfd(int fd)
+{
+ io *f = new(struct io);
+ f->fd = fd;
+ f->bufp = f->ebuf = f->buf;
+ f->strp = 0;
return f;
}
-io *openstr(void){
- io *f=new(struct io);
+
+io*
+openstr(void)
+{
+ io *f = new(struct io);
char *s;
f->fd=-1;
- f->bufp=f->strp=emalloc(101);
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ f->bufp = f->strp = emalloc(101);
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
return f;
}
/*
* Open a corebuffer to read. EOF occurs after reading len
* characters from buf.
*/
-io *opencore(char *s, int len)
+
+io*
+opencore(char *s, int len)
{
- io *f=new(struct io);
- char *buf=emalloc(len);
+ io *f = new(struct io);
+ char *buf = emalloc(len);
f->fd= -1 /*open("/dev/null", 0)*/;
- f->bufp=f->strp=buf;
- f->ebuf=buf+len;
+ f->bufp = f->strp = buf;
+ f->ebuf = buf+len;
Memcpy(buf, s, len);
return f;
}
-/*
-void rewind(io *io)
+
+void
+iorewind(io *io)
{
- if(io->fd==-1) io->bufp=io->strp;
+ if(io->fd==-1)
+ io->bufp = io->strp;
else{
- io->bufp=io->ebuf=io->buf;
+ io->bufp = io->ebuf = io->buf;
Seek(io->fd, 0L, 0);
}
}
-*/
-void closeio(io *io)
+
+void
+closeio(io *io)
{
- if(io->fd>=0) close(io->fd);
- if(io->strp) efree(io->strp);
+ if(io->fd>=0)
+ close(io->fd);
+ if(io->strp)
+ efree(io->strp);
efree((char *)io);
}
-int emptybuf(io *f)
+
+int
+emptybuf(io *f)
{
int n;
- if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF;
- f->bufp=f->buf;
- f->ebuf=f->buf+n;
+ if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
+ f->bufp = f->buf;
+ f->ebuf = f->buf+n;
return *f->bufp++&0xff;
}
diff --git a/rc/io.h b/rc/io.h
@@ -18,9 +18,9 @@ int rchr(io*);
void closeio(io*);
void flush(io*);
int fullbuf(io*, int);
-void pdec(io*, long);
-void poct(io*, ulong);
-void phex(io*, long);
+void pdec(io*, int);
+void poct(io*, unsigned);
+void pptr(io*, void*);
void pquo(io*, char*);
void pwrd(io*, char*);
void pstr(io*, char*);
diff --git a/rc/lex.c b/rc/lex.c
@@ -4,11 +4,15 @@
#include "getflags.h"
#include "fns.h"
int getnext(void);
-int wordchr(int c)
+
+int
+wordchr(int c)
{
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
}
-int idchr(int c)
+
+int
+idchr(int c)
{
/*
* Formerly:
@@ -17,127 +21,170 @@ int idchr(int c)
*/
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
-int future=EOF;
-int doprompt=1;
+int future = EOF;
+int doprompt = 1;
int inquote;
+int incomm;
/*
* Look ahead in the input stream
*/
-int nextc(void){
- if(future==EOF) future=getnext();
+
+int
+nextc(void)
+{
+ if(future==EOF)
+ future = getnext();
return future;
}
/*
* Consume the lookahead character.
*/
-int advance(void){
- int c=nextc();
- lastc=future;
- future=EOF;
+
+int
+advance(void)
+{
+ int c = nextc();
+ lastc = future;
+ future = EOF;
return c;
}
/*
* read a character from the input stream
*/
-int getnext(void){
- register int c;
- static int peekc=EOF;
+
+int
+getnext(void)
+{
+ int c;
+ static int peekc = EOF;
if(peekc!=EOF){
- c=peekc;
- peekc=EOF;
+ c = peekc;
+ peekc = EOF;
return c;
}
- if(runq->eof) return EOF;
- if(doprompt) pprompt();
- c=rchr(runq->cmdfd);
+ if(runq->eof)
+ return EOF;
+ if(doprompt)
+ pprompt();
+ c = rchr(runq->cmdfd);
if(!inquote && c=='\\'){
- c=rchr(runq->cmdfd);
- if(c=='\n'){
- doprompt=1;
+ c = rchr(runq->cmdfd);
+ if(c=='\n' && !incomm){ /* don't continue a comment */
+ doprompt = 1;
c=' ';
}
else{
- peekc=c;
+ peekc = c;
c='\\';
}
}
- doprompt=doprompt || c=='\n' || c==EOF;
- if(c==EOF) runq->eof++;
+ doprompt = doprompt || c=='\n' || c==EOF;
+ if(c==EOF)
+ runq->eof++;
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
return c;
}
-void pprompt(void){
+
+void
+pprompt(void)
+{
var *prompt;
if(runq->iflag){
pstr(err, promptstr);
flush(err);
- prompt=vlook("prompt");
+ prompt = vlook("prompt");
if(prompt->val && prompt->val->next)
- promptstr=prompt->val->next->word;
+ promptstr = prompt->val->next->word;
else
promptstr="\t";
}
runq->lineno++;
- doprompt=0;
+ doprompt = 0;
}
-void skipwhite(void){
+
+void
+skipwhite(void)
+{
int c;
for(;;){
- c=nextc();
- if(c=='#'){ /* Why did this used to be if(!inquote && c=='#') ?? */
+ c = nextc();
+ /* Why did this used to be if(!inquote && c=='#') ?? */
+ if(c=='#'){
+ incomm = 1;
for(;;){
- c=nextc();
- if(c=='\n' || c==EOF) break;
+ c = nextc();
+ if(c=='\n' || c==EOF) {
+ incomm = 0;
+ break;
+ }
advance();
}
}
- if(c==' ' || c=='\t') advance();
+ if(c==' ' || c=='\t')
+ advance();
else return;
}
}
-void skipnl(void){
- register int c;
+
+void
+skipnl(void)
+{
+ int c;
for(;;){
skipwhite();
- c=nextc();
- if(c!='\n') return;
+ c = nextc();
+ if(c!='\n')
+ return;
advance();
}
}
-int nextis(int c){
+
+int
+nextis(int c)
+{
if(nextc()==c){
advance();
return 1;
}
return 0;
}
-char *addtok(char *p, int val){
- if(p==0) return 0;
- if(p==&tok[NTOK]){
- *p=0;
+
+char*
+addtok(char *p, int val)
+{
+ if(p==0)
+ return 0;
+ if(p==&tok[NTOK-1]){
+ *p = 0;
yyerror("token buffer too short");
return 0;
}
*p++=val;
return p;
}
-char *addutf(char *p, int c){
- p=addtok(p, c);
+
+char*
+addutf(char *p, int c)
+{
+ p = addtok(p, c);
if(twobyte(c)) /* 2-byte escape */
return addtok(p, advance());
if(threebyte(c)){ /* 3-byte escape */
- p=addtok(p, advance());
+ p = addtok(p, advance());
return addtok(p, advance());
}
return p;
}
int lastdol; /* was the last token read '$' or '$#' or '"'? */
int lastword; /* was the last token read a word or compound word terminator? */
-int yylex(void){
- register int c, d=nextc();
- register char *w=tok;
- register struct tree *t;
- yylval.tree=0;
+
+int
+yylex(void)
+{
+ int c, d = nextc();
+ char *w = tok;
+ struct tree *t;
+ yylval.tree = 0;
/*
* Embarassing sneakiness: if the last token read was a quoted or unquoted
* WORD then we alter the meaning of what follows. If the next character
@@ -146,7 +193,7 @@ int yylex(void){
* we insert a `^' before it.
*/
if(lastword){
- lastword=0;
+ lastword = 0;
if(d=='('){
advance();
strcpy(tok, "( [SUB]");
@@ -157,15 +204,15 @@ int yylex(void){
return '^';
}
}
- inquote=0;
+ inquote = 0;
skipwhite();
- switch(c=advance()){
+ switch(c = advance()){
case EOF:
- lastdol=0;
+ lastdol = 0;
strcpy(tok, "EOF");
return EOF;
case '$':
- lastdol=1;
+ lastdol = 1;
if(nextis('#')){
strcpy(tok, "$#");
return COUNT;
@@ -177,7 +224,7 @@ int yylex(void){
strcpy(tok, "$");
return '$';
case '&':
- lastdol=0;
+ lastdol = 0;
if(nextis('&')){
skipnl();
strcpy(tok, "&&");
@@ -186,7 +233,7 @@ int yylex(void){
strcpy(tok, "&");
return '&';
case '|':
- lastdol=0;
+ lastdol = 0;
if(nextis(c)){
skipnl();
strcpy(tok, "||");
@@ -194,7 +241,7 @@ int yylex(void){
}
case '<':
case '>':
- lastdol=0;
+ lastdol = 0;
/*
* funny redirection tokens:
* redir: arrow | arrow '[' fd ']'
@@ -204,121 +251,128 @@ int yylex(void){
* some possibilities are nonsensical and get a message.
*/
*w++=c;
- t=newtree();
+ t = newtree();
switch(c){
case '|':
- t->type=PIPE;
- t->fd0=1;
- t->fd1=0;
+ t->type = PIPE;
+ t->fd0 = 1;
+ t->fd1 = 0;
break;
case '>':
- t->type=REDIR;
+ t->type = REDIR;
if(nextis(c)){
- t->rtype=APPEND;
+ t->rtype = APPEND;
*w++=c;
}
- else t->rtype=WRITE;
- t->fd0=1;
+ else t->rtype = WRITE;
+ t->fd0 = 1;
break;
case '<':
- t->type=REDIR;
+ t->type = REDIR;
if(nextis(c)){
- t->rtype=HERE;
+ t->rtype = HERE;
*w++=c;
- }
- else t->rtype=READ;
- t->fd0=0;
+ } else if (nextis('>')){
+ t->rtype = RDWR;
+ *w++=c;
+ } else t->rtype = READ;
+ t->fd0 = 0;
break;
}
if(nextis('[')){
*w++='[';
- c=advance();
+ c = advance();
+ *w++=c;
if(c<'0' || '9'<c){
RedirErr:
- *w++ = c;
- *w=0;
+ *w = 0;
yyerror(t->type==PIPE?"pipe syntax"
:"redirection syntax");
return EOF;
}
- t->fd0=0;
+ t->fd0 = 0;
do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
*w++=c;
- c=advance();
+ c = advance();
}while('0'<=c && c<='9');
if(c=='='){
*w++='=';
- if(t->type==REDIR) t->type=DUP;
- c=advance();
+ if(t->type==REDIR)
+ t->type = DUP;
+ c = advance();
if('0'<=c && c<='9'){
- t->rtype=DUPFD;
- t->fd1=t->fd0;
- t->fd0=0;
+ t->rtype = DUPFD;
+ t->fd1 = t->fd0;
+ t->fd0 = 0;
do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
*w++=c;
- c=advance();
+ c = advance();
}while('0'<=c && c<='9');
}
else{
- if(t->type==PIPE) goto RedirErr;
- t->rtype=CLOSE;
+ if(t->type==PIPE)
+ goto RedirErr;
+ t->rtype = CLOSE;
}
}
- *w=0;
if(c!=']'
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
goto RedirErr;
*w++=']';
}
*w='\0';
- yylval.tree=t;
- if(t->type==PIPE) skipnl();
+ yylval.tree = t;
+ if(t->type==PIPE)
+ skipnl();
return t->type;
case '\'':
- lastdol=0;
- lastword=1;
- inquote=1;
+ lastdol = 0;
+ lastword = 1;
+ inquote = 1;
for(;;){
- c=advance();
- if(c==EOF) break;
+ c = advance();
+ if(c==EOF)
+ break;
if(c=='\''){
if(nextc()!='\'')
break;
advance();
}
- w=addutf(w, c);
+ w = addutf(w, c);
}
- if(w!=0) *w='\0';
- t=token(tok, WORD);
- t->quoted=1;
- yylval.tree=t;
+ if(w!=0)
+ *w='\0';
+ t = token(tok, WORD);
+ t->quoted = 1;
+ yylval.tree = t;
return t->type;
}
if(!wordchr(c)){
- lastdol=0;
- tok[0]=c;
+ lastdol = 0;
+ tok[0] = c;
tok[1]='\0';
return c;
}
for(;;){
/* next line should have (char)c==GLOB, but ken's compiler is broken */
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
- w=addtok(w, GLOB);
- w=addutf(w, c);
- c=nextc();
+ w = addtok(w, GLOB);
+ w = addutf(w, c);
+ c = nextc();
if(lastdol?!idchr(c):!wordchr(c)) break;
advance();
}
- lastword=1;
- lastdol=0;
- if(w!=0) *w='\0';
- t=klook(tok);
- if(t->type!=WORD) lastword=0;
- t->quoted=0;
- yylval.tree=t;
+ lastword = 1;
+ lastdol = 0;
+ if(w!=0)
+ *w='\0';
+ t = klook(tok);
+ if(t->type!=WORD)
+ lastword = 0;
+ t->quoted = 0;
+ yylval.tree = t;
return t->type;
}
-
diff --git a/rc/pcmd.c b/rc/pcmd.c
@@ -5,39 +5,66 @@ char nl='\n'; /* change to semicolon for bourne-proofing */
#define c0 t->child[0]
#define c1 t->child[1]
#define c2 t->child[2]
-void pdeglob(io *f, char *s)
+
+void
+pdeglob(io *f, char *s)
{
while(*s){
- if(*s==GLOB) s++;
+ if(*s==GLOB)
+ s++;
pchr(f, *s++);
}
}
-void pcmd(io *f, tree *t)
+
+void
+pcmd(io *f, tree *t)
{
- if(t==0) return;
+ if(t==0)
+ return;
switch(t->type){
- default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break;
- case '$': pfmt(f, "$%t", c0); break;
- case '"': pfmt(f, "$\"%t", c0); break;
- case '&': pfmt(f, "%t&", c0); break;
- case '^': pfmt(f, "%t^%t", c0, c1); break;
- case '`': pfmt(f, "`%t", c0); break;
- case ANDAND: pfmt(f, "%t && %t", c0, c1); break;
- case BANG: pfmt(f, "! %t", c0); break;
- case BRACE: pfmt(f, "{%t}", c0); break;
- case COUNT: pfmt(f, "$#%t", c0); break;
- case FN: pfmt(f, "fn %t %t", c0, c1); break;
- case IF: pfmt(f, "if%t%t", c0, c1); break;
- case NOT: pfmt(f, "if not %t", c0); break;
- case OROR: pfmt(f, "%t || %t", c0, c1); break;
+ default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
+ break;
+ case '$': pfmt(f, "$%t", c0);
+ break;
+ case '"': pfmt(f, "$\"%t", c0);
+ break;
+ case '&': pfmt(f, "%t&", c0);
+ break;
+ case '^': pfmt(f, "%t^%t", c0, c1);
+ break;
+ case '`': pfmt(f, "`%t", c0);
+ break;
+ case ANDAND: pfmt(f, "%t && %t", c0, c1);
+ break;
+ case BANG: pfmt(f, "! %t", c0);
+ break;
+ case BRACE: pfmt(f, "{%t}", c0);
+ break;
+ case COUNT: pfmt(f, "$#%t", c0);
+ break;
+ case FN: pfmt(f, "fn %t %t", c0, c1);
+ break;
+ case IF: pfmt(f, "if%t%t", c0, c1);
+ break;
+ case NOT: pfmt(f, "if not %t", c0);
+ break;
+ case OROR: pfmt(f, "%t || %t", c0, c1);
+ break;
case PCMD:
- case PAREN: pfmt(f, "(%t)", c0); break;
- case SUB: pfmt(f, "$%t(%t)", c0, c1); break;
- case SIMPLE: pfmt(f, "%t", c0); break;
- case SUBSHELL: pfmt(f, "@ %t", c0); break;
- case SWITCH: pfmt(f, "switch %t %t", c0, c1); break;
- case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break;
- case WHILE: pfmt(f, "while %t%t", c0, c1); break;
+ case PAREN: pfmt(f, "(%t)", c0);
+ break;
+ case SUB: pfmt(f, "$%t(%t)", c0, c1);
+ break;
+ case SIMPLE: pfmt(f, "%t", c0);
+ break;
+ case SUBSHELL: pfmt(f, "@ %t", c0);
+ break;
+ case SWITCH: pfmt(f, "switch %t %t", c0, c1);
+ break;
+ case TWIDDLE: pfmt(f, "~ %t %t", c0, c1);
+ break;
+ case WHILE: pfmt(f, "while %t%t", c0, c1);
+ break;
case ARGLIST:
if(c0==0)
pfmt(f, "%t", c1);
@@ -48,22 +75,26 @@ void pcmd(io *f, tree *t)
break;
case ';':
if(c0){
- if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
+ if(c1)
+ pfmt(f, "%t%c%t", c0, nl, c1);
else pfmt(f, "%t", c0);
}
else pfmt(f, "%t", c1);
break;
case WORDS:
- if(c0) pfmt(f, "%t ", c0);
+ if(c0)
+ pfmt(f, "%t ", c0);
pfmt(f, "%t", c1);
break;
case FOR:
pfmt(f, "for(%t", c0);
- if(c1) pfmt(f, " in %t", c1);
+ if(c1)
+ pfmt(f, " in %t", c1);
pfmt(f, ")%t", c2);
break;
case WORD:
- if(t->quoted) pfmt(f, "%Q", t->str);
+ if(t->quoted)
+ pfmt(f, "%Q", t->str);
else pdeglob(f, t->str);
break;
case DUP:
@@ -79,27 +110,35 @@ void pcmd(io *f, tree *t)
case HERE:
pchr(f, '<');
case READ:
+ case RDWR:
pchr(f, '<');
- if(t->fd0!=0) pfmt(f, "[%d]", t->fd0);
+ if(t->rtype==RDWR)
+ pchr(f, '>');
+ if(t->fd0!=0)
+ pfmt(f, "[%d]", t->fd0);
break;
case APPEND:
pchr(f, '>');
case WRITE:
pchr(f, '>');
- if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
break;
}
pfmt(f, "%t", c0);
- if(c1) pfmt(f, " %t", c1);
+ if(c1)
+ pfmt(f, " %t", c1);
break;
case '=':
pfmt(f, "%t=%t", c0, c1);
- if(c2) pfmt(f, " %t", c2);
+ if(c2)
+ pfmt(f, " %t", c2);
break;
case PIPE:
pfmt(f, "%t|", c0);
if(t->fd1==0){
- if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
}
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
pfmt(f, "%t", c1);
diff --git a/rc/pfnc.c b/rc/pfnc.c
@@ -5,7 +5,7 @@
struct{
void (*f)(void);
char *name;
-}fname[]={
+}fname[] = {
Xappend, "Xappend",
Xasync, "Xasync",
Xbang, "Xbang",
@@ -18,6 +18,7 @@ struct{
Xjump, "Xjump",
Xmark, "Xmark",
Xpopm, "Xpopm",
+ Xrdwr, "Xrdwr",
Xread, "Xread",
Xreturn, "Xreturn",
Xtrue, "Xtrue",
@@ -50,18 +51,21 @@ struct{
Xrdfn, "Xrdfn",
Xqdol, "Xqdol",
0};
-void pfnc(io *fd, thread *t)
+
+void
+pfnc(io *fd, thread *t)
{
int i;
- void (*fn)(void)=t->code[t->pc].f;
+ void (*fn)(void) = t->code[t->pc].f;
list *a;
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
- for(i=0;fname[i].f;i++) if(fname[i].f==fn){
+ for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
pstr(fd, fname[i].name);
break;
}
- if(!fname[i].f) pfmt(fd, "%p", fn);
- for(a=t->argv;a;a=a->next) pfmt(fd, " (%v)", a->words);
+ if(!fname[i].f)
+ pfmt(fd, "%p", fn);
+ for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
pchr(fd, '\n');
flush(fd);
}
diff --git a/rc/plan9ish.c b/rc/plan9ish.c
@@ -27,12 +27,11 @@ char *syssigname[]={
char*
Rcmain(void)
{
- static char Rcmain[] = PREFIX"/etc/rcmain";
- char *rcmain = getenv("RCMAIN");
- return rcmain ? rcmain : Rcmain;
+ return unsharp("#9/rcmain");
}
char Fdprefix[]="/dev/fd/";
+long readnb(int, char *, long);
void execfinit(void);
void execbind(void);
void execmount(void);
@@ -129,7 +128,7 @@ void Vinit(void){
for(s=*env;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '\0':
- // pfmt(err, "rc: odd environment %q?\n", *env);
+ /* pfmt(err, "rc: odd environment %q?\n", *env); */
break;
case '=':
*s='\0';
@@ -200,7 +199,10 @@ int Waitfor(int pid, int unused0){
Waitmsg *w;
char errbuf[ERRMAX];
+ if(pid >= 0 && !havewaitpid(pid))
+ return 0;
while((w = wait()) != nil){
+ delwaitpid(w->pid);
if(w->pid==pid){
if(strncmp(w->msg, "signal: ", 8) == 0)
fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
@@ -208,7 +210,7 @@ int Waitfor(int pid, int unused0){
free(w);
return 0;
}
- if(strncmp(w->msg, "signal: ", 8) == 0)
+ if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
fprint(2, "%d: %s\n", w->pid, w->msg);
for(p=runq->ret;p;p=p->ret)
if(p->pid==w->pid){
@@ -218,7 +220,7 @@ int Waitfor(int pid, int unused0){
free(w);
}
- errstr(errbuf, sizeof errbuf);
+ rerrstr(errbuf, sizeof errbuf);
if(strcmp(errbuf, "interrupted")==0) return -1;
return 0;
}
@@ -412,9 +414,11 @@ int Opendir(char *name)
close(f);
return -1;
}
-int Readdir(int f, char *p)
+int Readdir(int f, char *p, int onlydirs)
{
int n;
+ USED(onlydirs); /* only advisory */
+
if(f<0 || f>=NFD)
return 0;
if(dir[f].i==dir[f].n){ /* read */
@@ -490,7 +494,7 @@ long Read(int fd, char *buf, long cnt)
{
int i;
- i = read(fd, buf, cnt);
+ i = readnb(fd, buf, cnt);
if(ntrap) dotrap();
return i;
}
@@ -547,3 +551,54 @@ void Memcpy(char *a, char *b, long n)
void *Malloc(ulong n){
return malloc(n);
}
+
+int
+exitcode(char *msg)
+{
+ int n;
+
+ n = atoi(msg);
+ if(n == 0)
+ n = 1;
+ return n;
+}
+
+int *waitpids;
+int nwaitpids;
+
+void
+addwaitpid(int pid)
+{
+ waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
+ if(waitpids == 0)
+ panic("Can't realloc %d waitpids", nwaitpids+1);
+ waitpids[nwaitpids++] = pid;
+}
+
+void
+delwaitpid(int pid)
+{
+ int r, w;
+
+ for(r=w=0; r<nwaitpids; r++)
+ if(waitpids[r] != pid)
+ waitpids[w++] = waitpids[r];
+ nwaitpids = w;
+}
+
+void
+clearwaitpids(void)
+{
+ nwaitpids = 0;
+}
+
+int
+havewaitpid(int pid)
+{
+ int i;
+
+ for(i=0; i<nwaitpids; i++)
+ if(waitpids[i] == pid)
+ return 1;
+ return 0;
+}
diff --git a/rc/rc.1 b/rc/rc.1
@@ -208,6 +208,11 @@ If
is followed by a parenthesized list of subscripts, the
value substituted is a list composed of the requested elements (origin 1).
The parenthesis must follow the variable name with no spaces.
+Subscripts can also take the form
+.IB m - n
+or
+.IB m -
+to indicate a sequence of elements.
Assignments to variables are described below.
.HP
.BI $# argument
diff --git a/rc/rc.h b/rc/rc.h
@@ -26,7 +26,7 @@
#define YYMAXDEPTH 500
#ifndef PAREN
#ifndef YYMAJOR
-#include "y.tab.h"
+#include "x.tab.h"
#endif
#endif
@@ -80,6 +80,7 @@ char tok[NTOK];
#define HERE 4
#define DUPFD 5
#define CLOSE 6
+#define RDWR 7
struct var{
char *name; /* ascii name */
word *val; /* value */
diff --git a/rc/simple.c b/rc/simple.c
@@ -15,22 +15,24 @@ exitnext(void){
while(c->f==Xpopredir) c++;
return c->f==Xexit;
}
-void Xsimple(void){
+
+void
+Xsimple(void)
+{
word *a;
- thread *p=runq;
+ thread *p = runq;
var *v;
struct builtin *bp;
- int pid, n;
- char buf[ERRMAX];
+ int pid;
globlist();
- a=runq->argv->words;
+ a = runq->argv->words;
if(a==0){
Xerror1("empty argument list");
return;
}
if(flag['x'])
pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs */
- v=gvlook(a->word);
+ v = gvlook(a->word);
if(v->fn)
execfunc(v);
else{
@@ -41,10 +43,10 @@ void Xsimple(void){
poplist();
return;
}
- a=a->next;
+ a = a->next;
popword();
}
- for(bp=Builtin;bp->name;bp++)
+ for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
(*bp->fnc)();
return;
@@ -58,30 +60,22 @@ void Xsimple(void){
else{
flush(err);
Updenv(); /* necessary so changes don't go out again */
- switch(pid=fork()){
- case -1:
+ if((pid = execforkexec()) < 0){
Xerror("try again");
return;
- case 0:
- pushword("exec");
- execexec();
- strcpy(buf, "can't exec: ");
- n = strlen(buf);
- errstr(buf+n, ERRMAX-n);
- Exit(buf);
- default:
- kidpid = pid;
- poplist();
- /* interrupts don't get us out */
- while(Waitfor(pid, 1) < 0)
- ;
- kidpid = 0;
}
+
+ /* interrupts don't get us out */
+ poplist();
+ while(Waitfor(pid, 1) < 0)
+ ;
}
}
}
-struct word nullpath={ "", 0};
-void doredir(redir *rp)
+struct word nullpath = { "", 0};
+
+void
+doredir(redir *rp)
{
if(rp){
doredir(rp->next);
@@ -92,22 +86,32 @@ void doredir(redir *rp)
close(rp->from);
}
break;
- case RDUP: Dup(rp->from, rp->to); break;
- case RCLOSE: close(rp->from); break;
+ case RDUP:
+ Dup(rp->from, rp->to);
+ break;
+ case RCLOSE:
+ close(rp->from);
+ break;
}
}
}
-word *searchpath(char *w){
+
+word*
+searchpath(char *w)
+{
word *path;
if(strncmp(w, "/", 1)==0
/* || strncmp(w, "#", 1)==0 */
|| strncmp(w, "./", 2)==0
|| strncmp(w, "../", 3)==0
- || (path=vlook("path")->val)==0)
+ || (path = vlook("path")->val)==0)
path=&nullpath;
return path;
}
-void execexec(void){
+
+void
+execexec(void)
+{
popword(); /* "exec" */
if(runq->argv->words==0){
Xerror1("empty argument list");
@@ -117,19 +121,24 @@ void execexec(void){
Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist();
}
-void execfunc(var *func)
+
+void
+execfunc(var *func)
{
word *starval;
popword();
- starval=runq->argv->words;
- runq->argv->words=0;
+ starval = runq->argv->words;
+ runq->argv->words = 0;
poplist();
- start(func->fn, func->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=starval;
- runq->local->changed=1;
+ start(func->fn, func->pc, runq->local);
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = starval;
+ runq->local->changed = 1;
}
-int dochdir(char *word){
+
+int
+dochdir(char *word)
+{
/* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2;
if(chdir(word)<0) return -1;
@@ -141,21 +150,26 @@ int dochdir(char *word){
}
return 1;
}
-void execcd(void){
- word *a=runq->argv->words;
+
+void
+execcd(void)
+{
+ word *a = runq->argv->words;
word *cdpath;
char dir[512];
setstatus("can't cd");
- cdpath=vlook("cdpath")->val;
+ cdpath = vlook("cdpath")->val;
switch(count(a)){
default:
pfmt(err, "Usage: cd [directory]\n");
break;
case 2:
- if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
- for(;cdpath;cdpath=cdpath->next){
+ if(a->next->word[0]=='/' || cdpath==0)
+ cdpath=&nullpath;
+ for(;cdpath;cdpath = cdpath->next){
strcpy(dir, cdpath->word);
- if(dir[0]) strcat(dir, "/");
+ if(dir[0])
+ strcat(dir, "/");
strcat(dir, a->next->word);
if(dochdir(dir)>=0){
if(strlen(cdpath->word)
@@ -165,10 +179,11 @@ void execcd(void){
break;
}
}
- if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
+ if(cdpath==0)
+ pfmt(err, "Can't cd %s: %r\n", a->next->word);
break;
case 1:
- a=vlook("HOME")->val;
+ a = vlook("home")->val;
if(count(a)>=1){
if(dochdir(a->word)>=0)
setstatus("");
@@ -181,14 +196,22 @@ void execcd(void){
}
poplist();
}
-void execexit(void){
+
+void
+execexit(void)
+{
switch(count(runq->argv->words)){
- default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
- case 2: setstatus(runq->argv->words->next->word);
+ default:
+ pfmt(err, "Usage: exit [status]\nExiting anyway\n");
+ case 2:
+ setstatus(runq->argv->words->next->word);
case 1: Xexit();
}
}
-void execshift(void){
+