Introduction
Introduction Statistics Contact Development Disclaimer Help
upgraded 9base to p9p 20090731 - 9base - revived minimalist port of Plan 9 user…
git clone git://git.suckless.org/9base
Log
Files
Refs
README
LICENSE
---
commit abc072187111c9098f80518e9c8d0b81ae1577d0
parent 89cb321008eab13102fa98bd1b28caadc2c5218e
Author: Anselm R Garbe <[email protected]>
Date: Fri, 31 Jul 2009 21:02:58 +0100
upgraded 9base to p9p 20090731
Diffstat:
M Makefile | 2 +-
A awk/README | 13 +++++++++++++
M awk/awk.h | 1 +
M awk/awkgram.y | 1 +
M awk/lex.c | 3 ++-
M awk/lib.c | 27 +++++++++++++++++++++++++++
M awk/main.c | 3 ++-
M awk/maketab.c | 1 +
M awk/parse.c | 1 +
M awk/proto.h | 3 +++
M awk/re.c | 18 +++++++++---------
M awk/run.c | 25 ++++++++++++++++---------
M awk/tran.c | 1 +
M bc/bc.1 | 2 +-
M bc/bc.y | 181 ++++++++++++++++-------------…
M config.mk | 4 +++-
M dc/dc.c | 31 ++++++++---------------------…
M grep/comp.c | 6 +++---
M grep/main.c | 14 +++++++++-----
M grep/sub.c | 2 +-
M lib9/Makefile | 199 +++++++++++++++++++++++++++++…
M lib9/_exits.c | 6 +++---
M lib9/_p9dialparse.c | 5 ++---
M lib9/_p9dir.c | 144 ++++++++++++++++-------------…
M lib9/atexit.c | 4 +++-
M lib9/bio.h | 21 +++------------------
M lib9/bio/bbuffered.c | 1 -
M lib9/bio/bflush.c | 1 -
M lib9/bio/bgetc.c | 1 -
M lib9/bio/bgetd.c | 1 -
M lib9/bio/binit.c | 7 ++-----
M lib9/bio/boffset.c | 5 ++---
M lib9/bio/brdline.c | 1 -
M lib9/bio/brdstr.c | 2 --
M lib9/bio/bread.c | 1 -
M lib9/bio/bseek.c | 11 ++++-------
M lib9/bio/bvprint.c | 7 +++----
M lib9/bio/bwrite.c | 1 -
M lib9/bio/lib9.std.h | 8 +++++++-
M lib9/convD2M.c | 61 +++++++++++++++++++++++++----…
M lib9/convM2D.c | 50 ++++++++++++++++++++++++++---…
M lib9/convM2S.c | 17 ++++++++++++++++-
M lib9/convS2M.c | 28 +++++++++++++++++++++++++---
A lib9/crypt.c | 68 +++++++++++++++++++++++++++++…
M lib9/ctime.c | 157 +++++++++++++++++++++++++++--…
M lib9/debugmalloc.c | 16 ++++++++--------
M lib9/dial.c | 21 ++++++++++++++-------
M lib9/dirfwstat.c | 6 +++++-
M lib9/dirread.c | 10 ++++++++--
M lib9/dirwstat.c | 24 ++++++++++++++++++------
M lib9/encodefmt.c | 11 ++---------
M lib9/errstr.c | 2 +-
A lib9/exitcode.c | 9 +++++++++
M lib9/fcallfmt.c | 4 ++--
M lib9/fmt.h | 17 ++++++++++++++++-
M lib9/fmt/LICENSE | 19 +++++++++++--------
C lib9/fmt/LICENSE -> lib9/fmt/NOTICE | 0
C lib9/fmt/LICENSE -> lib9/fmt/README | 0
M lib9/fmt/charstod.c | 14 +-------------
M lib9/fmt/dofmt.c | 128 +++++++++++++++++++++++------…
M lib9/fmt/dorfmt.c | 25 +++++++------------------
M lib9/fmt/errfmt.c | 14 +-------------
M lib9/fmt/fltfmt.c | 748 +++++++++++++++++++++--------…
M lib9/fmt/fmt.c | 17 +++--------------
M lib9/fmt/fmtdef.h | 27 ++++++++-------------------
M lib9/fmt/fmtfd.c | 18 ++++--------------
M lib9/fmt/fmtfdflush.c | 16 ++--------------
A lib9/fmt/fmtlocale.c | 55 +++++++++++++++++++++++++++++…
M lib9/fmt/fmtlock.c | 14 +-------------
A lib9/fmt/fmtnull.c | 33 +++++++++++++++++++++++++++++…
M lib9/fmt/fmtprint.c | 14 +-------------
M lib9/fmt/fmtquote.c | 25 ++++++++++---------------
M lib9/fmt/fmtrune.c | 14 +-------------
M lib9/fmt/fmtstr.c | 15 ++-------------
M lib9/fmt/fmtvprint.c | 14 +-------------
M lib9/fmt/fprint.c | 14 +-------------
A lib9/fmt/nan.h | 4 ++++
M lib9/fmt/nan64.c | 59 ++++++++++++++++++-----------…
M lib9/fmt/plan9.h | 5 +++++
M lib9/fmt/pow10.c | 14 +-------------
M lib9/fmt/print.c | 14 +-------------
M lib9/fmt/runefmtstr.c | 15 ++-------------
M lib9/fmt/runeseprint.c | 14 +-------------
M lib9/fmt/runesmprint.c | 14 +-------------
M lib9/fmt/runesnprint.c | 14 +-------------
M lib9/fmt/runesprint.c | 14 +-------------
M lib9/fmt/runevseprint.c | 15 ++-------------
M lib9/fmt/runevsmprint.c | 21 +++++----------------
M lib9/fmt/runevsnprint.c | 15 ++-------------
M lib9/fmt/seprint.c | 14 +-------------
M lib9/fmt/smprint.c | 14 +-------------
M lib9/fmt/snprint.c | 14 +-------------
M lib9/fmt/sprint.c | 21 ++++++---------------
M lib9/fmt/strtod.c | 20 ++++----------------
M lib9/fmt/test.c | 35 +++++++++++++++++++----------…
M lib9/fmt/vfprint.c | 14 +-------------
M lib9/fmt/vseprint.c | 15 ++-------------
M lib9/fmt/vsmprint.c | 21 +++++----------------
M lib9/fmt/vsnprint.c | 15 ++-------------
A lib9/getcallerpc-arm.c | 8 ++++++++
M lib9/getnetconn.c | 4 ++--
M lib9/getns.c | 25 ++++++++++++++++++++++++-
M lib9/lib9.h | 19 ++-----------------
M lib9/libc.h | 17 ++++++++++++-----
M lib9/malloctag.c | 4 ----
M lib9/nan.c | 2 +-
A lib9/netcrypt.c | 18 ++++++++++++++++++
M lib9/netmkaddr.c | 38 +++++++++++++++++++----------…
M lib9/notify.c | 9 +++++----
M lib9/nrand.c | 2 --
M lib9/nulldir.c | 2 +-
M lib9/opentemp.c | 13 +++++++++----
A lib9/pin.c | 11 +++++++++++
M lib9/portdate | 85 ++++++++++++++++++++---------…
M lib9/post9p.c | 93 +++++++++++++++++++++--------…
M lib9/rand.c | 3 ---
M lib9/readn.c | 1 -
M lib9/regex/regcomp.c | 10 +++++-----
M lib9/regex/regexec.c | 2 +-
M lib9/regex/rregexec.c | 19 +++++++++----------
M lib9/rfork.c | 10 +++++++---
M lib9/sendfd.c | 5 ++++-
M lib9/sleep.c | 12 ++++++++++++
M lib9/sysfatal.c | 5 -----
A lib9/test.c | 8 ++++++++
A lib9/testfltfmt.c | 183 +++++++++++++++++++++++++++++…
A lib9/testfmt.c | 148 +++++++++++++++++++++++++++++…
A lib9/testprint.c | 14 ++++++++++++++
A lib9/tm2sec.c | 110 +++++++++++++++++++++++++++++…
M lib9/truerand.c | 2 +-
M lib9/u.h | 23 ++++++++++++++++++++---
M lib9/utf.h | 2 +-
A lib9/utf/NOTICE | 13 +++++++++++++
A lib9/utf/README | 13 +++++++++++++
C lib9/lib9.h -> lib9/utf/lib9.h | 0
M lib9/utf/rune.c | 2 +-
M lib9/utf/utfecpy.c | 1 +
A lib9/write.c | 23 +++++++++++++++++++++++
A lib9/zoneinfo.c | 215 +++++++++++++++++++++++++++++…
A lib9/zoneinfo.h | 19 +++++++++++++++++++
M ls/ls.c | 11 +++++------
D mk/Makefile | 37 -----------------------------…
D mk/NOTICE | 27 ---------------------------
D mk/README | 7 -------
D mk/arc.c | 52 -----------------------------…
D mk/archive.c | 253 -----------------------------…
D mk/bufblock.c | 88 -----------------------------…
D mk/env.c | 149 -----------------------------…
D mk/file.c | 90 -----------------------------…
D mk/fns.h | 88 -----------------------------…
D mk/graph.c | 279 -----------------------------…
D mk/job.c | 33 -----------------------------…
D mk/lex.c | 146 -----------------------------…
D mk/main.c | 287 -----------------------------…
D mk/match.c | 49 -----------------------------…
D mk/mk.1 | 691 -----------------------------…
D mk/mk.c | 234 -----------------------------…
D mk/mk.h | 182 -----------------------------…
D mk/parse.c | 318 -----------------------------…
D mk/rc.c | 194 ------------------------------
D mk/recipe.c | 117 -----------------------------…
D mk/rule.c | 110 -----------------------------…
D mk/run.c | 296 -----------------------------…
D mk/sh.c | 206 -----------------------------…
D mk/shell.c | 80 -----------------------------…
D mk/shprint.c | 125 -----------------------------…
D mk/symtab.c | 97 ------------------------------
D mk/sys.h | 5 -----
D mk/sys.std.h | 22 ----------------------
D mk/unix.c | 341 -----------------------------…
D mk/var.c | 41 -----------------------------…
D mk/varsub.c | 256 -----------------------------…
D mk/word.c | 180 -----------------------------…
M rc/Makefile | 3 ++-
M rc/code.c | 226 +++++++++++++++++++----------…
M rc/exec.c | 1031 ++++++++++++++++-------------…
M rc/exec.h | 10 +++++++---
M rc/fns.h | 14 ++++++++++----
M rc/getflags.c | 171 ++++++++++++++++++-----------…
M rc/glob.c | 165 +++++++++++++++++++----------…
M rc/havefork.c | 53 +++++++++++++++++++++++++----…
M rc/here.c | 97 ++++++++++++++++++-----------…
M rc/io.c | 231 +++++++++++++++++++++--------…
M rc/io.h | 6 +++---
M rc/lex.c | 280 ++++++++++++++++++-----------…
M rc/pcmd.c | 107 +++++++++++++++++++++--------…
M rc/pfnc.c | 16 ++++++++++------
M rc/plan9ish.c | 71 +++++++++++++++++++++++++++--…
M rc/rc.1 | 5 +++++
M rc/rc.h | 3 ++-
M rc/simple.c | 331 ++++++++++++++++++-----------…
M rc/subr.c | 48 +++++++++++++++++++++--------…
M rc/trap.c | 25 ++++++++++++++-----------
M rc/tree.c | 132 +++++++++++++++++++----------…
M rc/unixcrap.c | 25 +++++++++++++++++++++++++
M rc/var.c | 98 ++++++++++++++++++++++-------…
M sed/sed.1 | 10 ++++++----
M sed/sed.c | 12 +++++++++---
M sort/sort.c | 7 +++----
M test/test.1 | 4 ++--
M test/test.c | 159 +++++++++++++++++++++++++++--…
M touch/touch.c | 10 ++++++++--
M yacc/yacc.c | 4 ++--
203 files changed, 4891 insertions(+), 7638 deletions(-)
---
diff --git a/Makefile b/Makefile
@@ -4,7 +4,7 @@
include config.mk
SUBDIRS = lib9 yacc awk basename bc dc cat cleanname date echo grep ls \
- mk rc read sed seq sleep sort tee test touch tr uniq
+ rc read sed seq sleep sort tee test touch tr uniq
all:
@echo 9base build options:
diff --git a/awk/README b/awk/README
@@ -0,0 +1,13 @@
+This 'awk' source is directly downloaded from the Plan 9 source
+
+http://cm.bell-labs.com/sources/plan9/sys/src/cmd/awk/
+
+as such, it's copyright is held by Lucent Technologies and distributed under t…
+Lucent Public License version 1.02 [http://www.opensource.org/licenses/lucent1…
+
+Modifications were made by Jeff Sickel in order to build using Plan 9 from User
+Space [http://swtch.com/plan9port/] to the following files:
+
+ mkfile
+ re.c
+
diff --git a/awk/awk.h b/awk/awk.h
@@ -182,3 +182,4 @@ extern int pairstack[], paircnt;
#define freeable(p) ( ((p)->tval & (STR|DONTFREE)) == STR )
#include "proto.h"
+
diff --git a/awk/awkgram.y b/awk/awkgram.y
@@ -486,3 +486,4 @@ void checkdup(Node *vl, Cell *cp) /* check if name a…
}
}
}
+
diff --git a/awk/lex.c b/awk/lex.c
@@ -86,8 +86,8 @@ Keyword keywords[] ={ /* keep sorted: binary searched …
{ "system", FSYSTEM, BLTIN },
{ "tolower", FTOLOWER, BLTIN },
{ "toupper", FTOUPPER, BLTIN },
- { "while", WHILE, WHILE },
{ "utf", FUTF, BLTIN },
+ { "while", WHILE, WHILE },
};
#define DEBUG
@@ -567,3 +567,4 @@ void unputstr(char *s) /* put a string back on input…
for (i = strlen(s)-1; i >= 0; i--)
unput(s[i]);
}
+
diff --git a/awk/lib.c b/awk/lib.c
@@ -673,6 +673,32 @@ int is_number(char *s)
{
double r;
char *ep;
+
+ /*
+ * fast could-it-be-a-number check before calling strtod,
+ * which takes a surprisingly long time to reject non-numbers.
+ */
+ switch (*s) {
+ case '0': case '1': case '2': case '3': case '4':
+ case '5': case '6': case '7': case '8': case '9':
+ case '\t':
+ case '\n':
+ case '\v':
+ case '\f':
+ case '\r':
+ case ' ':
+ case '-':
+ case '+':
+ case '.':
+ case 'n': /* nans */
+ case 'N':
+ case 'i': /* infs */
+ case 'I':
+ break;
+ default:
+ return 0; /* can't be a number */
+ }
+
errno = 0;
r = strtod(s, &ep);
if (ep == s || r == HUGE_VAL || errno == ERANGE)
@@ -684,3 +710,4 @@ int is_number(char *s)
else
return 0;
}
+
diff --git a/awk/main.c b/awk/main.c
@@ -57,7 +57,7 @@ int main(int argc, char *argv[])
cmdname = argv[0];
if (argc == 1) {
- fprintf(stderr, "Usage: %s [-f programfile | 'program'] [-Ffie…
+ fprintf(stderr, "Usage: %s [-F fieldsep] [-mf n] [-mr n] [-v v…
exit(1);
}
signal(SIGFPE, fpecatch);
@@ -195,3 +195,4 @@ char *cursource(void) /* current source file name */
else
return NULL;
}
+
diff --git a/awk/maketab.c b/awk/maketab.c
@@ -166,3 +166,4 @@ int main(int argc, char *argv[])
printf("}\n");
return 0;
}
+
diff --git a/awk/parse.c b/awk/parse.c
@@ -269,3 +269,4 @@ Node *itonp(int i) /* and vice versa */
{
return (Node *) (long) i;
}
+
diff --git a/awk/proto.h b/awk/proto.h
@@ -22,6 +22,8 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF
THIS SOFTWARE.
****************************************************************/
+#define getline p9getline
+
extern int yywrap(void);
extern void setfname(Cell *);
extern int constnode(Node *);
@@ -175,3 +177,4 @@ extern Cell *gsub(Node **, int);
extern FILE *popen(const char *, const char *);
extern int pclose(FILE *);
+
diff --git a/awk/re.c b/awk/re.c
@@ -25,15 +25,13 @@ THIS SOFTWARE.
#define DEBUG
#include <stdio.h>
+#include <u.h>
+#include <libc.h>
#include <ctype.h>
-#include <setjmp.h>
-#include <math.h>
-#include <string.h>
-#include <stdlib.h>
-#include <time.h>
+#include <bio.h>
+#include <regexp.h>
#include "awk.h"
#include "y.tab.h"
-#include "regexp.h"
/* This file provides the interface between the main body of
* awk and the pattern matching package. It preprocesses
@@ -187,7 +185,7 @@ void
/* T/F match indication - matched string not exported */
int
-match(void *p, char *s, char *q)
+match(void *p, char *s, char *start)
{
return regexec((Reprog *) p, (char *) s, 0, 0);
}
@@ -222,10 +220,11 @@ nematch(void *p, char *s, char *start)
}
/* in the parsing of regular expressions, metacharacters like . have */
/* to be seen literally; \056 is not a metacharacter. */
-int
+
+int
hexstr(char **pp) /* find and eval hex string at pp, return new p */
{
- int c;
+ char c;
int n = 0;
int i;
@@ -323,3 +322,4 @@ overflow(void)
{
FATAL("%s", "regular expression too big");
}
+
diff --git a/awk/run.c b/awk/run.c
@@ -133,6 +133,7 @@ void run(Node *a) /* execution of parse tree starts …
Cell *execute(Node *u) /* execute a node of the parse tree */
{
+ int nobj;
Cell *(*proc)(Node **, int);
Cell *x;
Node *a;
@@ -149,10 +150,11 @@ Cell *execute(Node *u) /* execute a node of the pa…
recbld();
return(x);
}
- if (notlegal(a->nobj)) /* probably a Cell* but too risk…
+ nobj = a->nobj;
+ if (notlegal(nobj)) /* probably a Cell* but too risky t…
FATAL("illegal statement");
- proc = proctab[a->nobj-FIRSTTOKEN];
- x = (*proc)(a->narg, a->nobj);
+ proc = proctab[nobj-FIRSTTOKEN];
+ x = (*proc)(a->narg, nobj);
if (isfld(x) && !donefld)
fldbld();
else if (isrec(x) && !donerec)
@@ -901,8 +903,10 @@ int format(char **pbuf, int *pbufsize, char *s, Node *a) …
if (isnum(x)) {
if (getfval(x))
sprintf(p, fmt, (int) getfval(x));
- else
+ else{
*p++ = '\0';
+ *p = '\0';
+ }
} else
sprintf(p, fmt, getsval(x)[0]);
break;
@@ -1540,6 +1544,7 @@ Cell *bltin(Node **a, int n) /* builtin functions.…
Cell *printstat(Node **a, int n) /* print a[0] */
{
+ int r;
Node *x;
Cell *y;
FILE *fp;
@@ -1553,14 +1558,15 @@ Cell *printstat(Node **a, int n) /* print a[0] */
fputs(getsval(y), fp);
tempfree(y);
if (x->nnext == NULL)
- fputs(*ORS, fp);
+ r = fputs(*ORS, fp);
else
- fputs(*OFS, fp);
+ r = fputs(*OFS, fp);
+ if (r == EOF)
+ FATAL("write error on %s", filename(fp));
}
if (a[1] != 0)
- fflush(fp);
- if (ferror(fp))
- FATAL("write error on %s", filename(fp));
+ if (fflush(fp) == EOF)
+ FATAL("write error on %s", filename(fp));
return(True);
}
@@ -1890,3 +1896,4 @@ void backsub(char **pb_ptr, char **sptr_ptr) /* ha…
*pb_ptr = pb;
*sptr_ptr = sptr;
}
+
diff --git a/awk/tran.c b/awk/tran.c
@@ -432,3 +432,4 @@ char *qstring(char *s, int delim) /* collect string …
*bp++ = 0;
return buf;
}
+
diff --git a/bc/bc.1 b/bc/bc.1
@@ -159,7 +159,7 @@ Function definitions
.B ,
.I L
.B ){
-.PD
+.PD0
.br
.B auto
.I L
diff --git a/bc/bc.y b/bc/bc.y
@@ -6,10 +6,8 @@
#define bsp_max 5000
Biobuf *in;
- #define stdin bstdin
- #define stdout bstdout
- Biobuf stdin;
- Biobuf stdout;
+ Biobuf bstdin;
+ Biobuf bstdout;
char cary[1000];
char* cp = { cary };
char string[1000];
@@ -19,7 +17,7 @@
int bindx = 0;
int lev = 0;
int ln;
- int* ttp;
+ char* ttp;
char* ss = "";
int bstack[10] = { 0 };
char* numb[15] =
@@ -28,8 +26,8 @@
" 6", " 7", " 8", " 9", " 10", " 11",
" 12", " 13", " 14"
};
- int* pre;
- int* post;
+ char* pre;
+ char* post;
long peekc = -1;
int sargc;
@@ -61,40 +59,39 @@
"u","v","w","x","y","z"
};
char* dot = { "." };
- int bspace[bsp_max];
- int* bsp_nxt = { bspace };
+ char* bspace[bsp_max];
+ char** bsp_nxt = bspace;
int bdebug = 0;
int lflag;
int cflag;
int sflag;
- int* bundle(int, ...);
- void conout(int*, char*);
+ char* bundle(int, ...);
+ void conout(char*, char*);
int cpeek(int, int, int);
int getch(void);
- int* geta(char*);
- int* getf(char*);
+ char* geta(char*);
+ char* getf(char*);
void getout(void);
- void output(int*);
+ void output(char*);
void pp(char*);
- void routput(int*);
+ void routput(char*);
void tp(char*);
void yyerror(char*, ...);
int yyparse(void);
typedef void* pointer;
-/* #pragma varargck type "lx" pointer */
+ #pragma varargck type "lx" pointer
%}
%union
{
- int* iptr;
char* cptr;
int cc;
}
-%type <iptr> pstat stat stat1 def slist dlets e ase nase
-%type <iptr> slist re fprefix cargs eora cons constant lora
+%type <cptr> pstat stat stat1 def slist dlets e ase nase
+%type <cptr> slist re fprefix cargs eora cons constant lora
%type <cptr> crs
%token <cptr> LETTER EQOP _AUTO DOT
@@ -124,7 +121,7 @@ stuff:
ttp = bundle(6, pre, $6, post , "0", numb[lev], "Q");
conout(ttp, (char*)$1);
rcrs = crs;
- output((int*)""); /* this is horse puk!! */
+ output("");
lev = bindx = 0;
}
@@ -550,8 +547,8 @@ def:
_DEFINE LETTER '('
{
$$ = getf($2);
- pre = (int*)"";
- post = (int*)"";
+ pre = (char*)"";
+ post = (char*)"";
lev = 1;
bindx = 0;
bstack[bindx] = 0;
@@ -789,76 +786,85 @@ loop:
peekc = -1;
if(ch >= 0)
return ch;
+
ifile++;
- if(ifile > sargc) {
- if(ifile >= sargc+2)
+ if(ifile >= sargc) {
+ if(ifile >= sargc+1)
getout();
- in = &stdin;
+ in = &bstdin;
Binit(in, 0, OREAD);
ln = 0;
goto loop;
}
- Bterm(in);
+ if(in)
+ Bterm(in);
if((in = Bopen(sargv[ifile], OREAD)) != 0){
ln = 0;
ss = sargv[ifile];
goto loop;
}
+ fprint(2, "open %s: %r\n", sargv[ifile]);
yyerror("cannot open input file");
return 0; /* shut up ken */
}
-int*
+char*
bundle(int a, ...)
{
- int i, *p, *q;
-
- p = &a;
- i = *p++;
+ int i;
+ char **q;
+ va_list arg;
+
+ i = a;
+ va_start(arg, a);
q = bsp_nxt;
if(bdebug)
fprint(2, "bundle %d elements at %lx\n", i, q);
while(i-- > 0) {
if(bsp_nxt >= &bspace[bsp_max])
yyerror("bundling space exceeded");
- *bsp_nxt++ = *p++;
+ *bsp_nxt++ = va_arg(arg, char*);
}
*bsp_nxt++ = 0;
- yyval.iptr = q;
- return q;
+ va_end(arg);
+ yyval.cptr = (char*)q;
+ return (char*)q;
}
void
-routput(int *p)
+routput(char *p)
{
+ char **pp;
+
if(bdebug)
fprint(2, "routput(%lx)\n", p);
- if(p >= &bspace[0] && p < &bspace[bsp_max]) {
+ if((char**)p >= &bspace[0] && (char**)p < &bspace[bsp_max]) {
/* part of a bundle */
- while(*p != 0)
- routput((int*)(*p++));
+ pp = (char**)p;
+ while(*pp != 0)
+ routput(*pp++);
} else
- Bprint(&stdout, (char*)p); /* character string */
+ Bprint(&bstdout, p); /* character string */
}
void
-output(int *p)
+output(char *p)
{
routput(p);
bsp_nxt = &bspace[0];
- Bprint(&stdout, "\n");
- Bflush(&stdout);
+ Bprint(&bstdout, "\n");
+ Bflush(&bstdout);
cp = cary;
crs = rcrs;
}
void
-conout(int *p, char *s)
+conout(char *p, char *s)
{
- Bprint(&stdout, "[");
+ Bprint(&bstdout, "[");
routput(p);
- Bprint(&stdout, "]s%s\n", s);
- Bflush(&stdout);
+ Bprint(&bstdout, "]s%s\n", s);
+ Bflush(&bstdout);
lev--;
}
@@ -867,8 +873,8 @@ yyerror(char *s, ...)
{
if(ifile > sargc)
ss = "teletype";
- Bprint(&stdout, "c[%s on line %d, %s]pc\n", s, ln+1, ss);
- Bflush(&stdout);
+ Bprint(&bstdout, "c[%s:%d, %s]pc\n", s, ln+1, ss);
+ Bflush(&bstdout);
cp = cary;
crs = rcrs;
bindx = 0;
@@ -881,9 +887,9 @@ pp(char *s)
{
/* puts the relevant stuff on pre and post for the letter s */
bundle(3, "S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
}
void
@@ -891,45 +897,45 @@ tp(char *s)
{
/* same as pp, but for temps */
bundle(3, "0S", s, pre);
- pre = yyval.iptr;
+ pre = yyval.cptr;
bundle(4, post, "L", s, "s.");
- post = yyval.iptr;
+ post = yyval.cptr;
}
void
yyinit(int argc, char **argv)
{
- Binit(&stdout, 1, OWRITE);
+ Binit(&bstdout, 1, OWRITE);
sargv = argv;
- sargc = argc - 1;
+ sargc = argc;
if(sargc == 0) {
- in = &stdin;
+ in = &bstdin;
Binit(in, 0, OREAD);
- } else if((in = Bopen(sargv[1], OREAD)) == 0)
+ } else if((in = Bopen(sargv[0], OREAD)) == 0)
yyerror("cannot open input file");
- ifile = 1;
+ ifile = 0;
ln = 0;
- ss = sargv[1];
+ ss = sargv[0];
}
void
getout(void)
{
- Bprint(&stdout, "q");
- Bflush(&stdout);
+ Bprint(&bstdout, "q");
+ Bflush(&bstdout);
exits(0);
}
-int*
+char*
getf(char *p)
{
- return (int*)funtab[*p - 'a'];
+ return funtab[*p - 'a'];
}
-int*
+char*
geta(char *p)
{
- return (int*)atab[*p - 'a'];
+ return atab[*p - 'a'];
}
void
@@ -937,37 +943,34 @@ main(int argc, char **argv)
{
int p[2];
- while(argc > 1 && *argv[1] == '-') {
- switch(argv[1][1]) {
- case 'd':
- bdebug++;
- break;
- case 'c':
- cflag++;
- break;
- case 'l':
- lflag++;
- break;
- case 's':
- sflag++;
- break;
- default:
- fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
- exits("usage");
- }
- argc--;
- argv++;
- }
+ ARGBEGIN{
+ case 'd':
+ bdebug++;
+ break;
+ case 'c':
+ cflag++;
+ break;
+ case 'l':
+ lflag++;
+ break;
+ case 's':
+ sflag++;
+ break;
+ default:
+ fprint(2, "Usage: bc [-l] [-c] [file ...]\n");
+ exits("usage");
+ }ARGEND
+
if(lflag) {
- argv--;
argc++;
- argv[1] = unsharp("#9/lib/bclib");
+ argv--;
+ *argv = unsharp("#9/lib/bclib");
}
if(cflag) {
yyinit(argc, argv);
for(;;)
yyparse();
- /* exits(0); */
+ exits(0);
}
pipe(p);
if(fork() == 0) {
@@ -981,5 +984,5 @@ main(int argc, char **argv)
dup(p[0], 0);
close(p[0]);
close(p[1]);
- execlp("dc", "dc", (char*)0);
+ execl(unsharp("#9/bin/dc"), "dc", nil);
}
diff --git a/config.mk b/config.mk
@@ -4,7 +4,9 @@
PREFIX = /usr/local/9
MANPREFIX = ${PREFIX}/share/man
-VERSION = 20060209
+VERSION = 200907
+# 386, arm, etc31
+OBJTYPE = x86_64
# Linux/BSD
CFLAGS = -Wall -Wno-missing-braces -Wno-parentheses -Wno-switch -c -I. -D…
diff --git a/dc/dc.c b/dc/dc.c
@@ -165,7 +165,6 @@ void release(Blk *p);
Blk* dcgetwd(Blk *p);
void putwd(Blk *p, Blk *c);
Blk* lookwd(Blk *p);
-char* nalloc(char *p, unsigned nbytes);
int getstk(void);
/********debug only**/
@@ -1222,7 +1221,7 @@ init(int argc, char *argv[])
readptr = &readstk[0];
k=0;
sp = sptr = &symlst[0];
- while(sptr < &symlst[TBLSZ]) {
+ while(sptr < &symlst[TBLSZ-1]) {
sptr->next = ++sp;
sptr++;
}
@@ -2103,14 +2102,13 @@ copy(Blk *hptr, int size)
if(size > maxsize)
maxsize = size;
sz = length(hptr);
- ptr = nalloc(hptr->beg, size);
+ ptr = malloc(size);
if(ptr == 0) {
- garbage("copy");
- if((ptr = nalloc(hptr->beg, size)) == 0) {
- Bprint(&bout,"copy size %d\n",size);
- ospace("copy");
- }
+ Bprint(&bout,"copy size %d\n",size);
+ ospace("copy");
}
+ memmove(ptr, hptr->beg, sz);
+ memset(ptr+sz, 0, size-sz);
if((hdr = hfree) == 0)
hdr = morehd();
hfree = (Blk *)hdr->rd;
@@ -2149,7 +2147,7 @@ seekc(Blk *hptr, int n)
lbytes += nn - hptr->last;
if(n > longest)
longest = n;
-/* free(hptr->beg); *//**/
+/* free(hptr->beg); */
p = realloc(hptr->beg, n);
if(p == 0) {
/* hptr->beg = realloc(hptr->beg, hptr->last-hptr->beg);
@@ -2194,7 +2192,7 @@ more(Blk *hptr)
longest = size;
lbytes += size/2;
lmore++;
-/* free(hptr->beg);*//**/
+/* free(hptr->beg);*/
p = realloc(hptr->beg, size);
if(p == 0) {
@@ -2269,19 +2267,6 @@ lookwd(Blk *p)
return(*wp->rdw);
}
-char*
-nalloc(char *p, unsigned nbytes)
-{
- char *q, *r;
-
- q = r = malloc(nbytes);
- if(q==0)
- return(0);
- while(nbytes--)
- *q++ = *p++;
- return(r);
-}
-
int
getstk(void)
{
diff --git a/grep/comp.c b/grep/comp.c
@@ -128,12 +128,12 @@ loop:
Rune tab1[] =
{
0x007f,
- 0x07ff,
+ 0x07ff
};
Rune tab2[] =
{
0x003f,
- 0x0fff,
+ 0x0fff
};
Re2
@@ -144,7 +144,7 @@ rclass(Rune p0, Rune p1)
Re2 x;
if(p0 > p1)
- return re2char(0xff, 0xff); // no match
+ return re2char(0xff, 0xff); /* no match */
/*
* bust range into same length
diff --git a/grep/main.c b/grep/main.c
@@ -21,6 +21,10 @@ main(int argc, char *argv[])
flags[ARGC()]++;
break;
+ case 'q': /* gnu grep -q means plan 9 grep -s */
+ flags['s']++;
+ break;
+
case 'E': /* ignore, turns gnu grep into egrep */
break;
@@ -170,11 +174,11 @@ loop:
increment(s, c);
goto loop;
}
-// if(flags['2'])
-// if(s->match)
-// print("%d: %.2x**\n", s, c);
-// else
-// print("%d: %.2x\n", s, c);
+/* if(flags['2']) */
+/* if(s->match) */
+/* print("%d: %.2x**\n", s, c); */
+/* else */
+/* print("%d: %.2x\n", s, c); */
lp++;
s = ns;
if(c == '\n') {
diff --git a/grep/sub.c b/grep/sub.c
@@ -30,7 +30,7 @@ sal(int n)
State *s;
s = mal(sizeof(*s));
-// s->next = mal(256*sizeof(*s->next));
+/* s->next = mal(256*sizeof(*s->next)); */
s->count = n;
s->re = mal(n*sizeof(*state0->re));
return s;
diff --git a/lib9/Makefile b/lib9/Makefile
@@ -15,16 +15,203 @@ include ../config.mk
LIB=lib9.a
TARG=lib9
+O=o
# following objects are not compiled for several reasons
-# crypt.o
-# netcrypt.o
-# convD2M.o
-# convM2D.o
-# convM2S.o
-# convS2M.o
+# crypt.$(O)
+# netcrypt.$(O)
+# convD2M.$(O)
+# convM2D.$(O)
+# convM2S.$(O)
+# convS2M.$(O)
+
+NUM=\
+ fmt/charstod.$(O)\
+ fmt/pow10.$(O)\
+
+FMTOFILES=\
+ fmt/dofmt.$(O)\
+ fmt/fltfmt.$(O)\
+ fmt/fmt.$(O)\
+ fmt/fmtfd.$(O)\
+ fmt/fmtfdflush.$(O)\
+ fmt/fmtlocale.$(O)\
+ fmtlock2.$(O)\
+ fmt/fmtnull.$(O)\
+ fmt/fmtprint.$(O)\
+ fmt/fmtquote.$(O)\
+ fmt/fmtrune.$(O)\
+ fmt/fmtstr.$(O)\
+ fmt/fmtvprint.$(O)\
+ fmt/fprint.$(O)\
+ fmt/nan64.$(O)\
+ fmt/print.$(O)\
+ fmt/runefmtstr.$(O)\
+ fmt/runeseprint.$(O)\
+ fmt/runesmprint.$(O)\
+ fmt/runesnprint.$(O)\
+ fmt/runesprint.$(O)\
+ fmt/runevseprint.$(O)\
+ fmt/runevsmprint.$(O)\
+ fmt/runevsnprint.$(O)\
+ fmt/seprint.$(O)\
+ fmt/smprint.$(O)\
+ fmt/snprint.$(O)\
+ fmt/sprint.$(O)\
+ fmt/strtod.$(O)\
+ fmt/vfprint.$(O)\
+ fmt/vseprint.$(O)\
+ fmt/vsmprint.$(O)\
+ fmt/vsnprint.$(O)\
+ $(NUM)\
+
+UTFOFILES=\
+ utf/rune.$(O)\
+ utf/runestrcat.$(O)\
+ utf/runestrchr.$(O)\
+ utf/runestrcmp.$(O)\
+ utf/runestrcpy.$(O)\
+ utf/runestrdup.$(O)\
+ utf/runestrlen.$(O)\
+ utf/runestrecpy.$(O)\
+ utf/runestrncat.$(O)\
+ utf/runestrncmp.$(O)\
+ utf/runestrncpy.$(O)\
+ utf/runestrrchr.$(O)\
+ utf/runestrstr.$(O)\
+ utf/runetype.$(O)\
+ utf/utfecpy.$(O)\
+ utf/utflen.$(O)\
+ utf/utfnlen.$(O)\
+ utf/utfrrune.$(O)\
+ utf/utfrune.$(O)\
+ utf/utfutf.$(O)\
+
+BIOFILES=\
+ bio/bbuffered.$(O)\
+ bio/bfildes.$(O)\
+ bio/bflush.$(O)\
+ bio/bgetc.$(O)\
+ bio/bgetrune.$(O)\
+ bio/bgetd.$(O)\
+ bio/binit.$(O)\
+ bio/boffset.$(O)\
+ bio/bprint.$(O)\
+ bio/bputc.$(O)\
+ bio/bputrune.$(O)\
+ bio/brdline.$(O)\
+ bio/brdstr.$(O)\
+ bio/bread.$(O)\
+ bio/bseek.$(O)\
+ bio/bvprint.$(O)\
+ bio/bwrite.$(O)\
+
+REGEXFILES=\
+ regex/regcomp.$(O)\
+ regex/regerror.$(O)\
+ regex/regexec.$(O)\
+ regex/regsub.$(O)\
+ regex/regaux.$(O)\
+ regex/rregexec.$(O)\
+ regex/rregsub.$(O)\
+
+LIB9OFILES=\
+ _exits.$(O)\
+ _p9dialparse.$(O)\
+ _p9dir.$(O)\
+ announce.$(O)\
+ argv0.$(O)\
+ atexit.$(O)\
+ atoi.$(O)\
+ atol.$(O)\
+ atoll.$(O)\
+ atnotify.$(O)\
+ await.$(O)\
+ cistrcmp.$(O)\
+ cistrncmp.$(O)\
+ cistrstr.$(O)\
+ cleanname.$(O)\
+ create.$(O)\
+ ctime.$(O)\
+ dial.$(O)\
+ dirfstat.$(O)\
+ dirfwstat.$(O)\
+ dirmodefmt.$(O)\
+ dirread.$(O)\
+ dirstat.$(O)\
+ dirwstat.$(O)\
+ dup.$(O)\
+ encodefmt.$(O)\
+ errstr.$(O)\
+ exec.$(O)\
+ execl.$(O)\
+ exitcode.$(O)\
+ fcallfmt.$(O)\
+ get9root.$(O)\
+ getcallerpc-$(OBJTYPE).$(O)\
+ getenv.$(O)\
+ getfields.$(O)\
+ getnetconn.$(O)\
+ getns.$(O)\
+ getuser.$(O)\
+ getwd.$(O)\
+ jmp.$(O)\
+ lrand.$(O)\
+ lnrand.$(O)\
+ main.$(O)\
+ malloc.$(O)\
+ malloctag.$(O)\
+ mallocz.$(O)\
+ nan.$(O)\
+ needsrcquote.$(O)\
+ needstack.$(O)\
+ netmkaddr.$(O)\
+ notify.$(O)\
+ nrand.$(O)\
+ nulldir.$(O)\
+ open.$(O)\
+ opentemp.$(O)\
+ pin.$(O)\
+ pipe.$(O)\
+ post9p.$(O)\
+ postnote.$(O)\
+ qlock.$(O)\
+ quote.$(O)\
+ rand.$(O)\
+ read9pmsg.$(O)\
+ readcons.$(O)\
+ readn.$(O)\
+ rfork.$(O)\
+ searchpath.$(O)\
+ seek.$(O)\
+ sendfd.$(O)\
+ sleep.$(O)\
+ strdup.$(O)\
+ strecpy.$(O)\
+ sysfatal.$(O)\
+ syslog.$(O)\
+ sysname.$(O)\
+ time.$(O)\
+ tm2sec.$(O)\
+ tokenize.$(O)\
+ truerand.$(O)\
+ u16.$(O)\
+ u32.$(O)\
+ u64.$(O)\
+ unsharp.$(O)\
+ wait.$(O)\
+ waitpid.$(O)\
+ write.$(O)\
+ zoneinfo.$(O)\
OFILES=\
+ $(FMTOFILES)\
+ $(UTFOFILES)\
+ $(BIOFILES)\
+ $(REGEXFILES)\
+ $(LIB9OFILES)
+
+OFILESOLD=\
fmt/dofmt.o\
fmt/fltfmt.o\
fmt/fmt.o\
diff --git a/lib9/_exits.c b/lib9/_exits.c
@@ -4,7 +4,7 @@
void
_exits(char *s)
{
- if(s && *s)
- _exit(1);
- _exit(0);
+ if(s == 0 || *s == 0)
+ _exit(0);
+ _exit(exitcode(s));
}
diff --git a/lib9/_p9dialparse.c b/lib9/_p9dialparse.c
@@ -26,6 +26,8 @@ static struct {
"tcp", "venti", 17034,
"tcp", "wiki", 17035,
"tcp", "secstore", 5356,
+ "udp", "dns", 53,
+ "tcp", "dns", 53,
};
static int
@@ -82,9 +84,6 @@ p9dialparse(char *addr, char **pnet, char **punix, u32int *ph…
struct hostent *he;
struct sockaddr_un *sockun;
- if(strncmp(addr, "/net/", 5) == 0)
- addr += 5;
-
*punix = nil;
net = addr;
if((host = strchr(net, '!')) == nil){
diff --git a/lib9/_p9dir.c b/lib9/_p9dir.c
@@ -7,50 +7,67 @@
#include <pwd.h>
#include <grp.h>
-#if defined(__FreeBSD__) || defined(__OpenBSD__)
+#if defined(__APPLE__)
+#define _HAVESTGEN
+#include <sys/disk.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ u64int bc;
+ u32int bs;
+
+ bs = 0;
+ bc = 0;
+ ioctl(fd, DKIOCGETBLOCKSIZE, &bs);
+ ioctl(fd, DKIOCGETBLOCKCOUNT, &bc);
+ if(bs >0 && bc > 0)
+ return bc*bs;
+ return 0;
+}
+
+#elif defined(__FreeBSD__)
+#define _HAVESTGEN
+#include <sys/disk.h>
+#include <sys/disklabel.h>
+#include <sys/ioctl.h>
+static vlong
+disksize(int fd, struct stat *st)
+{
+ off_t mediasize;
+
+ if(ioctl(fd, DIOCGMEDIASIZE, &mediasize) >= 0)
+ return mediasize;
+ return 0;
+}
+
+#elif defined(__OpenBSD__)
+#define _HAVESTGEN
#include <sys/disklabel.h>
#include <sys/ioctl.h>
-static int diskdev[] = {
- 151, /* aacd */
- 116, /* ad */
- 157, /* ar */
- 118, /* afd */
- 133, /* amrd */
- 13, /* da */
- 102, /* fla */
- 109, /* idad */
- 95, /* md */
- 131, /* mlxd */
- 168, /* pst */
- 147, /* twed */
- 43, /* vn */
- 3, /* wd */
- 87, /* wfd */
-};
-static int
-isdisk(struct stat *st)
+static vlong
+disksize(int fd, struct stat *st)
{
- int i, dev;
+ struct disklabel lab;
+ int n;
if(!S_ISCHR(st->st_mode))
return 0;
- dev = major(st->st_rdev);
- for(i=0; i<nelem(diskdev); i++)
- if(diskdev[i] == dev)
- return 1;
- return 0;
+ if(ioctl(fd, DIOCGDINFO, &lab) < 0)
+ return 0;
+ n = minor(st->st_rdev)&7;
+ if(n >= lab.d_npartitions)
+ return 0;
+ return (vlong)lab.d_partitions[n].p_size * lab.d_secsize;
}
-#define _HAVEDISKLABEL
-#endif
-#if defined(__linux__)
+#elif defined(__linux__)
#include <linux/hdreg.h>
#include <linux/fs.h>
#include <sys/ioctl.h>
#undef major
#define major(dev) ((int)(((dev) >> 8) & 0xff))
static vlong
-disksize(int fd, int dev)
+disksize(int fd, struct stat *st)
{
u64int u64;
long l;
@@ -64,18 +81,21 @@ disksize(int fd, int dev)
return u64;
#endif
if(ioctl(fd, BLKGETSIZE, &l) >= 0)
- return (vlong)l*512;
+ return l*512;
if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
return 0;
}
-#define _HAVEDISKSIZE
-#endif
-#if !defined(__linux__) && !defined(__sun__)
-#define _HAVESTGEN
+#else
+static vlong
+disksize(int fd, struct stat *st)
+{
+ return 0;
+}
#endif
+int _p9usepwlibrary = 1;
/*
* Caching the last group and passwd looked up is
* a significant win (stupidly enough) on most systems.
@@ -122,11 +142,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir…
/* user */
if(p && st->st_uid == uid && p->pw_uid == uid)
;
- else{
+ else if(_p9usepwlibrary){
p = getpwuid(st->st_uid);
uid = st->st_uid;
}
- if(p == nil){
+ if(p == nil || st->st_uid != uid || p->pw_uid != uid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
s = tmp;
}else
@@ -145,11 +165,11 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir…
/* group */
if(g && st->st_gid == gid && g->gr_gid == gid)
;
- else{
+ else if(_p9usepwlibrary){
g = getgrgid(st->st_gid);
gid = st->st_gid;
}
- if(g == nil){
+ if(g == nil || st->st_gid != gid || g->gr_gid != gid){
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
s = tmp;
}else
@@ -173,57 +193,41 @@ _p9dir(struct stat *lst, struct stat *st, char *name, Dir…
#ifdef _HAVESTGEN
d->qid.vers = st->st_gen;
#endif
+ if(d->qid.vers == 0)
+ d->qid.vers = st->st_mtime + st->st_ctime;
d->mode = st->st_mode&0777;
d->atime = st->st_atime;
d->mtime = st->st_mtime;
d->length = st->st_size;
- if(S_ISDIR(st->st_mode)){
+ if(S_ISLNK(lst->st_mode)){ /* yes, lst not st */
+ d->mode |= DMSYMLINK;
+ d->length = lst->st_size;
+ }
+ else if(S_ISDIR(st->st_mode)){
d->length = 0;
d->mode |= DMDIR;
d->qid.type = QTDIR;
}
- if(S_ISLNK(lst->st_mode)) /* yes, lst not st */
- d->mode |= DMSYMLINK;
- if(S_ISFIFO(st->st_mode))
+ else if(S_ISFIFO(st->st_mode))
d->mode |= DMNAMEDPIPE;
- if(S_ISSOCK(st->st_mode))
+ else if(S_ISSOCK(st->st_mode))
d->mode |= DMSOCKET;
- if(S_ISBLK(st->st_mode)){
+ else if(S_ISBLK(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('b'<<16)|st->st_rdev;
}
- if(S_ISCHR(st->st_mode)){
+ else if(S_ISCHR(st->st_mode)){
d->mode |= DMDEVICE;
d->qid.path = ('c'<<16)|st->st_rdev;
}
/* fetch real size for disks */
-#ifdef _HAVEDISKSIZE
- if(S_ISBLK(st->st_mode) && (fd = open(name, O_RDONLY)) >= 0){
- d->length = disksize(fd, major(st->st_dev));
- close(fd);
- }
-#endif
-#ifdef _HAVEDISKLABEL
- if(isdisk(st)){
- int fd, n;
- struct disklabel lab;
-
- if((fd = open(name, O_RDONLY)) < 0)
- goto nosize;
- if(ioctl(fd, DIOCGDINFO, &lab) < 0)
- goto nosize;
- n = minor(st->st_rdev)&7;
- if(n >= lab.d_npartitions)
- goto nosize;
-
- d->length = (vlong)(lab.d_partitions[n].p_size) * lab.…
-
- nosize:
- if(fd >= 0)
+ if(S_ISBLK(lst->st_mode) || S_ISCHR(lst->st_mode)){
+ if((fd = open(name, O_RDONLY)) >= 0){
+ d->length = disksize(fd, st);
close(fd);
+ }
}
-#endif
}
return sz;
diff --git a/lib9/atexit.c b/lib9/atexit.c
@@ -50,5 +50,7 @@ exits(char *s)
onex[i].f = 0;
(*f)();
}
- exit(s && *s ? 1 : 0);
+ if(s == 0 || *s == 0)
+ exit(0);
+ exit(exitcode(s));
}
diff --git a/lib9/bio.h b/lib9/bio.h
@@ -8,23 +8,8 @@ extern "C" {
AUTOLIB(bio)
#endif
-#include <sys/types.h> /* for off_t */
-#include <stdarg.h>
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
-#define OREAD 0 /* open for read */
-#define OWRITE 1 /* write */
-#define ORDWR 2 /* read and write */
-#define OEXEC 3 /* execute, == read but check execute per…
-#define OTRUNC 16 /* or'ed in (except for exec), truncate…
-#define OCEXEC 32 /* or'ed in, close on exec */
-#define ORCLOSE 64 /* or'ed in, remove on close */
-#define ODIRECT 128 /* or'ed in, direct access */
-#define ONONBLOCK 256 /* or'ed in, non-blocking call */
-#define OEXCL 0x1000 /* or'ed in, exclusive use (create o…
-#define OLOCK 0x2000 /* or'ed in, lock after opening */
-#define OAPPEND 0x4000 /* or'ed in, append only */
-
typedef struct Biobuf Biobuf;
enum
@@ -52,7 +37,7 @@ struct Biobuf
int state; /* r/w/inactive */
int fid; /* open file */
int flag; /* magic if malloc'ed */
- off_t offset; /* offset of buffer in file */
+ long long offset; /* offset of buffer in file */
int bsize; /* size of buffer */
unsigned char* bbuf; /* pointer to beginning of …
unsigned char* ebuf; /* pointer to end of buffer…
@@ -85,7 +70,7 @@ long Bgetrune(Biobuf*);
int Binit(Biobuf*, int, int);
int Binits(Biobuf*, int, int, unsigned char*, int);
int Blinelen(Biobuf*);
-off_t Boffset(Biobuf*);
+long long Boffset(Biobuf*);
Biobuf* Bopen(char*, int);
int Bprint(Biobuf*, char*, ...);
int Bputc(Biobuf*, int);
@@ -93,7 +78,7 @@ int Bputrune(Biobuf*, long);
void* Brdline(Biobuf*, int);
char* Brdstr(Biobuf*, int, int);
long Bread(Biobuf*, void*, long);
-off_t Bseek(Biobuf*, off_t, int);
+long long Bseek(Biobuf*, long long, int);
int Bterm(Biobuf*);
int Bungetc(Biobuf*);
int Bungetrune(Biobuf*);
diff --git a/lib9/bio/bbuffered.c b/lib9/bio/bbuffered.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
int
Bbuffered(Biobuf *bp)
diff --git a/lib9/bio/bflush.c b/lib9/bio/bflush.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
int
Bflush(Biobuf *bp)
diff --git a/lib9/bio/bgetc.c b/lib9/bio/bgetc.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
int
Bgetc(Biobuf *bp)
diff --git a/lib9/bio/bgetd.c b/lib9/bio/bgetd.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
struct bgetd
{
diff --git a/lib9/bio/binit.c b/lib9/bio/binit.c
@@ -1,8 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-#include <stdlib.h>
-#include <unistd.h>
enum
{
@@ -125,13 +122,13 @@ Bopen(char *name, int mode)
return 0;
case OREAD:
- f = open(name, OREAD);
+ f = open(name, mode);
if(f < 0)
return 0;
break;
case OWRITE:
- f = creat(name, 0666);
+ f = create(name, mode, 0666);
if(f < 0)
return 0;
}
diff --git a/lib9/bio/boffset.c b/lib9/bio/boffset.c
@@ -1,11 +1,10 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-off_t
+vlong
Boffset(Biobuf *bp)
{
- off_t n;
+ vlong n;
switch(bp->state) {
default:
diff --git a/lib9/bio/brdline.c b/lib9/bio/brdline.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
void*
Brdline(Biobuf *bp, int delim)
diff --git a/lib9/bio/brdstr.c b/lib9/bio/brdstr.c
@@ -1,7 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <stdlib.h>
-#include <unistd.h>
static char*
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
diff --git a/lib9/bio/bread.c b/lib9/bio/bread.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
long
Bread(Biobuf *bp, void *ap, long count)
diff --git a/lib9/bio/bseek.c b/lib9/bio/bseek.c
@@ -1,13 +1,10 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
-#include <sys/types.h>
-#include <unistd.h>
-off_t
-Bseek(Biobuf *bp, off_t offset, int base)
+long long
+Bseek(Biobuf *bp, long long offset, int base)
{
- long long n, d;
+ vlong n, d;
int bufsz;
switch(bp->state) {
@@ -55,7 +52,7 @@ Bseek(Biobuf *bp, off_t offset, int base)
case Bwactive:
Bflush(bp);
- n = lseek(bp->fid, offset, base);
+ n = seek(bp->fid, offset, base);
break;
}
bp->offset = n;
diff --git a/lib9/bio/bvprint.c b/lib9/bio/bvprint.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <fmt.h>
static int
fmtBflush(Fmt *f)
@@ -30,10 +29,10 @@ Bvprint(Biobuf *bp, char *fmt, va_list arg)
f.flush = fmtBflush;
f.farg = bp;
f.nfmt = 0;
+ fmtlocaleinit(&f, nil, nil, nil);
n = fmtvprint(&f, fmt, arg);
bp->ocount = (char*)f.to - (char*)f.stop;
+ if(n == 0)
+ n = f.nfmt;
return n;
}
-
-
-
diff --git a/lib9/bio/bwrite.c b/lib9/bio/bwrite.c
@@ -1,6 +1,5 @@
#include "lib9.h"
#include <bio.h>
-#include <unistd.h>
long
Bwrite(Biobuf *bp, void *ap, long count)
diff --git a/lib9/bio/lib9.std.h b/lib9/bio/lib9.std.h
@@ -1,3 +1,6 @@
+#define _FILE_OFFSET_BITS 64
+#define _LARGEFILE64_SOURCE
+
#include <utf.h>
#include <fmt.h>
@@ -13,8 +16,11 @@
#define ORCLOSE 0
#define OTRUNC 0
-
#define nil ((void*)0)
typedef long long vlong;
typedef unsigned long long uvlong;
+
+#define seek(fd, offset, whence) lseek(fd, offset, whence)
+#define create(name, mode, perm) creat(name, perm)
+
diff --git a/lib9/convD2M.c b/lib9/convD2M.c
@@ -3,30 +3,44 @@
#include <fcall.h>
uint
-sizeD2M(Dir *d)
+sizeD2Mu(Dir *d, int dotu)
{
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr, fixlen;
sv[0] = d->name;
sv[1] = d->uid;
sv[2] = d->gid;
sv[3] = d->muid;
-
+
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
ns = 0;
- for(i = 0; i < 4; i++)
+ for(i = 0; i < nstr; i++)
if(sv[i])
ns += strlen(sv[i]);
- return STATFIXLEN + ns;
+ return fixlen + ns;
}
uint
-convD2M(Dir *d, uchar *buf, uint nbuf)
+sizeD2M(Dir *d)
+{
+ return sizeD2Mu(d, 0);
+}
+
+uint
+convD2Mu(Dir *d, uchar *buf, uint nbuf, int dotu)
{
uchar *p, *ebuf;
- char *sv[4];
- int i, ns, nsv[4], ss;
+ char *sv[5];
+ int i, ns, nsv[5], ss, nstr, fixlen;
if(nbuf < BIT16SZ)
return 0;
@@ -39,8 +53,16 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
sv[2] = d->gid;
sv[3] = d->muid;
+ fixlen = STATFIXLEN;
+ nstr = 4;
+ if(dotu){
+ fixlen = STATFIXLENU;
+ sv[4] = d->ext;
+ nstr = 5;
+ }
+
ns = 0;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
if(sv[i])
nsv[i] = strlen(sv[i]);
else
@@ -48,7 +70,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
ns += nsv[i];
}
- ss = STATFIXLEN + ns;
+ ss = fixlen + ns;
/* set size befor erroring, so user can know how much is needed */
/* note that length excludes count field itself */
@@ -77,7 +99,7 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
PBIT64(p, d->length);
p += BIT64SZ;
- for(i = 0; i < 4; i++){
+ for(i = 0; i < nstr; i++){
ns = nsv[i];
if(p + ns + BIT16SZ > ebuf)
return 0;
@@ -87,9 +109,24 @@ convD2M(Dir *d, uchar *buf, uint nbuf)
memmove(p, sv[i], ns);
p += ns;
}
+
+ if(dotu){
+ PBIT32(p, d->uidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->gidnum);
+ p += BIT32SZ;
+ PBIT32(p, d->muidnum);
+ p += BIT32SZ;
+ }
if(ss != p - buf)
return 0;
return p - buf;
}
+
+uint
+convD2M(Dir *d, uchar *buf, uint nbuf)
+{
+ return convD2Mu(d, buf, nbuf, 0);
+}
diff --git a/lib9/convM2D.c b/lib9/convM2D.c
@@ -3,10 +3,10 @@
#include <fcall.h>
int
-statcheck(uchar *buf, uint nbuf)
+statchecku(uchar *buf, uint nbuf, int dotu)
{
uchar *ebuf;
- int i;
+ int i, nstr;
ebuf = buf + nbuf;
@@ -15,26 +15,38 @@ statcheck(uchar *buf, uint nbuf)
buf += STATFIXLEN - 4 * BIT16SZ;
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
if(buf + BIT16SZ > ebuf)
return -1;
buf += BIT16SZ + GBIT16(buf);
}
+ if(dotu)
+ buf += 3*BIT32SZ;
+
if(buf != ebuf)
return -1;
return 0;
}
+int
+statcheck(uchar *buf, uint nbuf)
+{
+ return statchecku(buf, nbuf, 0);
+}
+
static char nullstring[] = "";
uint
-convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+convM2Du(uchar *buf, uint nbuf, Dir *d, char *strs, int dotu)
{
uchar *p, *ebuf;
- char *sv[4];
- int i, ns;
+ char *sv[5];
+ int i, ns, nstr;
if(nbuf < STATFIXLEN)
return 0;
@@ -62,7 +74,10 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
d->length = GBIT64(p);
p += BIT64SZ;
- for(i = 0; i < 4; i++){
+ nstr = 4;
+ if(dotu)
+ nstr = 5;
+ for(i = 0; i < nstr; i++){
if(p + BIT16SZ > ebuf)
return 0;
ns = GBIT16(p);
@@ -78,17 +93,38 @@ convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
p += ns;
}
+ if(dotu){
+ if(p + BIT32SZ*3 > ebuf)
+ return 0;
+ d->uidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->gidnum = GBIT32(p);
+ p += BIT32SZ;
+ d->muidnum = GBIT32(p);
+ p += BIT32SZ;
+ }
+
if(strs){
d->name = sv[0];
d->uid = sv[1];
d->gid = sv[2];
d->muid = sv[3];
+ d->ext = nullstring;
+ if(dotu)
+ d->ext = sv[4];
}else{
d->name = nullstring;
d->uid = nullstring;
d->gid = nullstring;
d->muid = nullstring;
+ d->ext = nullstring;
}
return p - buf;
}
+
+uint
+convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
+{
+ return convM2Du(buf, nbuf, d, strs, 0);
+}
diff --git a/lib9/convM2S.c b/lib9/convM2S.c
@@ -48,7 +48,7 @@ gqid(uchar *p, uchar *ep, Qid *q)
* to test at end of routine.
*/
uint
-convM2S(uchar *ap, uint nap, Fcall *f)
+convM2Su(uchar *ap, uint nap, Fcall *f, int dotu)
{
uchar *p, *ep;
uint i, size;
@@ -161,6 +161,8 @@ convM2S(uchar *ap, uint nap, Fcall *f)
p += BIT32SZ;
f->mode = GBIT8(p);
p += BIT8SZ;
+ if(dotu)
+ p = gstring(p, ep, &f->extension);
break;
case Tread:
@@ -229,6 +231,13 @@ convM2S(uchar *ap, uint nap, Fcall *f)
case Rerror:
p = gstring(p, ep, &f->ename);
+ f->errornum = 0;
+ if(dotu){
+ if(p+BIT16SZ > ep)
+ return 0;
+ f->errornum = GBIT16(p);
+ p += BIT16SZ;
+ }
break;
case Rflush:
@@ -321,3 +330,9 @@ convM2S(uchar *ap, uint nap, Fcall *f)
return size;
return 0;
}
+
+uint
+convM2S(uchar *ap, uint nap, Fcall *f)
+{
+ return convM2Su(ap, nap, f, 0);
+}
diff --git a/lib9/convS2M.c b/lib9/convS2M.c
@@ -46,7 +46,7 @@ stringsz(char *s)
}
uint
-sizeS2M(Fcall *f)
+sizeS2Mu(Fcall *f, int dotu)
{
uint n;
int i;
@@ -102,6 +102,8 @@ sizeS2M(Fcall *f)
n += stringsz(f->name);
n += BIT32SZ;
n += BIT8SZ;
+ if(dotu)
+ n += stringsz(f->extension);
break;
case Tread:
@@ -141,6 +143,8 @@ sizeS2M(Fcall *f)
case Rerror:
n += stringsz(f->ename);
+ if(dotu)
+ n += BIT16SZ;
break;
case Rflush:
@@ -198,12 +202,18 @@ sizeS2M(Fcall *f)
}
uint
-convS2M(Fcall *f, uchar *ap, uint nap)
+sizeS2M(Fcall *f)
+{
+ return sizeS2Mu(f, 0);
+}
+
+uint
+convS2Mu(Fcall *f, uchar *ap, uint nap, int dotu)
{
uchar *p;
uint i, size;
- size = sizeS2M(f);
+ size = sizeS2Mu(f, dotu);
if(size == 0)
return 0;
if(size > nap)
@@ -279,6 +289,8 @@ convS2M(Fcall *f, uchar *ap, uint nap)
p += BIT32SZ;
PBIT8(p, f->mode);
p += BIT8SZ;
+ if(dotu)
+ p = pstring(p, f->extension);
break;
case Tread:
@@ -331,6 +343,10 @@ convS2M(Fcall *f, uchar *ap, uint nap)
case Rerror:
p = pstring(p, f->ename);
+ if(dotu){
+ PBIT16(p, f->errornum);
+ p += BIT16SZ;
+ }
break;
case Rflush:
@@ -397,3 +413,9 @@ convS2M(Fcall *f, uchar *ap, uint nap)
return 0;
return size;
}
+
+uint
+convS2M(Fcall *f, uchar *ap, uint nap)
+{
+ return convS2Mu(f, ap, nap, 0);
+}
diff --git a/lib9/crypt.c b/lib9/crypt.c
@@ -0,0 +1,68 @@
+/*
+ * Data Encryption Standard
+ * D.P.Mitchell 83/06/08.
+ *
+ * block_cipher(key, block, decrypting)
+ *
+ * these routines use the non-standard 7 byte format
+ * for DES keys.
+ */
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+#include <libsec.h>
+
+/*
+ * destructively encrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+encrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[32];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ for(i = 0; i < n; i++){
+ block_cipher(ekey, buf, 0);
+ buf += 7;
+ }
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 0);
+ return 1;
+}
+
+/*
+ * destructively decrypt the buffer, which
+ * must be at least 8 characters long.
+ */
+int
+decrypt(void *key, void *vbuf, int n)
+{
+ ulong ekey[128];
+ uchar *buf;
+ int i, r;
+
+ if(n < 8)
+ return 0;
+ key_setup(key, ekey);
+ buf = vbuf;
+ n--;
+ r = n % 7;
+ n /= 7;
+ buf += n * 7;
+ if(r)
+ block_cipher(ekey, buf - 7 + r, 1);
+ for(i = 0; i < n; i++){
+ buf -= 7;
+ block_cipher(ekey, buf, 1);
+ }
+ return 1;
+}
diff --git a/lib9/ctime.c b/lib9/ctime.c
@@ -1,21 +1,135 @@
+/*
+ * This routine converts time as follows.
+ * The epoch is 0000 Jan 1 1970 GMT.
+ * The argument time is in seconds since then.
+ * The localtime(t) entry returns a pointer to an array
+ * containing
+ *
+ * seconds (0-59)
+ * minutes (0-59)
+ * hours (0-23)
+ * day of month (1-31)
+ * month (0-11)
+ * year-1970
+ * weekday (0-6, Sun is 0)
+ * day of the year
+ * daylight savings flag
+ *
+ * The routine gets the daylight savings time from the environment.
+ *
+ * asctime(tvec))
+ * where tvec is produced by localtime
+ * returns a ptr to a character string
+ * that has the ascii time in the form
+ *
+ * \\
+ * Thu Jan 01 00:00:00 GMT 1970n0
+ * 012345678901234567890123456789
+ * 0 1 2
+ *
+ * ctime(t) just calls localtime, then asctime.
+ */
+
#include <u.h>
#include <libc.h>
-static
-void
-ct_numb(char *cp, int n)
+#include "zoneinfo.h"
+
+static char dmsize[12] =
{
+ 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
- cp[0] = ' ';
- if(n >= 10)
- cp[0] = (n/10)%10 + '0';
- cp[1] = n%10 + '0';
+#define dysize ctimedysize
+static int dysize(int);
+static void ct_numb(char*, int);
+
+char*
+ctime(long t)
+{
+ return asctime(localtime(t));
+}
+
+Tm*
+localtime(long tim)
+{
+ Tinfo ti;
+ Tm *ct;
+
+ if (zonelookuptinfo(&ti, tim)!=-1) {
+ ct = gmtime(tim+ti.tzoff);
+ strncpy(ct->zone, ti.zone, sizeof ct->zone);
+ ct->zone[sizeof ct->zone-1] = 0;
+ ct->tzoff = ti.tzoff;
+ return ct;
+ }
+ return gmtime(tim);
+}
+
+Tm*
+gmtime(long tim)
+{
+ int d0, d1;
+ long hms, day;
+ static Tm xtime;
+
+ /*
+ * break initial number into days
+ */
+ hms = tim % 86400L;
+ day = tim / 86400L;
+ if(hms < 0) {
+ hms += 86400L;
+ day -= 1;
+ }
+
+ /*
+ * generate hours:minutes:seconds
+ */
+ xtime.sec = hms % 60;
+ d1 = hms / 60;
+ xtime.min = d1 % 60;
+ d1 /= 60;
+ xtime.hour = d1;
+
+ /*
+ * day is the day number.
+ * generate day of the week.
+ * The addend is 4 mod 7 (1/1/1970 was Thursday)
+ */
+
+ xtime.wday = (day + 7340036L) % 7;
+
+ /*
+ * year number
+ */
+ if(day >= 0)
+ for(d1 = 1970; day >= dysize(d1); d1++)
+ day -= dysize(d1);
+ else
+ for (d1 = 1970; day < 0; d1--)
+ day += dysize(d1-1);
+ xtime.year = d1-1900;
+ xtime.yday = d0 = day;
+
+ /*
+ * generate month
+ */
+
+ if(dysize(d1) == 366)
+ dmsize[1] = 29;
+ for(d1 = 0; d0 >= dmsize[d1]; d1++)
+ d0 -= dmsize[d1];
+ dmsize[1] = 28;
+ xtime.mday = d0 + 1;
+ xtime.mon = d1;
+ strcpy(xtime.zone, "GMT");
+ return &xtime;
}
char*
asctime(Tm *t)
{
- int i;
char *ncp;
static char cbuf[30];
@@ -33,12 +147,6 @@ asctime(Tm *t)
ct_numb(cbuf+14, t->min+100);
ct_numb(cbuf+17, t->sec+100);
ncp = t->zone;
- for(i=0; i<3; i++)
- if(ncp[i] == 0)
- break;
- for(; i<3; i++)
- ncp[i] = '?';
- ncp = t->zone;
cbuf[20] = *ncp++;
cbuf[21] = *ncp++;
cbuf[22] = *ncp;
@@ -50,9 +158,24 @@ asctime(Tm *t)
return cbuf;
}
-char*
-ctime(long t)
+static
+int
+dysize(int y)
{
- return asctime(localtime(t));
+
+ if(y%4 == 0 && (y%100 != 0 || y%400 == 0))
+ return 366;
+ return 365;
+}
+
+static
+void
+ct_numb(char *cp, int n)
+{
+
+ cp[0] = ' ';
+ if(n >= 10)
+ cp[0] = (n/10)%10 + '0';
+ cp[1] = n%10 + '0';
}
diff --git a/lib9/debugmalloc.c b/lib9/debugmalloc.c
@@ -111,13 +111,13 @@ p9malloc(ulong n)
void *v;
if(n == 0)
n++;
-//fprint(2, "%s %d malloc\n", argv0, getpid());
+/*fprint(2, "%s %d malloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = malloc(n+Overhead);
v = mark(v, getcallerpc(&n), n, MallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donemalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */
return v;
}
@@ -127,13 +127,13 @@ p9free(void *v)
if(v == nil)
return;
-//fprint(2, "%s %d free\n", argv0, getpid());
+/*fprint(2, "%s %d free\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, FreeMagic);
free(v);
unlock(&malloclock);
-//fprint(2, "%s %d donefree\n", argv0, getpid());
+/*fprint(2, "%s %d donefree\n", argv0, getpid()); */
}
void*
@@ -141,26 +141,26 @@ p9calloc(ulong a, ulong b)
{
void *v;
-//fprint(2, "%s %d calloc\n", argv0, getpid());
+/*fprint(2, "%s %d calloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = calloc(a*b+Overhead, 1);
v = mark(v, getcallerpc(&a), a*b, CallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donecalloc\n", argv0, getpid());
+/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */
return v;
}
void*
p9realloc(void *v, ulong n)
{
-//fprint(2, "%s %d realloc\n", argv0, getpid());
+/*fprint(2, "%s %d realloc\n", argv0, getpid()); */
lock(&malloclock);
mallocpid = getpid();
v = mark(v, getcallerpc(&v), 0, CheckMagic);
v = realloc(v, n+Overhead);
v = mark(v, getcallerpc(&v), n, ReallocMagic);
unlock(&malloclock);
-//fprint(2, "%s %d donerealloc\n", argv0, getpid());
+/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */
return v;
}
diff --git a/lib9/dial.c b/lib9/dial.c
@@ -60,10 +60,6 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
}
free(buf);
- memset(&sa, 0, sizeof sa);
- memmove(&sa.sin_addr, &host, 4);
- sa.sin_family = AF_INET;
- sa.sin_port = htons(port);
if((s = socket(AF_INET, proto, 0)) < 0)
return -1;
@@ -98,9 +94,17 @@ p9dial(char *addr, char *local, char *dummy2, int *dummy3)
free(buf);
}
- if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
- close(s);
- return -1;
+ n = 1;
+ setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
+ if(host != 0){
+ memset(&sa, 0, sizeof sa);
+ memmove(&sa.sin_addr, &host, 4);
+ sa.sin_family = AF_INET;
+ sa.sin_port = htons(port);
+ if(connect(s, (struct sockaddr*)&sa, sizeof sa) < 0){
+ close(s);
+ return -1;
+ }
}
if(proto == SOCK_STREAM){
int one = 1;
@@ -114,6 +118,9 @@ Unix:
free(buf);
return -1;
}
+ /* Allow regular files in addition to Unix sockets. */
+ if((s = open(unix, ORDWR)) >= 0)
+ return s;
memset(&su, 0, sizeof su);
su.sun_family = AF_UNIX;
if(strlen(unix)+1 > sizeof su.sun_path){
diff --git a/lib9/dirfwstat.c b/lib9/dirfwstat.c
@@ -4,7 +4,7 @@
#include <sys/time.h>
#include <sys/stat.h>
-#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__)
+#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defi…
/* do nothing -- futimes exists and is fine */
#elif defined(__SunOS5_9__)
@@ -48,6 +48,10 @@ dirfwstat(int fd, Dir *dir)
if(futimes(fd, tv) < 0)
ret = -1;
}
+ if(~dir->length != 0){
+ if(ftruncate(fd, dir->length) < 0)
+ ret = -1;
+ }
return ret;
}
diff --git a/lib9/dirread.c b/lib9/dirread.c
@@ -18,19 +18,25 @@ mygetdents(int fd, struct dirent *buf, int n)
nn = getdirentries(fd, (void*)buf, n, &off);
return nn;
}
-#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__) || de…
+#elif defined(__APPLE__) || defined(__FreeBSD__) || defined(__OpenBSD__)
static int
mygetdents(int fd, struct dirent *buf, int n)
{
long off;
return getdirentries(fd, (void*)buf, n, &off);
}
-#elif defined(__sun__)
+#elif defined(__sun__) || defined(__NetBSD__)
static int
mygetdents(int fd, struct dirent *buf, int n)
{
return getdents(fd, (void*)buf, n);
}
+#elif defined(__AIX__)
+static int
+mygetdents(int fd, struct dirent *buf, int n)
+{
+ return getdirent(fd, (void*)buf, n);
+}
#endif
static int
diff --git a/lib9/dirwstat.c b/lib9/dirwstat.c
@@ -3,17 +3,29 @@
#include <libc.h>
#include <sys/time.h>
#include <utime.h>
+#include <sys/stat.h>
int
dirwstat(char *file, Dir *dir)
{
+ int ret;
struct utimbuf ub;
/* BUG handle more */
- if(~dir->mtime == 0)
- return 0;
-
- ub.actime = dir->mtime;
- ub.modtime = dir->mtime;
- return utime(file, &ub);
+ ret = 0;
+ if(~dir->mode != 0){
+ if(chmod(file, dir->mode) < 0)
+ ret = -1;
+ }
+ if(~dir->mtime != 0){
+ ub.actime = dir->mtime;
+ ub.modtime = dir->mtime;
+ if(utime(file, &ub) < 0)
+ ret = -1;
+ }
+ if(~dir->length != 0){
+ if(truncate(file, dir->length) < 0)
+ ret = -1;
+ }
+ return ret;
}
diff --git a/lib9/encodefmt.c b/lib9/encodefmt.c
@@ -1,11 +1,4 @@
#include <lib9.h>
-#include <ctype.h>
-#include <stdlib.h>
-#include "fmt.h"
-
-extern int enc64(char*, int, uchar*, int);
-extern int enc32(char*, int, uchar*, int);
-extern int enc16(char*, int, uchar*, int);
int
encodefmt(Fmt *f)
@@ -16,7 +9,7 @@ encodefmt(Fmt *f)
int ilen;
int rv;
uchar *b;
- char obuf[64]; // rsc optimization
+ char obuf[64]; /* rsc optimization */
b = va_arg(f->args, uchar*);
if(b == 0)
@@ -51,7 +44,7 @@ encodefmt(Fmt *f)
} else
buf = obuf;
- // convert
+ /* convert */
out = buf;
switch(f->r){
case '<':
diff --git a/lib9/errstr.c b/lib9/errstr.c
@@ -12,7 +12,7 @@
enum
{
- EPLAN9 = 0x19283745,
+ EPLAN9 = 0x19283745
};
char *(*_syserrstr)(void);
diff --git a/lib9/exitcode.c b/lib9/exitcode.c
@@ -0,0 +1,9 @@
+#include <u.h>
+#include <libc.h>
+
+int
+exitcode(char *s)
+{
+ return 1;
+}
+
diff --git a/lib9/fcallfmt.c b/lib9/fcallfmt.c
@@ -124,7 +124,7 @@ fcallfmt(Fmt *fmt)
break;
case Rstat:
p = seprint(buf, e, "Rstat tag %ud ", tag);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
@@ -135,7 +135,7 @@ fcallfmt(Fmt *fmt)
break;
case Twstat: /* 126 */
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
- if(f->nstat > sizeof tmp)
+ if(f->stat == nil || f->nstat > sizeof tmp)
seprint(p, e, " stat(%d bytes)", f->nstat);
else{
d = (Dir*)tmp;
diff --git a/lib9/fmt.h b/lib9/fmt.h
@@ -34,6 +34,18 @@ struct Fmt{
int width;
int prec;
unsigned long flags;
+ char *decimal; /* decimal point; cannot be "" */
+
+ /* For %'d */
+ char *thousands; /* separator for thousands */
+
+ /*
+ * Each char is an integer indicating #digits before next separator. V…
+ * \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in P…
+ * \x00: repeat previous indefinitely
+ * \x**: count that many
+ */
+ char *grouping; /* descriptor of separator place…
};
enum{
@@ -43,7 +55,8 @@ enum{
FmtSharp = FmtPrec << 1,
FmtSpace = FmtSharp << 1,
FmtSign = FmtSpace << 1,
- FmtZero = FmtSign << 1,
+ FmtApost = FmtSign << 1,
+ FmtZero = FmtApost << 1,
FmtUnsigned = FmtZero << 1,
FmtShort = FmtUnsigned << 1,
FmtLong = FmtShort << 1,
@@ -64,6 +77,8 @@ double fmtcharstod(int(*f)(void*), void *vp);
int fmtfdflush(Fmt *f);
int fmtfdinit(Fmt *f, int fd, char *buf, int size);
int fmtinstall(int c, int (*f)(Fmt*));
+int fmtnullinit(Fmt*);
+void fmtlocaleinit(Fmt*, char*, char*, char*);
int fmtprint(Fmt *f, char *fmt, ...);
int fmtrune(Fmt *f, int r);
int fmtrunestrcpy(Fmt *f, Rune *s);
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/LICENSE
@@ -1,19 +1,22 @@
/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
+ * The authors of this software are Rob Pike and Ken Thompson,
+ * with contributions from Mike Burrows and Sean Dorward.
+ *
+ * Copyright (c) 2002-2006 by Lucent Technologies.
+ * Portions Copyright (c) 2004 Google Inc.
+ *
* Permission to use, copy, modify, and distribute this software for any
* purpose without fee is hereby granted, provided that this entire notice
* is included in all copies of any software which is or includes a copy
* or modification of this software and in all copies of the supporting
* documentation for such software.
* THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE …
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
-*/
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES
+ * NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
+ * THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURP…
+ */
This is a Unix port of the Plan 9 formatted I/O package.
-Please send comments about the packaging
-to Russ Cox <[email protected]>.
+Please send comments about the packaging to Russ Cox <[email protected]>.
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/NOTICE
diff --git a/lib9/fmt/LICENSE b/lib9/fmt/README
diff --git a/lib9/fmt/charstod.c b/lib9/fmt/charstod.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/dofmt.c b/lib9/fmt/dofmt.c
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -97,7 +87,7 @@ __fmtflush(Fmt *f, void *t, int len)
/*
* put a formatted block of memory sz bytes long of n runes into the output bu…
- * left/right justified in a field of at least f->width charactes
+ * left/right justified in a field of at least f->width characters (if FmtWidt…
*/
int
__fmtpad(Fmt *f, int n)
@@ -139,8 +129,10 @@ __fmtcpy(Fmt *f, const void *vm, int n, int sz)
m = (char*)vm;
me = m + sz;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
@@ -194,8 +186,10 @@ __fmtrcpy(Fmt *f, const void *vm, int n)
int w;
m = (Rune*)vm;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if((fl & FmtPrec) && n > f->prec)
n = f->prec;
if(f->runes){
@@ -252,15 +246,23 @@ int
fmtstrcpy(Fmt *f, char *s)
{
int i, j;
- Rune r;
if(!s)
return __fmtcpy(f, "<nil>", 5, 5);
/* if precision is specified, make sure we don't wander off the end */
if(f->flags & FmtPrec){
+#ifdef PLAN9PORT
+ Rune r;
i = 0;
for(j=0; j<f->prec && s[i]; j++)
i += chartorune(&r, s+i);
+#else
+ /* ANSI requires precision in bytes, not Runes */
+ for(i=0; i<f->prec; i++)
+ if(s[i] == 0)
+ break;
+ j = utfnlen(s, i); /* won't print partial at end */
+#endif
return __fmtcpy(f, s, j, i);
}
return __fmtcpy(f, s, utflen(s), strlen(s));
@@ -324,10 +326,14 @@ __percentfmt(Fmt *f)
int
__ifmt(Fmt *f)
{
- char buf[70], *p, *conv;
+ char buf[140], *p, *conv;
+ /* 140: for 64 bits of binary + 3-byte sep every 4 digits */
uvlong vu;
ulong u;
int neg, base, i, n, fl, w, isv;
+ int ndig, len, excess, bytelen;
+ char *grouping;
+ char *thousands;
neg = 0;
fl = f->flags;
@@ -339,11 +345,11 @@ __ifmt(Fmt *f)
* Unsigned verbs for ANSI C
*/
switch(f->r){
- case 'x':
- case 'X':
case 'o':
- case 'u':
case 'p':
+ case 'u':
+ case 'x':
+ case 'X':
fl |= FmtUnsigned;
fl &= ~(FmtSign|FmtSpace);
break;
@@ -381,21 +387,25 @@ __ifmt(Fmt *f)
u = va_arg(f->args, int);
}
conv = "0123456789abcdef";
+ grouping = "\4"; /* for hex, octal etc. (undefined by spec but …
+ thousands = f->thousands;
switch(f->r){
case 'd':
case 'i':
case 'u':
base = 10;
- break;
- case 'x':
- base = 16;
+ grouping = f->grouping;
break;
case 'X':
- base = 16;
conv = "0123456789ABCDEF";
+ /* fall through */
+ case 'x':
+ base = 16;
+ thousands = ":";
break;
case 'b':
base = 2;
+ thousands = ":";
break;
case 'o':
base = 8;
@@ -413,7 +423,11 @@ __ifmt(Fmt *f)
}
}
p = buf + sizeof buf - 1;
- n = 0;
+ n = 0; /* in runes */
+ excess = 0; /* number of bytes > number runes */
+ ndig = 0;
+ len = utflen(thousands);
+ bytelen = strlen(thousands);
if(isv){
while(vu){
i = vu % base;
@@ -422,6 +436,12 @@ __ifmt(Fmt *f)
*p-- = ',';
n++;
}
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = conv[i];
n++;
}
@@ -433,16 +453,47 @@ __ifmt(Fmt *f)
*p-- = ',';
n++;
}
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = conv[i];
n++;
}
}
if(n == 0){
- *p-- = '0';
- n = 1;
+ /*
+ * "The result of converting a zero value with
+ * a precision of zero is no characters." - ANSI
+ *
+ * "For o conversion, # increases the precision, if and only if
+ * necessary, to force the first digit of the result to be a z…
+ * (if the value and precision are both 0, a single 0 is print…
+ */
+ if(!(fl & FmtPrec) || f->prec != 0 || (f->r == 'o' && (fl & Fm…
+ *p-- = '0';
+ n = 1;
+ if(fl & FmtApost)
+ __needsep(&ndig, &grouping);
+ }
+
+ /*
+ * Zero values don't get 0x.
+ */
+ if(f->r == 'x' || f->r == 'X')
+ fl &= ~FmtSharp;
}
- for(w = f->prec; n < w && p > buf+3; n++)
+ for(w = f->prec; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = '0';
+ }
if(neg || (fl & (FmtSign|FmtSpace)))
n++;
if(fl & FmtSharp){
@@ -456,9 +507,19 @@ __ifmt(Fmt *f)
}
}
if((fl & FmtZero) && !(fl & (FmtLeft|FmtPrec))){
- for(w = f->width; n < w && p > buf+3; n++)
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
+ for(; n < w && p > buf+3; n++){
+ if((fl & FmtApost) && __needsep(&ndig, &grouping)){
+ n += len;
+ excess += bytelen - len;
+ p -= bytelen;
+ memmove(p+1, thousands, bytelen);
+ }
*p-- = '0';
- f->width = 0;
+ }
+ f->flags &= ~FmtWidth;
}
if(fl & FmtSharp){
if(base == 16)
@@ -473,7 +534,7 @@ __ifmt(Fmt *f)
else if(fl & FmtSpace)
*p-- = ' ';
f->flags &= ~FmtPrec;
- return __fmtcpy(f, p + 1, n, n);
+ return __fmtcpy(f, p + 1, n, n + excess);
}
int
@@ -514,6 +575,9 @@ __flagfmt(Fmt *f)
case '#':
f->flags |= FmtSharp;
break;
+ case '\'':
+ f->flags |= FmtApost;
+ break;
case ' ':
f->flags |= FmtSpace;
break;
diff --git a/lib9/fmt/dorfmt.c b/lib9/fmt/dorfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -19,6 +7,7 @@
/* format the output into f->to and return the number of characters fmted */
+/* BUG: THIS FILE IS NOT UPDATED TO THE NEW SPEC */
int
dorfmt(Fmt *f, const Rune *fmt)
{
@@ -30,8 +19,8 @@ dorfmt(Fmt *f, const Rune *fmt)
nfmt = f->nfmt;
for(;;){
if(f->runes){
- rt = f->to;
- rs = f->stop;
+ rt = (Rune*)f->to;
+ rs = (Rune*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRCHAR(f, rt, rs, r);
}
@@ -41,8 +30,8 @@ dorfmt(Fmt *f, const Rune *fmt)
return f->nfmt - nfmt;
f->stop = rs;
}else{
- t = f->to;
- s = f->stop;
+ t = (char*)f->to;
+ s = (char*)f->stop;
while((r = *fmt++) && r != '%'){
FMTRUNE(f, t, f->stop, r);
}
@@ -53,7 +42,7 @@ dorfmt(Fmt *f, const Rune *fmt)
f->stop = s;
}
- fmt = __fmtdispatch(f, (Rune*)fmt, 1);
+ fmt = (Rune*)__fmtdispatch(f, (Rune*)fmt, 1);
if(fmt == nil)
return -1;
}
diff --git a/lib9/fmt/errfmt.c b/lib9/fmt/errfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <errno.h>
#include <string.h>
diff --git a/lib9/fmt/fltfmt.c b/lib9/fmt/fltfmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdio.h>
#include <math.h>
#include <float.h>
@@ -18,11 +6,12 @@
#include <stdlib.h>
#include <errno.h>
#include <stdarg.h>
-#include <ctype.h>
#include <fmt.h>
+#include <assert.h>
#include "plan9.h"
#include "fmt.h"
#include "fmtdef.h"
+#include "nan.h"
enum
{
@@ -54,8 +43,8 @@ static double pows10[] =
1e140, 1e141, 1e142, 1e143, 1e144, 1e145, 1e146, 1e147, 1e148, 1e149,
1e150, 1e151, 1e152, 1e153, 1e154, 1e155, 1e156, 1e157, 1e158, 1e159,
};
-
-#define pow10(x) fmtpow10(x)
+#define npows10 ((int)(sizeof(pows10)/sizeof(pows10[0])))
+#define pow10(x) fmtpow10(x)
static double
pow10(int n)
@@ -65,330 +54,615 @@ pow10(int n)
neg = 0;
if(n < 0){
- if(n < DBL_MIN_10_EXP){
- return 0.;
- }
neg = 1;
n = -n;
- }else if(n > DBL_MAX_10_EXP){
- return HUGE_VAL;
}
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0])))
+
+ if(n < npows10)
d = pows10[n];
else{
- d = pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d = pows10[npows10-1];
for(;;){
- n -= sizeof(pows10)/sizeof(pows10[0]) - 1;
- if(n < (int)(sizeof(pows10)/sizeof(pows10[0]))){
+ n -= npows10 - 1;
+ if(n < npows10){
d *= pows10[n];
break;
}
- d *= pows10[sizeof(pows10)/sizeof(pows10[0]) - 1];
+ d *= pows10[npows10 - 1];
}
}
- if(neg){
+ if(neg)
return 1./d;
- }
return d;
}
+/*
+ * add 1 to the decimal integer string a of length n.
+ * if 99999 overflows into 10000, return 1 to tell caller
+ * to move the virtual decimal point.
+ */
static int
-xadd(char *a, int n, int v)
+xadd1(char *a, int n)
{
char *b;
int c;
- if(n < 0 || n >= NSIGNIF)
+ if(n < 0 || n > NSIGNIF)
return 0;
- for(b = a+n; b >= a; b--) {
- c = *b + v;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b + 1;
if(c <= '9') {
*b = c;
return 0;
}
*b = '0';
- v = 1;
}
- *a = '1'; /* overflow adding */
+ /*
+ * need to overflow adding digit.
+ * shift number down and insert 1 at beginning.
+ * decimal is known to be 0s or we wouldn't
+ * have gotten this far. (e.g., 99999+1 => 00000)
+ */
+ a[0] = '1';
return 1;
}
+/*
+ * subtract 1 from the decimal integer string a.
+ * if 10000 underflows into 09999, make it 99999
+ * and return 1 to tell caller to move the virtual
+ * decimal point. this way, xsub1 is inverse of xadd1.
+ */
static int
-xsub(char *a, int n, int v)
+xsub1(char *a, int n)
{
char *b;
int c;
- for(b = a+n; b >= a; b--) {
- c = *b - v;
+ if(n < 0 || n > NSIGNIF)
+ return 0;
+ for(b = a+n-1; b >= a; b--) {
+ c = *b - 1;
if(c >= '0') {
+ if(c == '0' && b == a) {
+ /*
+ * just zeroed the top digit; shift everyone u…
+ * decimal is known to be 9s or we wouldn't
+ * have gotten this far. (e.g., 10000-1 => 09…
+ */
+ *b = '9';
+ return 1;
+ }
*b = c;
return 0;
}
*b = '9';
- v = 1;
}
- *a = '9'; /* underflow subtracting */
- return 1;
+ /*
+ * can't get here. the number a is always normalized
+ * so that it has a nonzero first digit.
+ */
+ abort();
}
+/*
+ * format exponent like sprintf(p, "e%+02d", e)
+ */
static void
-xdtoa(Fmt *fmt, char *s2, double f)
+xfmtexp(char *p, int e, int ucase)
{
- char s1[NSIGNIF+10];
- double g, h;
- int e, d, i, n;
- int c1, c2, c3, c4, ucase, sign, chr, prec;
+ char se[9];
+ int i;
- prec = FDEFLT;
- if(fmt->flags & FmtPrec)
- prec = fmt->prec;
- if(prec > FDIGIT)
- prec = FDIGIT;
- if(__isNaN(f)) {
- strcpy(s2, "NaN");
- return;
- }
- if(__isInf(f, 1)) {
- strcpy(s2, "+Inf");
- return;
- }
- if(__isInf(f, -1)) {
- strcpy(s2, "-Inf");
- return;
+ *p++ = ucase ? 'E' : 'e';
+ if(e < 0) {
+ *p++ = '-';
+ e = -e;
+ } else
+ *p++ = '+';
+ i = 0;
+ while(e) {
+ se[i++] = e % 10 + '0';
+ e /= 10;
}
- sign = 0;
+ while(i < 2)
+ se[i++] = '0';
+ while(i > 0)
+ *p++ = se[--i];
+ *p++ = '\0';
+}
+
+/*
+ * compute decimal integer m, exp such that:
+ * f = m*10^exp
+ * m is as short as possible with losing exactness
+ * assumes special cases (NaN, +Inf, -Inf) have been handled.
+ */
+static void
+xdtoa(double f, char *s, int *exp, int *neg, int *ns)
+{
+ int c, d, e2, e, ee, i, ndigit, oerrno;
+ char tmp[NSIGNIF+10];
+ double g;
+
+ oerrno = errno; /* in case strtod smashes errno */
+
+ /*
+ * make f non-negative.
+ */
+ *neg = 0;
if(f < 0) {
f = -f;
- sign++;
- }
- ucase = 0;
- chr = fmt->r;
- if(isupper(chr)) {
- ucase = 1;
- chr = tolower(chr);
+ *neg = 1;
}
- e = 0;
- g = f;
- if(g != 0) {
- frexp(f, &e);
- e = e * .301029995664;
- if(e >= -150 && e <= +150) {
- d = 0;
- h = f;
- } else {
- d = e/2;
- h = f * pow10(-d);
- }
- g = h * pow10(d-e);
- while(g < 1) {
- e--;
- g = h * pow10(d-e);
- }
- while(g >= 10) {
- e++;
- g = h * pow10(d-e);
- }
+ /*
+ * must handle zero specially.
+ */
+ if(f == 0){
+ *exp = 0;
+ s[0] = '0';
+ s[1] = '\0';
+ *ns = 1;
+ return;
+ }
+
+ /*
+ * find g,e such that f = g*10^e.
+ * guess 10-exponent using 2-exponent, then fine tune.
+ */
+ frexp(f, &e2);
+ e = (int)(e2 * .301029995664);
+ g = f * pow10(-e);
+ while(g < 1) {
+ e--;
+ g = f * pow10(-e);
+ }
+ while(g >= 10) {
+ e++;
+ g = f * pow10(-e);
}
/*
- * convert NSIGNIF digits and convert
- * back to get accuracy.
+ * convert NSIGNIF digits as a first approximation.
*/
for(i=0; i<NSIGNIF; i++) {
- d = g;
- s1[i] = d + '0';
- g = (g - d) * 10;
+ d = (int)g;
+ s[i] = d+'0';
+ g = (g-d) * 10;
}
- s1[i] = 0;
+ s[i] = 0;
/*
- * try decimal rounding to eliminate 9s
+ * adjust e because s is 314159... not 3.14159...
*/
- c2 = prec + 1;
- if(chr == 'f')
- c2 += e;
- if(c2 >= NSIGNIF-2) {
- strcpy(s2, s1);
- d = e;
- s1[NSIGNIF-2] = '0';
- s1[NSIGNIF-1] = '0';
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- if(xadd(s1, NSIGNIF-3, 1)) {
- e++;
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- }
- g = strtod(s1, nil);
- if(g == f)
- goto found;
- strcpy(s1, s2);
- e = d;
- }
+ e -= NSIGNIF-1;
+ xfmtexp(s+NSIGNIF, e, 0);
/*
- * convert back so s1 gets exact answer
+ * adjust conversion until strtod(s) == f exactly.
*/
- for(;;) {
- sprint(s1+NSIGNIF, "e%d", e-NSIGNIF+1);
- g = strtod(s1, nil);
+ for(i=0; i<10; i++) {
+ g = fmtstrtod(s, nil);
if(f > g) {
- if(xadd(s1, NSIGNIF-1, 1))
+ if(xadd1(s, NSIGNIF)) {
+ /* gained a digit */
e--;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
continue;
}
if(f < g) {
- if(xsub(s1, NSIGNIF-1, 1))
+ if(xsub1(s, NSIGNIF)) {
+ /* lost a digit */
e++;
+ xfmtexp(s+NSIGNIF, e, 0);
+ }
continue;
}
break;
}
-found:
/*
- * sign
+ * play with the decimal to try to simplify.
*/
- d = 0;
- i = 0;
- if(sign)
- s2[d++] = '-';
- else if(fmt->flags & FmtSign)
- s2[d++] = '+';
- else if(fmt->flags & FmtSpace)
- s2[d++] = ' ';
/*
- * copy into final place
- * c1 digits of leading '0'
- * c2 digits from conversion
- * c3 digits of trailing '0'
- * c4 digits after '.'
+ * bump last few digits up to 9 if we can
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '9') {
+ s[i] = '9';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * add 1 in hopes of turning 9s to 0s
+ */
+ if(s[NSIGNIF-1] == '9') {
+ strcpy(tmp, s);
+ ee = e;
+ if(xadd1(tmp, NSIGNIF)) {
+ ee--;
+ xfmtexp(tmp+NSIGNIF, ee, 0);
+ }
+ g = fmtstrtod(tmp, nil);
+ if(g == f) {
+ strcpy(s, tmp);
+ e = ee;
+ }
+ }
+
+ /*
+ * bump last few digits down to 0 as we can.
+ */
+ for(i=NSIGNIF-1; i>=NSIGNIF-3; i--) {
+ c = s[i];
+ if(c != '0') {
+ s[i] = '0';
+ g = fmtstrtod(s, nil);
+ if(g != f) {
+ s[i] = c;
+ break;
+ }
+ }
+ }
+
+ /*
+ * remove trailing zeros.
+ */
+ ndigit = NSIGNIF;
+ while(ndigit > 1 && s[ndigit-1] == '0'){
+ e++;
+ --ndigit;
+ }
+ s[ndigit] = 0;
+ *exp = e;
+ *ns = ndigit;
+ errno = oerrno;
+}
+
+#ifdef PLAN9PORT
+static char *special[] = { "NaN", "NaN", "+Inf", "+Inf", "-Inf", "-Inf" };
+#else
+static char *special[] = { "nan", "NAN", "inf", "INF", "-inf", "-INF" };
+#endif
+
+int
+__efgfmt(Fmt *fmt)
+{
+ char buf[NSIGNIF+10], *dot, *digits, *p, *s, suf[10], *t;
+ double f;
+ int c, chr, dotwid, e, exp, fl, ndigits, neg, newndigits;
+ int pad, point, prec, realchr, sign, sufwid, ucase, wid, z1, z2;
+ Rune r, *rs, *rt;
+
+ if(fmt->flags&FmtLong)
+ f = va_arg(fmt->args, long double);
+ else
+ f = va_arg(fmt->args, double);
+
+ /*
+ * extract formatting flags
*/
- c1 = 0;
- c2 = prec + 1;
- c3 = 0;
- c4 = prec;
+ fl = fmt->flags;
+ fmt->flags = 0;
+ prec = FDEFLT;
+ if(fl & FmtPrec)
+ prec = fmt->prec;
+ chr = fmt->r;
+ ucase = 0;
switch(chr) {
- default:
- if(xadd(s1, c2, 5))
- e++;
+ case 'A':
+ case 'E':
+ case 'F':
+ case 'G':
+ chr += 'a'-'A';
+ ucase = 1;
break;
+ }
+
+ /*
+ * pick off special numbers.
+ */
+ if(__isNaN(f)) {
+ s = special[0+ucase];
+ special:
+ fmt->flags = fl & (FmtWidth|FmtLeft);
+ return __fmtcpy(fmt, s, strlen(s), strlen(s));
+ }
+ if(__isInf(f, 1)) {
+ s = special[2+ucase];
+ goto special;
+ }
+ if(__isInf(f, -1)) {
+ s = special[4+ucase];
+ goto special;
+ }
+
+ /*
+ * get exact representation.
+ */
+ digits = buf;
+ xdtoa(f, digits, &exp, &neg, &ndigits);
+
+ /*
+ * get locale's decimal point.
+ */
+ dot = fmt->decimal;
+ if(dot == nil)
+ dot = ".";
+ dotwid = utflen(dot);
+
+ /*
+ * now the formatting fun begins.
+ * compute parameters for actual fmt:
+ *
+ * pad: number of spaces to insert before/after field.
+ * z1: number of zeros to insert before digits
+ * z2: number of zeros to insert after digits
+ * point: number of digits to print before decimal point
+ * ndigits: number of digits to use from digits[]
+ * suf: trailing suffix, like "e-5"
+ */
+ realchr = chr;
+ switch(chr){
case 'g':
/*
- * decide on 'e' of 'f' style convers
+ * convert to at most prec significant digits. (prec=0 means 1)
+ */
+ if(prec == 0)
+ prec = 1;
+ if(ndigits > prec) {
+ if(digits[prec] >= '5' && xadd1(digits, prec))
+ exp++;
+ exp += ndigits-prec;
+ ndigits = prec;
+ }
+
+ /*
+ * extra rules for %g (implemented below):
+ * trailing zeros removed after decimal unless FmtSharp.
+ * decimal point only if digit follows.
+ */
+
+ /* fall through to %e */
+ default:
+ case 'e':
+ /*
+ * one significant digit before decimal, no leading zeros.
+ */
+ point = 1;
+ z1 = 0;
+
+ /*
+ * decimal point is after ndigits digits right now.
+ * slide to be after first.
+ */
+ e = exp + (ndigits-1);
+
+ /*
+ * if this is %g, check exponent and convert prec
*/
- if(xadd(s1, c2, 5))
- e++;
- if(e >= -5 && e <= prec) {
- c1 = -e - 1;
- c4 = prec - e;
- chr = 'h'; // flag for 'f' style
+ if(realchr == 'g') {
+ if(-4 <= e && e < prec)
+ goto casef;
+ prec--; /* one digit before decimal; rest after…
+ }
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(1+prec >= ndigits)
+ z2 = 1+prec - ndigits;
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = 1+prec;
+ if(digits[newndigits] >= '5' && xadd1(digits, newndigi…
+ /*
+ * had 999e4, now have 100e5
+ */
+ e++;
+ }
+ ndigits = newndigits;
+ z2 = 0;
}
+ xfmtexp(suf, e, ucase);
+ sufwid = strlen(suf);
break;
+
+ casef:
case 'f':
- if(xadd(s1, c2+e, 5))
- e++;
- c1 = -e;
- if(c1 > prec)
- c1 = c2;
- c2 += e;
+ /*
+ * determine where digits go with respect to decimal point
+ */
+ if(ndigits+exp > 0) {
+ point = ndigits+exp;
+ z1 = 0;
+ } else {
+ point = 1;
+ z1 = 1 + -(ndigits+exp);
+ }
+
+ /*
+ * %g specifies prec = number of significant digits
+ * convert to number of digits after decimal point
+ */
+ if(realchr == 'g')
+ prec += z1 - point;
+
+ /*
+ * compute trailing zero padding or truncate digits.
+ */
+ if(point+prec >= z1+ndigits)
+ z2 = point+prec - (z1+ndigits);
+ else {
+ /*
+ * truncate digits
+ */
+ assert(realchr != 'g');
+ newndigits = point+prec - z1;
+ if(newndigits < 0) {
+ z1 += newndigits;
+ newndigits = 0;
+ } else if(newndigits == 0) {
+ /* perhaps round up */
+ if(digits[0] >= '5'){
+ digits[0] = '1';
+ newndigits = 1;
+ goto newdigit;
+ }
+ } else if(digits[newndigits] >= '5' && xadd1(digits, n…
+ /*
+ * digits was 999, is now 100; make it 1000
+ */
+ digits[newndigits++] = '0';
+ newdigit:
+ /*
+ * account for new digit
+ */
+ if(z1) /* 0.099 => 0.100 or 0.99 => 1.0…
+ z1--;
+ else /* 9.99 => 10.00 */
+ point++;
+ }
+ z2 = 0;
+ ndigits = newndigits;
+ }
+ sufwid = 0;
break;
}
-
+
/*
- * clean up c1 c2 and c3
+ * if %g is given without FmtSharp, remove trailing zeros.
+ * must do after truncation, so that e.g. print %.3g 1.001
+ * produces 1, not 1.00. sorry, but them's the rules.
*/
- if(c1 < 0)
- c1 = 0;
- if(c2 < 0)
- c2 = 0;
- if(c2 > NSIGNIF) {
- c3 = c2-NSIGNIF;
- c2 = NSIGNIF;
+ if(realchr == 'g' && !(fl & FmtSharp)) {
+ if(z1+ndigits+z2 >= point) {
+ if(z1+ndigits < point)
+ z2 = point - (z1+ndigits);
+ else{
+ z2 = 0;
+ while(z1+ndigits > point && digits[ndigits-1] …
+ ndigits--;
+ }
+ }
}
/*
- * copy digits
+ * compute width of all digits and decimal point and suffix if any
*/
- while(c1 > 0) {
- if(c1+c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c1--;
- }
- while(c2 > 0) {
- if(c2+c3 == c4)
- s2[d++] = '.';
- s2[d++] = s1[i++];
- c2--;
+ wid = z1+ndigits+z2;
+ if(wid > point)
+ wid += dotwid;
+ else if(wid == point){
+ if(fl & FmtSharp)
+ wid += dotwid;
+ else
+ point++; /* do not print any decimal point */
}
- while(c3 > 0) {
- if(c3 == c4)
- s2[d++] = '.';
- s2[d++] = '0';
- c3--;
+ wid += sufwid;
+
+ /*
+ * determine sign
+ */
+ sign = 0;
+ if(neg)
+ sign = '-';
+ else if(fl & FmtSign)
+ sign = '+';
+ else if(fl & FmtSpace)
+ sign = ' ';
+ if(sign)
+ wid++;
+
+ /*
+ * compute padding
+ */
+ pad = 0;
+ if((fl & FmtWidth) && fmt->width > wid)
+ pad = fmt->width - wid;
+ if(pad && !(fl & FmtLeft) && (fl & FmtZero)){
+ z1 += pad;
+ point += pad;
+ pad = 0;
}
/*
- * strip trailing '0' on g conv
+ * format the actual field. too bad about doing this twice.
*/
- if(fmt->flags & FmtSharp) {
- if(0 == c4)
- s2[d++] = '.';
- } else
- if(chr == 'g' || chr == 'h') {
- for(n=d-1; n>=0; n--)
- if(s2[n] != '0')
- break;
- for(i=n; i>=0; i--)
- if(s2[i] == '.') {
- d = n;
- if(i != n)
- d++;
- break;
+ if(fmt->runes){
+ if(pad && !(fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ rt = (Rune*)fmt->to;
+ rs = (Rune*)fmt->stop;
+ if(sign)
+ FMTRCHAR(fmt, rt, rs, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
}
- }
- if(chr == 'e' || chr == 'g') {
- if(ucase)
- s2[d++] = 'E';
- else
- s2[d++] = 'e';
- c1 = e;
- if(c1 < 0) {
- s2[d++] = '-';
- c1 = -c1;
- } else
- s2[d++] = '+';
- if(c1 >= 100) {
- s2[d++] = c1/100 + '0';
- c1 = c1%100;
+ FMTRCHAR(fmt, rt, rs, c);
+ if(--point == 0) {
+ for(p = dot; *p; ){
+ p += chartorune(&r, p);
+ FMTRCHAR(fmt, rt, rs, r);
+ }
+ }
+ }
+ fmt->nfmt += rt - (Rune*)fmt->to;
+ fmt->to = rt;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __rfmtpad(fmt, pad) < 0)
+ return -1;
+ }else{
+ if(pad && !(fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
+ t = (char*)fmt->to;
+ s = (char*)fmt->stop;
+ if(sign)
+ FMTCHAR(fmt, t, s, sign);
+ while(z1>0 || ndigits>0 || z2>0) {
+ if(z1 > 0){
+ z1--;
+ c = '0';
+ }else if(ndigits > 0){
+ ndigits--;
+ c = *digits++;
+ }else{
+ z2--;
+ c = '0';
+ }
+ FMTCHAR(fmt, t, s, c);
+ if(--point == 0)
+ for(p=dot; *p; p++)
+ FMTCHAR(fmt, t, s, *p);
}
- s2[d++] = c1/10 + '0';
- s2[d++] = c1%10 + '0';
+ fmt->nfmt += t - (char*)fmt->to;
+ fmt->to = t;
+ if(sufwid && __fmtcpy(fmt, suf, sufwid, sufwid) < 0)
+ return -1;
+ if(pad && (fl & FmtLeft) && __fmtpad(fmt, pad) < 0)
+ return -1;
}
- s2[d] = 0;
-}
-
-static int
-floatfmt(Fmt *fmt, double f)
-{
- char s[FDIGIT+10];
-
- xdtoa(fmt, s, f);
- fmt->flags &= FmtWidth|FmtLeft;
- __fmtcpy(fmt, s, strlen(s), strlen(s));
return 0;
}
-int
-__efgfmt(Fmt *f)
-{
- double d;
-
- d = va_arg(f->args, double);
- return floatfmt(f, d);
-}
diff --git a/lib9/fmt/fmt.c b/lib9/fmt/fmt.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -29,7 +17,7 @@ struct Convfmt
volatile Fmts fmt; /* for spin lock in fmtfmt; av…
};
-struct
+static struct
{
/* lock by calling __fmtlock, __fmtunlock */
int nfmt;
@@ -40,6 +28,7 @@ static Convfmt knownfmt[] = {
' ', __flagfmt,
'#', __flagfmt,
'%', __percentfmt,
+ '\'', __flagfmt,
'+', __flagfmt,
',', __flagfmt,
'-', __flagfmt,
diff --git a/lib9/fmt/fmtdef.h b/lib9/fmt/fmtdef.h
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE …
- * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* dofmt -- format to a buffer
@@ -53,6 +41,7 @@ void __fmtunlock(void);
int __ifmt(Fmt *f);
int __isInf(double d, int sign);
int __isNaN(double d);
+int __needsep(int*, char**);
int __needsquotes(char *s, int *quotelenp);
int __percentfmt(Fmt *f);
void __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo *q, i…
@@ -66,9 +55,9 @@ int __strfmt(Fmt *f);
#define FMTCHAR(f, t, s, c)\
do{\
if(t + 1 > (char*)s){\
- t = __fmtflush(f, t, 1);\
+ t = (char*)__fmtflush(f, t, 1);\
if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
else\
return -1;\
}\
@@ -78,9 +67,9 @@ int __strfmt(Fmt *f);
#define FMTRCHAR(f, t, s, c)\
do{\
if(t + 1 > (Rune*)s){\
- t = __fmtflush(f, t, sizeof(Rune));\
+ t = (Rune*)__fmtflush(f, t, sizeof(Rune));\
if(t != nil)\
- s = f->stop;\
+ s = (Rune*)f->stop;\
else\
return -1;\
}\
@@ -92,9 +81,9 @@ int __strfmt(Fmt *f);
Rune _rune;\
int _runelen;\
if(t + UTFmax > (char*)s && t + (_runelen = runelen(r)) > (char*)s){\
- t = __fmtflush(f, t, _runelen);\
+ t = (char*)__fmtflush(f, t, _runelen);\
if(t != nil)\
- s = f->stop;\
+ s = (char*)f->stop;\
else\
return -1;\
}\
diff --git a/lib9/fmt/fmtfd.c b/lib9/fmt/fmtfd.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -40,7 +28,9 @@ fmtfdinit(Fmt *f, int fd, char *buf, int size)
f->to = buf;
f->stop = buf + size;
f->flush = __fmtFdFlush;
- f->farg = (void*)fd;
+ f->farg = (void*)(uintptr_t)fd;
+ f->flags = 0;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/fmtfdflush.c b/lib9/fmt/fmtfdflush.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <unistd.h>
#include "plan9.h"
@@ -27,7 +15,7 @@ __fmtFdFlush(Fmt *f)
int n;
n = (char*)f->to - (char*)f->start;
- if(n && write((int)f->farg, f->start, n) != n)
+ if(n && write((uintptr)f->farg, f->start, n) != n)
return 0;
f->to = f->start;
return 1;
diff --git a/lib9/fmt/fmtlocale.c b/lib9/fmt/fmtlocale.c
@@ -0,0 +1,55 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Fill in the internationalization stuff in the State structure.
+ * For nil arguments, provide the sensible defaults:
+ * decimal is a period
+ * thousands separator is a comma
+ * thousands are marked every three digits
+ */
+void
+fmtlocaleinit(Fmt *f, char *decimal, char *thousands, char *grouping)
+{
+ if(decimal == nil || decimal[0] == '\0')
+ decimal = ".";
+ if(thousands == nil)
+ thousands = ",";
+ if(grouping == nil)
+ grouping = "\3";
+ f->decimal = decimal;
+ f->thousands = thousands;
+ f->grouping = grouping;
+}
+
+/*
+ * We are about to emit a digit in e.g. %'d. If that digit would
+ * overflow a thousands (e.g.) grouping, tell the caller to emit
+ * the thousands separator. Always advance the digit counter
+ * and pointer into the grouping descriptor.
+ */
+int
+__needsep(int *ndig, char **grouping)
+{
+ int group;
+
+ (*ndig)++;
+ group = *(unsigned char*)*grouping;
+ /* CHAR_MAX means no further grouping. \0 means we got the empty strin…
+ if(group == 0xFF || group == 0x7f || group == 0x00)
+ return 0;
+ if(*ndig > group){
+ /* if we're at end of string, continue with this grouping; els…
+ if((*grouping)[1] != '\0')
+ (*grouping)++;
+ *ndig = 1;
+ return 1;
+ }
+ return 0;
+}
+
diff --git a/lib9/fmt/fmtlock.c b/lib9/fmt/fmtlock.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/fmtnull.c b/lib9/fmt/fmtnull.c
@@ -0,0 +1,33 @@
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+#include <stdarg.h>
+#include <string.h>
+#include "plan9.h"
+#include "fmt.h"
+#include "fmtdef.h"
+
+/*
+ * Absorb output without using resources.
+ */
+static Rune nullbuf[32];
+
+static int
+__fmtnullflush(Fmt *f)
+{
+ f->to = nullbuf;
+ f->nfmt = 0;
+ return 0;
+}
+
+int
+fmtnullinit(Fmt *f)
+{
+ memset(f, 0, sizeof *f);
+ f->runes = 1;
+ f->start = nullbuf;
+ f->to = nullbuf;
+ f->stop = nullbuf+nelem(nullbuf);
+ f->flush = __fmtnullflush;
+ fmtlocaleinit(f, nil, nil, nil);
+ return 0;
+}
+
diff --git a/lib9/fmt/fmtprint.c b/lib9/fmt/fmtprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fmtquote.c b/lib9/fmt/fmtquote.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -103,6 +91,11 @@ __quotesetup(char *s, Rune *r, int nin, int nout, Quoteinfo…
/* advance output */
q->nbytesout += w;
q->nrunesout++;
+
+#ifndef PLAN9PORT
+ /* ANSI requires precision in bytes, not Runes. */
+ nin-= w-1; /* and then n-- in the loop */
+#endif
}
}
@@ -120,8 +113,10 @@ qstrfmt(char *sin, Rune *rin, Quoteinfo *q, Fmt *f)
rm = rin;
rme = rm + q->nrunesin;
- w = f->width;
fl = f->flags;
+ w = 0;
+ if(fl & FmtWidth)
+ w = f->width;
if(f->runes){
if(!(fl & FmtLeft) && __rfmtpad(f, w - q->nrunesout) < 0)
return -1;
@@ -209,7 +204,7 @@ __quotestrfmt(int runesin, Fmt *f)
outlen = (char*)f->stop - (char*)f->to;
__quotesetup(s, r, nin, outlen, &q, f->flags&FmtSharp, f->runes);
-//print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nb…
+/*print("bytes in %d bytes out %d runes in %d runesout %d\n", q.nbytesin, q.nb…
if(runesin){
if(!q.quoted)
diff --git a/lib9/fmt/fmtrune.c b/lib9/fmt/fmtrune.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fmtstr.c b/lib9/fmt/fmtstr.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
@@ -23,5 +11,6 @@ fmtstrflush(Fmt *f)
if(f->start == nil)
return nil;
*(char*)f->to = '\0';
+ f->to = f->start;
return (char*)f->start;
}
diff --git a/lib9/fmt/fmtvprint.c b/lib9/fmt/fmtvprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/fprint.c b/lib9/fmt/fprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/nan.h b/lib9/fmt/nan.h
@@ -0,0 +1,4 @@
+extern double __NaN(void);
+extern double __Inf(int);
+extern int __isNaN(double);
+extern int __isInf(double, int);
diff --git a/lib9/fmt/nan64.c b/lib9/fmt/nan64.c
@@ -6,58 +6,67 @@
*/
#include "plan9.h"
+#include <assert.h>
#include "fmt.h"
#include "fmtdef.h"
-#if defined (__APPLE__) || (__powerpc__)
-#define _NEEDLL
-#endif
-
static uvlong uvnan = ((uvlong)0x7FF00000<<32)|0x00000001;
static uvlong uvinf = ((uvlong)0x7FF00000<<32)|0x00000000;
static uvlong uvneginf = ((uvlong)0xFFF00000<<32)|0x00000000;
+/* gcc sees through the obvious casts. */
+static uvlong
+d2u(double d)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.d = d;
+ return u.v;
+}
+
+static double
+u2d(uvlong v)
+{
+ union {
+ uvlong v;
+ double d;
+ } u;
+ assert(sizeof(u.d) == sizeof(u.v));
+ u.v = v;
+ return u.d;
+}
+
double
__NaN(void)
{
- uvlong *p;
-
- /* gcc complains about "return *(double*)&uvnan;" */
- p = &uvnan;
- return *(double*)p;
+ return u2d(uvnan);
}
int
__isNaN(double d)
{
uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
- return (ulong)(x>>32)==0x7FF00000 && !__isInf(d, 0);
+
+ x = d2u(d);
+ /* IEEE 754: exponent bits 0x7FF and non-zero mantissa */
+ return (x&uvinf) == uvinf && (x&~uvneginf) != 0;
}
double
__Inf(int sign)
{
- uvlong *p;
-
- if(sign < 0)
- p = &uvinf;
- else
- p = &uvneginf;
- return *(double*)p;
+ return u2d(sign < 0 ? uvneginf : uvinf);
}
int
__isInf(double d, int sign)
{
uvlong x;
- double *p;
-
- p = &d;
- x = *(uvlong*)p;
+
+ x = d2u(d);
if(sign == 0)
return x==uvinf || x==uvneginf;
else if(sign > 0)
diff --git a/lib9/fmt/plan9.h b/lib9/fmt/plan9.h
@@ -1,3 +1,5 @@
+#include <inttypes.h>
+
/*
* compiler directive on Plan 9
*/
@@ -14,12 +16,15 @@
#define ulong _fmtulong
#define vlong _fmtvlong
#define uvlong _fmtuvlong
+#define uintptr _fmtuintptr
+
typedef unsigned char uchar;
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned long ulong;
typedef unsigned long long uvlong;
typedef long long vlong;
+typedef uintptr_t uintptr;
/*
* nil cannot be ((void*)0) on ANSI C,
diff --git a/lib9/fmt/pow10.c b/lib9/fmt/pow10.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/print.c b/lib9/fmt/print.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/runefmtstr.c b/lib9/fmt/runefmtstr.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <stdlib.h>
#include "plan9.h"
@@ -23,5 +11,6 @@ runefmtstrflush(Fmt *f)
if(f->start == nil)
return nil;
*(Rune*)f->to = '\0';
+ f->to = f->start;
return f->start;
}
diff --git a/lib9/fmt/runeseprint.c b/lib9/fmt/runeseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesmprint.c b/lib9/fmt/runesmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesnprint.c b/lib9/fmt/runesnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runesprint.c b/lib9/fmt/runesprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/fmt/runevseprint.c b/lib9/fmt/runevseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ runevseprint(Rune *buf, Rune *e, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
diff --git a/lib9/fmt/runevsmprint.c b/lib9/fmt/runevsmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@ runeFmtStrFlush(Fmt *f)
if(f->start == nil)
return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
n *= 2;
s = (Rune*)f->start;
f->start = realloc(s, sizeof(Rune)*n);
@@ -47,7 +35,7 @@ runeFmtStrFlush(Fmt *f)
free(s);
return 0;
}
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->to = (Rune*)f->start + ((Rune*)f->to - s);
f->stop = (Rune*)f->start + n - 1;
return 1;
@@ -67,8 +55,9 @@ runefmtstrinit(Fmt *f)
f->to = f->start;
f->stop = (Rune*)f->start + n - 1;
f->flush = runeFmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/runevsnprint.c b/lib9/fmt/runevsnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ runevsnprint(Rune *buf, int len, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(Rune*)f.to = '\0';
diff --git a/lib9/fmt/seprint.c b/lib9/fmt/seprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/smprint.c b/lib9/fmt/smprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/snprint.c b/lib9/fmt/snprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/sprint.c b/lib9/fmt/sprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include <fmt.h>
#include "plan9.h"
@@ -28,9 +16,12 @@ sprint(char *buf, char *fmt, ...)
/*
* on PowerPC, the stack is near the top of memory, so
* we must be sure not to overflow a 32-bit pointer.
+ *
+ * careful! gcc-4.2 assumes buf+len < buf can never be true and
+ * optimizes the test away. casting to uintptr works around this bug.
*/
- if(buf+len < buf)
- len = -(uint)buf-1;
+ if((uintptr)buf+len < (uintptr)buf)
+ len = -(uintptr)buf-1;
va_start(args, fmt);
n = vsnprint(buf, len, fmt, args);
diff --git a/lib9/fmt/strtod.c b/lib9/fmt/strtod.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <math.h>
#include <ctype.h>
@@ -67,7 +55,7 @@ enum
S4, /* _+#.# #S4 eS5 */
S5, /* _+#.#e +S6 #S7 */
S6, /* _+#.#e+ #S7 */
- S7, /* _+#.#e+# #S7 */
+ S7 /* _+#.#e+# #S7 */
};
static int xcmp(char*, char*);
@@ -239,7 +227,7 @@ fmtstrtod(const char *as, char **aas)
/* close approx by naive conversion */
mid[0] = 0;
mid[1] = 1;
- for(i=0; c=a[i]; i++) {
+ for(i=0; (c=a[i]) != '\0'; i++) {
mid[0] = mid[0]*10 + (c-'0');
mid[1] = mid[1]*10;
if(i >= 8)
@@ -521,7 +509,7 @@ xcmp(char *a, char *b)
{
int c1, c2;
- while(c1 = *b++) {
+ while((c1 = *b++) != '\0') {
c2 = *a++;
if(isupper(c2))
c2 = tolower(c2);
diff --git a/lib9/fmt/test.c b/lib9/fmt/test.c
@@ -1,16 +1,6 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
+/* Copyright (c) 2004 Google Inc.; see LICENSE */
+
#include <stdio.h>
#include <stdarg.h>
#include <utf.h>
@@ -40,5 +30,24 @@ main(int argc, char *argv[])
print("%d\n", 23);
print("%i\n", 23);
print("%0.10d\n", 12345);
+
+ /* test %4$d formats */
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$06d %2$d %1$d\n", 444, 333, 111, 222);
+ print("%3$d %4$*5$06d %2$d %1$d\n", 444, 333, 111, 222, 20);
+ print("%3$hd %4$*5$06d %2$d %1$d\n", 444, 333, (short)111, 222, 20);
+ print("%3$lld %4$*5$06d %2$d %1$d\n", 444, 333, 111LL, 222, 20);
+
+ /* test %'d formats */
+ print("%'d %'d %'d\n", 1, 2222, 33333333);
+ print("%'019d\n", 0);
+ print("%08d %08d %08d\n", 1, 2222, 33333333);
+ print("%'08d %'08d %'08d\n", 1, 2222, 33333333);
+ print("%'x %'X %'b\n", 0x11111111, 0xabcd1234, 12345);
+ print("%'lld %'lld %'lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%019lld %019lld %019lld\n", 1LL, 222222222LL, 3333333333333LL);
+ print("%'019lld %'019lld %'019lld\n", 1LL, 222222222LL, 3333333333333L…
+ print("%'020lld %'020lld %'020lld\n", 1LL, 222222222LL, 3333333333333L…
+ print("%'llx %'llX %'llb\n", 0x111111111111LL, 0xabcd12345678LL, 11234…
return 0;
}
diff --git a/lib9/fmt/vfprint.c b/lib9/fmt/vfprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
diff --git a/lib9/fmt/vseprint.c b/lib9/fmt/vseprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdarg.h>
#include "plan9.h"
#include "fmt.h"
@@ -31,6 +19,7 @@ vseprint(char *buf, char *e, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
diff --git a/lib9/fmt/vsmprint.c b/lib9/fmt/vsmprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
/*
* Plan 9 port version must include libc.h in order to
* get Plan 9 debugging malloc, which sometimes returns
@@ -36,7 +24,7 @@ fmtStrFlush(Fmt *f)
if(f->start == nil)
return 0;
- n = (int)f->farg;
+ n = (uintptr)f->farg;
n *= 2;
s = (char*)f->start;
f->start = realloc(s, n);
@@ -47,7 +35,7 @@ fmtStrFlush(Fmt *f)
free(s);
return 0;
}
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->to = (char*)f->start + ((char*)f->to - s);
f->stop = (char*)f->start + n - 1;
return 1;
@@ -67,8 +55,9 @@ fmtstrinit(Fmt *f)
f->to = f->start;
f->stop = (char*)f->start + n - 1;
f->flush = fmtStrFlush;
- f->farg = (void*)n;
+ f->farg = (void*)(uintptr)n;
f->nfmt = 0;
+ fmtlocaleinit(f, nil, nil, nil);
return 0;
}
diff --git a/lib9/fmt/vsnprint.c b/lib9/fmt/vsnprint.c
@@ -1,16 +1,4 @@
-/*
- * The authors of this software are Rob Pike and Ken Thompson.
- * Copyright (c) 2002 by Lucent Technologies.
- * Permission to use, copy, modify, and distribute this software for any
- * purpose without fee is hereby granted, provided that this entire notice
- * is included in all copies of any software which is or includes a copy
- * or modification of this software and in all copies of the supporting
- * documentation for such software.
- * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
- * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE
- * ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
- * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
- */
+/* Copyright (c) 2002-2006 Lucent Technologies; see LICENSE */
#include <stdlib.h>
#include <stdarg.h>
#include "plan9.h"
@@ -32,6 +20,7 @@ vsnprint(char *buf, int len, char *fmt, va_list args)
f.farg = nil;
f.nfmt = 0;
VA_COPY(f.args,args);
+ fmtlocaleinit(&f, nil, nil, nil);
dofmt(&f, fmt);
VA_END(f.args);
*(char*)f.to = '\0';
diff --git a/lib9/getcallerpc-arm.c b/lib9/getcallerpc-arm.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+ulong
+getcallerpc(void *x)
+{
+ return ((ulong*)x)[-2];
+}
+
diff --git a/lib9/getnetconn.c b/lib9/getnetconn.c
@@ -91,12 +91,12 @@ getnetconninfo(char *dir, int fd)
nci->spec = unknown;
if(nci->dir == nil || nci->root == nil)
goto err;
- sn = sizeof sn;
+ sn = sizeof u;
if(getsockname(fd, &u.sa, &sn) < 0)
goto err;
if(convert(fd, &u.sa, &nci->lsys, &nci->lserv, &nci->laddr) < 0)
goto err;
- sn = sizeof sn;
+ sn = sizeof u;
if(getpeername(fd, &u.sa, &sn) < 0)
goto err;
if(convert(fd, &u.sa, &nci->rsys, &nci->rserv, &nci->raddr) < 0)
diff --git a/lib9/getns.c b/lib9/getns.c
@@ -2,6 +2,17 @@
#include <libc.h>
#include <ctype.h>
+static int
+isme(char *uid)
+{
+ int n;
+ char *p;
+
+ n = strtol(uid, &p, 10);
+ if(*p == 0 && p > uid)
+ return n == getuid();
+ return strcmp(getuser(), uid) == 0;
+}
/*
* Absent other hints, it works reasonably well to use
* the X11 display name as the name space identifier.
@@ -18,8 +29,15 @@ nsfromdisplay(void)
char *disp, *p;
if((disp = getenv("DISPLAY")) == nil){
+#ifdef __APPLE__
+ // Might be running native GUI on OS X.
+ disp = strdup(":0.0");
+ if(disp == nil)
+ return nil;
+#else
werrstr("$DISPLAY not set");
return nil;
+#endif
}
/* canonicalize: xxx:0.0 => xxx:0 */
@@ -31,6 +49,11 @@ nsfromdisplay(void)
if(strcmp(p, ".0") == 0)
*p = 0;
}
+
+ /* turn /tmp/launch/:0 into _tmp_launch_:0 (OS X 10.5) */
+ for(p=disp; *p; p++)
+ if(*p == '/')
+ *p = '_';
p = smprint("/tmp/ns.%s.%s", getuser(), disp);
free(disp);
@@ -48,7 +71,7 @@ nsfromdisplay(void)
free(p);
return nil;
}
- if((d->mode&0777) != 0700 || strcmp(d->uid, getuser()) != 0){
+ if((d->mode&0777) != 0700 || !isme(d->uid)){
werrstr("bad name space dir %s", p);
free(p);
free(d);
diff --git a/lib9/lib9.h b/lib9/lib9.h
@@ -1,17 +1,2 @@
-#include <string.h>
-#include "utf.h"
-
-#define nil ((void*)0)
-
-#define uchar _fmtuchar
-#define ushort _fmtushort
-#define uint _fmtuint
-#define ulong _fmtulong
-#define vlong _fmtvlong
-#define uvlong _fmtuvlong
-
-typedef unsigned char uchar;
-typedef unsigned short ushort;
-typedef unsigned int uint;
-typedef unsigned long ulong;
-
+#include <u.h>
+#include <libc.h>
diff --git a/lib9/libc.h b/lib9/libc.h
@@ -349,7 +349,7 @@ extern vlong p9nsec(void);
enum
{
PNPROC = 1,
- PNGROUP = 2,
+ PNGROUP = 2
};
/* extern int abs(int); <stdlib.h> */
@@ -376,6 +376,7 @@ extern int dec16(uchar*, int, char*, int);
extern int enc16(char*, int, uchar*, int);
extern int encodefmt(Fmt*);
extern int dirmodefmt(Fmt*);
+extern int exitcode(char*);
extern void exits(char*);
extern double frexp(double, int*);
extern ulong getcallerpc(void*);
@@ -390,7 +391,7 @@ extern int iounit(int);
/* extern double ldexp(double, int); <math.h> */
extern void p9longjmp(p9jmp_buf, int);
extern char* mktemp(char*);
-extern int opentemp(char*);
+extern int opentemp(char*, int);
/* extern double modf(double, double*); <math.h> */
extern void p9notejmp(void*, p9jmp_buf, int);
extern void perror(const char*);
@@ -416,6 +417,9 @@ extern long p9time(long*);
extern void needstack(int);
extern char* readcons(char*, char*, int);
+extern void (*_pin)(void);
+extern void (*_unpin)(void);
+
#ifndef NOPLAN9DEFINES
#define atexit p9atexit
#define atexitdont p9atexitdont
@@ -670,7 +674,7 @@ enum
RFNOWAIT = (1<<6),
RFCNAMEG = (1<<10),
RFCENVG = (1<<11),
- RFCFDG = (1<<12),
+ RFCFDG = (1<<12)
/* RFREND = (1<<13), */
/* RFNOMNT = (1<<14) */
};
@@ -789,6 +793,7 @@ extern int p9waitpid(void);
extern long write(int, void*, long);
extern long writev(int, IOchunk*, int);
*/
+extern long p9write(int, void*, long);
/* extern int wstat(char*, uchar*, int); give up */
extern ulong rendezvous(ulong, ulong);
@@ -809,6 +814,7 @@ extern ulong rendezvous(ulong, ulong);
#define open p9open
#define pipe p9pipe
#define waitfor p9waitfor
+#define write p9write
#endif
extern Dir* dirstat(char*);
@@ -828,7 +834,8 @@ extern char* get9root(void);
extern char* unsharp(char*);
extern int sendfd(int, int);
extern int recvfd(int);
-extern int post9pservice(int, char*);
+extern int post9pservice(int, char*, char*);
+extern int chattyfuse;
/* external names that we don't want to step on */
#ifndef NOPLAN9DEFINES
@@ -900,7 +907,7 @@ extern int post9pservice(int, char*);
#ifdef __GNUC__
# if __GNUC__ >= 3
# undef USED
-# define USED(x) { ulong __y __attribute__ ((unused)); __y = (u…
+# define USED(x) ((void)(x))
# endif
#endif
diff --git a/lib9/malloctag.c b/lib9/malloctag.c
@@ -1,9 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define USED(x) if(x){}else{}
-#define lrand p9lrand
-
void
setmalloctag(void *v, ulong t)
{
diff --git a/lib9/nan.c b/lib9/nan.c
@@ -1,6 +1,6 @@
#include <u.h>
#include <libc.h>
-#include "nan.h"
+#include "fmt/nan.h"
double
NaN(void)
diff --git a/lib9/netcrypt.c b/lib9/netcrypt.c
@@ -0,0 +1,18 @@
+#include <u.h>
+#include <libc.h>
+#include <auth.h>
+
+int
+netcrypt(void *key, void *chal)
+{
+ uchar buf[8], *p;
+
+ strncpy((char*)buf, chal, 7);
+ buf[7] = '\0';
+ for(p = buf; *p && *p != '\n'; p++)
+ ;
+ *p = '\0';
+ encrypt(key, buf, 8);
+ sprint(chal, "%.2ux%.2ux%.2ux%.2ux", buf[0], buf[1], buf[2], buf[3]);
+ return 1;
+}
diff --git a/lib9/netmkaddr.c b/lib9/netmkaddr.c
@@ -16,21 +16,25 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
*/
cp = strchr(linear, '!');
if(cp == 0){
- if(defnet==0){
- if(defsrv)
- snprint(addr, sizeof(addr), "net!%s!%s",
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "net!%s", linear);
+ if(defnet == 0)
+ defnet = "net";
+ /* allow unix sockets to omit unix! prefix */
+ if(access(linear, 0) >= 0){
+ snprint(addr, sizeof(addr), "unix!%s", linear);
+ return addr;
}
- else {
- if(defsrv)
- snprint(addr, sizeof(addr), "%s!%s!%s", defnet,
- linear, defsrv);
- else
- snprint(addr, sizeof(addr), "%s!%s", defnet,
- linear);
+ /* allow host:service in deference to Unix convention */
+ if((cp = strchr(linear, ':')) != nil){
+ snprint(addr, sizeof(addr), "%s!%.*s!%s",
+ defnet, utfnlen(linear, cp-linear),
+ linear, cp+1);
+ return addr;
}
+ if(defsrv)
+ snprint(addr, sizeof(addr), "%s!%s!%s",
+ defnet, linear, defsrv);
+ else
+ snprint(addr, sizeof(addr), "%s!%s", defnet, linear);
return addr;
}
@@ -42,11 +46,17 @@ netmkaddr(char *linear, char *defnet, char *defsrv)
return linear;
/*
+ * if the network is unix, no service
+ */
+ if(strncmp(linear, "unix!", 5) == 0)
+ return linear;
+
+ /*
* add default service
*/
if(defsrv == 0)
return linear;
- snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
+ snprint(addr, sizeof(addr), "%s!%s", linear, defsrv);
return addr;
}
diff --git a/lib9/notify.c b/lib9/notify.c
@@ -38,6 +38,7 @@ enum
{
Restart = 1<<0,
Ignore = 1<<1,
+ NoNotify = 1<<2,
};
static Sig sigs[] = {
@@ -58,7 +59,7 @@ static Sig sigs[] = {
SIGPIPE, Ignore,
SIGALRM, 0,
SIGTERM, 0,
- SIGTSTP, Restart|Ignore,
+ SIGTSTP, Restart|Ignore|NoNotify,
/* SIGTTIN, Restart|Ignore, */
/* SIGTTOU, Restart|Ignore, */
SIGXCPU, 0,
@@ -67,10 +68,10 @@ static Sig sigs[] = {
SIGUSR1, 0,
SIGUSR2, 0,
#ifdef SIGWINCH
- SIGWINCH, Restart|Ignore,
+ SIGWINCH, Restart|Ignore|NoNotify,
#endif
#ifdef SIGINFO
- SIGINFO, Restart|Ignore,
+ SIGINFO, Restart|Ignore|NoNotify,
#endif
};
@@ -266,7 +267,7 @@ noteinit(void)
*/
if(handler(sig->sig) != SIG_DFL)
continue;
- notifyseton(sig->sig, 1);
+ notifyseton(sig->sig, !(sig->flags&NoNotify));
}
}
diff --git a/lib9/nrand.c b/lib9/nrand.c
@@ -1,7 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define lrand p9lrand
#define MASK 0x7fffffffL
int
diff --git a/lib9/nulldir.c b/lib9/nulldir.c
@@ -5,5 +5,5 @@ void
nulldir(Dir *d)
{
memset(d, ~0, sizeof(Dir));
- d->name = d->uid = d->gid = d->muid = "";
+ d->name = d->uid = d->gid = d->muid = d->ext = "";
}
diff --git a/lib9/opentemp.c b/lib9/opentemp.c
@@ -2,14 +2,19 @@
#include <libc.h>
int
-opentemp(char *template)
+opentemp(char *template, int mode)
{
- int fd;
+ int fd, fd1;
fd = mkstemp(template);
if(fd < 0)
return -1;
- remove(template);
- return fd;
+ if((fd1 = open(template, mode)) < 0){
+ remove(template);
+ close(fd);
+ return -1;
+ }
+ close(fd);
+ return fd1;
}
diff --git a/lib9/pin.c b/lib9/pin.c
@@ -0,0 +1,11 @@
+#include <u.h>
+#include <libc.h>
+
+static void
+nop(void)
+{
+}
+
+void (*_pin)(void) = nop;
+void (*_unpin)(void) = nop;
+
diff --git a/lib9/portdate b/lib9/portdate
@@ -1,30 +1,55 @@
-dofmt.c 2004/1225
-dorfmt.c 2004/1225
-errfmt.c 2004/1225
-fltfmt.c 2004/1225
-fmt.c 2004/1225
-fmtfd.c 2004/1225
-fmtlock.c 2004/1225
-fmtprint.c 2004/1225
-fmtquote.c 2004/1225
-fmtrune.c 2004/1225
-fmtstr.c 2004/1225
-fmtvprint.c 2004/1225
-fprint.c 2004/1225
-print.c 2004/1225
-runefmtstr.c 2004/1225
-runeseprint.c 2004/1225
-runesmprint.c 2004/1225
-runesnprint.c 2004/1225
-runesprint.c 2004/1225
-runevseprint.c 2004/1225
-runevsmprint.c 2004/1225
-runevsnprint.c 2004/1225
-seprint.c 2004/1225
-smprint.c 2004/1225
-snprint.c 2004/1225
-sprint.c 2004/1225
-vfprint.c 2004/1225
-vseprint.c 2004/1225
-vsmprint.c 2004/1225
-vsnprint.c 2004/1225
+announce.c 2004/1225
+atexit.c 2004/1225
+atnotify.c 2004/1225
+atol.c 2004/1225
+atoll.c 2004/1225
+cistrcmp.c 2004/1225
+cistrncmp.c 2004/1225
+cistrstr.c 2004/1225
+cleanname.c 2004/1225
+convD2M.c 2004/1225
+convM2D.c 2004/1225
+convM2S.c 2004/1225
+convS2M.c 2004/1225
+ctime.c 2004/1225
+dial.c 2004/1225
+dirfstat.c 2004/1225
+dirfwstat.c 2004/1225
+dirmodefmt.c 2004/1225
+dirread.c 2004/1225
+dirstat.c 2004/1225
+dirwstat.c 2004/1225
+encodefmt.c 2004/1225
+fcallfmt.c 2004/1225
+fork.c 2004/1225
+getenv.c 2004/1225
+getfields.c 2004/1225
+getuser.c 2004/1225
+getwd.c 2004/1225
+lnrand.c 2004/1225
+lock.c 2004/1225
+lrand.c 2004/1225
+malloc.c 2004/1225
+nan.c 2004/1225
+needsrcquote.c 2004/1225
+netmkaddr.c 2004/1225
+nrand.c 2004/1225
+nulldir.c 2004/1225
+postnote.c 2004/1225
+qlock.c 2004/1225
+quote.c 2004/1225
+rand.c 2004/1225
+read9pmsg.c 2004/1225
+readn.c 2004/1225
+strdup.c 2004/1225
+strecpy.c 2004/1225
+sysfatal.c 2004/1225
+sysname.c 2004/1225
+time.c 2004/1225
+tokenize.c 2004/1225
+truerand.c 2004/1225
+u16.c 2004/1225
+u32.c 2004/1225
+u64.c 2004/1225
+wait.c 2004/1225
+waitpid.c 2004/1225
diff --git a/lib9/post9p.c b/lib9/post9p.c
@@ -1,46 +1,83 @@
#include <u.h>
#include <libc.h>
+int chattyfuse;
+
int
-post9pservice(int fd, char *name)
+post9pservice(int fd, char *name, char *mtpt)
{
- int i;
- char *ns, *s;
+ int i, pid;
+ char *ns, *addr;
Waitmsg *w;
- if(strchr(name, '!')) /* assume is already network address */
- s = strdup(name);
- else{
- if((ns = getns()) == nil)
- return -1;
- s = smprint("unix!%s/%s", ns, name);
- free(ns);
- }
- if(s == nil)
- return -1;
- switch(fork()){
- case -1:
+ if(name == nil && mtpt == nil){
+ close(fd);
+ werrstr("nothing to do");
return -1;
- case 0:
- dup(fd, 0);
- dup(fd, 1);
- for(i=3; i<20; i++)
- close(i);
- execlp("9pserve", "9pserve", "-u", s, (char*)0);
- fprint(2, "exec 9pserve: %r\n");
- _exits("exec");
- default:
- w = wait();
- if(w == nil)
+ }
+
+ if(name){
+ if(strchr(name, '!')) /* assume is already network addr…
+ addr = strdup(name);
+ else{
+ if((ns = getns()) == nil)
+ return -1;
+ addr = smprint("unix!%s/%s", ns, name);
+ free(ns);
+ }
+ if(addr == nil)
+ return -1;
+ switch(pid = fork()){
+ case -1:
return -1;
+ case 0:
+ dup(fd, 0);
+ dup(fd, 1);
+ for(i=3; i<20; i++)
+ close(i);
+ execlp("9pserve", "9pserve", "-u", addr, (char*)0);
+ fprint(2, "exec 9pserve: %r\n");
+ _exits("exec");
+ }
close(fd);
- free(s);
+ w = waitfor(pid);
+ if(w == nil)
+ return -1;
if(w->msg && w->msg[0]){
free(w);
werrstr("9pserve failed");
return -1;
}
free(w);
- return 0;
+ if(mtpt){
+ /* reopen */
+ if((fd = dial(addr, nil, nil, nil)) < 0){
+ werrstr("cannot reopen for mount: %r");
+ return -1;
+ }
+ }
+ free(addr);
+ }
+ if(mtpt){
+ switch(pid = rfork(RFFDG|RFPROC|RFNOWAIT)){
+ case -1:
+ return -1;
+ case 0:
+ dup(fd, 0);
+ for(i=3; i<20; i++)
+ close(i);
+
+ /* Try v9fs on Linux, which will mount 9P directly. */
+ execlp("mount9p", "mount9p", "-", mtpt, (char*)0);
+
+ if(chattyfuse)
+ execlp("9pfuse", "9pfuse", "-D", "-", mtpt, (c…
+ else
+ execlp("9pfuse", "9pfuse", "-", mtpt, (char*)0…
+ fprint(2, "exec 9pfuse: %r\n");
+ _exits("exec");
+ }
+ close(fd);
}
+ return 0;
}
diff --git a/lib9/rand.c b/lib9/rand.c
@@ -1,8 +1,5 @@
#include <lib9.h>
-extern long p9lrand(void);
-#define lrand p9lrand
-
int
p9rand(void)
{
diff --git a/lib9/readn.c b/lib9/readn.c
@@ -1,5 +1,4 @@
#include <lib9.h>
-#include <unistd.h>
long
readn(int f, void *av, long n)
diff --git a/lib9/regex/regcomp.c b/lib9/regex/regcomp.c
@@ -261,18 +261,18 @@ optimize(Reprog *pp)
case STAR:
case PLUS:
case QUEST:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
break;
case CCLASS:
case NCCLASS:
- *(char **)&inst->u1.right += diff;
+ inst->u1.right = (void*)((char*)inst->u1.right + diff);
cl = inst->u1.cp;
- *(char **)&cl->end += diff;
+ cl->end = (void*)((char*)cl->end + diff);
break;
}
- *(char **)&inst->u2.left += diff;
+ inst->u2.left = (void*)((char*)inst->u2.left + diff);
}
- *(char **)&npp->startinst += diff;
+ npp->startinst = (void*)((char*)npp->startinst + diff);
return npp;
}
diff --git a/lib9/regex/regexec.c b/lib9/regex/regexec.c
@@ -58,7 +58,7 @@ regexec1(Reprog *progp, /* program to run */
p = utfrune(s, '\n');
if(p == 0 || s == j->eol)
return match;
- s = p;
+ s = p+1;
break;
}
}
diff --git a/lib9/regex/rregexec.c b/lib9/regex/rregexec.c
@@ -25,6 +25,7 @@ rregexec1(Reprog *progp, /* program to run */
Relist* tle; /* ends of this and next list */
Relist* nle;
int match;
+ Rune *p;
match = 0;
checkstart = j->startchar;
@@ -44,20 +45,18 @@ rregexec1(Reprog *progp, /* program to run */
if(checkstart) {
switch(j->starttype) {
case RUNE:
- while(*s != j->startchar) {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, j->startchar);
+ if(p == 0 || p == j->reol)
+ return match;
+ s = p;
break;
case BOL:
if(s == bol)
break;
- while(*s != '\n') {
- if(*s == 0 || s == j->reol)
- return match;
- s++;
- }
+ p = runestrchr(s, '\n');
+ if(p == 0 || s == j->reol)
+ return match;
+ s = p+1;
break;
}
}
diff --git a/lib9/rfork.c b/lib9/rfork.c
@@ -17,11 +17,12 @@ p9rfork(int flags)
int p[2];
int n;
char buf[128], *q;
+ extern char **environ;
if((flags&(RFPROC|RFFDG|RFMEM)) == (RFPROC|RFFDG)){
/* check other flags before we commit */
- flags &= ~(RFPROC|RFFDG);
- n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT));
+ flags &= ~(RFPROC|RFFDG|RFENVG);
+ n = (flags & ~(RFNOTEG|RFNAMEG|RFNOWAIT|RFCENVG));
if(n){
werrstr("unknown flags %08ux in rfork", n);
return -1;
@@ -99,9 +100,12 @@ p9rfork(int flags)
}
if(pid != 0)
return pid;
+ if(flags&RFCENVG)
+ if(environ)
+ *environ = nil;
}
if(flags&RFPROC){
- werrstr("cannot use rfork for shared memory -- use ffork");
+ werrstr("cannot use rfork for shared memory -- use libthread");
return -1;
}
if(flags&RFNAMEG){
diff --git a/lib9/sendfd.c b/lib9/sendfd.c
@@ -78,7 +78,10 @@ recvfd(int s)
if((n=recvmsg(s, &msg, 0)) < 0)
return -1;
-
+ if(n == 0){
+ werrstr("unexpected EOF");
+ return -1;
+ }
cmsg = CMSG_FIRSTHDR(&msg);
fd = *(int*)CMSG_DATA(cmsg);
return fd;
diff --git a/lib9/sleep.c b/lib9/sleep.c
@@ -1,9 +1,21 @@
#include <u.h>
#define NOPLAN9DEFINES
+#include <sys/param.h>
#include <sys/time.h>
#include <sched.h>
#include <libc.h>
+#if defined(__NetBSD__) || (defined(__OpenBSD__) && OpenBSD <= 200611)
+#if !defined(sched_yield)
+# define sched_yield() \
+ do{ struct timespec ts; \
+ ts.tv_sec = 0; \
+ ts.tv_nsec = 0; \
+ nanosleep(&ts, 0); \
+ }while(0)
+#endif
+#endif
+
int
p9sleep(long milli)
{
diff --git a/lib9/sysfatal.c b/lib9/sysfatal.c
@@ -1,10 +1,5 @@
#include <lib9.h>
-#include <stdarg.h>
-#include "fmt.h"
-extern char *argv0;
-extern void __fixargv0(void);
-extern void exits(char*);
void (*_sysfatal)(char*, ...);
void
diff --git a/lib9/test.c b/lib9/test.c
@@ -0,0 +1,8 @@
+#include <lib9.h>
+
+int
+main(int argc, char **argv)
+{
+ werrstr("hello world");
+ print("%r\n");
+}
diff --git a/lib9/testfltfmt.c b/lib9/testfltfmt.c
@@ -0,0 +1,183 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+/*
+ * try all combination of flags and float conversions
+ * with some different widths & precisions
+ */
+
+#define Njust 2
+#define Nplus 3
+#define Nalt 2
+#define Nzero 2
+#define Nspec 5
+#define Nwidth 5
+#define Nprec 5
+
+static double fmtvals[] = {
+ 3.1415925535897932e15,
+ 3.1415925535897932e14,
+ 3.1415925535897932e13,
+ 3.1415925535897932e12,
+ 3.1415925535897932e11,
+ 3.1415925535897932e10,
+ 3.1415925535897932e9,
+ 3.1415925535897932e8,
+ 3.1415925535897932e7,
+ 3.1415925535897932e6,
+ 3.1415925535897932e5,
+ 3.1415925535897932e4,
+ 3.1415925535897932e3,
+ 3.1415925535897932e2,
+ 3.1415925535897932e1,
+ 3.1415925535897932e0,
+ 3.1415925535897932e-1,
+ 3.1415925535897932e-2,
+ 3.1415925535897932e-3,
+ 3.1415925535897932e-4,
+ 3.1415925535897932e-5,
+ 3.1415925535897932e-6,
+ 3.1415925535897932e-7,
+ 3.1415925535897932e-8,
+ 3.1415925535897932e-9,
+ 3.1415925535897932e-10,
+ 3.1415925535897932e-11,
+ 3.1415925535897932e-12,
+ 3.1415925535897932e-13,
+ 3.1415925535897932e-14,
+ 3.1415925535897932e-15,
+};
+
+/*
+ * are the numbers close?
+ * used to compare long numbers where the last few digits are garbage
+ * due to precision problems
+ */
+static int
+numclose(char *num1, char *num2)
+{
+ int ndig;
+ double d1, d2;
+ enum { MAXDIG = 15 };
+
+ d1 = fmtstrtod(num1, 0);
+ d2 = fmtstrtod(num2, 0);
+ if(d1 != d2)
+ return 0;
+
+ ndig = 0;
+ while (*num1) {
+ if (*num1 >= '0' && *num1 <= '9') {
+ ndig++;
+ if (ndig > MAXDIG) {
+ if (!(*num2 >= '0' && *num2 <= '9')) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ }
+ } else if (*num1 != *num2) {
+ return 0;
+ } else if (*num1 == 'e' || *num1 == 'E') {
+ ndig = 0;
+ }
+ num1++;
+ num2++;
+ }
+ if (*num1 || !num2)
+ return 0;
+ return 1;
+}
+
+static void
+doit(int just, int plus, int alt, int zero, int width, int prec, int spec)
+{
+ char format[256];
+ char *p;
+ const char *s;
+ int i;
+
+ p = format;
+ *p++ = '%';
+ if (just > 0)
+ *p++ = "-"[just - 1];
+ if (plus > 0)
+ *p++ = "+ "[plus - 1];
+ if (alt > 0)
+ *p++ = "#"[alt - 1];
+ if (zero > 0)
+ *p++ = "0"[zero - 1];
+
+ s = "";
+ switch (width) {
+ case 1: s = "1"; break;
+ case 2: s = "5"; break;
+ case 3: s = "10"; break;
+ case 4: s = "15"; break;
+ }
+ strcpy(p, s);
+
+ s = "";
+ switch (prec) {
+ case 1: s = ".0"; break;
+ case 2: s = ".2"; break;
+ case 3: s = ".5"; break;
+ case 4: s = ".15"; break;
+ }
+ strcat(p, s);
+
+ p = strchr(p, '\0');
+ *p++ = "efgEG"[spec];
+ *p = '\0';
+
+ for (i = 0; i < sizeof(fmtvals) / sizeof(fmtvals[0]); i++) {
+ char ref[1024], buf[1024];
+ Rune rbuf[1024];
+ double d1, d2;
+
+ sprintf(ref, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), format, fmtvals[i]);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)…
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)…
+ // exits("oops");
+ }
+
+ /* Check again with output to rune string */
+ runesnprint(rbuf, 1024, format, fmtvals[i]);
+ snprint(buf, sizeof(buf), "%S", rbuf);
+ if (strcmp(ref, buf) != 0
+ && !numclose(ref, buf)) {
+ d1 = fmtstrtod(ref, 0);
+ d2 = fmtstrtod(buf, 0);
+ fprintf(stderr, "%s: ref='%s'%s fmt='%s'%s\n",
+ format,
+ ref, d1==fmtvals[i] ? "" : " (ref is inexact!)…
+ buf, d2==fmtvals[i] ? "" : " (fmt is inexact!)…
+ // exits("oops");
+ }
+ }
+}
+
+void
+main(int argc, char **argv)
+{
+ int just, plus, alt, zero, width, prec, spec;
+
+ for (just = 0; just < Njust; just++)
+ for (plus = 0; plus < Nplus; plus++)
+ for (alt = 0; alt < Nalt; alt++)
+ for (zero = 0; zero < Nzero; zero++)
+ for (width = 0; width < Nwidth; width++)
+ for (prec = 0; prec < Nprec; prec++)
+ for (spec = 0; spec < Nspec; spec++)
+ doit(just, plus, alt, zero, width, prec, spec);
+
+ exits(0);
+}
diff --git a/lib9/testfmt.c b/lib9/testfmt.c
@@ -0,0 +1,148 @@
+#include <u.h>
+#include <libc.h>
+#include <stdio.h>
+
+int failed;
+
+/* Consume argument and ignore it */
+int
+Zflag(Fmt* f)
+{
+ if(va_arg(f->args, int))
+ ;
+ return 1; /* it's a flag */
+}
+
+void
+verify(char *s, char *t)
+{
+ if(strcmp(s, t) != 0){
+ failed = 1;
+ fprintf(stderr, "error: (%s) != (%s)\n", s, t);
+ }
+ free(s);
+}
+
+Rune lightsmiley = 0x263a;
+Rune darksmiley = 0x263b;
+
+/* Test printer that loads unusual decimal point and separator */
+char*
+mysmprint(char *fmt, ...)
+{
+ Fmt f;
+
+ if(fmtstrinit(&f) < 0)
+ return 0;
+ va_start(f.args, fmt);
+ f.decimal = smprint("%C", lightsmiley);
+ f.thousands = smprint("%C", darksmiley);
+ f.grouping = "\1\2\3\4";
+ if(dofmt(&f, fmt) < 0)
+ return 0;
+ va_end(f.args);
+ return fmtstrflush(&f);
+}
+
+double near1[] = {
+ 0.5,
+ 0.95,
+ 0.995,
+ 0.9995,
+ 0.99995,
+ 0.999995,
+ 0.9999995,
+ 0.99999995,
+ 0.999999995,
+};
+
+void
+main(int argc, char **argv)
+{
+ int i, j;
+
+ quotefmtinstall();
+ fmtinstall('Z', Zflag);
+ fmtinstall(L'\x263a', Zflag);
+#ifdef PLAN9PORT
+{ extern int __ifmt(Fmt*);
+ fmtinstall('i', __ifmt);
+}
+#endif
+
+ verify(smprint("hello world"), "hello world");
+#ifdef PLAN9PORT
+ verify(smprint("x: %ux", 0x87654321), "x: 87654321");
+#else
+ verify(smprint("x: %x", 0x87654321), "x: 87654321");
+#endif
+ verify(smprint("d: %d", 0x87654321), "d: -2023406815");
+ verify(smprint("s: %s", "hi there"), "s: hi there");
+ verify(smprint("q: %q", "hi i'm here"), "q: 'hi i''m here'");
+ verify(smprint("c: %c", '!'), "c: !");
+ verify(smprint("g: %g %g %g", 3.14159, 3.14159e10, 3.14159e-10), "g: 3…
+ verify(smprint("e: %e %e %e", 3.14159, 3.14159e10, 3.14159e-10), "e: 3…
+ verify(smprint("f: %f %f %f", 3.14159, 3.14159e10, 3.14159e-10), "f: 3…
+ verify(smprint("smiley: %C", (Rune)0x263a), "smiley: \xe2\x98\xba");
+ verify(smprint("%g %.18g", 2e25, 2e25), "2e+25 2e+25");
+ verify(smprint("%2.18g", 1.0), " 1");
+ verify(smprint("%f", 3.1415927/4), "0.785398");
+ verify(smprint("%d", 23), "23");
+ verify(smprint("%i", 23), "23");
+ verify(smprint("%Zi", 1234, 23), "23");
+
+ /* ANSI and their wacky corner cases */
+ verify(smprint("%.0d", 0), "");
+ verify(smprint("%.0o", 0), "");
+ verify(smprint("%.0x", 0), "");
+ verify(smprint("%#.0o", 0), "0");
+ verify(smprint("%#.0x", 0), "");
+
+ /* difficult floating point tests that many libraries get wrong */
+ verify(smprint("%.100f", 1.0), "1.000000000000000000000000000000000000…
+ verify(smprint("%.100g", 1.0), "1");
+ verify(smprint("%0100f", 1.0), "00000000000000000000000000000000000000…
+ for(i=1; i<9; i++)
+ for(j=0; j<=i; j++)
+ verify(smprint("%.*g", j, near1[i]), "1");
+
+ /* test $ reorderings */
+ verify(smprint("%3$d %4$06d %2$d %1$d", 444, 333, 111, 222), "111 0002…
+ verify(smprint("%3$Zd %5$06d %2$d %1$d", 444, 333, 555, 111, 222), "11…
+ verify(smprint("%3$d %4$*5$06d %2$d %1$d", 444, 333, 111, 222, 20), "1…
+ verify(smprint("%3$hd %4$*5$06d %2$d %1$d", 444, 333, (short)111, 222,…
+ verify(smprint("%3$\xe2\x98\xba""d %5$06d %2$d %1$d", 444, 333, 555, 1…
+
+ /* test %'d formats */
+ verify(smprint("%'d %'d %'d", 1, 2222, 33333333), "1 2,222 33,333,333"…
+ verify(smprint("%'019d", 0), "000,000,000,000,000");
+ verify(smprint("%'08d %'08d %'08d", 1, 2222, 33333333), "0,000,001 0,0…
+#ifdef PLAN9PORT
+ verify(smprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "1111…
+#else
+ verify(smprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:11…
+#endif
+ verify(smprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333LL)…
+ verify(smprint("%'019lld %'019lld %'019lld", 1LL, 222222222LL, 3333333…
+#ifdef PLAN9PORT
+ verify(smprint("%'llux %'lluX %'llub", 0x111111111111LL, 0xabcd1234567…
+#else
+ verify(smprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678LL…
+#endif
+
+ /* test %'d with custom (utf-8!) separators */
+ /* x and b still use : */
+ verify(mysmprint("%'d %'d %'d", 1, 2222, 33333333), "1 2\xe2\x98\xbb""…
+#ifdef PLAN9PORT
+ verify(mysmprint("%'ux %'uX %'ub", 0x11111111, 0xabcd1234, 12345), "11…
+#else
+ verify(mysmprint("%'x %'X %'b", 0x11111111, 0xabcd1234, 12345), "1111:…
+#endif
+ verify(mysmprint("%'lld %'lld %'lld", 1LL, 222222222LL, 3333333333333L…
+ verify(mysmprint("%'llx %'llX %'llb", 0x111111111111LL, 0xabcd12345678…
+ verify(mysmprint("%.4f", 3.14159), "3\xe2\x98\xba""1416");
+
+ if(failed)
+ sysfatal("tests failed");
+ exits(0);
+}
diff --git a/lib9/testprint.c b/lib9/testprint.c
@@ -0,0 +1,14 @@
+#include <u.h>
+#include <libc.h>
+
+void
+main(int argc, char **argv)
+{
+ char c;
+
+ c = argv[1][strlen(argv[1])-1];
+ if(c == 'f' || c == 'e' || c == 'g' || c == 'F' || c == 'E' || c == 'G…
+ print(argv[1], atof(argv[2]));
+ else if(c == 'x' || c == 'u' || c == 'd' || c == 'c' || c == 'C' || c …
+ print(argv[1], atoi(argv[2]));
+}
diff --git a/lib9/tm2sec.c b/lib9/tm2sec.c
@@ -0,0 +1,110 @@
+#include <u.h>
+#include <libc.h>
+
+#include "zoneinfo.h"
+
+#define SEC2MIN 60L
+#define SEC2HOUR (60L*SEC2MIN)
+#define SEC2DAY (24L*SEC2HOUR)
+
+/*
+ * days per month plus days/year
+ */
+static int dmsize[] =
+{
+ 365, 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+static int ldmsize[] =
+{
+ 366, 31, 29, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
+};
+
+/*
+ * return the days/month for the given year
+ */
+static int *
+yrsize(int y)
+{
+ if((y%4) == 0 && ((y%100) != 0 || (y%400) == 0))
+ return ldmsize;
+ else
+ return dmsize;
+}
+
+/*
+ * compute seconds since Jan 1 1970 GMT
+ * and convert to our timezone.
+ */
+long
+tm2sec(Tm *tm)
+{
+ Tinfo ti0, ti1, *ti;
+ long secs;
+ int i, yday, year, *d2m;
+
+ secs = 0;
+
+ /*
+ * seconds per year
+ */
+ year = tm->year + 1900;
+ for(i = 1970; i < year; i++){
+ d2m = yrsize(i);
+ secs += d2m[0] * SEC2DAY;
+ }
+
+ /*
+ * if mday is set, use mon and mday to compute yday
+ */
+ if(tm->mday){
+ yday = 0;
+ d2m = yrsize(year);
+ for(i=0; i<tm->mon; i++)
+ yday += d2m[i+1];
+ yday += tm->mday-1;
+ }else{
+ yday = tm->yday;
+ }
+ secs += yday * SEC2DAY;
+
+ /*
+ * hours, minutes, seconds
+ */
+ secs += tm->hour * SEC2HOUR;
+ secs += tm->min * SEC2MIN;
+ secs += tm->sec;
+
+ /*
+ * Assume the local time zone if zone is not GMT
+ */
+ if(strcmp(tm->zone, "GMT") != 0) {
+ i = zonelookuptinfo(&ti0, secs);
+ ti = &ti0;
+ if (i != -1)
+ if (ti->tzoff!=0) {
+ /*
+ * to what local time period `secs' belongs?
+ */
+ if (ti->tzoff>0) {
+ /*
+ * east of GMT; check previous local time tran…
+ */
+ if (ti->t+ti->tzoff > secs)
+ if (zonetinfo(&ti1, i-1)!=-1)
+ ti = &ti1;
+ } else
+ /*
+ * west of GMT; check next local time transiti…
+ */
+ if (zonetinfo(&ti1, i+1))
+ if (ti1.t+ti->tzoff < secs)
+ ti = &ti1;
+// fprint(2, "tt: %ld+%d %ld\n", (long)ti->t, ti->tzoff…
+ secs -= ti->tzoff;
+ }
+ }
+
+ if(secs < 0)
+ secs = 0;
+ return secs;
+}
diff --git a/lib9/truerand.c b/lib9/truerand.c
@@ -15,7 +15,7 @@ truerand(void)
if(randfd < 0 || read(randfd, buf, 1) != 1)
randfd = open(randfile="/dev/srandom", OREAD); …
if(randfd < 0)
- sysfatal("can't open /dev/random: %r");
+ sysfatal("can't open %s: %r", randfile);
fcntl(randfd, F_SETFD, FD_CLOEXEC);
}
for(i=0; i<sizeof(buf); i += n)
diff --git a/lib9/u.h b/lib9/u.h
@@ -7,9 +7,10 @@ extern "C" {
#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
#if defined(__sun__)
# define __EXTENSIONS__ 1 /* SunOS */
-# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5…
+# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5…
/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
# else
+ /* What's left? */
# define __MAKECONTEXT_V2_SOURCE 1
# endif
#endif
@@ -20,6 +21,17 @@ extern "C" {
# define _XOPEN_SOURCE 1000
# define _XOPEN_SOURCE_EXTENDED 1
#endif
+#if defined(__FreeBSD__)
+# include <sys/cdefs.h>
+ /* for strtoll */
+# undef __ISO_C_VISIBLE
+# define __ISO_C_VISIBLE 1999
+# undef __LONG_LONG_SUPPORTED
+# define __LONG_LONG_SUPPORTED
+#endif
+#if defined(__AIX__)
+# define _XOPEN_SOURCE 1
+#endif
#define _LARGEFILE64_SOURCE 1
#define _FILE_OFFSET_BITS 64
@@ -33,8 +45,6 @@ extern "C" {
#include <assert.h>
#include <setjmp.h>
#include <stddef.h>
-#include <utf.h>
-#include <fmt.h>
#include <math.h>
#include <ctype.h> /* for tolower */
@@ -138,6 +148,7 @@ typedef int8_t s8int;
typedef uint16_t u16int;
typedef int16_t s16int;
typedef uintptr_t uintptr;
+typedef intptr_t intptr;
typedef uint32_t u32int;
typedef int32_t s32int;
@@ -150,17 +161,23 @@ typedef int32_t s32int;
* Funny-named symbols to tip off 9l to autolink.
*/
#define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
+#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
/*
* Gcc is too smart for its own good.
*/
#if defined(__GNUC__)
+# undef strcmp /* causes way too many warnings */
# if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__))
# undef AUTOLIB
# define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((wea…
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attri…
# else
# undef AUTOLIB
# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute_…
+# undef AUTOFRAMEWORK
+# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x …
# endif
#endif
diff --git a/lib9/utf.h b/lib9/utf.h
@@ -11,7 +11,7 @@ enum
UTFmax = 3, /* maximum bytes per rune */
Runesync = 0x80, /* cannot represent part of a U…
Runeself = 0x80, /* rune and UTF sequences are t…
- Runeerror = 0xFFFD, /* decoding error in UTF */
+ Runeerror = 0xFFFD /* decoding error in UTF */
};
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
diff --git a/lib9/utf/NOTICE b/lib9/utf/NOTICE
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE …
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff --git a/lib9/utf/README b/lib9/utf/README
@@ -0,0 +1,13 @@
+/*
+ * The authors of this software are Rob Pike and Ken Thompson.
+ * Copyright (c) 1998-2002 by Lucent Technologies.
+ * Permission to use, copy, modify, and distribute this software for any
+ * purpose without fee is hereby granted, provided that this entire notice
+ * is included in all copies of any software which is or includes a copy
+ * or modification of this software and in all copies of the supporting
+ * documentation for such software.
+ * THIS SOFTWARE IS BEING PROVIDED "AS IS", WITHOUT ANY EXPRESS OR IMPLIED
+ * WARRANTY. IN PARTICULAR, NEITHER THE AUTHORS NOR LUCENT TECHNOLOGIES MAKE …
+ * REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
+ * OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
+ */
diff --git a/lib9/lib9.h b/lib9/utf/lib9.h
diff --git a/lib9/utf/rune.c b/lib9/utf/rune.c
@@ -37,7 +37,7 @@ enum
Maskx = (1<<Bitx)-1, /* 0011 1111 */
Testx = Maskx ^ 0xFF, /* 1100 0000 */
- Bad = Runeerror,
+ Bad = Runeerror
};
int
diff --git a/lib9/utf/utfecpy.c b/lib9/utf/utfecpy.c
@@ -11,6 +11,7 @@
* ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING THE MERCHANTABILITY
* OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
*/
+#define _BSD_SOURCE 1 /* memccpy */
#include <stdarg.h>
#include <string.h>
#include "plan9.h"
diff --git a/lib9/write.c b/lib9/write.c
@@ -0,0 +1,23 @@
+#include <u.h>
+#define NOPLAN9DEFINES
+#include <libc.h>
+
+long
+p9write(int f, void *av, long n)
+{
+ char *a;
+ long m, t;
+
+ a = av;
+ t = 0;
+ while(t < n){
+ m = write(f, a+t, n-t);
+ if(m <= 0){
+ if(t == 0)
+ return m;
+ break;
+ }
+ t += m;
+ }
+ return t;
+}
diff --git a/lib9/zoneinfo.c b/lib9/zoneinfo.c
@@ -0,0 +1,215 @@
+#include <u.h>
+#include <libc.h>
+
+/*
+ * Access local time entries of zoneinfo files.
+ * Formats 0 and 2 are supported, and 4-byte timestamps
+ *
+ * Copyright © 2008 M. Teichgräber
+ * Contributed under the terms of the Lucent Public License 1.02.
+ */
+#include "zoneinfo.h"
+
+static
+struct Zoneinfo
+{
+ int timecnt; /* # of transition times */
+ int typecnt; /* # of local time types */
+ int charcnt; /* # of characters of time zone abb…
+
+ uchar *ptime;
+ uchar *ptype;
+ uchar *ptt;
+ uchar *pzone;
+} z;
+
+static uchar *tzdata;
+
+static
+uchar*
+readtzfile(char *file)
+{
+ uchar *p;
+ int fd;
+ Dir *d;
+
+ fd = open(file, OREAD);
+ if (fd<0)
+ return nil;
+ d = dirfstat(fd);
+ if (d==nil)
+ return nil;
+ p = malloc(d->length);
+ if (p!=nil)
+ readn(fd, p, d->length);
+ free(d);
+ close(fd);
+ return p;
+}
+static char *zonefile;
+void
+tzfile(char *f)
+{
+ if (tzdata!=nil) {
+ free(tzdata);
+ tzdata = nil;
+ }
+ z.timecnt = 0;
+ zonefile = f;
+}
+
+static
+long
+get4(uchar *p)
+{
+ return (p[0]<<24)+(p[1]<<16)+(p[2]<<8)+p[3];
+}
+
+enum {
+ TTinfosz = 4+1+1,
+};
+
+static
+int
+parsehead(void)
+{
+ uchar *p;
+ int ver;
+
+ ver = tzdata[4];
+ if (ver!=0)
+ if (ver!='2')
+ return -1;
+
+ p = tzdata + 4 + 1 + 15;
+
+ z.timecnt = get4(p+3*4);
+ z.typecnt = get4(p+4*4);
+ if (z.typecnt==0)
+ return -1;
+ z.charcnt = get4(p+5*4);
+ z.ptime = p+6*4;
+ z.ptype = z.ptime + z.timecnt*4;
+ z.ptt = z.ptype + z.timecnt;
+ z.pzone = z.ptt + z.typecnt*TTinfosz;
+ return 0;
+}
+
+static
+void
+ttinfo(Tinfo *ti, int tti)
+{
+ uchar *p;
+ int i;
+
+ i = z.ptype[tti];
+ assert(i<z.typecnt);
+ p = z.ptt + i*TTinfosz;
+ ti->tzoff = get4(p);
+ ti->dlflag = p[4];
+ assert(p[5]<z.charcnt);
+ ti->zone = (char*)z.pzone + p[5];
+}
+
+static
+void
+readtimezone(void)
+{
+ char *tmp;
+
+ z.timecnt = 0;
+ switch (zonefile==nil) {
+ default:
+ if ((tmp=getenv("timezone"))!=nil) {
+ tzdata = readtzfile(tmp);
+ free(tmp);
+ break;
+ }
+ zonefile = "/etc/localtime";
+ /* fall through */
+ case 0:
+ tzdata = readtzfile(zonefile);
+ }
+ if (tzdata==nil)
+ return;
+
+ if (strncmp("TZif", (char*)tzdata, 4)!=0)
+ goto errfree;
+
+ if (parsehead()==-1) {
+ errfree:
+ free(tzdata);
+ tzdata = nil;
+ z.timecnt = 0;
+ return;
+ }
+}
+
+static
+tlong
+gett4(uchar *p)
+{
+ long l;
+
+ l = get4(p);
+ if (l<0)
+ return 0;
+ return l;
+}
+int
+zonetinfo(Tinfo *ti, int i)
+{
+ if (tzdata==nil)
+ readtimezone();
+ if (i<0 || i>=z.timecnt)
+ return -1;
+ ti->t = gett4(z.ptime + 4*i);
+ ttinfo(ti, i);
+ return i;
+}
+
+int
+zonelookuptinfo(Tinfo *ti, tlong t)
+{
+ uchar *p;
+ int i;
+ tlong oldtt, tt;
+
+ if (tzdata==nil)
+ readtimezone();
+ oldtt = 0;
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ tt = gett4(p);
+ if (t<tt)
+ break;
+ oldtt = tt;
+ p += 4;
+ }
+ if (i>0) {
+ ttinfo(ti, i-1);
+ ti->t = oldtt;
+// fprint(2, "t:%ld off:%d dflag:%d %s\n", (long)ti->t, ti->tzo…
+ return i-1;
+ }
+ return -1;
+}
+
+void
+zonedump(int fd)
+{
+ int i;
+ uchar *p;
+ tlong t;
+ Tinfo ti;
+
+ if (tzdata==nil)
+ readtimezone();
+ p = z.ptime;
+ for (i=0; i<z.timecnt; i++) {
+ t = gett4(p);
+ ttinfo(&ti, i);
+ fprint(fd, "%ld\t%d\t%d\t%s\n", (long)t, ti.tzoff, ti.dlflag, …
+ p += 4;
+ }
+}
diff --git a/lib9/zoneinfo.h b/lib9/zoneinfo.h
@@ -0,0 +1,19 @@
+#define zonetinfo _p9zonetinfo
+#define zonedump _p9zonedump
+#define zonelookuptinfo _p9zonelookuptinfo
+
+typedef long tlong;
+
+typedef
+struct Tinfo
+{
+ long t;
+ int tzoff;
+ int dlflag;
+ char *zone;
+} Tinfo;
+
+extern int zonelookuptinfo(Tinfo*, tlong);
+extern int zonetinfo(Tinfo*, int);
+extern void zonedump(int fd);
+
diff --git a/ls/ls.c b/ls/ls.c
@@ -227,17 +227,16 @@ format(Dir *db, char *name)
db->qid.type);
if(lflag)
Bprint(&bin,
- Qflag? "%M %C %*ud %*s %s %*llud %s %s\n" : "%M %C %*u…
+ "%M %C %*ud %*s %s %*llud %s ",
db->mode, db->type,
vwidth, db->dev,
-uwidth, db->uid,
db->gid,
(int)(glwidth-strlen(db->gid)), db->length,
- asciitime(uflag? db->atime : db->mtime), name);
- else
- Bprint(&bin,
- Qflag? "%s%s\n" : "%q%s\n",
- name, fileflag(db));
+ asciitime(uflag? db->atime : db->mtime));
+ Bprint(&bin,
+ Qflag? "%s%s\n" : "%q%s\n",
+ name, fileflag(db));
}
void
diff --git a/mk/Makefile b/mk/Makefile
@@ -1,37 +0,0 @@
-# basename - basename unix port from plan9
-# Depends on ../lib9
-
-TARG = mk
-OFILES = arc.o archive.o bufblock.o env.o file.o graph.o job.o\
- lex.o main.o match.o mk.o parse.o recipe.o rc.o rule.o\
- run.o sh.o shell.o shprint.o symtab.o var.o varsub.o\
- word.o unix.o
-MANFILES = ${TARG}.1
-
-include ../config.mk
-
-all: ${TARG}
- @echo built ${TARG}
-
-install: ${TARG}
- @mkdir -p ${DESTDIR}${PREFIX}/bin
- @cp -f ${TARG} ${DESTDIR}${PREFIX}/bin/
- @chmod 755 ${DESTDIR}${PREFIX}/bin/${TARG}
- @mkdir -p ${DESTDIR}${MANPREFIX}/man1
- @cp -f ${MANFILES} ${DESTDIR}${MANPREFIX}/man1
- @chmod 444 ${DESTDIR}${MANPREFIX}/man1/${MANFILES}
-
-uninstall:
- rm -f ${DESTDIR}${PREFIX}/bin/${TARG}
- rm -f ${DESTDIR}${PREFIX}/man1/${MANFILES}
-
-.c.o:
- @echo CC $*.c
- @${CC} ${CFLAGS} -I../lib9 -I${PREFIX}/include -I../lib9 $*.c
-
-clean:
- rm -f ${OFILES} ${TARG}
-
-${TARG}: ${OFILES}
- @echo LD ${TARG}
- @${CC} ${LDFLAGS} -o ${TARG} ${OFILES} -L${PREFIX}/lib -L../lib9 -l9
diff --git a/mk/NOTICE b/mk/NOTICE
@@ -1,27 +0,0 @@
-Copyright © 1994-1999 Lucent Technologies Inc. All rights reserved.
-Portions Copyright © 1995-1997 C H Forsyth ([email protected]). All …
-Portions Copyright © 1997-1999 Vita Nuova Limited. All rights reserved.
-Portions Copyright © 2000-2002 Vita Nuova Holdings Limited (www.vitanuova.com…
-
-Under a licence agreement with Lucent Technologies Inc. effective 1st March 20…
-Vita Nuova Holdings Limited has the right to determine (within a specified sco…
-the form and content of sublicences for this software.
-
-Vita Nuova Holdings Limited now makes this software available as Free
-Software under the terms of the `GNU General Public LIcense, Version 2'
-(see the file LICENCE or http://www.fsf.org/copyleft/gpl.html for
-the full terms and conditions). One of the conditions of that licence
-is that you must keep intact all notices that refer to that licence and to the…
-of any warranty: for this software, note that includes this NOTICE file in par…
-
-This suite of programs is distributed in the hope that it will be useful,
-but WITHOUT ANY WARRANTY; without even the implied warranty of
-MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
-`GNU General Public License' for more details.
-
-This copyright NOTICE applies to all files in this directory and
-subdirectories, unless another copyright notice appears in a given
-file or subdirectory. If you take code from this software to use in
-other programs, you must somehow include with it an appropriate
-copyright notice that includes the copyright notice and the other
-notices above.
diff --git a/mk/README b/mk/README
@@ -1,7 +0,0 @@
-This is a Unix port of mk,
-originally done for the Inferno operating system.
-
-Russ Cox repackaged this to build as a standalone
-Unix program. Send comments about packaging to
-Russ Cox <[email protected]>
-
diff --git a/mk/arc.c b/mk/arc.c
@@ -1,52 +0,0 @@
-#include "mk.h"
-
-Arc *
-newarc(Node *n, Rule *r, char *stem, Resub *match)
-{
- Arc *a;
-
- a = (Arc *)Malloc(sizeof(Arc));
- a->n = n;
- a->r = r;
- a->stem = strdup(stem);
- rcopy(a->match, match, NREGEXP);
- a->next = 0;
- a->flag = 0;
- a->prog = r->prog;
- return(a);
-}
-
-void
-dumpa(char *s, Arc *a)
-{
- char buf[1024];
-
- Bprint(&bout, "%sArc@%p: n=%p r=%p flag=0x%x stem='%s'",
- s, a, a->n, a->r, a->flag, a->stem);
- if(a->prog)
- Bprint(&bout, " prog='%s'", a->prog);
- Bprint(&bout, "\n");
-
- if(a->n){
- snprint(buf, sizeof(buf), "%s ", (*s == ' ')? s:"");
- dumpn(buf, a->n);
- }
-}
-
-void
-nrep(void)
-{
- Symtab *sym;
- Word *w;
-
- sym = symlook("NREP", S_VAR, 0);
- if(sym){
- w = (Word *) sym->value;
- if (w && w->s && *w->s)
- nreps = atoi(w->s);
- }
- if(nreps < 1)
- nreps = 1;
- if(DEBUG(D_GRAPH))
- Bprint(&bout, "nreps = %d\n", nreps);
-}
diff --git a/mk/archive.c b/mk/archive.c
@@ -1,253 +0,0 @@
-#include "mk.h"
-#define ARMAG "!<arch>\n"
-#define SARMAG 8
-
-#define ARFMAG "`\n"
-#define SARNAME 16
-
-struct ar_hdr
-{
- char name[SARNAME];
- char date[12];
- char uid[6];
- char gid[6];
- char mode[8];
- char size[10];
- char fmag[2];
-};
-#define SAR_HDR (SARNAME+44)
-
-static int dolong = 1;
-
-static void atimes(char *);
-static char *split(char*, char**);
-
-long
-readn(int f, void *av, long n)
-{
- char *a;
- long m, t;
-
- a = av;
- t = 0;
- while(t < n){
- m = read(f, a+t, n-t);
- if(m <= 0){
- if(t == 0)
- return m;
- break;
- }
- t += m;
- }
- return t;
-}
-long
-atimeof(int force, char *name)
-{
- Symtab *sym;
- long t;
- char *archive, *member, buf[512];
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- t = mtime(archive);
- sym = symlook(archive, S_AGG, 0);
- if(sym){
- if(force || (t > (long)sym->value)){
- atimes(archive);
- sym->value = (void *)t;
- }
- }
- else{
- atimes(archive);
- /* mark the aggegate as having been done */
- symlook(strdup(archive), S_AGG, "")->value = (void *)t;
- }
- /* truncate long member name to sizeof of name field in archiv…
- if(dolong)
- snprint(buf, sizeof(buf), "%s(%s)", archive, member);
- else
- snprint(buf, sizeof(buf), "%s(%.*s)", archive, SARNAME, member…
- sym = symlook(buf, S_TIME, 0);
- if (sym)
- return (long)sym->value; /* uggh */
- return 0;
-}
-
-void
-atouch(char *name)
-{
- char *archive, *member;
- int fd, i;
- struct ar_hdr h;
- long t;
-
- archive = split(name, &member);
- if(archive == 0)
- Exit();
-
- fd = open(archive, ORDWR);
- if(fd < 0){
- fd = create(archive, OWRITE, 0666);
- if(fd < 0){
- fprint(2, "create %s: %r\n", archive);
- Exit();
- }
- write(fd, ARMAG, SARMAG);
- }
- if(symlook(name, S_TIME, 0)){
- /* hoon off and change it in situ */
- LSEEK(fd, SARMAG, 0);
- while(read(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- for(i = SARNAME-1; i > 0 && h.name[i] == ' '; i--)
- ;
- h.name[i+1]=0;
- if(strcmp(member, h.name) == 0){
- t = SARNAME-sizeof(h); /* ughgghh */
- LSEEK(fd, t, 1);
- fprint(fd, "%-12ld", time(0));
- break;
- }
- t = atol(h.size);
- if(t&01) t++;
- LSEEK(fd, t, 1);
- }
- }
- close(fd);
-}
-
-static void
-atimes(char *ar)
-{
- struct ar_hdr h;
- long t;
- int fd, i, namelen;
- char buf[2048], *p, *strings;
- char name[1024];
- Symtab *sym;
-
- strings = nil;
- fd = open(ar, OREAD);
- if(fd < 0)
- return;
-
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return;
- }
- while(readn(fd, (char *)&h, sizeof(h)) == sizeof(h)){
- t = atol(h.date);
- if(t == 0) /* as it sometimes happens; thanks ken */
- t = 1;
- namelen = 0;
- if(memcmp(h.name, "#1/", 3) == 0){ /* BSD */
- namelen = atoi(h.name+3);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- if(readn(fd, name, namelen) != namelen)
- break;
- name[namelen] = 0;
- }else if(memcmp(h.name, "// ", 2) == 0){ /* GNU */
- /* date, uid, gid, mode all ' ' */
- for(i=2; i<16+12+6+6+8; i++)
- if(h.name[i] != ' ')
- goto skip;
- t = atol(h.size);
- if(t&01)
- t++;
- free(strings);
- strings = malloc(t+1);
- if(strings){
- if(readn(fd, strings, t) != t){
- free(strings);
- strings = nil;
- break;
- }
- strings[t] = 0;
- continue;
- }
- goto skip;
- }else if(strings && h.name[0]=='/' && isdigit((uchar)h.name[1]…
- i = strtol(h.name+1, &p, 10);
- if(*p != ' ' || i >= strlen(strings))
- goto skip;
- p = strings+i;
- for(; *p && *p != '/'; p++)
- ;
- namelen = p-(strings+i);
- if(namelen >= sizeof name){
- namelen = 0;
- goto skip;
- }
- memmove(name, strings+i, namelen);
- name[namelen] = 0;
- namelen = 0;
- }else{
- strncpy(name, h.name, sizeof(h.name));
- for(i = sizeof(h.name)-1; i > 0 && name[i] == ' '; i--)
- ;
- if(name[i] == '/') /* system V bug */
- i--;
- name[i+1]=0;
- }
- snprint(buf, sizeof buf, "%s(%s)", ar, name);
- sym = symlook(strdup(buf), S_TIME, (void *)t);
- sym->value = (void *)t;
- skip:
- t = atol(h.size);
- if(t&01) t++;
- t -= namelen;
- LSEEK(fd, t, 1);
- }
- close(fd);
- free(strings);
-}
-
-static int
-type(char *file)
-{
- int fd;
- char buf[SARMAG];
-
- fd = open(file, OREAD);
- if(fd < 0){
- if(symlook(file, S_BITCH, 0) == 0){
- if(strlen(file) < 2 || strcmp(file+strlen(file)-2, ".a…
- Bprint(&bout, "%s doesn't exist: assuming it w…
- symlook(file, S_BITCH, (void *)file);
- }
- return 1;
- }
- if(read(fd, buf, SARMAG) != SARMAG){
- close(fd);
- return 0;
- }
- close(fd);
- return !strncmp(ARMAG, buf, SARMAG);
-}
-
-static char*
-split(char *name, char **member)
-{
- char *p, *q;
-
- p = strdup(name);
- q = utfrune(p, '(');
- if(q){
- *q++ = 0;
- if(member)
- *member = q;
- q = utfrune(q, ')');
- if (q)
- *q = 0;
- if(type(p))
- return p;
- free(p);
- fprint(2, "mk: '%s' is not an archive\n", name);
- }
- return 0;
-}
diff --git a/mk/bufblock.c b/mk/bufblock.c
@@ -1,88 +0,0 @@
-#include "mk.h"
-
-static Bufblock *freelist;
-#define QUANTA 4096
-
-Bufblock *
-newbuf(void)
-{
- Bufblock *p;
-
- if (freelist) {
- p = freelist;
- freelist = freelist->next;
- } else {
- p = (Bufblock *) Malloc(sizeof(Bufblock));
- p->start = Malloc(QUANTA*sizeof(*p->start));
- p->end = p->start+QUANTA;
- }
- p->current = p->start;
- *p->start = 0;
- p->next = 0;
- return p;
-}
-
-void
-freebuf(Bufblock *p)
-{
- p->next = freelist;
- freelist = p;
-}
-
-void
-growbuf(Bufblock *p)
-{
- int n;
- Bufblock *f;
- char *cp;
-
- n = p->end-p->start+QUANTA;
- /* search the free list for a big buffer */
- for (f = freelist; f; f = f->next) {
- if (f->end-f->start >= n) {
- memcpy(f->start, p->start, p->end-p->start);
- cp = f->start;
- f->start = p->start;
- p->start = cp;
- cp = f->end;
- f->end = p->end;
- p->end = cp;
- f->current = f->start;
- break;
- }
- }
- if (!f) { /* not found - grow it */
- p->start = Realloc(p->start, n);
- p->end = p->start+n;
- }
- p->current = p->start+n-QUANTA;
-}
-
-void
-bufcpy(Bufblock *buf, char *cp, int n)
-{
-
- while (n--)
- insert(buf, *cp++);
-}
-
-void
-insert(Bufblock *buf, int c)
-{
-
- if (buf->current >= buf->end)
- growbuf(buf);
- *buf->current++ = c;
-}
-
-void
-rinsert(Bufblock *buf, Rune r)
-{
- int n;
-
- n = runelen(r);
- if (buf->current+n > buf->end)
- growbuf(buf);
- runetochar(buf->current, &r);
- buf->current += n;
-}
diff --git a/mk/env.c b/mk/env.c
@@ -1,149 +0,0 @@
-#include "mk.h"
-
-enum {
- ENVQUANTA=10
-};
-
-Envy *envy;
-static int nextv;
-
-static char *myenv[] =
-{
- "target",
- "stem",
- "prereq",
- "pid",
- "nproc",
- "newprereq",
- "alltarget",
- "newmember",
- "stem0", /* must be in order from here */
- "stem1",
- "stem2",
- "stem3",
- "stem4",
- "stem5",
- "stem6",
- "stem7",
- "stem8",
- "stem9",
- 0,
-};
-
-void
-initenv(void)
-{
- char **p;
-
- for(p = myenv; *p; p++)
- symlook(*p, S_INTERNAL, (void *)"");
- readenv(); /* o.s. dependent */
-}
-
-static void
-envinsert(char *name, Word *value)
-{
- static int envsize;
-
- if (nextv >= envsize) {
- envsize += ENVQUANTA;
- envy = (Envy *) Realloc((char *) envy, envsize*sizeof(Envy));
- }
- envy[nextv].name = name;
- envy[nextv++].values = value;
-}
-
-static void
-envupd(char *name, Word *value)
-{
- Envy *e;
-
- for(e = envy; e->name; e++)
- if(strcmp(name, e->name) == 0){
- delword(e->values);
- e->values = value;
- return;
- }
- e->name = name;
- e->values = value;
- envinsert(0,0);
-}
-
-static void
-ecopy(Symtab *s)
-{
- char **p;
-
- if(symlook(s->name, S_NOEXPORT, 0))
- return;
- for(p = myenv; *p; p++)
- if(strcmp(*p, s->name) == 0)
- return;
- envinsert(s->name, (Word *) s->value);
-}
-
-void
-execinit(void)
-{
- char **p;
-
- nextv = 0;
- for(p = myenv; *p; p++)
- envinsert(*p, stow(""));
-
- symtraverse(S_VAR, ecopy);
- envinsert(0, 0);
-}
-
-Envy*
-buildenv(Job *j, int slot)
-{
- char **p, *cp, *qp;
- Word *w, *v, **l;
- int i;
- char buf[256];
-
- envupd("target", wdup(j->t));
- if(j->r->attr&REGEXP)
- envupd("stem",newword(""));
- else
- envupd("stem", newword(j->stem));
- envupd("prereq", wdup(j->p));
- sprint(buf, "%d", getpid());
- envupd("pid", newword(buf));
- sprint(buf, "%d", slot);
- envupd("nproc", newword(buf));
- envupd("newprereq", wdup(j->np));
- envupd("alltarget", wdup(j->at));
- l = &v;
- v = w = wdup(j->np);
- while(w){
- cp = strchr(w->s, '(');
- if(cp){
- qp = strchr(cp+1, ')');
- if(qp){
- *qp = 0;
- strcpy(w->s, cp+1);
- l = &w->next;
- w = w->next;
- continue;
- }
- }
- *l = w->next;
- free(w->s);
- free(w);
- w = *l;
- }
- envupd("newmember", v);
- /* update stem0 -> stem9 */
- for(p = myenv; *p; p++)
- if(strcmp(*p, "stem0") == 0)
- break;
- for(i = 0; *p; i++, p++){
- if((j->r->attr&REGEXP) && j->match[i])
- envupd(*p, newword(j->match[i]));
- else
- envupd(*p, newword(""));
- }
- return envy;
-}
diff --git a/mk/file.c b/mk/file.c
@@ -1,90 +0,0 @@
-#include "mk.h"
-
-/* table-driven version in bootes dump of 12/31/96 */
-
-long
-mtime(char *name)
-{
- return mkmtime(name);
-}
-
-long
-timeof(char *name, int force)
-{
- Symtab *sym;
- long t;
-
- if(utfrune(name, '('))
- return atimeof(force, name); /* archive */
-
- if(force)
- return mtime(name);
-
-
- sym = symlook(name, S_TIME, 0);
- if (sym)
- return (long) sym->value; /* uggh */
-
- t = mtime(name);
- if(t == 0)
- return 0;
-
- symlook(name, S_TIME, (void*)t); /* install time in cac…
- return t;
-}
-
-void
-touch(char *name)
-{
- Bprint(&bout, "touch(%s)\n", name);
- if(nflag)
- return;
-
- if(utfrune(name, '('))
- atouch(name); /* archive */
- else if(chgtime(name) < 0) {
- fprint(2, "%s: %r\n", name);
- Exit();
- }
-}
-
-void
-delete(char *name)
-{
- if(utfrune(name, '(') == 0) { /* file */
- if(remove(name) < 0)
- fprint(2, "remove %s: %r\n", name);
- } else
- fprint(2, "hoon off; mk can'tdelete archive members\n");
-}
-
-void
-timeinit(char *s)
-{
- long t;
- char *cp;
- Rune r;
- int c, n;
-
- t = time(0);
- while (*s) {
- cp = s;
- do{
- n = chartorune(&r, s);
- if (r == ' ' || r == ',' || r == '\n')
- break;
- s += n;
- } while(*s);
- c = *s;
- *s = 0;
- symlook(strdup(cp), S_TIME, (void *)t)->value = (void *)t;
- if (c)
- *s++ = c;
- while(*s){
- n = chartorune(&r, s);
- if(r != ' ' && r != ',' && r != '\n')
- break;
- s += n;
- }
- }
-}
diff --git a/mk/fns.h b/mk/fns.h
@@ -1,88 +0,0 @@
-#undef waitfor
-#define waitfor mkwaitfor
-
-void addrule(char*, Word*, char*, Word*, int, int, char*);
-void addrules(Word*, Word*, char*, int, int, char*);
-void addw(Word*, char*);
-void assert(char*, int);
-int assline(Biobuf *, Bufblock *);
-long atimeof(int,char*);
-void atouch(char*);
-void bufcpy(Bufblock *, char *, int);
-Envy *buildenv(Job*, int);
-void catchnotes(void);
-int chgtime(char*);
-void clrmade(Node*);
-void delete(char*);
-void delword(Word*);
-int dorecipe(Node*);
-void dumpa(char*, Arc*);
-void dumpj(char*, Job*, int);
-void dumpn(char*, Node*);
-void dumpr(char*, Rule*);
-void dumpv(char*);
-void dumpw(char*, Word*);
-void execinit(void);
-int execsh(char*, char*, Bufblock*, Envy*, Shell*, Word*);
-void Exit(void);
-void expunge(int, char*);
-void freebuf(Bufblock*);
-void front(char*);
-Node *graph(char*);
-void growbuf(Bufblock *);
-void initenv(void);
-void initshell(void);
-void insert(Bufblock *, int);
-void ipop(void);
-void ipush(void);
-void killchildren(char*);
-void *Malloc(int);
-char *maketmp(int*);
-int match(char*, char*, char*, Shell*);
-char *membername(char*, int, char*);
-void mk(char*);
-unsigned long mkmtime(char*);
-long mtime(char*);
-Arc *newarc(Node*, Rule*, char*, Resub*);
-Bufblock *newbuf(void);
-Job *newjob(Rule*, Node*, char*, char**, Word*, Word*, Word*, Word*);
-Word *newword(char*);
-int nextrune(Biobuf*, int);
-int nextslot(void);
-void nproc(void);
-void nrep(void);
-int outofdate(Node*, Arc*, int);
-void parse(char*, int, int);
-int pipecmd(char*, Envy*, int*, Shell*, Word*);
-void popshell(void);
-void prusage(void);
-void pushshell(void);
-void rcopy(char**, Resub*, int);
-void readenv(void);
-void *Realloc(void*, int);
-void rinsert(Bufblock *, Rune);
-char *rulecnt(void);
-void run(Job*);
-char *setshell(Word*);
-void setvar(char*, void*);
-int shargv(Word*, int, char***);
-char *shname(char*);
-void shprint(char*, Envy*, Bufblock*, Shell*);
-Word *stow(char*);
-void subst(char*, char*, char*);
-void symdel(char*, int);
-void syminit(void);
-Symtab *symlook(char*, int, void*);
-void symstat(void);
-void symtraverse(int, void(*)(Symtab*));
-void timeinit(char*);
-long timeof(char*, int);
-void touch(char*);
-void update(int, Node*);
-void usage(void);
-Word *varsub(char**);
-int waitfor(char*);
-int waitup(int, int*);
-Word *wdup(Word*);
-int work(Node*, Node*, Arc*);
-char *wtos(Word*, int);
diff --git a/mk/graph.c b/mk/graph.c
@@ -1,279 +0,0 @@
-#include "mk.h"
-
-static Node *applyrules(char *, char *);
-static void togo(Node *);
-static int vacuous(Node *);
-static Node *newnode(char *);
-static void trace(char *, Arc *);
-static void cyclechk(Node *);
-static void ambiguous(Node *);
-static void attribute(Node *);
-
-Node *
-graph(char *target)
-{
- Node *node;
- char *cnt;
-
- cnt = rulecnt();
- node = applyrules(target, cnt);
- free(cnt);
- cyclechk(node);
- node->flags |= PROBABLE; /* make sure it doesn't get deleted */
- vacuous(node);
- ambiguous(node);
- attribute(node);
- return(node);
-}
-
-static Node *
-applyrules(char *target, char *cnt)
-{
- Symtab *sym;
- Node *node;
- Rule *r;
- Arc head, *a = &head;
- Word *w;
- char stem[NAMEBLOCK], buf[NAMEBLOCK];
- Resub rmatch[NREGEXP];
-
-/* print("applyrules(%lux='%s')\n", target, target);*//**/
- sym = symlook(target, S_NODE, 0);
- if(sym)
- return (Node *)(sym->value);
- target = strdup(target);
- node = newnode(target);
- head.n = 0;
- head.next = 0;
- sym = symlook(target, S_TARGET, 0);
- memset((char*)rmatch, 0, sizeof(rmatch));
- for(r = sym? (Rule *)(sym->value):0; r; r = r->chain){
- if(r->attr&META) continue;
- if(strcmp(target, r->target)) continue;
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || …
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
- node->flags |= PROBABLE;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, "", rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- a->next = newarc(applyrules(w->s, cnt), r, "",…
- a = a->next;
- }
- cnt[r->rule]--;
- head.n = node;
- }
- for(r = metarules; r; r = r->next){
- if((!r->recipe || !*r->recipe) && (!r->tail || !r->tail->s || …
- if ((r->attr&NOVIRT) && a != &head && (a->r->attr&VIR))
- continue;
- if(r->attr&REGEXP){
- stem[0] = 0;
- patrule = r;
- memset((char*)rmatch, 0, sizeof(rmatch));
- if(regexec(r->pat, node->name, rmatch, NREGEXP) == 0)
- continue;
- } else {
- if(!match(node->name, r->target, stem, r->shellt)) con…
- }
- if(cnt[r->rule] >= nreps) continue;
- cnt[r->rule]++;
-
-/* if(r->attr&VIR)
- * node->flags |= VIRTUAL;
- * if(r->attr&NOREC)
- * node->flags |= NORECIPE;
- * if(r->attr&DEL)
- * node->flags |= DELETE;
- */
-
- if(!r->tail || !r->tail->s || !*r->tail->s) {
- a->next = newarc((Node *)0, r, stem, rmatch);
- a = a->next;
- } else
- for(w = r->tail; w; w = w->next){
- if(r->attr&REGEXP)
- regsub(w->s, buf, sizeof buf, rmatch, …
- else
- subst(stem, w->s, buf);
- a->next = newarc(applyrules(buf, cnt), r, stem…
- a = a->next;
- }
- cnt[r->rule]--;
- }
- a->next = node->prereqs;
- node->prereqs = head.next;
- return(node);
-}
-
-static void
-togo(Node *node)
-{
- Arc *la, *a;
-
- /* delete them now */
- la = 0;
- for(a = node->prereqs; a; la = a, a = a->next)
- if(a->flag&TOGO){
- if(a == node->prereqs)
- node->prereqs = a->next;
- else
- la->next = a->next, a = la;
- }
-}
-
-static int
-vacuous(Node *node)
-{
- Arc *la, *a;
- int vac = !(node->flags&PROBABLE);
-
- if(node->flags&READY)
- return(node->flags&VACUOUS);
- node->flags |= READY;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && vacuous(a->n) && (a->r->attr&META))
- a->flag |= TOGO;
- else
- vac = 0;
- /* if a rule generated arcs that DON'T go; no others from that rule go…
- for(a = node->prereqs; a; a = a->next)
- if((a->flag&TOGO) == 0)
- for(la = node->prereqs; la; la = la->next)
- if((la->flag&TOGO) && (la->r == a->r)){
- la->flag &= ~TOGO;
- }
- togo(node);
- if(vac)
- node->flags |= VACUOUS;
- return(vac);
-}
-
-static Node *
-newnode(char *name)
-{
- register Node *node;
-
- node = (Node *)Malloc(sizeof(Node));
- symlook(name, S_NODE, (void *)node);
- node->name = name;
- node->time = timeof(name, 0);
- node->prereqs = 0;
- node->flags = node->time? PROBABLE : 0;
- node->next = 0;
- return(node);
-}
-
-void
-dumpn(char *s, Node *n)
-{
- char buf[1024];
- Arc *a;
-
- snprint(buf, sizeof buf, "%s ", (*s == ' ')? s:"");
- Bprint(&bout, "%s%s@%ld: time=%ld flags=0x%x next=%ld\n",
- s, n->name, n, n->time, n->flags, n->next);
- for(a = n->prereqs; a; a = a->next)
- dumpa(buf, a);
-}
-
-static void
-trace(char *s, Arc *a)
-{
- fprint(2, "\t%s", s);
- while(a){
- fprint(2, " <-(%s:%d)- %s", a->r->file, a->r->line,
- a->n? a->n->name:"");
- if(a->n){
- for(a = a->n->prereqs; a; a = a->next)
- if(*a->r->recipe) break;
- } else
- a = 0;
- }
- fprint(2, "\n");
-}
-
-static void
-cyclechk(Node *n)
-{
- Arc *a;
-
- if((n->flags&CYCLE) && n->prereqs){
- fprint(2, "mk: cycle in graph detected at target %s\n", n->nam…
- Exit();
- }
- n->flags |= CYCLE;
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- cyclechk(a->n);
- n->flags &= ~CYCLE;
-}
-
-static void
-ambiguous(Node *n)
-{
- Arc *a;
- Rule *r = 0;
- Arc *la;
- int bad = 0;
-
- la = 0;
- for(a = n->prereqs; a; a = a->next){
- if(a->n)
- ambiguous(a->n);
- if(*a->r->recipe == 0) continue;
- if(r == 0)
- r = a->r, la = a;
- else{
- if(r->recipe != a->r->recipe){
- if((r->attr&META) && !(a->r->attr&META)){
- la->flag |= TOGO;
- r = a->r, la = a;
- } else if(!(r->attr&META) && (a->r->attr&META)…
- a->flag |= TOGO;
- continue;
- }
- }
- if(r->recipe != a->r->recipe){
- if(bad == 0){
- fprint(2, "mk: ambiguous recipes for %…
- bad = 1;
- trace(n->name, la);
- }
- trace(n->name, a);
- }
- }
- }
- if(bad)
- Exit();
- togo(n);
-}
-
-static void
-attribute(Node *n)
-{
- register Arc *a;
-
- for(a = n->prereqs; a; a = a->next){
- if(a->r->attr&VIR)
- n->flags |= VIRTUAL;
- if(a->r->attr&NOREC)
- n->flags |= NORECIPE;
- if(a->r->attr&DEL)
- n->flags |= DELETE;
- if(a->n)
- attribute(a->n);
- }
- if(n->flags&VIRTUAL)
- n->time = 0;
-}
diff --git a/mk/job.c b/mk/job.c
@@ -1,33 +0,0 @@
-#include "mk.h"
-
-Job *
-newjob(Rule *r, Node *nlist, char *stem, char **match, Word *pre, Word *npre, …
-{
- register Job *j;
-
- j = (Job *)Malloc(sizeof(Job));
- j->r = r;
- j->n = nlist;
- j->stem = stem;
- j->match = match;
- j->p = pre;
- j->np = npre;
- j->t = tar;
- j->at = atar;
- j->nproc = -1;
- j->next = 0;
- return(j);
-}
-
-void
-dumpj(char *s, Job *j, int all)
-{
- Bprint(&bout, "%s\n", s);
- while(j){
- Bprint(&bout, "job@%ld: r=%ld n=%ld stem='%s' nproc=%d\n",
- j, j->r, j->n, j->stem, j->nproc);
- Bprint(&bout, "\ttarget='%s' alltarget='%s' prereq='%s' nprere…
- wtos(j->t, ' '), wtos(j->at, ' '), wtos(j->p, ' '), wt…
- j = all? j->next : 0;
- }
-}
diff --git a/mk/lex.c b/mk/lex.c
@@ -1,146 +0,0 @@
-#include "mk.h"
-
-static int bquote(Biobuf*, Bufblock*);
-
-/*
- * Assemble a line skipping blank lines, comments, and eliding
- * escaped newlines
- */
-int
-assline(Biobuf *bp, Bufblock *buf)
-{
- int c;
- int lastc;
-
- buf->current=buf->start;
- while ((c = nextrune(bp, 1)) >= 0){
- switch(c)
- {
- case '\r': /* consumes CRs for Win95 */
- continue;
- case '\n':
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break; /* skip empty lines */
- case '\\':
- case '\'':
- case '"':
- rinsert(buf, c);
- if (shellt->escapetoken(bp, buf, 1, c) == 0)
- Exit();
- break;
- case '`':
- if (bquote(bp, buf) == 0)
- Exit();
- break;
- case '#':
- lastc = '#';
- while ((c = Bgetc(bp)) != '\n') {
- if (c < 0)
- goto eof;
- if(c != '\r')
- lastc = c;
- }
- mkinline++;
- if (lastc == '\\')
- break; /* propagate escaped new…
- if (buf->current != buf->start) {
- insert(buf, 0);
- return 1;
- }
- break;
- default:
- rinsert(buf, c);
- break;
- }
- }
-eof:
- insert(buf, 0);
- return *buf->start != 0;
-}
-
-/*
- * assemble a back-quoted shell command into a buffer
- */
-static int
-bquote(Biobuf *bp, Bufblock *buf)
-{
- int c, line, term;
- int start;
-
- line = mkinline;
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- if(c == '{'){
- term = '}'; /* rc style */
- while((c = Bgetrune(bp)) == ' ' || c == '\t')
- ;
- } else
- term = '`'; /* sh style */
-
- start = buf->current-buf->start;
- for(;c > 0; c = nextrune(bp, 0)){
- if(c == term){
- insert(buf, '\n');
- insert(buf,0);
- buf->current = buf->start+start;
- execinit();
- execsh(0, buf->current, buf, envy, shellt, shellcmd);
- return 1;
- }
- if(c == '\n')
- break;
- if(c == '\'' || c == '"' || c == '\\'){
- insert(buf, c);
- if(!shellt->escapetoken(bp, buf, 1, c))
- return 0;
- continue;
- }
- rinsert(buf, c);
- }
- SYNERR(line);
- fprint(2, "missing closing %c after `\n", term);
- return 0;
-}
-
-/*
- * get next character stripping escaped newlines
- * the flag specifies whether escaped newlines are to be elided or
- * replaced with a blank.
- */
-int
-nextrune(Biobuf *bp, int elide)
-{
- int c, c2;
- static int savec;
-
- if(savec){
- c = savec;
- savec = 0;
- return c;
- }
-
- for (;;) {
- c = Bgetrune(bp);
- if (c == '\\') {
- c2 = Bgetrune(bp);
- if(c2 == '\r'){
- savec = c2;
- c2 = Bgetrune(bp);
- }
- if (c2 == '\n') {
- savec = 0;
- mkinline++;
- if (elide)
- continue;
- return ' ';
- }
- Bungetrune(bp);
- }
- if (c == '\n')
- mkinline++;
- return c;
- }
-}
diff --git a/mk/main.c b/mk/main.c
@@ -1,287 +0,0 @@
-#include "mk.h"
-
-#define MKFILE "mkfile"
-
-int debug;
-Rule *rules, *metarules;
-int nflag = 0;
-int tflag = 0;
-int iflag = 0;
-int kflag = 0;
-int aflag = 0;
-int uflag = 0;
-char *explain = 0;
-Word *target1;
-int nreps = 1;
-Job *jobs;
-Biobuf bout;
-Rule *patrule;
-void badusage(void);
-#ifdef PROF
-short buf[10000];
-#endif
-
-int
-main(int argc, char **argv)
-{
- Word *w;
- char *s, *temp;
- char *files[256], **f = files, **ff;
- int sflag = 0;
- int i;
- int tfd = -1;
- Biobuf tb;
- Bufblock *buf;
- Bufblock *whatif;
-
- /*
- * start with a copy of the current environment variables
- * instead of sharing them
- */
-
- Binit(&bout, 1, OWRITE);
- buf = newbuf();
- whatif = 0;
- USED(argc);
- for(argv++; *argv && (**argv == '-'); argv++)
- {
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- switch(argv[0][1])
- {
- case 'a':
- aflag = 1;
- break;
- case 'd':
- if(*(s = &argv[0][2]))
- while(*s) switch(*s++)
- {
- case 'p': debug |= D_PARSE; break;
- case 'g': debug |= D_GRAPH; break;
- case 'e': debug |= D_EXEC; break;
- }
- else
- debug = 0xFFFF;
- break;
- case 'e':
- explain = &argv[0][2];
- break;
- case 'f':
- if(*++argv == 0)
- badusage();
- *f++ = *argv;
- bufcpy(buf, argv[0], strlen(argv[0]));
- insert(buf, ' ');
- break;
- case 'i':
- iflag = 1;
- break;
- case 'k':
- kflag = 1;
- break;
- case 'n':
- nflag = 1;
- break;
- case 's':
- sflag = 1;
- break;
- case 't':
- tflag = 1;
- break;
- case 'u':
- uflag = 1;
- break;
- case 'w':
- if(whatif == 0)
- whatif = newbuf();
- else
- insert(whatif, ' ');
- if(argv[0][2])
- bufcpy(whatif, &argv[0][2], strlen(&argv[0][2]…
- else {
- if(*++argv == 0)
- badusage();
- bufcpy(whatif, &argv[0][0], strlen(&argv[0][0]…
- }
- break;
- default:
- badusage();
- }
- }
-#ifdef PROF
- {
- extern etext();
- monitor(main, etext, buf, sizeof buf, 300);
- }
-#endif
-
- if(aflag)
- iflag = 1;
- usage();
- syminit();
- initshell();
- initenv();
- usage();
-
- /*
- assignment args become null strings
- */
- temp = 0;
- for(i = 0; argv[i]; i++) if(utfrune(argv[i], '=')){
- bufcpy(buf, argv[i], strlen(argv[i]));
- insert(buf, ' ');
- if(tfd < 0){
- temp = maketmp(&tfd);
- if(temp == 0) {
- fprint(2, "temp file: %r\n");
- Exit();
- }
- Binit(&tb, tfd, OWRITE);
- }
- Bprint(&tb, "%s\n", argv[i]);
- *argv[i] = 0;
- }
- if(tfd >= 0){
- Bflush(&tb);
- LSEEK(tfd, 0L, 0);
- parse("command line args", tfd, 1);
- remove(temp);
- }
-
- if (buf->current != buf->start) {
- buf->current--;
- insert(buf, 0);
- }
- symlook("MKFLAGS", S_VAR, (void *) stow(buf->start));
- buf->current = buf->start;
- for(i = 0; argv[i]; i++){
- if(*argv[i] == 0) continue;
- if(i)
- insert(buf, ' ');
- bufcpy(buf, argv[i], strlen(argv[i]));
- }
- insert(buf, 0);
- symlook("MKARGS", S_VAR, (void *) stow(buf->start));
- freebuf(buf);
-
- if(f == files){
- if(access(MKFILE, 4) == 0)
- parse(MKFILE, open(MKFILE, 0), 0);
- } else
- for(ff = files; ff < f; ff++)
- parse(*ff, open(*ff, 0), 0);
- if(DEBUG(D_PARSE)){
- dumpw("default targets", target1);
- dumpr("rules", rules);
- dumpr("metarules", metarules);
- dumpv("variables");
- }
- if(whatif){
- insert(whatif, 0);
- timeinit(whatif->start);
- freebuf(whatif);
- }
- execinit();
- /* skip assignment args */
- while(*argv && (**argv == 0))
- argv++;
-
- catchnotes();
- if(*argv == 0){
- if(target1)
- for(w = target1; w; w = w->next)
- mk(w->s);
- else {
- fprint(2, "mk: nothing to mk\n");
- Exit();
- }
- } else {
- if(sflag){
- for(; *argv; argv++)
- if(**argv)
- mk(*argv);
- } else {
- Word *head, *tail, *t;
-
- /* fake a new rule with all the args as prereqs */
- tail = 0;
- t = 0;
- for(; *argv; argv++)
- if(**argv){
- if(tail == 0)
- tail = t = newword(*argv);
- else {
- t->next = newword(*argv);
- t = t->next;
- }
- }
- if(tail->next == 0)
- mk(tail->s);
- else {
- head = newword("command line arguments");
- addrules(head, tail, strdup(""), VIR, mkinline…
- mk(head->s);
- }
- }
- }
- if(uflag)
- prusage();
- exits(0);
- return 0;
-}
-
-void
-badusage(void)
-{
-
- fprint(2, "Usage: mk [-f file] [-n] [-a] [-e] [-t] [-k] [-i] [-d[egp]]…
- Exit();
-}
-
-void *
-Malloc(int n)
-{
- register void *s;
-
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void *
-Realloc(void *s, int n)
-{
- if(s)
- s = realloc(s, n);
- else
- s = malloc(n);
- if(!s) {
- fprint(2, "mk: cannot alloc %d bytes\n", n);
- Exit();
- }
- return(s);
-}
-
-void
-assert(char *s, int n)
-{
- if(!n){
- fprint(2, "mk: Assertion ``%s'' failed.\n", s);
- Exit();
- }
-}
-
-void
-regerror(char *s)
-{
- if(patrule)
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- patrule->file, patrule->line, s);
- else
- fprint(2, "mk: %s:%d: regular expression error; %s\n",
- infile, mkinline, s);
- Exit();
-}
diff --git a/mk/match.c b/mk/match.c
@@ -1,49 +0,0 @@
-#include "mk.h"
-
-int
-match(char *name, char *template, char *stem, Shell *sh)
-{
- Rune r;
- int n;
-
- while(*name && *template){
- n = chartorune(&r, template);
- if (PERCENT(r))
- break;
- while (n--)
- if(*name++ != *template++)
- return 0;
- }
- if(!PERCENT(*template))
- return 0;
- n = strlen(name)-strlen(template+1);
- if (n < 0)
- return 0;
- if (strcmp(template+1, name+n))
- return 0;
- strncpy(stem, name, n);
- stem[n] = 0;
- if(*template == '&')
- return !sh->charin(stem, "./");
- return 1;
-}
-
-void
-subst(char *stem, char *template, char *dest)
-{
- Rune r;
- char *s;
- int n;
-
- while(*template){
- n = chartorune(&r, template);
- if (PERCENT(r)) {
- template += n;
- for (s = stem; *s; s++)
- *dest++ = *s;
- } else
- while (n--)
- *dest++ = *template++;
- }
- *dest = 0;
-}
diff --git a/mk/mk.1 b/mk/mk.1
@@ -1,691 +0,0 @@
-.TH MK 1
-.SH NAME
-mk \- maintain (make) related files
-.SH SYNOPSIS
-.B mk
-[
-.B -f
-.I mkfile
-] ...
-[
-.I option ...
-]
-[
-.I target ...
-]
-.SH DESCRIPTION
-.I Mk
-uses the dependency rules specified in
-.I mkfile
-to control the update (usually by compilation) of
-.I targets
-(usually files)
-from the source files upon which they depend.
-The
-.I mkfile
-(default
-.LR mkfile )
-contains a
-.I rule
-for each target that identifies the files and other
-targets upon which it depends and an
-.IR sh (1)
-script, a
-.IR recipe ,
-to update the target.
-The script is run if the target does not exist
-or if it is older than any of the files it depends on.
-.I Mkfile
-may also contain
-.I meta-rules
-that define actions for updating implicit targets.
-If no
-.I target
-is specified, the target of the first rule (not meta-rule) in
-.I mkfile
-is updated.
-.PP
-The environment variable
-.B $NPROC
-determines how many targets may be updated simultaneously;
-Some operating systems, e.g., Plan 9, set
-.B $NPROC
-automatically to the number of CPUs on the current machine.
-.PP
-Options are:
-.TP \w'\fL-d[egp]\ 'u
-.B -a
-Assume all targets to be out of date.
-Thus, everything is updated.
-.PD 0
-.TP
-.BR -d [ egp ]
-Produce debugging output
-.RB ( p
-is for parsing,
-.B g
-for graph building,
-.B e
-for execution).
-.TP
-.B -e
-Explain why each target is made.
-.TP
-.B -i
-Force any missing intermediate targets to be made.
-.TP
-.B -k
-Do as much work as possible in the face of errors.
-.TP
-.B -n
-Print, but do not execute, the commands
-needed to update the targets.
-.TP
-.B -s
-Make the command line arguments sequentially rather than in parallel.
-.TP
-.B -t
-Touch (update the modified date of) file targets, without
-executing any recipes.
-.TP
-.BI -w target1 , target2,...
-Pretend the modify time for each
-.I target
-is the current time; useful in conjunction with
-.B -n
-to learn what updates would be triggered by
-modifying the
-.IR targets .
-.PD
-.SS The \fLmkfile\fP
-A
-.I mkfile
-consists of
-.I assignments
-(described under `Environment') and
-.IR rules .
-A rule contains
-.I targets
-and a
-.IR tail .
-A target is a literal string
-and is normally a file name.
-The tail contains zero or more
-.I prerequisites
-and an optional
-.IR recipe ,
-which is an
-.B shell
-script.
-Each line of the recipe must begin with white space.
-A rule takes the form
-.IP
-.EX
-target: prereq1 prereq2
- \f2recipe using\fP prereq1, prereq2 \f2to build\fP target
-.EE
-.PP
-When the recipe is executed,
-the first character on every line is elided.
-.PP
-After the colon on the target line, a rule may specify
-.IR attributes ,
-described below.
-.PP
-A
-.I meta-rule
-has a target of the form
-.IB A % B
-where
-.I A
-and
-.I B
-are (possibly empty) strings.
-A meta-rule acts as a rule for any potential target whose
-name matches
-.IB A % B
-with
-.B %
-replaced by an arbitrary string, called the
-.IR stem .
-In interpreting a meta-rule,
-the stem is substituted for all occurrences of
-.B %
-in the prerequisite names.
-In the recipe of a meta-rule, the environment variable
-.B $stem
-contains the string matched by the
-.BR % .
-For example, a meta-rule to compile a C program using
-.IR 9c (1)
-might be:
-.IP
-.EX
-%: %.c
- 9c -c $stem.c
- 9l -o $stem $stem.o
-.EE
-.PP
-Meta-rules may contain an ampersand
-.B &
-rather than a percent sign
-.BR % .
-A
-.B %
-matches a maximal length string of any characters;
-an
-.B &
-matches a maximal length string of any characters except period
-or slash.
-.PP
-The text of the
-.I mkfile
-is processed as follows.
-Lines beginning with
-.B <
-followed by a file name are replaced by the contents of the named
-file.
-Lines beginning with
-.B "<|"
-followed by a file name are replaced by the output
-of the execution of the named
-file.
-Blank lines and comments, which run from unquoted
-.B #
-characters to the following newline, are deleted.
-The character sequence backslash-newline is deleted,
-so long lines in
-.I mkfile
-may be folded.
-Non-recipe lines are processed by substituting for
-.BI `{ command }
-the output of the
-.I command
-when run by
-.IR sh .
-References to variables are replaced by the variables' values.
-Special characters may be quoted using single quotes
-.BR \&''
-as in
-.IR sh (1).
-.PP
-Assignments and rules are distinguished by
-the first unquoted occurrence of
-.B :
-(rule)
-or
-.B =
-(assignment).
-.PP
-A later rule may modify or override an existing rule under the
-following conditions:
-.TP
-\-
-If the targets of the rules exactly match and one rule
-contains only a prerequisite clause and no recipe, the
-clause is added to the prerequisites of the other rule.
-If either or both targets are virtual, the recipe is
-always executed.
-.TP
-\-
-If the targets of the rules match exactly and the
-prerequisites do not match and both rules
-contain recipes,
-.I mk
-reports an ``ambiguous recipe'' error.
-.TP
-\-
-If the target and prerequisites of both rules match exactly,
-the second rule overrides the first.
-.SS Environment
-Rules may make use of
-shell
-environment variables.
-A legal reference of the form
-.B $OBJ
-or
-.B ${name}
-is expanded as in
-.IR sh (1).
-A reference of the form
-.BI ${name: A % B = C\fL%\fID\fL}\fR,
-where
-.I A, B, C, D
-are (possibly empty) strings,
-has the value formed by expanding
-.B $name
-and substituting
-.I C
-for
-.I A
-and
-.I D
-for
-.I B
-in each word in
-.B $name
-that matches pattern
-.IB A % B\f1.
-.PP
-Variables can be set by
-assignments of the form
-.I
- var\fL=\fR[\fIattr\fL=\fR]\fIvalue\fR
-.br
-Blanks in the
-.I value
-break it into words.
-Such variables are exported
-to the environment of
-recipes as they are executed, unless
-.BR U ,
-the only legal attribute
-.IR attr ,
-is present.
-The initial value of a variable is
-taken from (in increasing order of precedence)
-the default values below,
-.I mk's
-environment, the
-.IR mkfiles ,
-and any command line assignment as an argument to
-.IR mk .
-A variable assignment argument overrides the first (but not any subsequent)
-assignment to that variable.
-.PP
-The variable
-.B MKFLAGS
-contains all the option arguments (arguments starting with
-.L -
-or containing
-.LR = )
-and
-.B MKARGS
-contains all the targets in the call to
-.IR mk .
-.PP
-The variable
-.B MKSHELL
-contains the shell command line
-.I mk
-uses to run recipes.
-If the first word of the command ends in
-.B rc
-or
-.BR rcsh ,
-.I mk
-uses
-.IR rc (1)'s
-quoting rules; otherwise it uses
-.IR sh (1)'s.
-The
-.B MKSHELL
-variable is consulted when the mkfile is read, not when it is executed,
-so that different shells can be used within a single mkfile:
-.IP
-.EX
-MKSHELL=$PLAN9/bin/rc
-use-rc:V:
- for(i in a b c) echo $i
-
-MKSHELL=sh
-use-sh:V:
- for i in a b c; do echo $i; done
-.EE
-.LP
-Mkfiles included via
-.B <
-or
-.B <|
-.RI ( q.v. )
-see their own private copy of
-.BR MKSHELL ,
-which always starts set to
-.B sh .
-.PP
-Dynamic information may be included in the mkfile by using a line of the form
-.IP
-\fR<|\fIcommand\fR \fIargs\fR
-.LP
-This runs the command
-.I command
-with the given arguments
-.I args
-and pipes its standard output to
-.I mk
-to be included as part of the mkfile. For instance, the Inferno kernels
-use this technique
-to run a shell command with an awk script and a configuration
-file as arguments in order for
-the
-.I awk
-script to process the file and output a set of variables and their values.
-.SS Execution
-.PP
-During execution,
-.I mk
-determines which targets must be updated, and in what order,
-to build the
-.I names
-specified on the command line.
-It then runs the associated recipes.
-.PP
-A target is considered up to date if it has no prerequisites or
-if all its prerequisites are up to date and it is newer
-than all its prerequisites.
-Once the recipe for a target has executed, the target is
-considered up to date.
-.PP
-The date stamp
-used to determine if a target is up to date is computed
-differently for different types of targets.
-If a target is
-.I virtual
-(the target of a rule with the
-.B V
-attribute),
-its date stamp is initially zero; when the target is
-updated the date stamp is set to
-the most recent date stamp of its prerequisites.
-Otherwise, if a target does not exist as a file,
-its date stamp is set to the most recent date stamp of its prerequisites,
-or zero if it has no prerequisites.
-Otherwise, the target is the name of a file and
-the target's date stamp is always that file's modification date.
-The date stamp is computed when the target is needed in
-the execution of a rule; it is not a static value.
-.PP
-Nonexistent targets that have prerequisites
-and are themselves prerequisites are treated specially.
-Such a target
-.I t
-is given the date stamp of its most recent prerequisite
-and if this causes all the targets which have
-.I t
-as a prerequisite to be up to date,
-.I t
-is considered up to date.
-Otherwise,
-.I t
-is made in the normal fashion.
-The
-.B -i
-flag overrides this special treatment.
-.PP
-Files may be made in any order that respects
-the preceding restrictions.
-.PP
-A recipe is executed by supplying the recipe as standard input to
-the command
-.BR /bin/sh .
-(Note that unlike
-.IR make ,
-.I mk
-feeds the entire recipe to the shell rather than running each line
-of the recipe separately.)
-The environment is augmented by the following variables:
-.TP 14
-.B $alltarget
-all the targets of this rule.
-.TP
-.B $newprereq
-the prerequisites that caused this rule to execute.
-.TP
-.B $newmember
-the prerequisites that are members of an aggregate
-that caused this rule to execute.
-When the prerequisites of a rule are members of an
-aggregate,
-.B $newprereq
-contains the name of the aggregate and out of date
-members, while
-.B $newmember
-contains only the name of the members.
-.TP
-.B $nproc
-the process slot for this recipe.
-It satisfies
-.RB 0≤ $nproc < $NPROC .
-.TP
-.B $pid
-the process id for the
-.I mk
-executing the recipe.
-.TP
-.B $prereq
-all the prerequisites for this rule.
-.TP
-.B $stem
-if this is a meta-rule,
-.B $stem
-is the string that matched
-.B %
-or
-.BR & .
-Otherwise, it is empty.
-For regular expression meta-rules (see below), the variables
-.LR stem0 ", ...,"
-.L stem9
-are set to the corresponding subexpressions.
-.TP
-.B $target
-the targets for this rule that need to be remade.
-.PP
-These variables are available only during the execution of a recipe,
-not while evaluating the
-.IR mkfile .
-.PP
-Unless the rule has the
-.B Q
-attribute,
-the recipe is printed prior to execution
-with recognizable environment variables expanded.
-Commands returning error status
-cause
-.I mk
-to terminate.
-.PP
-Recipes and backquoted
-.B rc
-commands in places such as assignments
-execute in a copy of
-.I mk's
-environment; changes they make to
-environment variables are not visible from
-.IR mk .
-.PP
-Variable substitution in a rule is done when
-the rule is read; variable substitution in the recipe is done
-when the recipe is executed. For example:
-.IP
-.EX
-bar=a.c
-foo: $bar
- $CC -o foo $bar
-bar=b.c
-.EE
-.PP
-will compile
-.B b.c
-into
-.BR foo ,
-if
-.B a.c
-is newer than
-.BR foo .
-.SS Aggregates
-Names of the form
-.IR a ( b )
-refer to member
-.I b
-of the aggregate
-.IR a .
-Currently, the only aggregates supported are
-.I 9ar
-(see
-.IR 9c (1))
-archives.
-.SS Attributes
-The colon separating the target from the prerequisites
-may be
-immediately followed by
-.I attributes
-and another colon.
-The attributes are:
-.TP
-.B D
-If the recipe exits with a non-null status, the target is deleted.
-.TP
-.B E
-Continue execution if the recipe draws errors.
-.TP
-.B N
-If there is no recipe, the target has its time updated.
-.TP
-.B n
-The rule is a meta-rule that cannot be a target of a virtual rule.
-Only files match the pattern in the target.
-.TP
-.B P
-The characters after the
-.B P
-until the terminating
-.B :
-are taken as a program name.
-It will be invoked as
-.B "sh -c prog 'arg1' 'arg2'"
-and should return a zero exit status
-if and only if arg1 is up to date with respect to arg2.
-Date stamps are still propagated in the normal way.
-.TP
-.B Q
-The recipe is not printed prior to execution.
-.TP
-.B R
-The rule is a meta-rule using regular expressions.
-In the rule,
-.B %
-has no special meaning.
-The target is interpreted as a regular expression as defined in
-.IR regexp (7).
-The prerequisites may contain references
-to subexpressions in form
-.BI \e n\f1,
-as in the substitute command of
-.IR sed (1).
-.TP
-.B U
-The targets are considered to have been updated
-even if the recipe did not do so.
-.TP
-.B V
-The targets of this rule are marked as virtual.
-They are distinct from files of the same name.
-.PD
-.SH EXAMPLES
-A simple mkfile to compile a program:
-.IP
-.EX
-.ta 8n +8n +8n +8n +8n +8n +8n
-</$objtype/mkfile
-
-prog: a.$O b.$O c.$O
- $LD $LDFLAGS -o $target $prereq
-
-%.$O: %.c
- $CC $CFLAGS $stem.c
-.EE
-.PP
-Override flag settings in the mkfile:
-.IP
-.EX
-% mk target 'CFLAGS=-S -w'
-.EE
-.PP
-Maintain a library:
-.IP
-.EX
-libc.a(%.$O):N: %.$O
-libc.a: libc.a(abs.$O) libc.a(access.$O) libc.a(alarm.$O) ...
- ar r libc.a $newmember
-.EE
-.PP
-String expression variables to derive names from a master list:
-.IP
-.EX
-NAMES=alloc arc bquote builtins expand main match mk var word
-OBJ=${NAMES:%=%.$O}
-.EE
-.PP
-Regular expression meta-rules:
-.IP
-.EX
-([^/]*)/(.*)\e.$O:R: \e1/\e2.c
- cd $stem1; $CC $CFLAGS $stem2.c
-.EE
-.PP
-A correct way to deal with
-.IR yacc (1)
-grammars.
-The file
-.B lex.c
-includes the file
-.B x.tab.h
-rather than
-.B y.tab.h
-in order to reflect changes in content, not just modification time.
-.IP
-.EX
-lex.$O: x.tab.h
-x.tab.h: y.tab.h
- cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
-y.tab.c y.tab.h: gram.y
- $YACC -d gram.y
-.EE
-.PP
-The above example could also use the
-.B P
-attribute for the
-.B x.tab.h
-rule:
-.IP
-.EX
-x.tab.h:Pcmp -s: y.tab.h
- cp y.tab.h x.tab.h
-.EE
-.SH SOURCE
-.B \*9/src/cmd/mk
-.SH SEE ALSO
-.IR sh (1),
-.IR regexp (7)
-.PP
-A. Hume,
-``Mk: a Successor to Make''
-(Tenth Edition Research Unix Manuals).
-.PP
-Andrew G. Hume and Bob Flandrena,
-``Maintaining Files on Plan 9 with Mk''.
-DOCPREFIX/doc/mk.pdf
-.SH HISTORY
-Andrew Hume wrote
-.I mk
-for Tenth Edition Research Unix.
-It was later ported to Plan 9.
-This software is a port of the Plan 9 version back to Unix.
-.SH BUGS
-Identical recipes for regular expression meta-rules only have one target.
-.PP
-Seemingly appropriate input like
-.B CFLAGS=-DHZ=60
-is parsed as an erroneous attribute; correct it by inserting
-a space after the first
-.LR = .
-.PP
-The recipes printed by
-.I mk
-before being passed to
-the shell
-for execution are sometimes erroneously expanded
-for printing. Don't trust what's printed; rely
-on what the shell
-does.
diff --git a/mk/mk.c b/mk/mk.c
@@ -1,234 +0,0 @@
-#include "mk.h"
-
-int runerrs;
-
-void
-mk(char *target)
-{
- Node *node;
- int did = 0;
-
- nproc(); /* it can be updated dynamically */
- nrep(); /* it can be updated dynamically */
- runerrs = 0;
- node = graph(target);
- if(DEBUG(D_GRAPH)){
- dumpn("new target\n", node);
- Bflush(&bout);
- }
- clrmade(node);
- while(node->flags&NOTMADE){
- if(work(node, (Node *)0, (Arc *)0))
- did = 1; /* found something to do */
- else {
- if(waitup(1, (int *)0) > 0){
- if(node->flags&(NOTMADE|BEINGMADE)){
- assert("must be run errors", runerrs);
- break; /* nothing more waiting …
- }
- }
- }
- }
- if(node->flags&BEINGMADE)
- waitup(-1, (int *)0);
- while(jobs)
- waitup(-2, (int *)0);
- assert("target didn't get done", runerrs || (node->flags&MADE));
- if(did == 0)
- Bprint(&bout, "mk: '%s' is up to date\n", node->name);
-}
-
-void
-clrmade(Node *n)
-{
- Arc *a;
-
- n->flags &= ~(CANPRETEND|PRETENDING);
- if(strchr(n->name, '(') ==0 || n->time)
- n->flags |= CANPRETEND;
- MADESET(n, NOTMADE);
- for(a = n->prereqs; a; a = a->next)
- if(a->n)
- clrmade(a->n);
-}
-
-static void
-unpretend(Node *n)
-{
- MADESET(n, NOTMADE);
- n->flags &= ~(CANPRETEND|PRETENDING);
- n->time = 0;
-}
-
-static char*
-dir(void)
-{
- static char buf[1024];
-
- return getcwd(buf, sizeof buf);
-}
-
-int
-work(Node *node, Node *p, Arc *parc)
-{
- Arc *a, *ra;
- int weoutofdate;
- int ready;
- int did = 0;
-
- /*print("work(%s) flags=0x%x time=%ld\n", node->name, node->flags, nod…
- if(node->flags&BEINGMADE)
- return(did);
- if((node->flags&MADE) && (node->flags&PRETENDING) && p && outofdate(p,…
- if(explain)
- fprint(1, "unpretending %s(%ld) because %s is out of d…
- node->name, node->time, p->name, p->time);
- unpretend(node);
- }
- /*
- have a look if we are pretending in case
- someone has been unpretended out from underneath us
- */
- if(node->flags&MADE){
- if(node->flags&PRETENDING){
- node->time = 0;
- }else
- return(did);
- }
- /* consider no prerequsite case */
- if(node->prereqs == 0){
- if(node->time == 0){
- fprint(2, "mk: don't know how to make '%s' in %s\n", n…
- if(kflag){
- node->flags |= BEINGMADE;
- runerrs++;
- } else
- Exit();
- } else
- MADESET(node, MADE);
- return(did);
- }
- /*
- now see if we are out of date or what
- */
- ready = 1;
- weoutofdate = aflag;
- ra = 0;
- for(a = node->prereqs; a; a = a->next)
- if(a->n){
- did = work(a->n, node, a) || did;
- if(a->n->flags&(NOTMADE|BEINGMADE))
- ready = 0;
- if(outofdate(node, a, 0)){
- weoutofdate = 1;
- if((ra == 0) || (ra->n == 0)
- || (ra->n->time < a->n->time))
- ra = a;
- }
- } else {
- if(node->time == 0){
- if(ra == 0)
- ra = a;
- weoutofdate = 1;
- }
- }
- if(ready == 0) /* can't do anything now */
- return(did);
- if(weoutofdate == 0){
- MADESET(node, MADE);
- return(did);
- }
- /*
- can we pretend to be made?
- */
- if((iflag == 0) && (node->time == 0) && (node->flags&(PRETENDING|CANPR…
- && p && ra->n && !outofdate(p, ra, 0)){
- node->flags &= ~CANPRETEND;
- MADESET(node, MADE);
- if(explain && ((node->flags&PRETENDING) == 0))
- fprint(1, "pretending %s has time %ld\n", node->name, …
- node->flags |= PRETENDING;
- return(did);
- }
- /*
- node is out of date and we REALLY do have to do something.
- quickly rescan for pretenders
- */
- for(a = node->prereqs; a; a = a->next)
- if(a->n && (a->n->flags&PRETENDING)){
- if(explain)
- Bprint(&bout, "unpretending %s because of %s b…
- a->n->name, node->name, ra->n? ra->n->name : "…
-
- unpretend(a->n);
- did = work(a->n, node, a) || did;
- ready = 0;
- }
- if(ready == 0) /* try later unless nothing has happened for -k'…
- return(did || work(node, p, parc));
- did = dorecipe(node) || did;
- return(did);
-}
-
-void
-update(int fake, Node *node)
-{
- Arc *a;
-
- MADESET(node, fake? BEINGMADE : MADE);
- if(((node->flags&VIRTUAL) == 0) && (access(node->name, 0) == 0)){
- node->time = timeof(node->name, 1);
- node->flags &= ~(CANPRETEND|PRETENDING);
- for(a = node->prereqs; a; a = a->next)
- if(a->prog)
- outofdate(node, a, 1);
- } else {
- node->time = 1;
- for(a = node->prereqs; a; a = a->next)
- if(a->n && outofdate(node, a, 1))
- node->time = a->n->time;
- }
-/* print("----node %s time=%ld flags=0x%x\n", node->name, node->time, n…
-}
-
-static int
-pcmp(char *prog, char *p, char *q, Shell *sh, Word *shcmd)
-{
- char buf[3*NAMEBLOCK];
- int pid;
-
- Bflush(&bout);
- snprint(buf, sizeof buf, "%s '%s' '%s'\n", prog, p, q);
- pid = pipecmd(buf, 0, 0, sh, shcmd);
- while(waitup(-3, &pid) >= 0)
- ;
- return(pid? 2:1);
-}
-
-int
-outofdate(Node *node, Arc *arc, int eval)
-{
- char buf[3*NAMEBLOCK], *str;
- Symtab *sym;
- int ret;
-
- str = 0;
- if(arc->prog){
- snprint(buf, sizeof buf, "%s%c%s", node->name, 0377, arc->n->n…
- sym = symlook(buf, S_OUTOFDATE, 0);
- if(sym == 0 || eval){
- if(sym == 0)
- str = strdup(buf);
- ret = pcmp(arc->prog, node->name, arc->n->name, arc->r…
- if(sym)
- sym->value = (void *)ret;
- else
- symlook(str, S_OUTOFDATE, (void *)ret);
- } else
- ret = (int)sym->value;
- return(ret-1);
- } else if(strchr(arc->n->name, '(') && arc->n->time == 0) /* missing …
- return 1;
- else
- return node->time <= arc->n->time;
-}
diff --git a/mk/mk.h b/mk/mk.h
@@ -1,182 +0,0 @@
-#include "sys.h"
-
-#undef assert
-#define assert mkassert
-extern Biobuf bout;
-
-typedef struct Bufblock
-{
- struct Bufblock *next;
- char *start;
- char *end;
- char *current;
-} Bufblock;
-
-typedef struct Word
-{
- char *s;
- struct Word *next;
-} Word;
-
-typedef struct Envy
-{
- char *name;
- Word *values;
-} Envy;
-
-extern Envy *envy;
-
-typedef struct Shell
-{
- char *name;
- char *termchars; /* used in parse.c to isolate assignmen…
- int iws; /* inter-word separator in envi…
- char *(*charin)(char*, char*); /* search for unescaped c…
- char *(*expandquote)(char*, Rune, Bufblock*); /* extract…
- int (*escapetoken)(Biobuf*, Bufblock*, int, int); /* inp…
- char *(*copyq)(char*, Rune, Bufblock*); /* check for quo…
- int (*matchname)(char*); /* does name match */
-} Shell;
-
-typedef struct Rule
-{
- char *target; /* one target */
- Word *tail; /* constituents of targets …
- char *recipe; /* do it ! */
- short attr; /* attributes */
- short line; /* source line */
- char *file; /* source file */
- Word *alltargets; /* all the targets */
- int rule; /* rule number */
- Reprog *pat; /* reg exp goo */
- char *prog; /* to use in out of date */
- struct Rule *chain; /* hashed per target */
- struct Rule *next;
- Shell *shellt; /* shell to use with this rule */
- Word *shellcmd;
-} Rule;
-
-extern Rule *rules, *metarules, *patrule;
-
-/* Rule.attr */
-#define META 0x0001
-#define UNUSED 0x0002
-#define UPD 0x0004
-#define QUIET 0x0008
-#define VIR 0x0010
-#define REGEXP 0x0020
-#define NOREC 0x0040
-#define DEL 0x0080
-#define NOVIRT 0x0100
-
-#define NREGEXP 10
-
-typedef struct Arc
-{
- short flag;
- struct Node *n;
- Rule *r;
- char *stem;
- char *prog;
- char *match[NREGEXP];
- struct Arc *next;
-} Arc;
-
- /* Arc.flag */
-#define TOGO 1
-
-typedef struct Node
-{
- char *name;
- long time;
- unsigned short flags;
- Arc *prereqs;
- struct Node *next; /* list for a rule */
-} Node;
-
- /* Node.flags */
-#define VIRTUAL 0x0001
-#define CYCLE 0x0002
-#define READY 0x0004
-#define CANPRETEND 0x0008
-#define PRETENDING 0x0010
-#define NOTMADE 0x0020
-#define BEINGMADE 0x0040
-#define MADE 0x0080
-#define MADESET(n,m) n->flags = (n->flags&~(NOTMADE|BEIN…
-#define PROBABLE 0x0100
-#define VACUOUS 0x0200
-#define NORECIPE 0x0400
-#define DELETE 0x0800
-#define NOMINUSE 0x1000
-
-typedef struct Job
-{
- Rule *r; /* master rule for job */
- Node *n; /* list of node targets */
- char *stem;
- char **match;
- Word *p; /* prerequistes */
- Word *np; /* new prerequistes */
- Word *t; /* targets */
- Word *at; /* all targets */
- int nproc; /* slot number */
- struct Job *next;
-} Job;
-extern Job *jobs;
-
-typedef struct Symtab
-{
- short space;
- char *name;
- void *value;
- struct Symtab *next;
-} Symtab;
-
-enum {
- S_VAR, /* variable -> value */
- S_TARGET, /* target -> rule */
- S_TIME, /* file -> time */
- S_PID, /* pid -> products */
- S_NODE, /* target name -> node */
- S_AGG, /* aggregate -> time */
- S_BITCH, /* bitched about aggregate not there */
- S_NOEXPORT, /* var -> noexport */
- S_OVERRIDE, /* can't override */
- S_OUTOFDATE, /* n1\377n2 -> 2(outofdate) or 1(not outofdate) */
- S_MAKEFILE, /* target -> node */
- S_MAKEVAR, /* dumpable mk variable */
- S_EXPORTED, /* var -> current exported value */
- S_WESET, /* variable; we set in the mkfile */
- S_INTERNAL /* an internal mk variable (e.g., stem, target) */
-};
-
-extern int debug;
-extern int nflag, tflag, iflag, kflag, aflag, mflag;
-extern int mkinline;
-extern char *infile;
-extern int nreps;
-extern char *explain;
-extern Shell *shellt;
-extern Word *shellcmd;
-
-extern Shell shshell, rcshell;
-
-#define SYNERR(l) (fprint(2, "mk: %s:%d: syntax error; ", infile…
-#define RERR(r) (fprint(2, "mk: %s:%d: rule error; ", (r…
-#define NAMEBLOCK 1000
-#define BIGBLOCK 20000
-
-#define SEP(c) (((c)==' ')||((c)=='\t')||((c)=='\n'))
-#define WORDCHR(r) ((r) > ' ' && !utfrune("!\"#$%&'()*+,-./:;<=>?@[\\]^…
-
-#define DEBUG(x) (debug&(x))
-#define D_PARSE 0x01
-#define D_GRAPH 0x02
-#define D_EXEC 0x04
-
-#define LSEEK(f,o,p) seek(f,o,p)
-
-#define PERCENT(ch) (((ch) == '%') || ((ch) == '&'))
-
-#include "fns.h"
diff --git a/mk/parse.c b/mk/parse.c
@@ -1,318 +0,0 @@
-#include "mk.h"
-
-char *infile;
-int mkinline;
-static int rhead(char *, Word **, Word **, int *, char **);
-static char *rbody(Biobuf*);
-extern Word *target1;
-
-void
-parse(char *f, int fd, int varoverride)
-{
- int hline;
- char *body;
- Word *head, *tail;
- int attr, set, pid;
- char *prog, *p;
- int newfd;
- Biobuf in;
- Bufblock *buf;
- char *err;
-
- if(fd < 0){
- fprint(2, "open %s: %r\n", f);
- Exit();
- }
- pushshell();
- ipush();
- infile = strdup(f);
- mkinline = 1;
- Binit(&in, fd, OREAD);
- buf = newbuf();
- while(assline(&in, buf)){
- hline = mkinline;
- switch(rhead(buf->start, &head, &tail, &attr, &prog))
- {
- case '<':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include file name\n");
- Exit();
- }
- newfd = open(p, OREAD);
- if(newfd < 0){
- fprint(2, "warning: skipping missing include f…
- } else
- parse(p, newfd, 0);
- break;
- case '|':
- p = wtos(tail, ' ');
- if(*p == 0){
- SYNERR(-1);
- fprint(2, "missing include program name\n");
- Exit();
- }
- execinit();
- pid=pipecmd(p, envy, &newfd, shellt, shellcmd);
- if(newfd < 0){
- fprint(2, "warning: skipping missing program f…
- } else
- parse(p, newfd, 0);
- while(waitup(-3, &pid) >= 0)
- ;
- if(pid != 0){
- fprint(2, "bad include program status\n");
- Exit();
- }
- break;
- case ':':
- body = rbody(&in);
- addrules(head, tail, body, attr, hline, prog);
- break;
- case '=':
- if(head->next){
- SYNERR(-1);
- fprint(2, "multiple vars on left side of assig…
- Exit();
- }
- if(symlook(head->s, S_OVERRIDE, 0)){
- set = varoverride;
- } else {
- set = 1;
- if(varoverride)
- symlook(head->s, S_OVERRIDE, (void *)"…
- }
- if(set){
-/*
-char *cp;
-dumpw("tail", tail);
-cp = wtos(tail, ' '); print("assign %s to %s\n", head->s, cp); free(cp);
-*/
- setvar(head->s, (void *) tail);
- symlook(head->s, S_WESET, (void *)"");
- if(strcmp(head->s, "MKSHELL") == 0){
- if((err = setshell(tail)) != nil){
- SYNERR(hline);
- fprint(2, "%s\n", err);
- Exit();
- break;
- }
- }
- }
- if(attr)
- symlook(head->s, S_NOEXPORT, (void *)"");
- break;
- default:
- SYNERR(hline);
- fprint(2, "expected one of :<=\n");
- Exit();
- break;
- }
- }
- close(fd);
- freebuf(buf);
- ipop();
- popshell();
-}
-
-void
-addrules(Word *head, Word *tail, char *body, int attr, int hline, char *prog)
-{
- Word *w;
-
- assert("addrules args", head && body);
- /* tuck away first non-meta rule as default target*/
- if(target1 == 0 && !(attr&REGEXP)){
- for(w = head; w; w = w->next)
- if(shellt->charin(w->s, "%&"))
- break;
- if(w == 0)
- target1 = wdup(head);
- }
- for(w = head; w; w = w->next)
- addrule(w->s, tail, body, head, attr, hline, prog);
-}
-
-static int
-rhead(char *line, Word **h, Word **t, int *attr, char **prog)
-{
- char *p;
- char *pp;
- int sep;
- Rune r;
- int n;
- Word *w;
-
- p = shellt->charin(line,":=<");
- if(p == 0)
- return('?');
- sep = *p;
- *p++ = 0;
- if(sep == '<' && *p == '|'){
- sep = '|';
- p++;
- }
- *attr = 0;
- *prog = 0;
- if(sep == '='){
- pp = shellt->charin(p, shellt->termchars); /* termchars…
- if (pp && *pp == '=') {
- while (p != pp) {
- n = chartorune(&r, p);
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n",*…
- Exit();
- case 'U':
- *attr = 1;
- break;
- }
- p += n;
- }
- p++; /* skip trailing '=' */
- }
- }
- if((sep == ':') && *p && (*p != ' ') && (*p != '\t')){
- while (*p) {
- n = chartorune(&r, p);
- if (r == ':')
- break;
- p += n;
- switch(r)
- {
- default:
- SYNERR(-1);
- fprint(2, "unknown attribute '%c'\n", p[-1]);
- Exit();
- case 'D':
- *attr |= DEL;
- break;
- case 'E':
- *attr |= NOMINUSE;
- break;
- case 'n':
- *attr |= NOVIRT;
- break;
- case 'N':
- *attr |= NOREC;
- break;
- case 'P':
- pp = utfrune(p, ':');
- if (pp == 0 || *pp == 0)
- goto eos;
- *pp = 0;
- *prog = strdup(p);
- *pp = ':';
- p = pp;
- break;
- case 'Q':
- *attr |= QUIET;
- break;
- case 'R':
- *attr |= REGEXP;
- break;
- case 'U':
- *attr |= UPD;
- break;
- case 'V':
- *attr |= VIR;
- break;
- }
- }
- if (*p++ != ':') {
- eos:
- SYNERR(-1);
- fprint(2, "missing trailing :\n");
- Exit();
- }
- }
- *h = w = stow(line);
- if(*w->s == 0 && sep != '<' && sep != '|' && sep != 'S') {
- SYNERR(mkinline-1);
- fprint(2, "no var on left side of assignment/rule\n");
- Exit();
- }
- *t = stow(p);
- return(sep);
-}
-
-static char *
-rbody(Biobuf *in)
-{
- Bufblock *buf;
- int r, lastr;
- char *p;
-
- lastr = '\n';
- buf = newbuf();
- for(;;){
- r = Bgetrune(in);
- if (r < 0)
- break;
- if (lastr == '\n') {
- if (r == '#')
- rinsert(buf, r);
- else if (r != ' ' && r != '\t') {
- Bungetrune(in);
- break;
- }
- } else
- rinsert(buf, r);
- lastr = r;
- if (r == '\n')
- mkinline++;
- }
- insert(buf, 0);
- p = strdup(buf->start);
- freebuf(buf);
- return p;
-}
-
-struct input
-{
- char *file;
- int line;
- struct input *next;
-};
-static struct input *inputs = 0;
-
-void
-ipush(void)
-{
- struct input *in, *me;
-
- me = (struct input *)Malloc(sizeof(*me));
- me->file = infile;
- me->line = mkinline;
- me->next = 0;
- if(inputs == 0)
- inputs = me;
- else {
- for(in = inputs; in->next; )
- in = in->next;
- in->next = me;
- }
-}
-
-void
-ipop(void)
-{
- struct input *in, *me;
-
- assert("pop input list", inputs != 0);
- if(inputs->next == 0){
- me = inputs;
- inputs = 0;
- } else {
- for(in = inputs; in->next->next; )
- in = in->next;
- me = in->next;
- in->next = 0;
- }
- infile = me->file;
- mkinline = me->line;
- free((char *)me);
-}
diff --git a/mk/rc.c b/mk/rc.c
@@ -1,194 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on rc's syntax. Most
- * of the routines extract strings observing rc's escape conventions
- */
-
-
-/*
- * skip a token in single quotes.
- */
-static char *
-squote(char *cp)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == '\'') {
- n += chartorune(&r, cp+n);
- if(r != '\'')
- return(cp);
- }
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-
-/*
- * search a string for characters in a pattern set
- * characters in quotes and variable generators are escaped
- */
-char *
-rccharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\'': /* skip quoted string */
- cp = squote(cp+1); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash. Only the first is valid for rc. the
- * others are just inserted into the receiving buffer.
- */
-char*
-rcexpandquote(char *s, Rune r, Bufblock *b)
-{
- if (r != '\'') {
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == '\'') {
- if(*s == '\'')
- s++;
- else
- return s;
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash. Only the first is a valid escape for
- * rc; the others are just inserted into the receiving buffer.
- */
-int
-rcescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc != '\'')
- return 1;
-
- line = mkinline;
- while((c = nextrune(bp, 0)) > 0){
- if(c == '\''){
- if(preserve)
- rinsert(buf, c);
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if(c != '\''){
- Bungetrune(bp);
- return 1;
- }
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a single-quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == '\'')
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quote…
- * s points to char after opening quote, q.
- */
-char *
-rccopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'') /* copy quoted string */
- return copysingle(s, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '}')
- break;
- if(q == '\'')
- s = copysingle(s, buf); /* copy quoted string */
- }
- return s;
-}
-
-static int
-rcmatchname(char *name)
-{
- char *p;
-
- if((p = strchr(name, '/')) != nil)
- name = p+1;
- if(name[0] == 'r' && name[1] == 'c')
- return 1;
- return 0;
-}
-
-Shell rcshell = {
- "rc",
- "'= \t",
- '\1',
- rccharin,
- rcexpandquote,
- rcescapetoken,
- rccopyq,
- rcmatchname,
-};
diff --git a/mk/recipe.c b/mk/recipe.c
@@ -1,117 +0,0 @@
-#include "mk.h"
-
-int
-dorecipe(Node *node)
-{
- char buf[BIGBLOCK];
- register Node *n;
- Rule *r = 0;
- Arc *a, *aa;
- Word head, ahead, lp, ln, *w, *ww, *aw;
- Symtab *s;
- int did = 0;
-
- aa = 0;
- /*
- pick up the rule
- */
- for(a = node->prereqs; a; a = a->next)
- if(*a->r->recipe)
- r = (aa = a)->r;
- /*
- no recipe? go to buggery!
- */
- if(r == 0){
- if(!(node->flags&VIRTUAL) && !(node->flags&NORECIPE)){
- fprint(2, "mk: no recipe to make '%s'\n", node->name);
- Exit();
- }
- if(strchr(node->name, '(') && node->time == 0)
- MADESET(node, MADE);
- else
- update(0, node);
- if(tflag){
- if(!(node->flags&VIRTUAL))
- touch(node->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s'\n", no…
- }
- return(did);
- }
- /*
- build the node list
- */
- node->next = 0;
- head.next = 0;
- ww = &head;
- ahead.next = 0;
- aw = &ahead;
- if(r->attr&REGEXP){
- ww->next = newword(node->name);
- aw->next = newword(node->name);
- } else {
- for(w = r->alltargets; w; w = w->next){
- if(r->attr&META)
- subst(aa->stem, w->s, buf);
- else
- strcpy(buf, w->s);
- aw->next = newword(buf);
- aw = aw->next;
- if((s = symlook(buf, S_NODE, 0)) == 0)
- continue; /* not a node we are interest…
- n = (Node *)s->value;
- if(aflag == 0 && n->time) {
- for(a = n->prereqs; a; a = a->next)
- if(a->n && outofdate(n, a, 0))
- break;
- if(a == 0)
- continue;
- }
- ww->next = newword(buf);
- ww = ww->next;
- if(n == node) continue;
- n->next = node->next;
- node->next = n;
- }
- }
- for(n = node; n; n = n->next)
- if((n->flags&READY) == 0)
- return(did);
- /*
- gather the params for the job
- */
- lp.next = ln.next = 0;
- for(n = node; n; n = n->next){
- for(a = n->prereqs; a; a = a->next){
- if(a->n){
- addw(&lp, a->n->name);
- if(outofdate(n, a, 0)){
- addw(&ln, a->n->name);
- if(explain)
- fprint(1, "%s(%ld) < %s(%ld)\n…
- n->name, n->time, a->n…
- }
- } else {
- if(explain)
- fprint(1, "%s has no prerequisites\n",
- n->name);
- }
- }
- MADESET(n, BEINGMADE);
- }
- /*print("lt=%s ln=%s lp=%s\n",wtos(head.next, ' '),wtos(ln.next, ' '),…
- run(newjob(r, node, aa->stem, aa->match, lp.next, ln.next, head.next, …
- return(1);
-}
-
-void
-addw(Word *w, char *s)
-{
- Word *lw;
-
- for(lw = w; w = w->next; lw = w){
- if(strcmp(s, w->s) == 0)
- return;
- }
- lw->next = newword(s);
-}
diff --git a/mk/rule.c b/mk/rule.c
@@ -1,110 +0,0 @@
-#include "mk.h"
-
-static Rule *lr, *lmr;
-static int rcmp(Rule *r, char *target, Word *tail);
-static int nrules = 0;
-
-void
-addrule(char *head, Word *tail, char *body, Word *ahead, int attr, int hline, …
-{
- Rule *r;
- Rule *rr;
- Symtab *sym;
- int reuse;
-
- r = 0;
- reuse = 0;
- if(sym = symlook(head, S_TARGET, 0)){
- for(r = (Rule *)sym->value; r; r = r->chain)
- if(rcmp(r, head, tail) == 0){
- reuse = 1;
- break;
- }
- }
- if(r == 0)
- r = (Rule *)Malloc(sizeof(Rule));
- r->shellt = shellt;
- r->shellcmd = shellcmd;
- r->target = head;
- r->tail = tail;
- r->recipe = body;
- r->line = hline;
- r->file = infile;
- r->attr = attr;
- r->alltargets = ahead;
- r->prog = prog;
- r->rule = nrules++;
- if(!reuse){
- rr = (Rule *)symlook(head, S_TARGET, (void *)r)->value;
- if(rr != r){
- r->chain = rr->chain;
- rr->chain = r;
- } else
- r->chain = 0;
- }
- if(!reuse)
- r->next = 0;
- if((attr&REGEXP) || shellt->charin(head, "%&")){
- r->attr |= META;
- if(reuse)
- return;
- if(attr&REGEXP){
- patrule = r;
- r->pat = regcomp(head);
- }
- if(metarules == 0)
- metarules = lmr = r;
- else {
- lmr->next = r;
- lmr = r;
- }
- } else {
- if(reuse)
- return;
- r->pat = 0;
- if(rules == 0)
- rules = lr = r;
- else {
- lr->next = r;
- lr = r;
- }
- }
-}
-
-void
-dumpr(char *s, Rule *r)
-{
- Bprint(&bout, "%s: start=%ld shelltype=%s shellcmd=%s\n",
- s, r, r->shellt->name, wtos(r->shellcmd, ' '));
- for(; r; r = r->next){
- Bprint(&bout, "\tRule %ld: %s[%d] attr=%x next=%ld chain=%ld a…
- r, r->file, r->line, r->attr, r->next, r->chain, wtos(…
- if(r->prog)
- Bprint(&bout, " prog='%s'", r->prog);
- Bprint(&bout, "\n\ttarget=%s: %s\n", r->target, wtos(r->tail, …
- Bprint(&bout, "\trecipe@%ld='%s'\n", r->recipe, r->recipe);
- }
-}
-
-static int
-rcmp(Rule *r, char *target, Word *tail)
-{
- Word *w;
-
- if(strcmp(r->target, target))
- return 1;
- for(w = r->tail; w && tail; w = w->next, tail = tail->next)
- if(strcmp(w->s, tail->s))
- return 1;
- return(w || tail);
-}
-
-char *
-rulecnt(void)
-{
- char *s;
-
- s = Malloc(nrules);
- memset(s, 0, nrules);
- return(s);
-}
diff --git a/mk/run.c b/mk/run.c
@@ -1,296 +0,0 @@
-#include "mk.h"
-
-typedef struct Event
-{
- int pid;
- Job *job;
-} Event;
-static Event *events;
-static int nevents, nrunning, nproclimit;
-
-typedef struct Process
-{
- int pid;
- int status;
- struct Process *b, *f;
-} Process;
-static Process *phead, *pfree;
-static void sched(void);
-static void pnew(int, int), pdelete(Process *);
-
-int pidslot(int);
-
-void
-run(Job *j)
-{
- Job *jj;
-
- if(jobs){
- for(jj = jobs; jj->next; jj = jj->next)
- ;
- jj->next = j;
- } else
- jobs = j;
- j->next = 0;
- /* this code also in waitup after parse redirect */
- if(nrunning < nproclimit)
- sched();
-}
-
-static void
-sched(void)
-{
- char *flags;
- Job *j;
- Bufblock *buf;
- int slot;
- Node *n;
- Envy *e;
-
- if(jobs == 0){
- usage();
- return;
- }
- j = jobs;
- jobs = j->next;
- if(DEBUG(D_EXEC))
- fprint(1, "firing up job for target %s\n", wtos(j->t, ' '));
- slot = nextslot();
- events[slot].job = j;
- buf = newbuf();
- e = buildenv(j, slot);
- shprint(j->r->recipe, e, buf, j->r->shellt);
- if(!tflag && (nflag || !(j->r->attr&QUIET)))
- Bwrite(&bout, buf->start, (long)strlen(buf->start));
- freebuf(buf);
- if(nflag||tflag){
- for(n = j->n; n; n = n->next){
- if(tflag){
- if(!(n->flags&VIRTUAL))
- touch(n->name);
- else if(explain)
- Bprint(&bout, "no touch of virtual '%s…
- }
- n->time = time((long *)0);
- MADESET(n, MADE);
- }
- } else {
- if(DEBUG(D_EXEC))
- fprint(1, "recipe='%s'", j->r->recipe);/**/
- Bflush(&bout);
- if(j->r->attr&NOMINUSE)
- flags = 0;
- else
- flags = "-e";
- events[slot].pid = execsh(flags, j->r->recipe, 0, e, j->r->she…
- usage();
- nrunning++;
- if(DEBUG(D_EXEC))
- fprint(1, "pid for target %s = %d\n", wtos(j->t, ' '),…
- }
-}
-
-int
-waitup(int echildok, int *retstatus)
-{
- Envy *e;
- int pid;
- int slot;
- Symtab *s;
- Word *w;
- Job *j;
- char buf[ERRMAX];
- Bufblock *bp;
- int uarg = 0;
- int done;
- Node *n;
- Process *p;
- extern int runerrs;
-
- /* first check against the proces slist */
- if(retstatus)
- for(p = phead; p; p = p->f)
- if(p->pid == *retstatus){
- *retstatus = p->status;
- pdelete(p);
- return(-1);
- }
-again: /* rogue processes */
- pid = waitfor(buf);
- if(pid == -1){
- if(echildok > 0)
- return(1);
- else {
- fprint(2, "mk: (waitup %d): %r\n", echildok);
- Exit();
- }
- }
- if(DEBUG(D_EXEC))
- fprint(1, "waitup got pid=%d, status='%s'\n", pid, buf);
- if(retstatus && pid == *retstatus){
- *retstatus = buf[0]? 1:0;
- return(-1);
- }
- slot = pidslot(pid);
- if(slot < 0){
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n",…
- pnew(pid, buf[0]? 1:0);
- goto again;
- }
- j = events[slot].job;
- usage();
- nrunning--;
- events[slot].pid = -1;
- if(buf[0]){
- e = buildenv(j, slot);
- bp = newbuf();
- shprint(j->r->recipe, e, bp, j->r->shellt);
- front(bp->start);
- fprint(2, "mk: %s: exit status=%s", bp->start, buf);
- freebuf(bp);
- for(n = j->n, done = 0; n; n = n->next)
- if(n->flags&DELETE){
- if(done++ == 0)
- fprint(2, ", deleting");
- fprint(2, " '%s'", n->name);
- delete(n->name);
- }
- fprint(2, "\n");
- if(kflag){
- runerrs++;
- uarg = 1;
- } else {
- jobs = 0;
- Exit();
- }
- }
- for(w = j->t; w; w = w->next){
- if((s = symlook(w->s, S_NODE, 0)) == 0)
- continue; /* not interested in this node */
- update(uarg, (Node *)s->value);
- }
- if(nrunning < nproclimit)
- sched();
- return(0);
-}
-
-void
-nproc(void)
-{
- Symtab *sym;
- Word *w;
-
- if(sym = symlook("NPROC", S_VAR, 0)) {
- w = (Word *) sym->value;
- if (w && w->s && w->s[0])
- nproclimit = atoi(w->s);
- }
- if(nproclimit < 1)
- nproclimit = 1;
- if(DEBUG(D_EXEC))
- fprint(1, "nprocs = %d\n", nproclimit);
- if(nproclimit > nevents){
- if(nevents)
- events = (Event *)Realloc((char *)events, nproclimit*s…
- else
- events = (Event *)Malloc(nproclimit*sizeof(Event));
- while(nevents < nproclimit)
- events[nevents++].pid = 0;
- }
-}
-
-int
-nextslot(void)
-{
- int i;
-
- for(i = 0; i < nproclimit; i++)
- if(events[i].pid <= 0) return i;
- assert("out of slots!!", 0);
- return 0; /* cyntax */
-}
-
-int
-pidslot(int pid)
-{
- int i;
-
- for(i = 0; i < nevents; i++)
- if(events[i].pid == pid) return(i);
- if(DEBUG(D_EXEC))
- fprint(2, "mk: wait returned unexpected process %d\n", pid);
- return(-1);
-}
-
-
-static void
-pnew(int pid, int status)
-{
- Process *p;
-
- if(pfree){
- p = pfree;
- pfree = p->f;
- } else
- p = (Process *)Malloc(sizeof(Process));
- p->pid = pid;
- p->status = status;
- p->f = phead;
- phead = p;
- if(p->f)
- p->f->b = p;
- p->b = 0;
-}
-
-static void
-pdelete(Process *p)
-{
- if(p->f)
- p->f->b = p->b;
- if(p->b)
- p->b->f = p->f;
- else
- phead = p->f;
- p->f = pfree;
- pfree = p;
-}
-
-void
-killchildren(char *msg)
-{
- Process *p;
-
- kflag = 1; /* to make sure waitup doesn't exit */
- jobs = 0; /* make sure no more get scheduled */
- for(p = phead; p; p = p->f)
- expunge(p->pid, msg);
- while(waitup(1, (int *)0) == 0)
- ;
- Bprint(&bout, "mk: %s\n", msg);
- Exit();
-}
-
-static long tslot[1000];
-static long tick;
-
-void
-usage(void)
-{
- long t;
-
- time(&t);
- if(tick)
- tslot[nrunning] += (t-tick);
- tick = t;
-}
-
-void
-prusage(void)
-{
- int i;
-
- usage();
- for(i = 0; i <= nevents; i++)
- fprint(1, "%d: %ld\n", i, tslot[i]);
-}
diff --git a/mk/sh.c b/mk/sh.c
@@ -1,206 +0,0 @@
-#include "mk.h"
-
-/*
- * This file contains functions that depend on the shell's syntax. Most
- * of the routines extract strings observing the shell's escape convent…
- */
-
-
-/*
- * skip a token in quotes.
- */
-static char *
-squote(char *cp, int c)
-{
- Rune r;
- int n;
-
- while(*cp){
- n = chartorune(&r, cp);
- if(r == c)
- return cp;
- if(r == '\\')
- n += chartorune(&r, cp+n);
- cp += n;
- }
- SYNERR(-1); /* should never occur */
- fprint(2, "missing closing '\n");
- return 0;
-}
-/*
- * search a string for unescaped characters in a pattern set
- */
-static char *
-shcharin(char *cp, char *pat)
-{
- Rune r;
- int n, vargen;
-
- vargen = 0;
- while(*cp){
- n = chartorune(&r, cp);
- switch(r){
- case '\\': /* skip escaped char */
- cp += n;
- n = chartorune(&r, cp);
- break;
- case '\'': /* skip quoted string */
- case '"':
- cp = squote(cp+1, r); /* n must = 1 */
- if(!cp)
- return 0;
- break;
- case '$':
- if(*(cp+1) == '{')
- vargen = 1;
- break;
- case '}':
- if(vargen)
- vargen = 0;
- else if(utfrune(pat, r))
- return cp;
- break;
- default:
- if(vargen == 0 && utfrune(pat, r))
- return cp;
- break;
- }
- cp += n;
- }
- if(vargen){
- SYNERR(-1);
- fprint(2, "missing closing } in pattern generator\n");
- }
- return 0;
-}
-
-/*
- * extract an escaped token. Possible escape chars are single-quote,
- * double-quote,and backslash.
- */
-static char*
-shexpandquote(char *s, Rune esc, Bufblock *b)
-{
- Rune r;
-
- if (esc == '\\') {
- s += chartorune(&r, s);
- rinsert(b, r);
- return s;
- }
-
- while(*s){
- s += chartorune(&r, s);
- if(r == esc)
- return s;
- if (r == '\\') {
- rinsert(b, r);
- s += chartorune(&r, s);
- }
- rinsert(b, r);
- }
- return 0;
-}
-
-/*
- * Input an escaped token. Possible escape chars are single-quote,
- * double-quote and backslash.
- */
-static int
-shescapetoken(Biobuf *bp, Bufblock *buf, int preserve, int esc)
-{
- int c, line;
-
- if(esc == '\\') {
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c == '\n')
- mkinline++;
- rinsert(buf, c);
- return 1;
- }
-
- line = mkinline;
- while((c = nextrune(bp, 0)) >= 0){
- if(c == esc){
- if(preserve)
- rinsert(buf, c);
- return 1;
- }
- if(c == '\\') {
- rinsert(buf, c);
- c = Bgetrune(bp);
- if(c == '\r')
- c = Bgetrune(bp);
- if (c < 0)
- break;
- if (c == '\n')
- mkinline++;
- }
- rinsert(buf, c);
- }
- SYNERR(line); fprint(2, "missing closing %c\n", esc);
- return 0;
-}
-
-/*
- * copy a quoted string; s points to char after opening quote
- */
-static char *
-copysingle(char *s, Rune q, Bufblock *buf)
-{
- Rune r;
-
- while(*s){
- s += chartorune(&r, s);
- rinsert(buf, r);
- if(r == q)
- break;
- }
- return s;
-}
-/*
- * check for quoted strings. backquotes are handled here; single quote…
- * s points to char after opening quote, q.
- */
-static char *
-shcopyq(char *s, Rune q, Bufblock *buf)
-{
- if(q == '\'' || q == '"') /* copy quoted string */
- return copysingle(s, q, buf);
-
- if(q != '`') /* not quoted */
- return s;
-
- while(*s){ /* copy backquoted string */
- s += chartorune(&q, s);
- rinsert(buf, q);
- if(q == '`')
- break;
- if(q == '\'' || q == '"')
- s = copysingle(s, q, buf); /* copy quoted strin…
- }
- return s;
-}
-
-static int
-shmatchname(char *name)
-{
- USED(name);
-
- return 1;
-}
-
-
-Shell shshell = {
- "sh",
- "\"'= \t", /*used in parse.c to isolate assignment attribute*/
- ' ', /* inter-word separator in env */
- shcharin,
- shexpandquote,
- shescapetoken,
- shcopyq,
- shmatchname,
-};
-
diff --git a/mk/shell.c b/mk/shell.c
@@ -1,80 +0,0 @@
-#include "mk.h"
-
-static Shell *shells[] = {
- &rcshell,
- &shshell,
-};
-
-Shell *shelldefault = &shshell;
-
-Shell *shellt;
-Word *shellcmd;
-
-typedef struct Shellstack Shellstack;
-struct Shellstack
-{
- Shell *t;
- Word *w;
- Shellstack *next;
-};
-
-Shellstack *shellstack;
-
-char*
-setshell(Word *w)
-{
- int i;
-
- if(w->s == nil)
- return "shell name not found on line";
-
- for(i=0; i<nelem(shells); i++)
- if(shells[i]->matchname(w->s))
- break;
- if(i == nelem(shells))
- return "cannot determine shell type";
- shellt = shells[i];
- shellcmd = w;
- return nil;
-}
-
-void
-initshell(void)
-{
- shellcmd = stow(shelldefault->name);
- shellt = shelldefault;
- setvar("MKSHELL", shellcmd);
-}
-
-void
-pushshell(void)
-{
- Shellstack *s;
-
- /* save */
- s = Malloc(sizeof *s);
- s->t = shellt;
- s->w = shellcmd;
- s->next = shellstack;
- shellstack = s;
-
- initshell(); /* reset to defaults */
-}
-
-void
-popshell(void)
-{
- Shellstack *s;
-
- if(shellstack == nil){
- fprint(2, "internal shellstack error\n");
- Exit();
- }
-
- s = shellstack;
- shellstack = s->next;
- shellt = s->t;
- shellcmd = s->w;
- setvar("MKSHELL", shellcmd);
- free(s);
-}
diff --git a/mk/shprint.c b/mk/shprint.c
@@ -1,125 +0,0 @@
-#include "mk.h"
-
-static char *vexpand(char*, Envy*, Bufblock*);
-
-#define getfields mkgetfields
-
-static int
-getfields(char *str, char **args, int max, int mflag, char *set)
-{
- Rune r;
- int nr, intok, narg;
-
- if(max <= 0)
- return 0;
-
- narg = 0;
- args[narg] = str;
- if(!mflag)
- narg++;
- intok = 0;
- for(;; str += nr) {
- nr = chartorune(&r, str);
- if(r == 0)
- break;
- if(utfrune(set, r)) {
- if(narg >= max)
- break;
- *str = 0;
- intok = 0;
- args[narg] = str + nr;
- if(!mflag)
- narg++;
- } else {
- if(!intok && mflag)
- narg++;
- intok = 1;
- }
- }
- return narg;
-}
-
-void
-shprint(char *s, Envy *env, Bufblock *buf, Shell *sh)
-{
- int n;
- Rune r;
-
- while(*s) {
- n = chartorune(&r, s);
- if (r == '$')
- s = vexpand(s, env, buf);
- else {
- rinsert(buf, r);
- s += n;
- s = sh->copyq(s, r, buf); /*handle quoted strin…
- }
- }
- insert(buf, 0);
-}
-
-static char *
-mygetenv(char *name, Envy *env)
-{
- if (!env)
- return 0;
- if (symlook(name, S_WESET, 0) == 0 && symlook(name, S_INTERNAL, 0) == …
- return 0;
- /* only resolve internal variables and variables we've set */
- for(; env->name; env++){
- if (strcmp(env->name, name) == 0)
- return wtos(env->values, ' ');
- }
- return 0;
-}
-
-static char *
-vexpand(char *w, Envy *env, Bufblock *buf)
-{
- char *s, carry, *p, *q;
-
- assert("vexpand no $", *w == '$');
- p = w+1; /* skip dollar sign */
- if(*p == '{') {
- p++;
- q = utfrune(p, '}');
- if (!q)
- q = strchr(p, 0);
- } else
- q = shname(p);
- carry = *q;
- *q = 0;
- s = mygetenv(p, env);
- *q = carry;
- if (carry == '}')
- q++;
- if (s) {
- bufcpy(buf, s, strlen(s));
- free(s);
- } else /* copy name intact*/
- bufcpy(buf, w, q-w);
- return(q);
-}
-
-void
-front(char *s)
-{
- char *t, *q;
- int i, j;
- char *flds[512];
-
- q = strdup(s);
- i = getfields(q, flds, 512, 0, " \t\n");
- if(i > 5){
- flds[4] = flds[i-1];
- flds[3] = "...";
- i = 5;
- }
- t = s;
- for(j = 0; j < i; j++){
- for(s = flds[j]; *s; *t++ = *s++);
- *t++ = ' ';
- }
- *t = 0;
- free(q);
-}
diff --git a/mk/symtab.c b/mk/symtab.c
@@ -1,97 +0,0 @@
-#include "mk.h"
-
-#define NHASH 4099
-#define HASHMUL 79L /* this is a good value */
-static Symtab *hash[NHASH];
-
-void
-syminit(void)
-{
- Symtab **s, *ss, *next;
-
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s; ss; ss = next){
- next = ss->next;
- free((char *)ss);
- }
- *s = 0;
- }
-}
-
-Symtab *
-symlook(char *sym, int space, void *install)
-{
- long h;
- char *p;
- Symtab *s;
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h]; s; s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0))
- return(s);
- if(install == 0)
- return(0);
- s = (Symtab *)Malloc(sizeof(Symtab));
- s->space = space;
- s->name = sym;
- s->value = install;
- s->next = hash[h];
- hash[h] = s;
- return(s);
-}
-
-void
-symdel(char *sym, int space)
-{
- long h;
- char *p;
- Symtab *s, *ls;
-
- /* multiple memory leaks */
-
- for(p = sym, h = space; *p; h += *p++)
- h *= HASHMUL;
- if(h < 0)
- h = ~h;
- h %= NHASH;
- for(s = hash[h], ls = 0; s; ls = s, s = s->next)
- if((s->space == space) && (strcmp(s->name, sym) == 0)){
- if(ls)
- ls->next = s->next;
- else
- hash[h] = s->next;
- free((char *)s);
- }
-}
-
-void
-symtraverse(int space, void (*fn)(Symtab*))
-{
- Symtab **s, *ss;
-
- for(s = hash; s < &hash[NHASH]; s++)
- for(ss = *s; ss; ss = ss->next)
- if(ss->space == space)
- (*fn)(ss);
-}
-
-void
-symstat(void)
-{
- Symtab **s, *ss;
- int n;
- int l[1000];
-
- memset((char *)l, 0, sizeof(l));
- for(s = hash; s < &hash[NHASH]; s++){
- for(ss = *s, n = 0; ss; ss = ss->next)
- n++;
- l[n]++;
- }
- for(n = 0; n < 1000; n++)
- if(l[n]) Bprint(&bout, "%ld of length %d\n", l[n], n);
-}
diff --git a/mk/sys.h b/mk/sys.h
@@ -1,5 +0,0 @@
-#include <u.h>
-#include <libc.h>
-#include <bio.h>
-#include <regexp.h>
-
diff --git a/mk/sys.std.h b/mk/sys.std.h
@@ -1,22 +0,0 @@
-#include <utf.h>
-#include <fmt.h>
-#include <bio.h>
-#include <regexp9.h>
-#include <stdlib.h>
-#include <unistd.h>
-#include <fcntl.h>
-#include <string.h>
-#include <ctype.h>
-#include <time.h>
-
-#define OREAD O_RDONLY
-#define OWRITE O_WRONLY
-#define ORDWR O_RDWR
-#define nil 0
-#define nelem(x) (sizeof(x)/sizeof((x)[0]))
-#define seek lseek
-#define remove unlink
-#define exits(x) exit(x && *(char*)x ? 1 : 0)
-#define USED(x) if(x){}else
-#define create(name, mode, perm) open(name, mode|O_CREAT, perm)
-#define ERRMAX 256
diff --git a/mk/unix.c b/mk/unix.c
@@ -1,341 +0,0 @@
-#define NOPLAN9DEFINES
-#include "mk.h"
-#include <sys/wait.h>
-#include <signal.h>
-#include <sys/stat.h>
-#include <sys/time.h>
-
-char *shell = "/bin/sh";
-char *shellname = "sh";
-
-extern char **environ;
-
-static void
-mkperror(char *s)
-{
- fprint(2, "%s: %r\n", s);
-}
-
-void
-readenv(void)
-{
- char **p, *s;
- Word *w;
-
- for(p = environ; *p; p++){
-/* rsc 5/5/2004 -- This misparses fn#cd={whatever}
- s = shname(*p);
- if(*s == '=') {
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
-*/
- s = strchr(*p, '=');
- if(s){
- *s = 0;
- w = newword(s+1);
- } else
- w = newword("");
- if (symlook(*p, S_INTERNAL, 0))
- continue;
- s = strdup(*p);
- setvar(s, (void *)w);
- symlook(s, S_EXPORTED, (void*)"")->value = (void*)"";
- }
-}
-
-/*
- * done on child side of fork, so parent's env is not affected
- * and we don't care about freeing memory because we're going
- * to exec immediately after this.
- */
-void
-exportenv(Envy *e, Shell *sh)
-{
- int i;
- char **p;
- static char buf[16384];
-
- p = 0;
- for(i = 0; e->name; e++, i++) {
- p = (char**) Realloc(p, (i+2)*sizeof(char*));
- if(e->values)
- snprint(buf, sizeof buf, "%s=%s", e->name, wtos(e->va…
- else
- snprint(buf, sizeof buf, "%s=", e->name);
- p[i] = strdup(buf);
- }
- p[i] = 0;
- environ = p;
-}
-
-int
-waitfor(char *msg)
-{
- int status;
- int pid;
-
- *msg = 0;
- pid = wait(&status);
- if(pid > 0) {
- if(status&0x7f) {
- if(status&0x80)
- snprint(msg, ERRMAX, "signal %d, core dumped",…
- else
- snprint(msg, ERRMAX, "signal %d", status&0x7f);
- } else if(status&0xff00)
- snprint(msg, ERRMAX, "exit(%d)", (status>>8)&0xff);
- }
- return pid;
-}
-
-void
-expunge(int pid, char *msg)
-{
- if(strcmp(msg, "interrupt"))
- kill(pid, SIGINT);
- else
- kill(pid, SIGHUP);
-}
-
-int mypid;
-
-int
-shargv(Word *cmd, int extra, char ***pargv)
-{
- char **argv;
- int i, n;
- Word *w;
-
- n = 0;
- for(w=cmd; w; w=w->next)
- n++;
-
- argv = Malloc((n+extra+1)*sizeof(argv[0]));
- i = 0;
- for(w=cmd; w; w=w->next)
- argv[i++] = w->s;
- argv[n] = 0;
- *pargv = argv;
- return n;
-}
-
-int
-execsh(char *args, char *cmd, Bufblock *buf, Envy *e, Shell *sh, Word *shellcm…
-{
- char *p, **argv;
- int tot, n, pid, in[2], out[2];
-
- if(buf && pipe(out) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- mypid = getpid();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(buf)
- close(out[0]);
- if(pipe(in) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid != 0){
- dup2(in[0], 0);
- if(buf){
- dup2(out[1], 1);
- close(out[1]);
- }
- close(in[0]);
- close(in[1]);
- if (e)
- exportenv(e, sh);
- n = shargv(shellcmd, 1, &argv);
- argv[n++] = args;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- close(out[1]);
- close(in[0]);
- if(DEBUG(D_EXEC))
- fprint(1, "starting: %s\n", cmd);
- p = cmd+strlen(cmd);
- while(cmd < p){
- n = write(in[1], cmd, p-cmd);
- if(n < 0)
- break;
- cmd += n;
- }
- close(in[1]);
- _exit(0);
- }
- if(buf){
- close(out[1]);
- tot = 0;
- for(;;){
- if (buf->current >= buf->end)
- growbuf(buf);
- n = read(out[0], buf->current, buf->end-buf->current);
- if(n <= 0)
- break;
- buf->current += n;
- tot += n;
- }
- if (tot && buf->current[-1] == '\n')
- buf->current--;
- close(out[0]);
- }
- return pid;
-}
-
-int
-pipecmd(char *cmd, Envy *e, int *fd, Shell *sh, Word *shellcmd)
-{
- int pid, pfd[2];
- int n;
- char **argv;
-
- if(DEBUG(D_EXEC))
- fprint(1, "pipecmd='%s'\n", cmd);/**/
-
- if(fd && pipe(pfd) < 0){
- mkperror("pipe");
- Exit();
- }
- pid = fork();
- if(pid < 0){
- mkperror("mk fork");
- Exit();
- }
- if(pid == 0){
- if(fd){
- close(pfd[0]);
- dup2(pfd[1], 1);
- close(pfd[1]);
- }
- if(e)
- exportenv(e, sh);
- n = shargv(shellcmd, 2, &argv);
- argv[n++] = "-c";
- argv[n++] = cmd;
- argv[n] = 0;
- execvp(argv[0], argv);
- mkperror(shell);
- _exit(1);
- }
- if(fd){
- close(pfd[1]);
- *fd = pfd[0];
- }
- return pid;
-}
-
-void
-Exit(void)
-{
- while(wait(0) >= 0)
- ;
- exits("error");
-}
-
-static struct
-{
- int sig;
- char *msg;
-} sigmsgs[] =
-{
- SIGALRM, "alarm",
- SIGFPE, "sys: fp: fptrap",
- SIGPIPE, "sys: write on closed pipe",
- SIGILL, "sys: trap: illegal instruction",
-// SIGSEGV, "sys: segmentation violation",
- 0, 0
-};
-
-static void
-notifyf(int sig)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- if(sigmsgs[i].sig == sig)
- killchildren(sigmsgs[i].msg);
-
- /* should never happen */
- signal(sig, SIG_DFL);
- kill(getpid(), sig);
-}
-
-void
-catchnotes(void)
-{
- int i;
-
- for(i = 0; sigmsgs[i].msg; i++)
- signal(sigmsgs[i].sig, notifyf);
-}
-
-char*
-maketmp(int *pfd)
-{
- static char temp[] = "/tmp/mkargXXXXXX";
- static char buf[100];
- int fd;
-
- strcpy(buf, temp);
- fd = mkstemp(buf);
- if(fd < 0)
- return 0;
- *pfd = fd;
- return buf;
-}
-
-int
-chgtime(char *name)
-{
- if(access(name, 0) >= 0)
- return utimes(name, 0);
- return close(creat(name, 0666));
-}
-
-void
-rcopy(char **to, Resub *match, int n)
-{
- int c;
- char *p;
-
- *to = match->s.sp; /* stem0 matches complete target */
- for(to++, match++; --n > 0; to++, match++){
- if(match->s.sp && match->e.ep){
- p = match->e.ep;
- c = *p;
- *p = 0;
- *to = strdup(match->s.sp);
- *p = c;
- }
- else
- *to = 0;
- }
-}
-
-unsigned long
-mkmtime(char *name)
-{
- struct stat st;
-
- if(stat(name, &st) < 0)
- return 0;
-
- return st.st_mtime;
-}
diff --git a/mk/var.c b/mk/var.c
@@ -1,41 +0,0 @@
-#include "mk.h"
-
-void
-setvar(char *name, void *value)
-{
- symlook(name, S_VAR, value)->value = value;
- symlook(name, S_MAKEVAR, (void*)"");
-}
-
-static void
-print1(Symtab *s)
-{
- Word *w;
-
- Bprint(&bout, "\t%s=", s->name);
- for (w = (Word *) s->value; w; w = w->next)
- Bprint(&bout, "'%s'", w->s);
- Bprint(&bout, "\n");
-}
-
-void
-dumpv(char *s)
-{
- Bprint(&bout, "%s:\n", s);
- symtraverse(S_VAR, print1);
-}
-
-char *
-shname(char *a)
-{
- Rune r;
- int n;
-
- while (*a) {
- n = chartorune(&r, a);
- if (!WORDCHR(r))
- break;
- a += n;
- }
- return a;
-}
diff --git a/mk/varsub.c b/mk/varsub.c
@@ -1,256 +0,0 @@
-#include "mk.h"
-
-static Word *subsub(Word*, char*, char*);
-static Word *expandvar(char**);
-static Bufblock *varname(char**);
-static Word *extractpat(char*, char**, char*, char*);
-static int submatch(char*, Word*, Word*, int*, char**);
-static Word *varmatch(char *, char**);
-
-Word *
-varsub(char **s)
-{
- Bufblock *b;
- Word *w;
-
- if(**s == '{') /* either ${name} or ${name: A%B==C%D}*/
- return expandvar(s);
-
- b = varname(s);
- if(b == 0)
- return 0;
-
- w = varmatch(b->start, s);
- freebuf(b);
- return w;
-}
-
-/*
- * extract a variable name
- */
-static Bufblock*
-varname(char **s)
-{
- Bufblock *b;
- char *cp;
- Rune r;
- int n;
-
- b = newbuf();
- cp = *s;
- for(;;){
- n = chartorune(&r, cp);
- if (!WORDCHR(r))
- break;
- rinsert(b, r);
- cp += n;
- }
- if (b->current == b->start){
- SYNERR(-1);
- fprint(2, "missing variable name <%s>\n", *s);
- freebuf(b);
- return 0;
- }
- *s = cp;
- insert(b, 0);
- return b;
-}
-
-static Word*
-varmatch(char *name, char **s)
-{
- Word *w;
- Symtab *sym;
- char *cp;
-
- sym = symlook(name, S_VAR, 0);
- if(sym){
- /* check for at least one non-NULL value */
- for (w = (Word*)sym->value; w; w = w->next)
- if(w->s && *w->s)
- return wdup(w);
- }
- for(cp = *s; *cp == ' ' || *cp == '\t'; cp++) /* skip trailing …
- ;
- *s = cp;
- return 0;
-}
-
-static Word*
-expandvar(char **s)
-{
- Word *w;
- Bufblock *buf;
- Symtab *sym;
- char *cp, *begin, *end;
-
- begin = *s;
- (*s)++; /* skip the '{'…
- buf = varname(s);
- if (buf == 0)
- return 0;
- cp = *s;
- if (*cp == '}') { /* ${name} variant*/
- (*s)++; /* skip the '}'…
- w = varmatch(buf->start, s);
- freebuf(buf);
- return w;
- }
- if (*cp != ':') {
- SYNERR(-1);
- fprint(2, "bad variable name <%s>\n", buf->start);
- freebuf(buf);
- return 0;
- }
- cp++;
- end = shellt->charin(cp , "}");
- if(end == 0){
- SYNERR(-1);
- fprint(2, "missing '}': %s\n", begin);
- Exit();
- }
- *end = 0;
- *s = end+1;
-
- sym = symlook(buf->start, S_VAR, 0);
- if(sym == 0 || sym->value == 0)
- w = newword(buf->start);
- else
- w = subsub((Word*) sym->value, cp, end);
- freebuf(buf);
- return w;
-}
-
-static Word*
-extractpat(char *s, char **r, char *term, char *end)
-{
- int save;
- char *cp;
- Word *w;
-
- cp = shellt->charin(s, term);
- if(cp){
- *r = cp;
- if(cp == s)
- return 0;
- save = *cp;
- *cp = 0;
- w = stow(s);
- *cp = save;
- } else {
- *r = end;
- w = stow(s);
- }
- return w;
-}
-
-static Word*
-subsub(Word *v, char *s, char *end)
-{
- int nmid;
- Word *head, *tail, *w, *h;
- Word *a, *b, *c, *d;
- Bufblock *buf;
- char *cp, *enda;
-
- a = extractpat(s, &cp, "=%&", end);
- b = c = d = 0;
- if(PERCENT(*cp))
- b = extractpat(cp+1, &cp, "=", end);
- if(*cp == '=')
- c = extractpat(cp+1, &cp, "&%", end);
- if(PERCENT(*cp))
- d = stow(cp+1);
- else if(*cp)
- d = stow(cp);
-
- head = tail = 0;
- buf = newbuf();
- for(; v; v = v->next){
- h = w = 0;
- if(submatch(v->s, a, b, &nmid, &enda)){
- /* enda points to end of A match in source;
- * nmid = number of chars between end of A and start o…
- */
- if(c){
- h = w = wdup(c);
- while(w->next)
- w = w->next;
- }
- if(PERCENT(*cp) && nmid > 0){
- if(w){
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- } else {
- bufcpy(buf, enda, nmid);
- insert(buf, 0);
- h = w = newword(buf->start);
- }
- buf->current = buf->start;
- }
- if(d && *d->s){
- if(w){
-
- bufcpy(buf, w->s, strlen(w->s));
- bufcpy(buf, d->s, strlen(d->s));
- insert(buf, 0);
- free(w->s);
- w->s = strdup(buf->start);
- w->next = wdup(d->next);
- while(w->next)
- w = w->next;
- buf->current = buf->start;
- } else
- h = w = wdup(d);
- }
- }
- if(w == 0)
- h = w = newword(v->s);
-
- if(head == 0)
- head = h;
- else
- tail->next = h;
- tail = w;
- }
- freebuf(buf);
- delword(a);
- delword(b);
- delword(c);
- delword(d);
- return head;
-}
-
-static int
-submatch(char *s, Word *a, Word *b, int *nmid, char **enda)
-{
- Word *w;
- int n;
- char *end;
-
- n = 0;
- for(w = a; w; w = w->next){
- n = strlen(w->s);
- if(strncmp(s, w->s, n) == 0)
- break;
- }
- if(a && w == 0) /* a == NULL matches everything*/
- return 0;
-
- *enda = s+n; /* pointer to end a A part match */
- *nmid = strlen(s)-n; /* size of remainder of source */
- end = *enda+*nmid;
- for(w = b; w; w = w->next){
- n = strlen(w->s);
- if(strcmp(w->s, end-n) == 0){
- *nmid -= n;
- break;
- }
- }
- if(b && w == 0) /* b == NULL matches everything */
- return 0;
- return 1;
-}
diff --git a/mk/word.c b/mk/word.c
@@ -1,180 +0,0 @@
-#include "mk.h"
-
-static Word *nextword(char**);
-
-Word*
-newword(char *s)
-{
- Word *w;
-
- w = (Word *)Malloc(sizeof(Word));
- w->s = strdup(s);
- w->next = 0;
- return(w);
-}
-
-Word *
-stow(char *s)
-{
- Word *head, *w, *new;
-
- w = head = 0;
- while(*s){
- new = nextword(&s);
- if(new == 0)
- break;
- if (w)
- w->next = new;
- else
- head = w = new;
- while(w->next)
- w = w->next;
-
- }
- if (!head)
- head = newword("");
- return(head);
-}
-
-char *
-wtos(Word *w, int sep)
-{
- Bufblock *buf;
- char *cp;
-
- buf = newbuf();
- for(; w; w = w->next){
- for(cp = w->s; *cp; cp++)
- insert(buf, *cp);
- if(w->next)
- insert(buf, sep);
- }
- insert(buf, 0);
- cp = strdup(buf->start);
- freebuf(buf);
- return(cp);
-}
-
-Word*
-wdup(Word *w)
-{
- Word *v, *new, *base;
-
- v = base = 0;
- while(w){
- new = newword(w->s);
- if(v)
- v->next = new;
- else
- base = new;
- v = new;
- w = w->next;
- }
- return base;
-}
-
-void
-delword(Word *w)
-{
- Word *v;
-
- while(v = w){
- w = w->next;
- if(v->s)
- free(v->s);
- free(v);
- }
-}
-
-/*
- * break out a word from a string handling quotes, executions,
- * and variable expansions.
- */
-static Word*
-nextword(char **s)
-{
- Bufblock *b;
- Word *head, *tail, *w;
- Rune r;
- char *cp;
-
- cp = *s;
- b = newbuf();
- head = tail = 0;
- while(*cp == ' ' || *cp == '\t') /* leading white space…
- cp++;
- while(*cp){
- cp += chartorune(&r, cp);
- switch(r)
- {
- case ' ':
- case '\t':
- case '\n':
- goto out;
- case '\\':
- case '\'':
- case '"':
- cp = shellt->expandquote(cp, r, b);
- if(cp == 0){
- fprint(2, "missing closing quote: %s\n", *s);
- Exit();
- }
- break;
- case '$':
- w = varsub(&cp);
- if(w == 0)
- break;
- if(b->current != b->start){
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(w->s);
- w->s = strdup(b->start);
- b->current = b->start;
- }
- if(head){
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, w->s, strlen(w->s));
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(b->start);
- tail->next = w->next;
- free(w->s);
- free(w);
- b->current = b->start;
- } else
- tail = head = w;
- while(tail->next)
- tail = tail->next;
- break;
- default:
- rinsert(b, r);
- break;
- }
- }
-out:
- *s = cp;
- if(b->current != b->start){
- if(head){
- cp = b->current;
- bufcpy(b, tail->s, strlen(tail->s));
- bufcpy(b, b->start, cp-b->start);
- insert(b, 0);
- free(tail->s);
- tail->s = strdup(cp);
- } else {
- insert(b, 0);
- head = newword(b->start);
- }
- }
- freebuf(b);
- return head;
-}
-
-void
-dumpw(char *s, Word *w)
-{
- Bprint(&bout, "%s", s);
- for(; w; w = w->next)
- Bprint(&bout, " '%s'", w->s);
- Bputc(&bout, '\n');
-}
diff --git a/rc/Makefile b/rc/Makefile
@@ -4,7 +4,7 @@
TARG = rc
OFILES = code.o exec.o getflags.o glob.o here.o io.o lex.o \
pcmd.o pfnc.o simple.o subr.o trap.o tree.o unixcrap.o \
- var.o y.tab.o plan9ish.o
+ var.o y.tab.o plan9ish.o havefork.o
YFILES = syn.y
MANFILES = rc.1
@@ -23,6 +23,7 @@ all:
depend:
@echo YACC ${YFILES}
@${YACC} -d ${YFILES}
+ @cp y.tab.h x.tab.h
install: ${TARG}
@mkdir -p ${DESTDIR}${PREFIX}/bin
diff --git a/rc/code.c b/rc/code.c
@@ -7,9 +7,9 @@
#define c1 t->child[1]
#define c2 t->child[2]
int codep, ncode;
-#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f=…
-#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i=…
-#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s=…
+#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f …
+#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i …
+#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s …
void stuffdot(int);
char *fnstr(tree*);
void outcode(tree*, int);
@@ -17,22 +17,33 @@ void codeswitch(tree*, int);
int iscase(tree*);
code *codecopy(code*);
void codefree(code*);
-int morecode(void){
+
+int
+morecode(void)
+{
ncode+=100;
- codebuf=(code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
- if(codebuf==0) panic("Can't realloc %d bytes in morecode!",
+ codebuf = (code *)realloc((char *)codebuf, ncode*sizeof codebuf[0]);
+ if(codebuf==0)
+ panic("Can't realloc %d bytes in morecode!",
ncode*sizeof codebuf[0]);
+ memset(codebuf+ncode-100, 0, 100*sizeof codebuf[0]);
return 0;
}
-void stuffdot(int a){
- if(a<0 || codep<=a) panic("Bad address %d in stuffdot", a);
- codebuf[a].i=codep;
+
+void
+stuffdot(int a)
+{
+ if(a<0 || codep<=a)
+ panic("Bad address %d in stuffdot", a);
+ codebuf[a].i = codep;
}
-int compile(tree *t)
+
+int
+compile(tree *t)
{
- ncode=100;
- codebuf=(code *)emalloc(ncode*sizeof codebuf[0]);
- codep=0;
+ ncode = 100;
+ codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+ codep = 0;
emiti(0); /* reference count */
outcode(t, flag['e']?1:0);
if(nerror){
@@ -44,31 +55,39 @@ int compile(tree *t)
emitf(0);
return 1;
}
-void cleanhere(char *f)
+
+void
+cleanhere(char *f)
{
emitf(Xdelhere);
emits(strdup(f));
}
-char *fnstr(tree *t)
+
+char*
+fnstr(tree *t)
{
- io *f=openstr();
+ io *f = openstr();
char *v;
extern char nl;
- char svnl=nl;
+ char svnl = nl;
nl=';';
pfmt(f, "%t", t);
- nl=svnl;
- v=f->strp;
- f->strp=0;
+ nl = svnl;
+ v = f->strp;
+ f->strp = 0;
closeio(f);
return v;
}
-void outcode(tree *t, int eflag)
+
+void
+outcode(tree *t, int eflag)
{
int p, q;
tree *tt;
- if(t==0) return;
- if(t->type!=NOT && t->type!=';') runq->iflast=0;
+ if(t==0)
+ return;
+ if(t->type!=NOT && t->type!=';')
+ runq->iflast = 0;
switch(t->type){
default:
pfmt(err, "bad type %d in outcode\n", t->type);
@@ -92,10 +111,13 @@ void outcode(tree *t, int eflag)
break;
case '&':
emitf(Xasync);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
case ';':
outcode(c0, eflag);
@@ -110,15 +132,18 @@ void outcode(tree *t, int eflag)
break;
case '`':
emitf(Xbackq);
- p=emiti(0);
- outcode(c0, 0);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, 0);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
break;
case ANDAND:
outcode(c0, 0);
emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
@@ -144,7 +169,7 @@ void outcode(tree *t, int eflag)
outcode(c0, eflag);
if(c1){
emitf(Xfn);
- p=emiti(0);
+ p = emiti(0);
emits(fnstr(c1));
outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
@@ -157,22 +182,23 @@ void outcode(tree *t, int eflag)
case IF:
outcode(c0, 0);
emitf(Xif);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
emitf(Xwastrue);
stuffdot(p);
break;
case NOT:
- if(!runq->iflast) yyerror("`if not' does not follow `if(...)'"…
+ if(!runq->iflast)
+ yyerror("`if not' does not follow `if(...)'");
emitf(Xifnot);
- p=emiti(0);
+ p = emiti(0);
outcode(c0, eflag);
stuffdot(p);
break;
case OROR:
outcode(c0, 0);
emitf(Xfalse);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
stuffdot(p);
break;
@@ -183,15 +209,20 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xsimple);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
break;
case SUBSHELL:
emitf(Xsubshell);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
- if(eflag) emitf(Xeflag);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else
+ emits(fnstr(c0));
+ if(eflag)
+ emitf(Xeflag);
break;
case SWITCH:
codeswitch(t, eflag);
@@ -202,14 +233,16 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xmatch);
- if(eflag) emitf(Xeflag);
+ if(eflag)
+ emitf(Xeflag);
break;
case WHILE:
- q=codep;
+ q = codep;
outcode(c0, 0);
- if(q==codep) emitf(Xsettrue); /* empty condition == whi…
+ if(q==codep)
+ emitf(Xsettrue); /* empty condition == while(tr…
emitf(Xtrue);
- p=emiti(0);
+ p = emiti(0);
outcode(c1, eflag);
emitf(Xjump);
emiti(q);
@@ -235,8 +268,8 @@ void outcode(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
- p=emitf(Xfor);
- q=emiti(0);
+ p = emitf(Xfor);
+ q = emiti(0);
outcode(c2, eflag);
emitf(Xjump);
emiti(p);
@@ -263,10 +296,14 @@ void outcode(tree *t, int eflag)
case PIPEFD:
emitf(Xpipefd);
emiti(t->rtype);
- p=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ }
break;
case REDIR:
emitf(Xmark);
@@ -283,28 +320,31 @@ void outcode(tree *t, int eflag)
case HERE:
emitf(Xread);
break;
+ case RDWR:
+ emitf(Xrdwr);
+ break;
}
emiti(t->fd0);
outcode(c1, eflag);
emitf(Xpopredir);
break;
case '=':
- tt=t;
- for(;t && t->type=='=';t=c2);
+ tt = t;
+ for(;t && t->type=='=';t = c2);
if(t){
- for(t=tt;t->type=='=';t=c2){
+ for(t = tt;t->type=='=';t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
outcode(c0, eflag);
emitf(Xlocal);
}
- t=tt;
- outcode(c2, eflag);
- for(;t->type=='=';t=c2) emitf(Xunlocal);
+ outcode(t, eflag);
+ for(t = tt; t->type=='='; t = c2)
+ emitf(Xunlocal);
}
else{
- for(t=tt;t;t=c2){
+ for(t = tt;t;t = c2){
emitf(Xmark);
outcode(c1, eflag);
emitf(Xmark);
@@ -312,17 +352,22 @@ void outcode(tree *t, int eflag)
emitf(Xassign);
}
}
- t=tt; /* so tests below will work */
+ t = tt; /* so tests below will work */
break;
case PIPE:
emitf(Xpipe);
emiti(t->fd0);
emiti(t->fd1);
- p=emiti(0);
- q=emiti(0);
- outcode(c0, eflag);
- emitf(Xexit);
- stuffdot(p);
+ if(havefork){
+ p = emiti(0);
+ q = emiti(0);
+ outcode(c0, eflag);
+ emitf(Xexit);
+ stuffdot(p);
+ } else {
+ emits(fnstr(c0));
+ q = emiti(0);
+ }
outcode(c1, eflag);
emitf(Xreturn);
stuffdot(q);
@@ -330,8 +375,8 @@ void outcode(tree *t, int eflag)
break;
}
if(t->type!=NOT && t->type!=';')
- runq->iflast=t->type==IF;
- else if(c0) runq->iflast=c0->type==IF;
+ runq->iflast = t->type==IF;
+ else if(c0) runq->iflast = c0->type==IF;
}
/*
* switch code looks like this:
@@ -353,7 +398,9 @@ void outcode(tree *t, int eflag)
* leave:
* Xpopm
*/
-void codeswitch(tree *t, int eflag)
+
+void
+codeswitch(tree *t, int eflag)
{
int leave; /* patch jump address to leave switch */
int out; /* jump here to leave switch */
@@ -368,23 +415,23 @@ void codeswitch(tree *t, int eflag)
emitf(Xmark);
outcode(c0, eflag);
emitf(Xjump);
- nextcase=emiti(0);
- out=emitf(Xjump);
- leave=emiti(0);
+ nextcase = emiti(0);
+ out = emitf(Xjump);
+ leave = emiti(0);
stuffdot(nextcase);
- t=c1->child[0];
+ t = c1->child[0];
while(t->type==';'){
- tt=c1;
+ tt = c1;
emitf(Xmark);
- for(t=c0->child[0];t->type==ARGLIST;t=c0) outcode(c1, eflag);
+ for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, efla…
emitf(Xcase);
- nextcase=emiti(0);
- t=tt;
+ nextcase = emiti(0);
+ t = tt;
for(;;){
if(t->type==';'){
if(iscase(c0)) break;
outcode(c0, eflag);
- t=c1;
+ t = c1;
}
else{
if(!iscase(t)) outcode(t, eflag);
@@ -398,23 +445,32 @@ void codeswitch(tree *t, int eflag)
stuffdot(leave);
emitf(Xpopm);
}
-int iscase(tree *t)
+
+int
+iscase(tree *t)
{
- if(t->type!=SIMPLE) return 0;
- do t=c0; while(t->type==ARGLIST);
+ if(t->type!=SIMPLE)
+ return 0;
+ do t = c0; while(t->type==ARGLIST);
return t->type==WORD && !t->quoted && strcmp(t->str, "case")==0;
}
-code *codecopy(code *cp)
+
+code*
+codecopy(code *cp)
{
cp[0].i++;
return cp;
}
-void codefree(code *cp)
+
+void
+codefree(code *cp)
{
code *p;
- if(--cp[0].i!=0) return;
- for(p=cp+1;p->f;p++){
+ if(--cp[0].i!=0)
+ return;
+ for(p = cp+1;p->f;p++){
if(p->f==Xappend || p->f==Xclose || p->f==Xread || p->f==Xwrite
+ || p->f==Xrdwr
|| p->f==Xasync || p->f==Xbackq || p->f==Xcase || p->f==Xfalse
|| p->f==Xfor || p->f==Xjump
|| p->f==Xsubshell || p->f==Xtrue) p++;
diff --git a/rc/exec.c b/rc/exec.c
@@ -1,12 +1,3 @@
-#include <u.h>
-#include <signal.h>
-#if defined(PLAN9PORT) && defined(__sun__)
-# define BSD_COMP /* sigh. for TIOCNOTTY */
-#endif
-#ifdef __sun__
-#include <sys/termios.h>
-#endif
-#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
@@ -16,90 +7,118 @@
* Start executing the given code at the given pc with the given redirection
*/
char *argv0="rc";
-void start(code *c, int pc, var *local)
-{
- struct thread *p=new(struct thread);
- p->code=codecopy(c);
- p->pc=pc;
- p->argv=0;
- p->redir=p->startredir=runq?runq->redir:0;
- p->local=local;
- p->cmdfile=0;
- p->cmdfd=0;
- p->eof=0;
- p->iflag=0;
- p->lineno=1;
- p->pid=-1;
- p->ret=runq;
- runq=p;
-}
-word *newword(char *wd, word *next)
-{
- word *p=new(word);
- p->word=strdup(wd);
- p->next=next;
+
+void
+start(code *c, int pc, var *local)
+{
+ struct thread *p = new(struct thread);
+
+ p->code = codecopy(c);
+ p->pc = pc;
+ p->argv = 0;
+ p->redir = p->startredir = runq?runq->redir:0;
+ p->local = local;
+ p->cmdfile = 0;
+ p->cmdfd = 0;
+ p->eof = 0;
+ p->iflag = 0;
+ p->lineno = 1;
+ p->ret = runq;
+ runq = p;
+}
+
+word*
+newword(char *wd, word *next)
+{
+ word *p = new(word);
+ p->word = strdup(wd);
+ p->next = next;
return p;
}
-void pushword(char *wd)
+
+void
+pushword(char *wd)
{
- if(runq->argv==0) panic("pushword but no argv!", 0);
- runq->argv->words=newword(wd, runq->argv->words);
+ if(runq->argv==0)
+ panic("pushword but no argv!", 0);
+ runq->argv->words = newword(wd, runq->argv->words);
}
-void popword(void){
+
+void
+popword(void)
+{
word *p;
- if(runq->argv==0) panic("popword but no argv!", 0);
- p=runq->argv->words;
- if(p==0) panic("popword but no word!", 0);
- runq->argv->words=p->next;
+ if(runq->argv==0)
+ panic("popword but no argv!", 0);
+ p = runq->argv->words;
+ if(p==0)
+ panic("popword but no word!", 0);
+ runq->argv->words = p->next;
efree(p->word);
efree((char *)p);
}
-void freelist(word *w)
+
+void
+freelist(word *w)
{
word *nw;
while(w){
- nw=w->next;
+ nw = w->next;
efree(w->word);
efree((char *)w);
- w=nw;
+ w = nw;
}
}
-void pushlist(void){
- list *p=new(list);
- p->next=runq->argv;
- p->words=0;
- runq->argv=p;
-}
-void poplist(void){
- list *p=runq->argv;
- if(p==0) panic("poplist but no argv", 0);
+
+void
+pushlist(void)
+{
+ list *p = new(list);
+ p->next = runq->argv;
+ p->words = 0;
+ runq->argv = p;
+}
+
+void
+poplist(void)
+{
+ list *p = runq->argv;
+ if(p==0)
+ panic("poplist but no argv", 0);
freelist(p->words);
- runq->argv=p->next;
+ runq->argv = p->next;
efree((char *)p);
}
-int count(word *w)
+
+int
+count(word *w)
{
int n;
- for(n=0;w;n++) w=w->next;
+ for(n = 0;w;n++) w = w->next;
return n;
}
-void pushredir(int type, int from, int to){
- redir * rp=new(redir);
- rp->type=type;
- rp->from=from;
- rp->to=to;
- rp->next=runq->redir;
- runq->redir=rp;
-}
-var *newvar(char *name, var *next)
-{
- var *v=new(var);
- v->name=name;
- v->val=0;
- v->fn=0;
- v->changed=0;
- v->fnchanged=0;
- v->next=next;
+
+void
+pushredir(int type, int from, int to)
+{
+ redir * rp = new(redir);
+ rp->type = type;
+ rp->from = from;
+ rp->to = to;
+ rp->next = runq->redir;
+ runq->redir = rp;
+}
+
+var*
+newvar(char *name, var *next)
+{
+ var *v = new(var);
+ v->name = name;
+ v->val = 0;
+ v->fn = 0;
+ v->changed = 0;
+ v->fnchanged = 0;
+ v->next = next;
v->changefn = 0;
return v;
}
@@ -117,52 +136,59 @@ main(int argc, char *argv[])
char num[12], *rcmain;
int i;
- argc=getflags(argc, argv, "srdiIlxepvVc:1m:1[command]", 1);
- if(argc==-1) usage("[file [arg ...]]");
- if(argv[0][0]=='-') flag['l']=flagset;
- if(flag['I']) flag['i'] = 0;
+ /* needed for rcmain later */
+ putenv("PLAN9", unsharp("#9"));
+
+ argc = getflags(argc, argv, "SsrdiIlxepvVc:1m:1[command]", 1);
+ if(argc==-1)
+ usage("[file [arg ...]]");
+ if(argv[0][0]=='-')
+ flag['l'] = flagset;
+ if(flag['I'])
+ flag['i'] = 0;
else if(flag['i']==0 && argc==1 && Isatty(0)) flag['i'] = flagset;
- rcmain=flag['m']?flag['m'][0]:Rcmain();
- err=openfd(2);
+ rcmain = flag['m'] ? flag['m'][0] : Rcmain();
+ err = openfd(2);
kinit();
Trapinit();
Vinit();
- itoa(num, mypid=getpid());
+ inttoascii(num, mypid = getpid());
pathinit();
setvar("pid", newword(num, (word *)0));
setvar("cflag", flag['c']?newword(flag['c'][0], (word *)0)
:(word *)0);
setvar("rcname", newword(argv[0], (word *)0));
- i=0;
- bootstrap[i++].i=1;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xword;
+ i = 0;
+ bootstrap[i++].i = 1;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s="*";
- bootstrap[i++].f=Xassign;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xmark;
- bootstrap[i++].f=Xword;
+ bootstrap[i++].f = Xassign;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xmark;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s="*";
- bootstrap[i++].f=Xdol;
- bootstrap[i++].f=Xword;
- bootstrap[i++].s=rcmain;
- bootstrap[i++].f=Xword;
+ bootstrap[i++].f = Xdol;
+ bootstrap[i++].f = Xword;
+ bootstrap[i++].s = rcmain;
+ bootstrap[i++].f = Xword;
bootstrap[i++].s=".";
- bootstrap[i++].f=Xsimple;
- bootstrap[i++].f=Xexit;
- bootstrap[i].i=0;
+ bootstrap[i++].f = Xsimple;
+ bootstrap[i++].f = Xexit;
+ bootstrap[i].i = 0;
start(bootstrap, 1, (var *)0);
/* prime bootstrap argv */
pushlist();
argv0 = strdup(argv[0]);
- for(i=argc-1;i!=0;--i) pushword(argv[i]);
+ for(i = argc-1;i!=0;--i) pushword(argv[i]);
for(;;){
- if(flag['r']) pfnc(err, runq);
+ if(flag['r'])
+ pfnc(err, runq);
runq->pc++;
(*runq->code[runq->pc-1].f)();
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
}
- return 0;
}
/*
* Opcode routines
@@ -198,6 +224,7 @@ main(int argc, char *argv[])
* Xpipefd[type]{... Xreturn} connect {} to pipe (input or outp…
* depending on type), push /dev/fd/??
* Xpopm(value) pop value from stack
+ * Xrdwr(file)[fd] open file for reading and writing
* Xread(file)[fd] open file to read
* Xsettraps(names){... Xreturn} define trap functions
* Xshowtraps print trap list
@@ -209,16 +236,24 @@ main(int argc, char *argv[])
* Xword[string] push string
* Xwrite(file)[fd] open file to write
*/
-void Xappend(void){
+
+void
+Xappend(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1(">> requires singleton"); return;
- case 0: Xerror1(">> requires file"); return;
- case 1: break;
+ default:
+ Xerror1(">> requires singleton");
+ return;
+ case 0:
+ Xerror1(">> requires file");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=open(file, 1))<0 && (f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 1))<0 && (f = Creat(file))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -228,126 +263,114 @@ void Xappend(void){
runq->pc++;
poplist();
}
-void Xasync(void){
- int null=open("/dev/null", 0);
- int tty;
- int pid;
- char npid[10];
- if(null<0){
- Xerror("Can't open /dev/null\n");
- return;
- }
- switch(pid=rfork(RFFDG|RFPROC|RFNOTEG)){
- case -1:
- close(null);
- Xerror("try again");
- break;
- case 0:
- /*
- * I don't know what the right thing to do here is,
- * so this is all experimentally determined.
- * If we just dup /dev/null onto 0, then running
- * ssh foo & will reopen /dev/tty, try to read a password,
- * get a signal, and repeat, in a tight loop, forever.
- * Arguably this is a bug in ssh (it behaves the same
- * way under bash as under rc) but I'm fixing it here
- * anyway. If we dissociate the process from the tty,
- * then it won't be able to open /dev/tty ever again.
- * The SIG_IGN on SIGTTOU makes writing the tty
- * (via fd 1 or 2, for example) succeed even though
- * our pgrp is not the terminal's controlling pgrp.
- */
- if((tty=open("/dev/tty", OREAD)) >= 0){
- /*
- * Should make reads of tty fail, writes succeed.
- */
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
- ioctl(tty, TIOCNOTTY);
- close(tty);
- }
- if(isatty(0))
- pushredir(ROPEN, null, 0);
- else
- close(null);
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- close(null);
- runq->pc=runq->code[runq->pc].i;
- itoa(npid, pid);
- setvar("apid", newword(npid, (word *)0));
- break;
- }
-}
-void Xsettrue(void){
+
+void
+Xsettrue(void)
+{
setstatus("");
}
-void Xbang(void){
+
+void
+Xbang(void)
+{
setstatus(truestatus()?"false":"");
}
-void Xclose(void){
+
+void
+Xclose(void)
+{
pushredir(RCLOSE, runq->code[runq->pc].i, 0);
runq->pc++;
}
-void Xdup(void){
+
+void
+Xdup(void)
+{
pushredir(RDUP, runq->code[runq->pc].i, runq->code[runq->pc+1].i);
runq->pc+=2;
}
-void Xeflag(void){
+
+void
+Xeflag(void)
+{
if(eflagok && !truestatus()) Xexit();
}
-void Xexit(void){
+
+void
+Xexit(void)
+{
struct var *trapreq;
struct word *starval;
- static int beenhere=0;
+ static int beenhere = 0;
if(getpid()==mypid && !beenhere){
- trapreq=vlook("sigexit");
+ trapreq = vlook("sigexit");
if(trapreq->fn){
- beenhere=1;
+ beenhere = 1;
--runq->pc;
- starval=vlook("*")->val;
+ starval = vlook("*")->val;
start(trapreq->fn, trapreq->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=copywords(starval, (struct word *)0);
- runq->local->changed=1;
- runq->redir=runq->startredir=0;
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = copywords(starval, (struct word *)0…
+ runq->local->changed = 1;
+ runq->redir = runq->startredir = 0;
return;
}
}
Exit(getstatus());
}
-void Xfalse(void){
- if(truestatus()) runq->pc=runq->code[runq->pc].i;
+
+void
+Xfalse(void)
+{
+ if(truestatus()) runq->pc = runq->code[runq->pc].i;
else runq->pc++;
}
int ifnot; /* dynamic if not flag */
-void Xifnot(void){
+
+void
+Xifnot(void)
+{
if(ifnot)
runq->pc++;
else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
}
-void Xjump(void){
- runq->pc=runq->code[runq->pc].i;
+
+void
+Xjump(void)
+{
+ runq->pc = runq->code[runq->pc].i;
}
-void Xmark(void){
+
+void
+Xmark(void)
+{
pushlist();
}
-void Xpopm(void){
+
+void
+Xpopm(void)
+{
poplist();
}
-void Xread(void){
+
+void
+Xread(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1("< requires singleton\n"); return;
- case 0: Xerror1("< requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("< requires singleton\n");
+ return;
+ case 0:
+ Xerror1("< requires file\n");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=open(file, 0))<0){
+ file = runq->argv->words->word;
+ if((f = open(file, 0))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -356,51 +379,110 @@ void Xread(void){
runq->pc++;
poplist();
}
-void turfredir(void){
+
+void
+Xrdwr(void)
+{
+ char *file;
+ int f;
+
+ switch(count(runq->argv->words)){
+ default:
+ Xerror1("<> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("<> requires file\n");
+ return;
+ case 1:
+ break;
+ }
+ file = runq->argv->words->word;
+ if((f = open(file, ORDWR))<0){
+ pfmt(err, "%s: ", file);
+ Xerror("can't open");
+ return;
+ }
+ pushredir(ROPEN, f, runq->code[runq->pc].i);
+ runq->pc++;
+ poplist();
+}
+
+void
+turfredir(void)
+{
while(runq->redir!=runq->startredir)
Xpopredir();
}
-void Xpopredir(void){
- struct redir *rp=runq->redir;
- if(rp==0) panic("turfredir null!", 0);
- runq->redir=rp->next;
- if(rp->type==ROPEN) close(rp->from);
+
+void
+Xpopredir(void)
+{
+ struct redir *rp = runq->redir;
+ if(rp==0)
+ panic("turfredir null!", 0);
+ runq->redir = rp->next;
+ if(rp->type==ROPEN)
+ close(rp->from);
efree((char *)rp);
}
-void Xreturn(void){
- struct thread *p=runq;
+
+void
+Xreturn(void)
+{
+ struct thread *p = runq;
turfredir();
while(p->argv) poplist();
codefree(p->code);
- runq=p->ret;
+ runq = p->ret;
efree((char *)p);
- if(runq==0) Exit(getstatus());
+ if(runq==0)
+ Exit(getstatus());
}
-void Xtrue(void){
+
+void
+Xtrue(void)
+{
if(truestatus()) runq->pc++;
- else runq->pc=runq->code[runq->pc].i;
+ else runq->pc = runq->code[runq->pc].i;
}
-void Xif(void){
- ifnot=1;
+
+void
+Xif(void)
+{
+ ifnot = 1;
if(truestatus()) runq->pc++;
- else runq->pc=runq->code[runq->pc].i;
+ else runq->pc = runq->code[runq->pc].i;
}
-void Xwastrue(void){
- ifnot=0;
+
+void
+Xwastrue(void)
+{
+ ifnot = 0;
}
-void Xword(void){
+
+void
+Xword(void)
+{
pushword(runq->code[runq->pc++].s);
}
-void Xwrite(void){
+
+void
+Xwrite(void)
+{
char *file;
int f;
switch(count(runq->argv->words)){
- default: Xerror1("> requires singleton\n"); return;
- case 0: Xerror1("> requires file\n"); return;
- case 1: break;
+ default:
+ Xerror1("> requires singleton\n");
+ return;
+ case 0:
+ Xerror1("> requires file\n");
+ return;
+ case 1:
+ break;
}
- file=runq->argv->words->word;
- if((f=Creat(file))<0){
+ file = runq->argv->words->word;
+ if((f = Creat(file))<0){
pfmt(err, "%s: ", file);
Xerror("can't open");
return;
@@ -409,31 +491,35 @@ void Xwrite(void){
runq->pc++;
poplist();
}
-char *_list2str(word *words, int c){
+
+char*
+list2str(word *words)
+{
char *value, *s, *t;
- int len=0;
+ int len = 0;
word *ap;
- for(ap=words;ap;ap=ap->next)
+ for(ap = words;ap;ap = ap->next)
len+=1+strlen(ap->word);
- value=emalloc(len+1);
- s=value;
- for(ap=words;ap;ap=ap->next){
- for(t=ap->word;*t;) *s++=*t++;
- *s++=c;
- }
- if(s==value) *s='\0';
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=' ';
+ }
+ if(s==value)
+ *s='\0';
else s[-1]='\0';
return value;
}
-char *list2str(word *words){
- return _list2str(words, ' ');
-}
-void Xmatch(void){
+
+void
+Xmatch(void)
+{
word *p;
char *subject;
- subject=list2str(runq->argv->words);
+ subject = list2str(runq->argv->words);
setstatus("no match");
- for(p=runq->argv->next->words;p;p=p->next)
+ for(p = runq->argv->next->words;p;p = p->next)
if(match(subject, p->word, '\0')){
setstatus("");
break;
@@ -442,14 +528,17 @@ void Xmatch(void){
poplist();
poplist();
}
-void Xcase(void){
+
+void
+Xcase(void)
+{
word *p;
char *s;
- int ok=0;
- s=list2str(runq->argv->next->words);
- for(p=runq->argv->words;p;p=p->next){
+ int ok = 0;
+ s = list2str(runq->argv->next->words);
+ for(p = runq->argv->words;p;p = p->next){
if(match(s, p->word, '\0')){
- ok=1;
+ ok = 1;
break;
}
}
@@ -457,28 +546,33 @@ void Xcase(void){
if(ok)
runq->pc++;
else
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
poplist();
}
-word *conclist(word *lp, word *rp, word *tail)
+
+word*
+conclist(word *lp, word *rp, word *tail)
{
char *buf;
word *v;
if(lp->next || rp->next)
- tail=conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->next,
+ tail = conclist(lp->next==0?lp:lp->next, rp->next==0?rp:rp->ne…
tail);
- buf=emalloc(strlen(lp->word)+strlen(rp->word)+1);
+ buf = emalloc(strlen(lp->word)+strlen(rp->word)+1);
strcpy(buf, lp->word);
strcat(buf, rp->word);
- v=newword(buf, tail);
+ v = newword(buf, tail);
efree(buf);
return v;
}
-void Xconc(void){
- word *lp=runq->argv->words;
- word *rp=runq->argv->next->words;
- word *vp=runq->argv->next->next->words;
- int lc=count(lp), rc=count(rp);
+
+void
+Xconc(void)
+{
+ word *lp = runq->argv->words;
+ word *rp = runq->argv->next->words;
+ word *vp = runq->argv->next->next->words;
+ int lc = count(lp), rc = count(rp);
if(lc!=0 || rc!=0){
if(lc==0 || rc==0){
Xerror1("null list in concatenation");
@@ -488,42 +582,50 @@ void Xconc(void){
Xerror1("mismatched list lengths in concatenation");
return;
}
- vp=conclist(lp, rp, vp);
+ vp = conclist(lp, rp, vp);
}
poplist();
poplist();
- runq->argv->words=vp;
+ runq->argv->words = vp;
}
-void Xassign(void){
+
+void
+Xassign(void)
+{
var *v;
if(count(runq->argv->words)!=1){
Xerror1("variable name not singleton!");
return;
}
deglob(runq->argv->words->word);
- v=vlook(runq->argv->words->word);
+ v = vlook(runq->argv->words->word);
poplist();
globlist();
freewords(v->val);
- v->val=runq->argv->words;
- v->changed=1;
+ v->val = runq->argv->words;
+ v->changed = 1;
if(v->changefn)
v->changefn(v);
- runq->argv->words=0;
+ runq->argv->words = 0;
poplist();
}
/*
* copy arglist a, adding the copy to the front of tail
*/
-word *copywords(word *a, word *tail)
+
+word*
+copywords(word *a, word *tail)
{
- word *v=0, **end;
- for(end=&v;a;a=a->next,end=&(*end)->next)
- *end=newword(a->word, 0);
- *end=tail;
+ word *v = 0, **end;
+ for(end=&v;a;a = a->next,end=&(*end)->next)
+ *end = newword(a->word, 0);
+ *end = tail;
return v;
}
-void Xdol(void){
+
+void
+Xdol(void)
+{
word *a, *star;
char *s, *t;
int n;
@@ -531,24 +633,27 @@ void Xdol(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
- a=runq->argv->next->words;
+ n = 0;
+ for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
+ a = runq->argv->next->words;
if(n==0 || *t)
- a=copywords(vlook(s)->val, a);
+ a = copywords(vlook(s)->val, a);
else{
- star=vlook("*")->val;
+ star = vlook("*")->val;
if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
- a=newword(star->word, a);
+ while(--n) star = star->next;
+ a = newword(star->word, a);
}
}
poplist();
- runq->argv->words=a;
+ runq->argv->words = a;
}
-void Xqdol(void){
+
+void
+Xqdol(void)
+{
word *a, *p;
char *s;
int n;
@@ -556,20 +661,20 @@ void Xqdol(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- a=vlook(s)->val;
+ a = vlook(s)->val;
poplist();
- n=count(a);
+ n = count(a);
if(n==0){
pushword("");
return;
}
- for(p=a;p;p=p->next) n+=strlen(p->word);
- s=emalloc(n);
+ for(p = a;p;p = p->next) n+=strlen(p->word);
+ s = emalloc(n);
if(a){
strcpy(s, a->word);
- for(p=a->next;p;p=p->next){
+ for(p = a->next;p;p = p->next){
strcat(s, " ");
strcat(s, p->word);
}
@@ -579,37 +684,77 @@ void Xqdol(void){
pushword(s);
efree(s);
}
-word *subwords(word *val, int len, word *sub, word *a)
+
+word*
+copynwords(word *a, word *tail, int n)
{
- int n;
+ word *v, **end;
+
+ v = 0;
+ end = &v;
+ while(n-- > 0){
+ *end = newword(a->word, 0);
+ end = &(*end)->next;
+ a = a->next;
+ }
+ *end = tail;
+ return v;
+}
+
+word*
+subwords(word *val, int len, word *sub, word *a)
+{
+ int n, m;
char *s;
- if(!sub) return a;
- a=subwords(val, len, sub->next, a);
- s=sub->word;
+ if(!sub)
+ return a;
+ a = subwords(val, len, sub->next, a);
+ s = sub->word;
deglob(s);
- n=0;
- while('0'<=*s && *s<='9') n=n*10+ *s++ -'0';
- if(n<1 || len<n) return a;
- for(;n!=1;--n) val=val->next;
- return newword(val->word, a);
-}
-void Xsub(void){
+ m = 0;
+ n = 0;
+ while('0'<=*s && *s<='9')
+ n = n*10+ *s++ -'0';
+ if(*s == '-'){
+ if(*++s == 0)
+ m = len - n;
+ else{
+ while('0'<=*s && *s<='9')
+ m = m*10+ *s++ -'0';
+ m -= n;
+ }
+ }
+ if(n<1 || n>len || m<0)
+ return a;
+ if(n+m>len)
+ m = len-n;
+ while(--n > 0)
+ val = val->next;
+ return copynwords(val, a, m+1);
+}
+
+void
+Xsub(void)
+{
word *a, *v;
char *s;
if(count(runq->argv->next->words)!=1){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->next->words->word;
+ s = runq->argv->next->words->word;
deglob(s);
- a=runq->argv->next->next->words;
- v=vlook(s)->val;
- a=subwords(v, count(v), runq->argv->words, a);
+ a = runq->argv->next->next->words;
+ v = vlook(s)->val;
+ a = subwords(v, count(v), runq->argv->words, a);
poplist();
poplist();
- runq->argv->words=a;
+ runq->argv->words = a;
}
-void Xcount(void){
+
+void
+Xcount(void)
+{
word *a;
char *s, *t;
int n;
@@ -618,112 +763,102 @@ void Xcount(void){
Xerror1("variable name not singleton!");
return;
}
- s=runq->argv->words->word;
+ s = runq->argv->words->word;
deglob(s);
- n=0;
- for(t=s;'0'<=*t && *t<='9';t++) n=n*10+*t-'0';
+ n = 0;
+ for(t = s;'0'<=*t && *t<='9';t++) n = n*10+*t-'0';
if(n==0 || *t){
- a=vlook(s)->val;
- itoa(num, count(a));
+ a = vlook(s)->val;
+ inttoascii(num, count(a));
}
else{
- a=vlook("*")->val;
- itoa(num, a && 1<=n && n<=count(a)?1:0);
+ a = vlook("*")->val;
+ inttoascii(num, a && 1<=n && n<=count(a)?1:0);
}
poplist();
pushword(num);
}
-void Xlocal(void){
+
+void
+Xlocal(void)
+{
if(count(runq->argv->words)!=1){
Xerror1("variable name must be singleton\n");
return;
}
deglob(runq->argv->words->word);
- runq->local=newvar(strdup(runq->argv->words->word), runq->local);
- runq->local->val=copywords(runq->argv->next->words, (word *)0);
- runq->local->changed=1;
+ runq->local = newvar(strdup(runq->argv->words->word), runq->local);
+ runq->local->val = copywords(runq->argv->next->words, (word *)0);
+ runq->local->changed = 1;
poplist();
poplist();
}
-void Xunlocal(void){
- var *v=runq->local, *hid;
- if(v==0) panic("Xunlocal: no locals!", 0);
- runq->local=v->next;
- hid=vlook(v->name);
- hid->changed=1;
+
+void
+Xunlocal(void)
+{
+ var *v = runq->local, *hid;
+ if(v==0)
+ panic("Xunlocal: no locals!", 0);
+ runq->local = v->next;
+ hid = vlook(v->name);
+ hid->changed = 1;
efree(v->name);
freewords(v->val);
efree((char *)v);
}
-void freewords(word *w)
+
+void
+freewords(word *w)
{
word *nw;
while(w){
efree(w->word);
- nw=w->next;
+ nw = w->next;
efree((char *)w);
- w=nw;
+ w = nw;
}
}
-void Xfn(void){
+
+void
+Xfn(void)
+{
var *v;
word *a;
int end;
- end=runq->code[runq->pc].i;
- for(a=runq->argv->words;a;a=a->next){
- v=gvlook(a->word);
- if(v->fn) codefree(v->fn);
- v->fn=codecopy(runq->code);
- v->pc=runq->pc+2;
- v->fnchanged=1;
- }
- runq->pc=end;
+ end = runq->code[runq->pc].i;
+ for(a = runq->argv->words;a;a = a->next){
+ v = gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn = codecopy(runq->code);
+ v->pc = runq->pc+2;
+ v->fnchanged = 1;
+ }
+ runq->pc = end;
poplist();
}
-void Xdelfn(void){
+
+void
+Xdelfn(void)
+{
var *v;
word *a;
- for(a=runq->argv->words;a;a=a->next){
- v=gvlook(a->word);
- if(v->fn) codefree(v->fn);
- v->fn=0;
- v->fnchanged=1;
+ for(a = runq->argv->words;a;a = a->next){
+ v = gvlook(a->word);
+ if(v->fn)
+ codefree(v->fn);
+ v->fn = 0;
+ v->fnchanged = 1;
}
poplist();
}
-void Xpipe(void){
- struct thread *p=runq;
- int pc=p->pc, forkid;
- int lfd=p->code[pc++].i;
- int rfd=p->code[pc++].i;
- int pfd[2];
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- switch(forkid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- runq->ret=0;
- close(pfd[PRD]);
- pushredir(ROPEN, pfd[PWR], lfd);
- break;
- default:
- start(p->code, p->code[pc].i, runq->local);
- close(pfd[PWR]);
- pushredir(ROPEN, pfd[PRD], rfd);
- p->pc=p->code[pc+1].i;
- p->pid=forkid;
- break;
- }
-}
-char *concstatus(char *s, char *t)
+
+char*
+concstatus(char *s, char *t)
{
static char v[NSTATUS+1];
- int n=strlen(s);
+ int n = strlen(s);
strncpy(v, s, NSTATUS);
if(n<NSTATUS){
v[n]='|';
@@ -732,7 +867,10 @@ char *concstatus(char *s, char *t)
v[NSTATUS]='\0';
return v;
}
-void Xpipewait(void){
+
+void
+Xpipewait(void)
+{
char status[NSTATUS+1];
if(runq->pid==-1)
setstatus(concstatus(runq->status, getstatus()));
@@ -744,31 +882,35 @@ void Xpipewait(void){
setstatus(concstatus(getstatus(), status));
}
}
-void Xrdcmds(void){
- struct thread *p=runq;
+
+void
+Xrdcmds(void)
+{
+ struct thread *p = runq;
word *prompt;
flush(err);
- nerror=0;
+ nerror = 0;
if(flag['s'] && !truestatus())
pfmt(err, "status=%v\n", vlook("status")->val);
if(runq->iflag){
- prompt=vlook("prompt")->val;
+ prompt = vlook("prompt")->val;
if(prompt)
- promptstr=prompt->word;
+ promptstr = prompt->word;
else
promptstr="% ";
}
Noerror();
if(yyparse()){
if(!p->iflag || p->eof && !Eintr()){
- if(p->cmdfile) efree(p->cmdfile);
+ if(p->cmdfile)
+ efree(p->cmdfile);
closeio(p->cmdfd);
Xreturn(); /* should this be omitted? */
}
else{
if(Eintr()){
pchr(err, '\n');
- p->eof=0;
+ p->eof = 0;
}
--p->pc; /* go back for next command */
}
@@ -780,7 +922,9 @@ void Xrdcmds(void){
}
freenodes();
}
-void Xerror(char *s)
+
+void
+Xerror(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s: %r\n", s);
@@ -790,7 +934,9 @@ void Xerror(char *s)
setstatus("error");
while(!runq->iflag) Xreturn();
}
-void Xerror1(char *s)
+
+void
+Xerror1(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
pfmt(err, "rc: %s\n", s);
@@ -800,150 +946,55 @@ void Xerror1(char *s)
setstatus("error");
while(!runq->iflag) Xreturn();
}
-void Xbackq(void){
- char wd[8193];
- int c;
- char *s, *ewd=&wd[8192], *stop;
- struct io *f;
- var *ifs=vlook("ifs");
- word *v, *nextv;
- int pfd[2];
- int pid;
- stop=ifs->val?ifs->val->word:"";
- if(pipe(pfd)<0){
- Xerror("can't make pipe");
- return;
- }
- switch(pid=fork()){
- case -1: Xerror("try again");
- close(pfd[PRD]);
- close(pfd[PWR]);
- return;
- case 0:
- close(pfd[PRD]);
- start(runq->code, runq->pc+1, runq->local);
- pushredir(ROPEN, pfd[PWR], 1);
- return;
- default:
- close(pfd[PWR]);
- f=openfd(pfd[PRD]);
- s=wd;
- v=0;
- while((c=rchr(f))!=EOF){
- if(strchr(stop, c) || s==ewd){
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- s=wd;
- }
- }
- else *s++=c;
- }
- if(s!=wd){
- *s='\0';
- v=newword(wd, v);
- }
- closeio(f);
- Waitfor(pid, 0);
- /* v points to reversed arglist -- reverse it onto argv */
- while(v){
- nextv=v->next;
- v->next=runq->argv->words;
- runq->argv->words=v;
- v=nextv;
- }
- runq->pc=runq->code[runq->pc].i;
- return;
- }
-}
-/*
- * Who should wait for the exit from the fork?
- */
-void Xpipefd(void){
- struct thread *p=runq;
- int pc=p->pc;
- char name[40];
- int pfd[2];
- int sidefd, mainfd;
- if(pipe(pfd)<0){
- Xerror("can't get pipe");
- return;
- }
- if(p->code[pc].i==READ){
- sidefd=pfd[PWR];
- mainfd=pfd[PRD];
- }
- else{
- sidefd=pfd[PRD];
- mainfd=pfd[PWR];
- }
- switch(fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(p->code, pc+2, runq->local);
- close(mainfd);
- pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
- runq->ret=0;
- break;
- default:
- close(sidefd);
- pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop?…
- strcpy(name, Fdprefix);
- itoa(name+strlen(name), mainfd);
- pushword(name);
- p->pc=p->code[pc+1].i;
- break;
- }
-}
-void Xsubshell(void){
- int pid;
- switch(pid=fork()){
- case -1:
- Xerror("try again");
- break;
- case 0:
- start(runq->code, runq->pc+1, runq->local);
- runq->ret=0;
- break;
- default:
- Waitfor(pid, 1);
- runq->pc=runq->code[runq->pc].i;
- break;
- }
-}
-void setstatus(char *s)
+
+void
+setstatus(char *s)
{
setvar("status", newword(s, (word *)0));
}
-char *getstatus(void){
- var *status=vlook("status");
+
+char*
+getstatus(void)
+{
+ var *status = vlook("status");
return status->val?status->val->word:"";
}
-int truestatus(void){
+
+int
+truestatus(void)
+{
char *s;
- for(s=getstatus();*s;s++)
- if(*s!='|' && *s!='0') return 0;
+ for(s = getstatus();*s;s++)
+ if(*s!='|' && *s!='0')
+ return 0;
return 1;
}
-void Xdelhere(void){
+
+void
+Xdelhere(void)
+{
Unlink(runq->code[runq->pc++].s);
}
-void Xfor(void){
+
+void
+Xfor(void)
+{
if(runq->argv->words==0){
poplist();
- runq->pc=runq->code[runq->pc].i;
+ runq->pc = runq->code[runq->pc].i;
}
else{
freelist(runq->local->val);
- runq->local->val=runq->argv->words;
- runq->local->changed=1;
- runq->argv->words=runq->argv->words->next;
- runq->local->val->next=0;
+ runq->local->val = runq->argv->words;
+ runq->local->changed = 1;
+ runq->argv->words = runq->argv->words->next;
+ runq->local->val->next = 0;
runq->pc++;
}
}
-void Xglob(void){
+
+void
+Xglob(void)
+{
globlist();
}
diff --git a/rc/exec.h b/rc/exec.h
@@ -5,6 +5,7 @@ extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(vo…
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), …
extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
+extern void Xrdwr(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell…
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(…
@@ -51,7 +52,6 @@ struct thread{
int iflag; /* interactive? */
int lineno; /* linenumber */
int pid; /* process for Xpipewait to wait for */
- int done; /* have we seen a wait message for th…
char status[NSTATUS]; /* status for Xpipewait */
tree *treenodes; /* tree nodes created by this process …
thread *ret; /* who continues when this finishes */
@@ -61,12 +61,16 @@ code *codecopy(code*);
code *codebuf; /* compiler output */
int ntrap; /* number of outstanding traps */
int trap[NSIG]; /* number of outstanding traps …
-extern struct builtin{
+struct builtin{
char *name;
void (*fnc)(void);
-}Builtin[];
+};
+extern struct builtin Builtin[];
int eflagok; /* kludge flag so that -e doesn't exit in …
+int havefork;
+
void execcd(void), execwhatis(void), execeval(void), execexec(void);
+int execforkexec(void);
void execexit(void), execshift(void);
void execwait(void), execumask(void), execdot(void), execflag(void);
void execfunc(var*), execcmds(io *);
diff --git a/rc/fns.h b/rc/fns.h
@@ -7,13 +7,14 @@ int Eintr(void);
int Executable(char*);
void Execute(word*, word*);
void Exit(char*);
+int ForkExecute(char*, char**, int, int, int);
int Globsize(char*);
int Isatty(int);
void Memcpy(char*, char*, long);
void Noerror(void);
int Opendir(char*);
long Read(int, char*, long);
-int Readdir(int, char*);
+int Readdir(int, char*, int);
long Seek(int, long, long);
void Trapinit(void);
void Unlink(char*);
@@ -21,24 +22,29 @@ void Updenv(void);
void Vinit(void);
int Waitfor(int, int);
long Write(int, char*, long);
+void addwaitpid(int);
int advance(void);
int back(int);
void cleanhere(char*);
void codefree(code*);
int compile(tree*);
char * list2str(word*);
-char * _list2str(word*, int);
int count(word*);
void deglob(char*);
+void delwaitpid(int);
void dotrap(void);
void freenodes(void);
void freewords(word*);
void globlist(void);
+int havewaitpid(int);
int idchr(int);
-void itoa(char*, long);
+void inttoascii(char*, long);
void kinit(void);
+int mapfd(int);
int match(char*, char*, int);
int matchfn(char*, char*);
+char** mkargv(word*);
+void clearwaitpids(void);
void panic(char*, int);
void pathinit(void);
void poplist(void);
@@ -48,9 +54,9 @@ void pushlist(void);
void pushredir(int, int, int);
void pushword(char*);
void readhere(void);
+word* searchpath(char*);
void setstatus(char*);
void setvar(char*, word*);
-void _setvar(char*, word*, int);
void skipnl(void);
void start(code*, int, var*);
int truestatus(void);
diff --git a/rc/getflags.c b/rc/getflags.c
@@ -3,7 +3,7 @@
#include "rc.h"
#include "getflags.h"
#include "fns.h"
-char *flagset[]={"<flag>"};
+char *flagset[] = {"<flag>"};
char **flag[NFLAG];
char cmdline[NCMDLINE+1];
char *cmdname;
@@ -19,105 +19,118 @@ static int reason;
#define FLAGSYN 3
#define BADFLAG 4
static int badflag;
-int getflags(int argc, char *argv[], char *flags, int stop)
+
+int
+getflags(int argc, char *argv[], char *flags, int stop)
{
char *s, *t;
int i, j, c, count;
- flagarg=flags;
- if(cmdname==0) cmdname=argv[0];
- s=cmdline;
- for(i=0;i!=argc;i++){
- for(t=argv[i];*t;t++)
+ flagarg = flags;
+ if(cmdname==0)
+ cmdname = argv[0];
+ s = cmdline;
+ for(i = 0;i!=argc;i++){
+ for(t = argv[i];*t;t++)
if(s!=&cmdline[NCMDLINE])
*s++=*t;
if(i!=argc-1 && s!=&cmdline[NCMDLINE])
*s++=' ';
}
*s='\0';
- i=1;
+ i = 1;
while(i!=argc){
if(argv[i][0]!='-' || argv[i][1]=='\0'){
- if(stop) return argc;
+ if(stop)
+ return argc;
i++;
continue;
}
- s=argv[i]+1;
+ s = argv[i]+1;
while(*s){
c=*s++;
- count=scanflag(c, flags);
- if(count==-1) return -1;
- if(flag[c]){ reason=RESET; badflag=c; return -1; }
+ count = scanflag(c, flags);
+ if(count==-1)
+ return -1;
+ if(flag[c]){ reason = RESET; badflag = c; return -1; }
if(count==0){
- flag[c]=flagset;
+ flag[c] = flagset;
if(*s=='\0'){
- for(j=i+1;j<=argc;j++)
- argv[j-1]=argv[j];
+ for(j = i+1;j<=argc;j++)
+ argv[j-1] = argv[j];
--argc;
}
}
else{
if(*s=='\0'){
- for(j=i+1;j<=argc;j++)
- argv[j-1]=argv[j];
+ for(j = i+1;j<=argc;j++)
+ argv[j-1] = argv[j];
--argc;
- s=argv[i];
+ s = argv[i];
}
if(argc-i<count){
- reason=FEWARGS;
- badflag=c;
+ reason = FEWARGS;
+ badflag = c;
return -1;
}
reverse(argv+i, argv+argc);
reverse(argv+i, argv+argc-count);
reverse(argv+argc-count+1, argv+argc);
argc-=count;
- flag[c]=argv+argc+1;
- flag[c][0]=s;
+ flag[c] = argv+argc+1;
+ flag[c][0] = s;
s="";
}
}
}
return argc;
}
-static void reverse(char **p, char **q)
+
+static void
+reverse(char **p, char **q)
{
char *t;
- for(;p<q;p++,--q){ t=*p; *p=*q; *q=t; }
+ for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
}
-static int scanflag(int c, char *f)
+
+static int
+scanflag(int c, char *f)
{
int fc, count;
- if(0<=c && c<NFLAG) while(*f){
- if(*f==' '){
- f++;
- continue;
- }
- fc=*f++;
- if(*f==':'){
- f++;
- if(*f<'0' || '9'<*f){ reason=FLAGSYN; return -1; }
- count=0;
- while('0'<=*f && *f<='9') count=count*10+*f++-'0';
- }
- else
- count=0;
- if(*f=='['){
- do{
+ if(0<=c && c<NFLAG)
+ while(*f){
+ if(*f==' '){
+ f++;
+ continue;
+ }
+ fc=*f++;
+ if(*f==':'){
+ f++;
+ if(*f<'0' || '9'<*f){ reason = FLAGSYN; return…
+ count = 0;
+ while('0'<=*f && *f<='9') count = count*10+*f+…
+ }
+ else
+ count = 0;
+ if(*f=='['){
+ do{
+ f++;
+ if(*f=='\0'){ reason = FLAGSYN; return…
+ }while(*f!=']');
f++;
- if(*f=='\0'){ reason=FLAGSYN; return -1; }
- }while(*f!=']');
- f++;
+ }
+ if(c==fc)
+ return count;
}
- if(c==fc) return count;
- }
- reason=BADFLAG;
- badflag=c;
+ reason = BADFLAG;
+ badflag = c;
return -1;
}
-void usage(char *tail)
+
+void
+usage(char *tail)
{
char *s, *t, c;
- int count, nflag=0;
+ int count, nflag = 0;
switch(reason){
case RESET:
errs("Flag -");
@@ -140,46 +153,52 @@ void usage(char *tail)
}
errs("Usage: ");
errs(cmdname);
- for(s=flagarg;*s;){
+ for(s = flagarg;*s;){
c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
if(*s==':'){
s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
- else count=0;
+ else count = 0;
if(count==0){
- if(nflag==0) errs(" [-");
+ if(nflag==0)
+ errs(" [-");
nflag++;
errc(c);
}
if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
}
- if(nflag) errs("]");
- for(s=flagarg;*s;){
+ if(nflag)
+ errs("]");
+ for(s = flagarg;*s;){
c=*s;
- if(*s++==' ') continue;
+ if(*s++==' ')
+ continue;
if(*s==':'){
s++;
- count=0;
- while('0'<=*s && *s<='9') count=count*10+*s++-'0';
+ count = 0;
+ while('0'<=*s && *s<='9') count = count*10+*s++-'0';
}
- else count=0;
+ else count = 0;
if(count!=0){
errs(" [-");
errc(c);
if(*s=='['){
s++;
- t=s;
+ t = s;
while(*s!=']' && *s!='\0') s++;
errs(" ");
errn(t, s-t);
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
else
while(count--) errs(" arg");
@@ -188,7 +207,8 @@ void usage(char *tail)
else if(*s=='['){
s++;
while(*s!=']' && *s!='\0') s++;
- if(*s==']') s++;
+ if(*s==']')
+ s++;
}
}
if(tail){
@@ -198,20 +218,27 @@ void usage(char *tail)
errs("\n");
Exit("bad flags");
}
-static void errn(char *s, int count)
+
+static void
+errn(char *s, int count)
{
while(count){ errc(*s++); --count; }
}
-static void errs(char *s)
+
+static void
+errs(char *s)
{
while(*s) errc(*s++);
}
#define NBUF 80
-static char buf[NBUF], *bufp=buf;
-static void errc(int c){
+static char buf[NBUF], *bufp = buf;
+
+static void
+errc(int c)
+{
*bufp++=c;
if(bufp==&buf[NBUF] || c=='\n'){
Write(2, buf, bufp-buf);
- bufp=buf;
+ bufp = buf;
}
}
diff --git a/rc/glob.c b/rc/glob.c
@@ -6,68 +6,77 @@ struct word *globv;
/*
* delete all the GLOB marks from s, in place
*/
-void deglob(char *s)
+
+void
+deglob(char *s)
{
- char *t=s;
+ char *t = s;
do{
- if(*t==GLOB) t++;
+ if(*t==GLOB)
+ t++;
*s++=*t;
}while(*t++);
}
-int globcmp(const void *s, const void *t)
+
+int
+globcmp(const void *s, const void *t)
{
return strcmp(*(char**)s, *(char**)t);
}
-void globsort(word *left, word *right)
+
+void
+globsort(word *left, word *right)
{
char **list;
word *a;
- int n=0;
- for(a=left;a!=right;a=a->next) n++;
- list=(char **)emalloc(n*sizeof(char *));
- for(a=left,n=0;a!=right;a=a->next,n++) list[n]=a->word;
- qsort((char *)list, n, sizeof(char *), globcmp);
- for(a=left,n=0;a!=right;a=a->next,n++) a->word=list[n];
+ int n = 0;
+ for(a = left;a!=right;a = a->next) n++;
+ list = (char **)emalloc(n*sizeof(char *));
+ for(a = left,n = 0;a!=right;a = a->next,n++) list[n] = a->word;
+ qsort((void *)list, n, sizeof(void *), globcmp);
+ for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
efree((char *)list);
}
/*
* Push names prefixed by globname and suffixed by a match of p onto the astac…
* namep points to the end of the prefix in globname.
*/
-void globdir(char *p, char *namep)
+
+void
+globdir(char *p, char *namep)
{
char *t, *newp;
int f;
/* scan the pattern looking for a component with a metacharacter in it…
if(*p=='\0'){
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
return;
}
- t=namep;
- newp=p;
+ t = namep;
+ newp = p;
while(*newp){
if(*newp==GLOB)
break;
*t=*newp++;
if(*t++=='/'){
- namep=t;
- p=newp;
+ namep = t;
+ p = newp;
}
}
/* If we ran out of pattern, append the name if accessible */
if(*newp=='\0'){
*t='\0';
if(access(globname, 0)==0)
- globv=newword(globname, globv);
+ globv = newword(globname, globv);
return;
}
/* read the directory and recur for any entry that matches */
*namep='\0';
- if((f=Opendir(globname[0]?globname:"."))<0) return;
+ if((f = Opendir(globname[0]?globname:"."))<0) return;
while(*newp!='/' && *newp!='\0') newp++;
- while(Readdir(f, namep)){
+ while(Readdir(f, namep, *newp=='/')){
if(matchfn(namep, p)){
- for(t=namep;*t;t++);
+ for(t = namep;*t;t++);
globdir(newp, t);
}
}
@@ -77,22 +86,24 @@ void globdir(char *p, char *namep)
* Push all file names matched by p on the current thread's stack.
* If there are no matches, the list consists of p.
*/
-void glob(char *p)
+
+void
+glob(char *p)
{
- word *svglobv=globv;
- int globlen=Globsize(p);
+ word *svglobv = globv;
+ int globlen = Globsize(p);
if(!globlen){
deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
return;
}
- globname=emalloc(globlen);
+ globname = emalloc(globlen);
globname[0]='\0';
globdir(p, globname);
efree(globname);
if(svglobv==globv){
deglob(p);
- globv=newword(p, globv);
+ globv = newword(p, globv);
}
else
globsort(globv, svglobv);
@@ -100,12 +111,18 @@ void glob(char *p)
/*
* Do p and q point at equal utf codes
*/
-int equtf(char *p, char *q){
- if(*p!=*q) return 0;
+
+int
+equtf(char *p, char *q)
+{
+ if(*p!=*q)
+ return 0;
if(twobyte(*p)) return p[1]==q[1];
if(threebyte(*p)){
- if(p[1]!=q[1]) return 0;
- if(p[1]=='\0') return 1; /* broken code at end of strin…
+ if(p[1]!=q[1])
+ return 0;
+ if(p[1]=='\0')
+ return 1; /* broken code at end of string! */
return p[2]==q[2];
}
return 1;
@@ -114,7 +131,10 @@ int equtf(char *p, char *q){
* Return a pointer to the next utf code in the string,
* not jumping past nuls in broken utf codes!
*/
-char *nextutf(char *p){
+
+char*
+nextutf(char *p)
+{
if(twobyte(*p)) return p[1]=='\0'?p+1:p+2;
if(threebyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p+3;
return p+1;
@@ -122,7 +142,10 @@ char *nextutf(char *p){
/*
* Convert the utf code at *p to a unicode value
*/
-int unicode(char *p){
+
+int
+unicode(char *p)
+{
int u=*p&0xff;
if(twobyte(u)) return ((u&0x1f)<<6)|(p[1]&0x3f);
if(threebyte(u)) return (u<<12)|((p[1]&0x3f)<<6)|(p[2]&0x3f);
@@ -135,77 +158,97 @@ int unicode(char *p){
* ? matches any single character
* [...] matches the enclosed list of characters
*/
-int matchfn(char *s, char *p)
+
+int
+matchfn(char *s, char *p)
{
if(s[0]=='.' && (s[1]=='\0' || s[1]=='.' && s[2]=='\0') && p[0]!='.')
return 0;
return match(s, p, '/');
}
-int match(char *s, char *p, int stop)
+
+int
+match(char *s, char *p, int stop)
{
int compl, hit, lo, hi, t, c;
- for(;*p!=stop && *p!='\0';s=nextutf(s),p=nextutf(p)){
+ for(;*p!=stop && *p!='\0';s = nextutf(s),p = nextutf(p)){
if(*p!=GLOB){
if(!equtf(p, s)) return 0;
}
else switch(*++p){
case GLOB:
- if(*s!=GLOB) return 0;
+ if(*s!=GLOB)
+ return 0;
break;
case '*':
for(;;){
if(match(s, nextutf(p), stop)) return 1;
- if(!*s) break;
- s=nextutf(s);
+ if(!*s)
+ break;
+ s = nextutf(s);
}
return 0;
case '?':
- if(*s=='\0') return 0;
+ if(*s=='\0')
+ return 0;
break;
case '[':
- if(*s=='\0') return 0;
- c=unicode(s);
+ if(*s=='\0')
+ return 0;
+ c = unicode(s);
p++;
compl=*p=='~';
- if(compl) p++;
- hit=0;
+ if(compl)
+ p++;
+ hit = 0;
while(*p!=']'){
- if(*p=='\0') return 0; /* synta…
- lo=unicode(p);
- p=nextutf(p);
- if(*p!='-') hi=lo;
+ if(*p=='\0')
+ return 0; /* syntax err…
+ lo = unicode(p);
+ p = nextutf(p);
+ if(*p!='-')
+ hi = lo;
else{
p++;
- if(*p=='\0') return 0; /* synta…
- hi=unicode(p);
- p=nextutf(p);
- if(hi<lo){ t=lo; lo=hi; hi=t; }
+ if(*p=='\0')
+ return 0; /* syntax err…
+ hi = unicode(p);
+ p = nextutf(p);
+ if(hi<lo){ t = lo; lo = hi; hi = t; }
}
- if(lo<=c && c<=hi) hit=1;
+ if(lo<=c && c<=hi)
+ hit = 1;
}
- if(compl) hit=!hit;
- if(!hit) return 0;
+ if(compl)
+ hit=!hit;
+ if(!hit)
+ return 0;
break;
}
}
return *s=='\0';
}
-void globlist1(word *gl)
+
+void
+globlist1(word *gl)
{
if(gl){
globlist1(gl->next);
glob(gl->word);
}
}
-void globlist(void){
+
+void
+globlist(void)
+{
word *a;
- globv=0;
+ globv = 0;
globlist1(runq->argv->words);
poplist();
pushlist();
if(globv){
- for(a=globv;a->next;a=a->next);
- a->next=runq->argv->words;
- runq->argv->words=globv;
+ for(a = globv;a->next;a = a->next);
+ a->next = runq->argv->words;
+ runq->argv->words = globv;
}
}
diff --git a/rc/havefork.c b/rc/havefork.c
@@ -1,5 +1,9 @@
#include <u.h>
#include <signal.h>
+#if defined(PLAN9PORT) && defined(__sun__)
+# define BSD_COMP /* sigh. for TIOCNOTTY */
+#endif
+#include <sys/ioctl.h>
#include "rc.h"
#include "getflags.h"
#include "exec.h"
@@ -12,10 +16,9 @@ void
Xasync(void)
{
int null = open("/dev/null", 0);
+ int tty;
int pid;
- int tcpgrp, pgrp;
char npid[10];
-
if(null<0){
Xerror("Can't open /dev/null\n");
return;
@@ -26,17 +29,39 @@ Xasync(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
/*
- * Should make reads of tty fail, writes succeed.
+ * I don't know what the right thing to do here is,
+ * so this is all experimentally determined.
+ * If we just dup /dev/null onto 0, then running
+ * ssh foo & will reopen /dev/tty, try to read a password,
+ * get a signal, and repeat, in a tight loop, forever.
+ * Arguably this is a bug in ssh (it behaves the same
+ * way under bash as under rc) but I'm fixing it here
+ * anyway. If we dissociate the process from the tty,
+ * then it won't be able to open /dev/tty ever again.
+ * The SIG_IGN on SIGTTOU makes writing the tty
+ * (via fd 1 or 2, for example) succeed even though
+ * our pgrp is not the terminal's controlling pgrp.
*/
- signal(SIGTTIN, SIG_IGN);
- signal(SIGTTOU, SIG_IGN);
-
- pushredir(ROPEN, null, 0);
+ if((tty = open("/dev/tty", OREAD)) >= 0){
+ /*
+ * Should make reads of tty fail, writes succeed.
+ */
+ signal(SIGTTIN, SIG_IGN);
+ signal(SIGTTOU, SIG_IGN);
+ ioctl(tty, TIOCNOTTY);
+ close(tty);
+ }
+ if(isatty(0))
+ pushredir(ROPEN, null, 0);
+ else
+ close(null);
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
close(null);
runq->pc = runq->code[runq->pc].i;
inttoascii(npid, pid);
@@ -62,12 +87,14 @@ Xpipe(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(p->code, pc+2, runq->local);
runq->ret = 0;
close(pfd[PRD]);
pushredir(ROPEN, pfd[PWR], lfd);
break;
default:
+ addwaitpid(forkid);
start(p->code, p->code[pc].i, runq->local);
close(pfd[PWR]);
pushredir(ROPEN, pfd[PRD], rfd);
@@ -103,11 +130,13 @@ Xbackq(void)
close(pfd[PWR]);
return;
case 0:
+ clearwaitpids();
close(pfd[PRD]);
start(runq->code, runq->pc+1, runq->local);
pushredir(ROPEN, pfd[PWR], 1);
return;
default:
+ addwaitpid(pid);
close(pfd[PWR]);
f = openfd(pfd[PRD]);
s = wd;
@@ -144,7 +173,7 @@ void
Xpipefd(void)
{
struct thread *p = runq;
- int pc = p->pc;
+ int pc = p->pc, pid;
char name[40];
int pfd[2];
int sidefd, mainfd;
@@ -160,17 +189,19 @@ Xpipefd(void)
sidefd = pfd[PRD];
mainfd = pfd[PWR];
}
- switch(fork()){
+ switch(pid = fork()){
case -1:
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(p->code, pc+2, runq->local);
close(mainfd);
pushredir(ROPEN, sidefd, p->code[pc].i==READ?1:0);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
close(sidefd);
pushredir(ROPEN, mainfd, mainfd); /* isn't this a noop?…
strcpy(name, Fdprefix);
@@ -190,10 +221,12 @@ Xsubshell(void)
Xerror("try again");
break;
case 0:
+ clearwaitpids();
start(runq->code, runq->pc+1, runq->local);
runq->ret = 0;
break;
default:
+ addwaitpid(pid);
Waitfor(pid, 1);
runq->pc = runq->code[runq->pc].i;
break;
@@ -211,6 +244,7 @@ execforkexec(void)
case -1:
return -1;
case 0:
+ clearwaitpids();
pushword("exec");
execexec();
strcpy(buf, "can't exec: ");
@@ -218,5 +252,6 @@ execforkexec(void)
errstr(buf+n, ERRMAX-n);
Exit(buf);
}
+ addwaitpid(pid);
return pid;
}
diff --git a/rc/here.c b/rc/here.c
@@ -3,32 +3,37 @@
#include "io.h"
#include "fns.h"
struct here *here, **ehere;
-int ser=0;
+int ser = 0;
char tmp[]="/tmp/here0000.0000";
char hex[]="0123456789abcdef";
void psubst(io*, char*);
void pstrs(io*, word*);
-void hexnum(char *p, int n)
+
+void
+hexnum(char *p, int n)
{
*p++=hex[(n>>12)&0xF];
*p++=hex[(n>>8)&0xF];
*p++=hex[(n>>4)&0xF];
- *p=hex[n&0xF];
+ *p = hex[n&0xF];
}
-tree *heredoc(tree *tag)
+
+tree*
+heredoc(tree *tag)
{
- struct here *h=new(struct here);
- if(tag->type!=WORD) yyerror("Bad here tag");
- h->next=0;
+ struct here *h = new(struct here);
+ if(tag->type!=WORD)
+ yyerror("Bad here tag");
+ h->next = 0;
if(here)
- *ehere=h;
+ *ehere = h;
else
- here=h;
+ here = h;
ehere=&h->next;
- h->tag=tag;
+ h->tag = tag;
hexnum(&tmp[9], getpid());
hexnum(&tmp[14], ser++);
- h->name=strdup(tmp);
+ h->name = strdup(tmp);
return token(tmp, WORD);
}
/*
@@ -36,27 +41,32 @@ tree *heredoc(tree *tag)
* missubstitution, or a misrecognized EOF marker.
*/
#define NLINE 4096
-void readhere(void){
+
+void
+readhere(void)
+{
struct here *h, *nexth;
io *f;
char *s, *tag;
int c, subst;
char line[NLINE+1];
- for(h=here;h;h=nexth){
+ for(h = here;h;h = nexth){
subst=!h->tag->quoted;
- tag=h->tag->str;
- c=Creat(h->name);
- if(c<0) yyerror("can't create here document");
- f=openfd(c);
- s=line;
+ tag = h->tag->str;
+ c = Creat(h->name);
+ if(c<0)
+ yyerror("can't create here document");
+ f = openfd(c);
+ s = line;
pprompt();
- while((c=rchr(runq->cmdfd))!=EOF){
+ while((c = rchr(runq->cmdfd))!=EOF){
if(c=='\n' || s==&line[NLINE]){
*s='\0';
- if(strcmp(line, tag)==0) break;
- if(subst) psubst(f, line);
+ if(tag && strcmp(line, tag)==0) break;
+ if(subst)
+ psubst(f, line);
else pstr(f, line);
- s=line;
+ s = line;
if(c=='\n'){
pprompt();
pchr(f, c);
@@ -68,13 +78,15 @@ void readhere(void){
flush(f);
closeio(f);
cleanhere(h->name);
- nexth=h->next;
+ nexth = h->next;
efree((char *)h);
}
- here=0;
- doprompt=1;
+ here = 0;
+ doprompt = 1;
}
-void psubst(io *f, char *s)
+
+void
+psubst(io *f, char *s)
{
char *t, *u;
int savec, n;
@@ -83,48 +95,55 @@ void psubst(io *f, char *s)
if(*s!='$'){
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
}
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
pchr(f, *s++);
- if(*s=='\0') break;
+ if(*s=='\0')
+ break;
}
pchr(f, *s++);
}
else{
t=++s;
- if(*t=='$') pchr(f, *t++);
+ if(*t=='$')
+ pchr(f, *t++);
else{
while(*t && idchr(*t)) t++;
savec=*t;
*t='\0';
- n=0;
- for(u=s;*u && '0'<=*u && *u<='9';u++) n=n*10+*…
+ n = 0;
+ for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*…
if(n && *u=='\0'){
- star=vlook("*")->val;
+ star = vlook("*")->val;
if(star && 1<=n && n<=count(star)){
- while(--n) star=star->next;
+ while(--n) star = star->next;
pstr(f, star->word);
}
}
else
pstrs(f, vlook(s)->val);
- *t=savec;
- if(savec=='^') t++;
+ *t = savec;
+ if(savec=='^')
+ t++;
}
- s=t;
+ s = t;
}
}
}
-void pstrs(io *f, word *a)
+
+void
+pstrs(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pstr(f, a->word);
pchr(f, ' ');
- a=a->next;
+ a = a->next;
}
pstr(f, a->word);
}
diff --git a/rc/io.c b/rc/io.c
@@ -2,68 +2,121 @@
#include "exec.h"
#include "io.h"
#include "fns.h"
-int pfmtnest=0;
-void pfmt(io *f, char *fmt, ...){
+int pfmtnest = 0;
+
+void
+pfmt(io *f, char *fmt, ...)
+{
va_list ap;
char err[ERRMAX];
va_start(ap, fmt);
pfmtnest++;
for(;*fmt;fmt++)
- if(*fmt!='%') pchr(f, *fmt);
+ if(*fmt!='%')
+ pchr(f, *fmt);
else switch(*++fmt){
- case '\0': va_end(ap); return;
- case 'c': pchr(f, va_arg(ap, int)); break;
- case 'd': pdec(f, va_arg(ap, int)); break;
- case 'o': poct(f, va_arg(ap, unsigned)); break;
- case 'p': phex(f, (long)va_arg(ap, char *)); break; /*unportab…
- case 'Q': pquo(f, va_arg(ap, char *)); break;
- case 'q': pwrd(f, va_arg(ap, char *)); break;
- case 'r': errstr(err, sizeof err); pstr(f, err); break;
- case 's': pstr(f, va_arg(ap, char *)); break;
- case 't': pcmd(f, va_arg(ap, struct tree *)); break;
- case 'v': pval(f, va_arg(ap, struct word *)); break;
- default: pchr(f, *fmt); break;
+ case '\0':
+ va_end(ap);
+ return;
+ case 'c':
+ pchr(f, va_arg(ap, int));
+ break;
+ case 'd':
+ pdec(f, va_arg(ap, int));
+ break;
+ case 'o':
+ poct(f, va_arg(ap, unsigned));
+ break;
+ case 'p':
+ pptr(f, va_arg(ap, void*));
+ break;
+ case 'Q':
+ pquo(f, va_arg(ap, char *));
+ break;
+ case 'q':
+ pwrd(f, va_arg(ap, char *));
+ break;
+ case 'r':
+ rerrstr(err, sizeof err); pstr(f, err);
+ break;
+ case 's':
+ pstr(f, va_arg(ap, char *));
+ break;
+ case 't':
+ pcmd(f, va_arg(ap, struct tree *));
+ break;
+ case 'v':
+ pval(f, va_arg(ap, struct word *));
+ break;
+ default:
+ pchr(f, *fmt);
+ break;
}
va_end(ap);
- if(--pfmtnest==0) flush(f);
+ if(--pfmtnest==0)
+ flush(f);
}
-void pchr(io *b, int c)
+
+void
+pchr(io *b, int c)
{
- if(b->bufp==b->ebuf) fullbuf(b, c);
+ if(b->bufp==b->ebuf)
+ fullbuf(b, c);
else *b->bufp++=c;
}
-int rchr(io *b)
+
+int
+rchr(io *b)
{
- if(b->bufp==b->ebuf) return emptybuf(b);
+ if(b->bufp==b->ebuf)
+ return emptybuf(b);
return *b->bufp++ & 0xFF;
}
-void pquo(io *f, char *s)
+void
+pquo(io *f, char *s)
{
pchr(f, '\'');
for(;*s;s++)
- if(*s=='\'') pfmt(f, "''");
+ if(*s=='\'')
+ pfmt(f, "''");
else pchr(f, *s);
pchr(f, '\'');
}
-void pwrd(io *f, char *s)
+
+void
+pwrd(io *f, char *s)
{
char *t;
- for(t=s;*t;t++) if(!wordchr(*t)) break;
- if(t==s || *t) pquo(f, s);
+ for(t = s;*t;t++) if(!wordchr(*t)) break;
+ if(t==s || *t)
+ pquo(f, s);
else pstr(f, s);
}
-void phex(io *f, long p)
+
+void
+pptr(io *f, void *v)
{
int n;
- for(n=28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+ uintptr p;
+
+ p = (uintptr)v;
+ if(sizeof(uintptr) == sizeof(uvlong) && p>>32)
+ for(n = 60;n>=32;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
+
+ for(n = 28;n>=0;n-=4) pchr(f, "0123456789ABCDEF"[(p>>n)&0xF]);
}
-void pstr(io *f, char *s)
+
+void
+pstr(io *f, char *s)
{
- if(s==0) s="(null)";
+ if(s==0)
+ s="(null)";
while(*s) pchr(f, *s++);
}
-void pdec(io *f, long n)
+
+void
+pdec(io *f, int n)
{
if(n<0){
n=-n;
@@ -73,110 +126,136 @@ void pdec(io *f, long n)
return;
}
/* n is two's complement minimum integer */
- n=1-n;
+ n = 1-n;
pchr(f, '-');
pdec(f, n/10);
pchr(f, n%10+'1');
return;
}
- if(n>9) pdec(f, n/10);
+ if(n>9)
+ pdec(f, n/10);
pchr(f, n%10+'0');
}
-void poct(io *f, ulong n)
+
+void
+poct(io *f, unsigned n)
{
- if(n>7) poct(f, n>>3);
+ if(n>7)
+ poct(f, n>>3);
pchr(f, (n&7)+'0');
}
-void pval(io *f, word *a)
+
+void
+pval(io *f, word *a)
{
if(a){
while(a->next && a->next->word){
pwrd(f, a->word);
pchr(f, ' ');
- a=a->next;
+ a = a->next;
}
pwrd(f, a->word);
}
}
-int fullbuf(io *f, int c)
+
+int
+fullbuf(io *f, int c)
{
flush(f);
return *f->bufp++=c;
}
-void flush(io *f)
+
+void
+flush(io *f)
{
int n;
char *s;
if(f->strp){
- n=f->ebuf-f->strp;
- f->strp=realloc(f->strp, n+101);
- if(f->strp==0) panic("Can't realloc %d bytes in flush!", n+101…
- f->bufp=f->strp+n;
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ n = f->ebuf-f->strp;
+ f->strp = realloc(f->strp, n+101);
+ if(f->strp==0)
+ panic("Can't realloc %d bytes in flush!", n+101);
+ f->bufp = f->strp+n;
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
}
else{
- n=f->bufp-f->buf;
+ n = f->bufp-f->buf;
if(n && Write(f->fd, f->buf, n) < 0){
Write(3, "Write error\n", 12);
- if(ntrap) dotrap();
+ if(ntrap)
+ dotrap();
}
- f->bufp=f->buf;
- f->ebuf=f->buf+NBUF;
+ f->bufp = f->buf;
+ f->ebuf = f->buf+NBUF;
}
}
-io *openfd(int fd){
- io *f;
- f=new(struct io);
- f->fd=fd;
- f->bufp=f->ebuf=f->buf;
- f->strp=0;
+
+io*
+openfd(int fd)
+{
+ io *f = new(struct io);
+ f->fd = fd;
+ f->bufp = f->ebuf = f->buf;
+ f->strp = 0;
return f;
}
-io *openstr(void){
- io *f=new(struct io);
+
+io*
+openstr(void)
+{
+ io *f = new(struct io);
char *s;
f->fd=-1;
- f->bufp=f->strp=emalloc(101);
- f->ebuf=f->bufp+100;
- for(s=f->bufp;s<=f->ebuf;s++) *s='\0';
+ f->bufp = f->strp = emalloc(101);
+ f->ebuf = f->bufp+100;
+ for(s = f->bufp;s<=f->ebuf;s++) *s='\0';
return f;
}
/*
* Open a corebuffer to read. EOF occurs after reading len
* characters from buf.
*/
-io *opencore(char *s, int len)
+
+io*
+opencore(char *s, int len)
{
- io *f=new(struct io);
- char *buf=emalloc(len);
+ io *f = new(struct io);
+ char *buf = emalloc(len);
f->fd= -1 /*open("/dev/null", 0)*/;
- f->bufp=f->strp=buf;
- f->ebuf=buf+len;
+ f->bufp = f->strp = buf;
+ f->ebuf = buf+len;
Memcpy(buf, s, len);
return f;
}
-/*
-void rewind(io *io)
+
+void
+iorewind(io *io)
{
- if(io->fd==-1) io->bufp=io->strp;
+ if(io->fd==-1)
+ io->bufp = io->strp;
else{
- io->bufp=io->ebuf=io->buf;
+ io->bufp = io->ebuf = io->buf;
Seek(io->fd, 0L, 0);
}
}
-*/
-void closeio(io *io)
+
+void
+closeio(io *io)
{
- if(io->fd>=0) close(io->fd);
- if(io->strp) efree(io->strp);
+ if(io->fd>=0)
+ close(io->fd);
+ if(io->strp)
+ efree(io->strp);
efree((char *)io);
}
-int emptybuf(io *f)
+
+int
+emptybuf(io *f)
{
int n;
- if(f->fd==-1 || (n=Read(f->fd, f->buf, NBUF))<=0) return EOF;
- f->bufp=f->buf;
- f->ebuf=f->buf+n;
+ if(f->fd==-1 || (n = Read(f->fd, f->buf, NBUF))<=0) return EOF;
+ f->bufp = f->buf;
+ f->ebuf = f->buf+n;
return *f->bufp++&0xff;
}
diff --git a/rc/io.h b/rc/io.h
@@ -18,9 +18,9 @@ int rchr(io*);
void closeio(io*);
void flush(io*);
int fullbuf(io*, int);
-void pdec(io*, long);
-void poct(io*, ulong);
-void phex(io*, long);
+void pdec(io*, int);
+void poct(io*, unsigned);
+void pptr(io*, void*);
void pquo(io*, char*);
void pwrd(io*, char*);
void pstr(io*, char*);
diff --git a/rc/lex.c b/rc/lex.c
@@ -4,11 +4,15 @@
#include "getflags.h"
#include "fns.h"
int getnext(void);
-int wordchr(int c)
+
+int
+wordchr(int c)
{
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
}
-int idchr(int c)
+
+int
+idchr(int c)
{
/*
* Formerly:
@@ -17,127 +21,170 @@ int idchr(int c)
*/
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
}
-int future=EOF;
-int doprompt=1;
+int future = EOF;
+int doprompt = 1;
int inquote;
+int incomm;
/*
* Look ahead in the input stream
*/
-int nextc(void){
- if(future==EOF) future=getnext();
+
+int
+nextc(void)
+{
+ if(future==EOF)
+ future = getnext();
return future;
}
/*
* Consume the lookahead character.
*/
-int advance(void){
- int c=nextc();
- lastc=future;
- future=EOF;
+
+int
+advance(void)
+{
+ int c = nextc();
+ lastc = future;
+ future = EOF;
return c;
}
/*
* read a character from the input stream
*/
-int getnext(void){
- register int c;
- static int peekc=EOF;
+
+int
+getnext(void)
+{
+ int c;
+ static int peekc = EOF;
if(peekc!=EOF){
- c=peekc;
- peekc=EOF;
+ c = peekc;
+ peekc = EOF;
return c;
}
- if(runq->eof) return EOF;
- if(doprompt) pprompt();
- c=rchr(runq->cmdfd);
+ if(runq->eof)
+ return EOF;
+ if(doprompt)
+ pprompt();
+ c = rchr(runq->cmdfd);
if(!inquote && c=='\\'){
- c=rchr(runq->cmdfd);
- if(c=='\n'){
- doprompt=1;
+ c = rchr(runq->cmdfd);
+ if(c=='\n' && !incomm){ /* don't continue a com…
+ doprompt = 1;
c=' ';
}
else{
- peekc=c;
+ peekc = c;
c='\\';
}
}
- doprompt=doprompt || c=='\n' || c==EOF;
- if(c==EOF) runq->eof++;
+ doprompt = doprompt || c=='\n' || c==EOF;
+ if(c==EOF)
+ runq->eof++;
else if(flag['V'] || ndot>=2 && flag['v']) pchr(err, c);
return c;
}
-void pprompt(void){
+
+void
+pprompt(void)
+{
var *prompt;
if(runq->iflag){
pstr(err, promptstr);
flush(err);
- prompt=vlook("prompt");
+ prompt = vlook("prompt");
if(prompt->val && prompt->val->next)
- promptstr=prompt->val->next->word;
+ promptstr = prompt->val->next->word;
else
promptstr="\t";
}
runq->lineno++;
- doprompt=0;
+ doprompt = 0;
}
-void skipwhite(void){
+
+void
+skipwhite(void)
+{
int c;
for(;;){
- c=nextc();
- if(c=='#'){ /* Why did this used to be if(!inquote && …
+ c = nextc();
+ /* Why did this used to be if(!inquote && c=='#') ?? */
+ if(c=='#'){
+ incomm = 1;
for(;;){
- c=nextc();
- if(c=='\n' || c==EOF) break;
+ c = nextc();
+ if(c=='\n' || c==EOF) {
+ incomm = 0;
+ break;
+ }
advance();
}
}
- if(c==' ' || c=='\t') advance();
+ if(c==' ' || c=='\t')
+ advance();
else return;
}
}
-void skipnl(void){
- register int c;
+
+void
+skipnl(void)
+{
+ int c;
for(;;){
skipwhite();
- c=nextc();
- if(c!='\n') return;
+ c = nextc();
+ if(c!='\n')
+ return;
advance();
}
}
-int nextis(int c){
+
+int
+nextis(int c)
+{
if(nextc()==c){
advance();
return 1;
}
return 0;
}
-char *addtok(char *p, int val){
- if(p==0) return 0;
- if(p==&tok[NTOK]){
- *p=0;
+
+char*
+addtok(char *p, int val)
+{
+ if(p==0)
+ return 0;
+ if(p==&tok[NTOK-1]){
+ *p = 0;
yyerror("token buffer too short");
return 0;
}
*p++=val;
return p;
}
-char *addutf(char *p, int c){
- p=addtok(p, c);
+
+char*
+addutf(char *p, int c)
+{
+ p = addtok(p, c);
if(twobyte(c)) /* 2-byte escape */
return addtok(p, advance());
if(threebyte(c)){ /* 3-byte escape */
- p=addtok(p, advance());
+ p = addtok(p, advance());
return addtok(p, advance());
}
return p;
}
int lastdol; /* was the last token read '$' or '$#' or '"'? */
int lastword; /* was the last token read a word or compound word termin…
-int yylex(void){
- register int c, d=nextc();
- register char *w=tok;
- register struct tree *t;
- yylval.tree=0;
+
+int
+yylex(void)
+{
+ int c, d = nextc();
+ char *w = tok;
+ struct tree *t;
+ yylval.tree = 0;
/*
* Embarassing sneakiness: if the last token read was a quoted or unq…
* WORD then we alter the meaning of what follows. If the next charac…
@@ -146,7 +193,7 @@ int yylex(void){
* we insert a `^' before it.
*/
if(lastword){
- lastword=0;
+ lastword = 0;
if(d=='('){
advance();
strcpy(tok, "( [SUB]");
@@ -157,15 +204,15 @@ int yylex(void){
return '^';
}
}
- inquote=0;
+ inquote = 0;
skipwhite();
- switch(c=advance()){
+ switch(c = advance()){
case EOF:
- lastdol=0;
+ lastdol = 0;
strcpy(tok, "EOF");
return EOF;
case '$':
- lastdol=1;
+ lastdol = 1;
if(nextis('#')){
strcpy(tok, "$#");
return COUNT;
@@ -177,7 +224,7 @@ int yylex(void){
strcpy(tok, "$");
return '$';
case '&':
- lastdol=0;
+ lastdol = 0;
if(nextis('&')){
skipnl();
strcpy(tok, "&&");
@@ -186,7 +233,7 @@ int yylex(void){
strcpy(tok, "&");
return '&';
case '|':
- lastdol=0;
+ lastdol = 0;
if(nextis(c)){
skipnl();
strcpy(tok, "||");
@@ -194,7 +241,7 @@ int yylex(void){
}
case '<':
case '>':
- lastdol=0;
+ lastdol = 0;
/*
* funny redirection tokens:
* redir: arrow | arrow '[' fd ']'
@@ -204,121 +251,128 @@ int yylex(void){
* some possibilities are nonsensical and get a message.
*/
*w++=c;
- t=newtree();
+ t = newtree();
switch(c){
case '|':
- t->type=PIPE;
- t->fd0=1;
- t->fd1=0;
+ t->type = PIPE;
+ t->fd0 = 1;
+ t->fd1 = 0;
break;
case '>':
- t->type=REDIR;
+ t->type = REDIR;
if(nextis(c)){
- t->rtype=APPEND;
+ t->rtype = APPEND;
*w++=c;
}
- else t->rtype=WRITE;
- t->fd0=1;
+ else t->rtype = WRITE;
+ t->fd0 = 1;
break;
case '<':
- t->type=REDIR;
+ t->type = REDIR;
if(nextis(c)){
- t->rtype=HERE;
+ t->rtype = HERE;
*w++=c;
- }
- else t->rtype=READ;
- t->fd0=0;
+ } else if (nextis('>')){
+ t->rtype = RDWR;
+ *w++=c;
+ } else t->rtype = READ;
+ t->fd0 = 0;
break;
}
if(nextis('[')){
*w++='[';
- c=advance();
+ c = advance();
+ *w++=c;
if(c<'0' || '9'<c){
RedirErr:
- *w++ = c;
- *w=0;
+ *w = 0;
yyerror(t->type==PIPE?"pipe syntax"
:"redirection syntax");
return EOF;
}
- t->fd0=0;
+ t->fd0 = 0;
do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
*w++=c;
- c=advance();
+ c = advance();
}while('0'<=c && c<='9');
if(c=='='){
*w++='=';
- if(t->type==REDIR) t->type=DUP;
- c=advance();
+ if(t->type==REDIR)
+ t->type = DUP;
+ c = advance();
if('0'<=c && c<='9'){
- t->rtype=DUPFD;
- t->fd1=t->fd0;
- t->fd0=0;
+ t->rtype = DUPFD;
+ t->fd1 = t->fd0;
+ t->fd0 = 0;
do{
- t->fd0=t->fd0*10+c-'0';
+ t->fd0 = t->fd0*10+c-'0';
*w++=c;
- c=advance();
+ c = advance();
}while('0'<=c && c<='9');
}
else{
- if(t->type==PIPE) goto RedirErr;
- t->rtype=CLOSE;
+ if(t->type==PIPE)
+ goto RedirErr;
+ t->rtype = CLOSE;
}
}
- *w=0;
if(c!=']'
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND…
goto RedirErr;
*w++=']';
}
*w='\0';
- yylval.tree=t;
- if(t->type==PIPE) skipnl();
+ yylval.tree = t;
+ if(t->type==PIPE)
+ skipnl();
return t->type;
case '\'':
- lastdol=0;
- lastword=1;
- inquote=1;
+ lastdol = 0;
+ lastword = 1;
+ inquote = 1;
for(;;){
- c=advance();
- if(c==EOF) break;
+ c = advance();
+ if(c==EOF)
+ break;
if(c=='\''){
if(nextc()!='\'')
break;
advance();
}
- w=addutf(w, c);
+ w = addutf(w, c);
}
- if(w!=0) *w='\0';
- t=token(tok, WORD);
- t->quoted=1;
- yylval.tree=t;
+ if(w!=0)
+ *w='\0';
+ t = token(tok, WORD);
+ t->quoted = 1;
+ yylval.tree = t;
return t->type;
}
if(!wordchr(c)){
- lastdol=0;
- tok[0]=c;
+ lastdol = 0;
+ tok[0] = c;
tok[1]='\0';
return c;
}
for(;;){
/* next line should have (char)c==GLOB, but ken's compiler is …
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
- w=addtok(w, GLOB);
- w=addutf(w, c);
- c=nextc();
+ w = addtok(w, GLOB);
+ w = addutf(w, c);
+ c = nextc();
if(lastdol?!idchr(c):!wordchr(c)) break;
advance();
}
- lastword=1;
- lastdol=0;
- if(w!=0) *w='\0';
- t=klook(tok);
- if(t->type!=WORD) lastword=0;
- t->quoted=0;
- yylval.tree=t;
+ lastword = 1;
+ lastdol = 0;
+ if(w!=0)
+ *w='\0';
+ t = klook(tok);
+ if(t->type!=WORD)
+ lastword = 0;
+ t->quoted = 0;
+ yylval.tree = t;
return t->type;
}
-
diff --git a/rc/pcmd.c b/rc/pcmd.c
@@ -5,39 +5,66 @@ char nl='\n'; /* change to semicolon for bourn…
#define c0 t->child[0]
#define c1 t->child[1]
#define c2 t->child[2]
-void pdeglob(io *f, char *s)
+
+void
+pdeglob(io *f, char *s)
{
while(*s){
- if(*s==GLOB) s++;
+ if(*s==GLOB)
+ s++;
pchr(f, *s++);
}
}
-void pcmd(io *f, tree *t)
+
+void
+pcmd(io *f, tree *t)
{
- if(t==0) return;
+ if(t==0)
+ return;
switch(t->type){
- default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2); break;
- case '$': pfmt(f, "$%t", c0); break;
- case '"': pfmt(f, "$\"%t", c0); break;
- case '&': pfmt(f, "%t&", c0); break;
- case '^': pfmt(f, "%t^%t", c0, c1); break;
- case '`': pfmt(f, "`%t", c0); break;
- case ANDAND: pfmt(f, "%t && %t", c0, c1); break;
- case BANG: pfmt(f, "! %t", c0); break;
- case BRACE: pfmt(f, "{%t}", c0); break;
- case COUNT: pfmt(f, "$#%t", c0); break;
- case FN: pfmt(f, "fn %t %t", c0, c1); break;
- case IF: pfmt(f, "if%t%t", c0, c1); break;
- case NOT: pfmt(f, "if not %t", c0); break;
- case OROR: pfmt(f, "%t || %t", c0, c1); break;
+ default: pfmt(f, "bad %d %p %p %p", t->type, c0, c1, c2);
+ break;
+ case '$': pfmt(f, "$%t", c0);
+ break;
+ case '"': pfmt(f, "$\"%t", c0);
+ break;
+ case '&': pfmt(f, "%t&", c0);
+ break;
+ case '^': pfmt(f, "%t^%t", c0, c1);
+ break;
+ case '`': pfmt(f, "`%t", c0);
+ break;
+ case ANDAND: pfmt(f, "%t && %t", c0, c1);
+ break;
+ case BANG: pfmt(f, "! %t", c0);
+ break;
+ case BRACE: pfmt(f, "{%t}", c0);
+ break;
+ case COUNT: pfmt(f, "$#%t", c0);
+ break;
+ case FN: pfmt(f, "fn %t %t", c0, c1);
+ break;
+ case IF: pfmt(f, "if%t%t", c0, c1);
+ break;
+ case NOT: pfmt(f, "if not %t", c0);
+ break;
+ case OROR: pfmt(f, "%t || %t", c0, c1);
+ break;
case PCMD:
- case PAREN: pfmt(f, "(%t)", c0); break;
- case SUB: pfmt(f, "$%t(%t)", c0, c1); break;
- case SIMPLE: pfmt(f, "%t", c0); break;
- case SUBSHELL: pfmt(f, "@ %t", c0); break;
- case SWITCH: pfmt(f, "switch %t %t", c0, c1); break;
- case TWIDDLE: pfmt(f, "~ %t %t", c0, c1); break;
- case WHILE: pfmt(f, "while %t%t", c0, c1); break;
+ case PAREN: pfmt(f, "(%t)", c0);
+ break;
+ case SUB: pfmt(f, "$%t(%t)", c0, c1);
+ break;
+ case SIMPLE: pfmt(f, "%t", c0);
+ break;
+ case SUBSHELL: pfmt(f, "@ %t", c0);
+ break;
+ case SWITCH: pfmt(f, "switch %t %t", c0, c1);
+ break;
+ case TWIDDLE: pfmt(f, "~ %t %t", c0, c1);
+ break;
+ case WHILE: pfmt(f, "while %t%t", c0, c1);
+ break;
case ARGLIST:
if(c0==0)
pfmt(f, "%t", c1);
@@ -48,22 +75,26 @@ void pcmd(io *f, tree *t)
break;
case ';':
if(c0){
- if(c1) pfmt(f, "%t%c%t", c0, nl, c1);
+ if(c1)
+ pfmt(f, "%t%c%t", c0, nl, c1);
else pfmt(f, "%t", c0);
}
else pfmt(f, "%t", c1);
break;
case WORDS:
- if(c0) pfmt(f, "%t ", c0);
+ if(c0)
+ pfmt(f, "%t ", c0);
pfmt(f, "%t", c1);
break;
case FOR:
pfmt(f, "for(%t", c0);
- if(c1) pfmt(f, " in %t", c1);
+ if(c1)
+ pfmt(f, " in %t", c1);
pfmt(f, ")%t", c2);
break;
case WORD:
- if(t->quoted) pfmt(f, "%Q", t->str);
+ if(t->quoted)
+ pfmt(f, "%Q", t->str);
else pdeglob(f, t->str);
break;
case DUP:
@@ -79,27 +110,35 @@ void pcmd(io *f, tree *t)
case HERE:
pchr(f, '<');
case READ:
+ case RDWR:
pchr(f, '<');
- if(t->fd0!=0) pfmt(f, "[%d]", t->fd0);
+ if(t->rtype==RDWR)
+ pchr(f, '>');
+ if(t->fd0!=0)
+ pfmt(f, "[%d]", t->fd0);
break;
case APPEND:
pchr(f, '>');
case WRITE:
pchr(f, '>');
- if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
break;
}
pfmt(f, "%t", c0);
- if(c1) pfmt(f, " %t", c1);
+ if(c1)
+ pfmt(f, " %t", c1);
break;
case '=':
pfmt(f, "%t=%t", c0, c1);
- if(c2) pfmt(f, " %t", c2);
+ if(c2)
+ pfmt(f, " %t", c2);
break;
case PIPE:
pfmt(f, "%t|", c0);
if(t->fd1==0){
- if(t->fd0!=1) pfmt(f, "[%d]", t->fd0);
+ if(t->fd0!=1)
+ pfmt(f, "[%d]", t->fd0);
}
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
pfmt(f, "%t", c1);
diff --git a/rc/pfnc.c b/rc/pfnc.c
@@ -5,7 +5,7 @@
struct{
void (*f)(void);
char *name;
-}fname[]={
+}fname[] = {
Xappend, "Xappend",
Xasync, "Xasync",
Xbang, "Xbang",
@@ -18,6 +18,7 @@ struct{
Xjump, "Xjump",
Xmark, "Xmark",
Xpopm, "Xpopm",
+ Xrdwr, "Xrdwr",
Xread, "Xread",
Xreturn, "Xreturn",
Xtrue, "Xtrue",
@@ -50,18 +51,21 @@ struct{
Xrdfn, "Xrdfn",
Xqdol, "Xqdol",
0};
-void pfnc(io *fd, thread *t)
+
+void
+pfnc(io *fd, thread *t)
{
int i;
- void (*fn)(void)=t->code[t->pc].f;
+ void (*fn)(void) = t->code[t->pc].f;
list *a;
pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
- for(i=0;fname[i].f;i++) if(fname[i].f==fn){
+ for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
pstr(fd, fname[i].name);
break;
}
- if(!fname[i].f) pfmt(fd, "%p", fn);
- for(a=t->argv;a;a=a->next) pfmt(fd, " (%v)", a->words);
+ if(!fname[i].f)
+ pfmt(fd, "%p", fn);
+ for(a = t->argv;a;a = a->next) pfmt(fd, " (%v)", a->words);
pchr(fd, '\n');
flush(fd);
}
diff --git a/rc/plan9ish.c b/rc/plan9ish.c
@@ -27,12 +27,11 @@ char *syssigname[]={
char*
Rcmain(void)
{
- static char Rcmain[] = PREFIX"/etc/rcmain";
- char *rcmain = getenv("RCMAIN");
- return rcmain ? rcmain : Rcmain;
+ return unsharp("#9/rcmain");
}
char Fdprefix[]="/dev/fd/";
+long readnb(int, char *, long);
void execfinit(void);
void execbind(void);
void execmount(void);
@@ -129,7 +128,7 @@ void Vinit(void){
for(s=*env;*s && *s!='(' && *s!='=';s++);
switch(*s){
case '\0':
- // pfmt(err, "rc: odd environment %q?\n", *env);
+ /* pfmt(err, "rc: odd environment %q?\n", *env); */
break;
case '=':
*s='\0';
@@ -200,7 +199,10 @@ int Waitfor(int pid, int unused0){
Waitmsg *w;
char errbuf[ERRMAX];
+ if(pid >= 0 && !havewaitpid(pid))
+ return 0;
while((w = wait()) != nil){
+ delwaitpid(w->pid);
if(w->pid==pid){
if(strncmp(w->msg, "signal: ", 8) == 0)
fprint(mapfd(2), "%d: %s\n", w->pid, w->msg);
@@ -208,7 +210,7 @@ int Waitfor(int pid, int unused0){
free(w);
return 0;
}
- if(strncmp(w->msg, "signal: ", 8) == 0)
+ if(runq->iflag && strncmp(w->msg, "signal: ", 8) == 0)
fprint(2, "%d: %s\n", w->pid, w->msg);
for(p=runq->ret;p;p=p->ret)
if(p->pid==w->pid){
@@ -218,7 +220,7 @@ int Waitfor(int pid, int unused0){
free(w);
}
- errstr(errbuf, sizeof errbuf);
+ rerrstr(errbuf, sizeof errbuf);
if(strcmp(errbuf, "interrupted")==0) return -1;
return 0;
}
@@ -412,9 +414,11 @@ int Opendir(char *name)
close(f);
return -1;
}
-int Readdir(int f, char *p)
+int Readdir(int f, char *p, int onlydirs)
{
int n;
+ USED(onlydirs); /* only advisory */
+
if(f<0 || f>=NFD)
return 0;
if(dir[f].i==dir[f].n){ /* read */
@@ -490,7 +494,7 @@ long Read(int fd, char *buf, long cnt)
{
int i;
- i = read(fd, buf, cnt);
+ i = readnb(fd, buf, cnt);
if(ntrap) dotrap();
return i;
}
@@ -547,3 +551,54 @@ void Memcpy(char *a, char *b, long n)
void *Malloc(ulong n){
return malloc(n);
}
+
+int
+exitcode(char *msg)
+{
+ int n;
+
+ n = atoi(msg);
+ if(n == 0)
+ n = 1;
+ return n;
+}
+
+int *waitpids;
+int nwaitpids;
+
+void
+addwaitpid(int pid)
+{
+ waitpids = realloc(waitpids, (nwaitpids+1)*sizeof waitpids[0]);
+ if(waitpids == 0)
+ panic("Can't realloc %d waitpids", nwaitpids+1);
+ waitpids[nwaitpids++] = pid;
+}
+
+void
+delwaitpid(int pid)
+{
+ int r, w;
+
+ for(r=w=0; r<nwaitpids; r++)
+ if(waitpids[r] != pid)
+ waitpids[w++] = waitpids[r];
+ nwaitpids = w;
+}
+
+void
+clearwaitpids(void)
+{
+ nwaitpids = 0;
+}
+
+int
+havewaitpid(int pid)
+{
+ int i;
+
+ for(i=0; i<nwaitpids; i++)
+ if(waitpids[i] == pid)
+ return 1;
+ return 0;
+}
diff --git a/rc/rc.1 b/rc/rc.1
@@ -208,6 +208,11 @@ If
is followed by a parenthesized list of subscripts, the
value substituted is a list composed of the requested elements (origin 1).
The parenthesis must follow the variable name with no spaces.
+Subscripts can also take the form
+.IB m - n
+or
+.IB m -
+to indicate a sequence of elements.
Assignments to variables are described below.
.HP
.BI $# argument
diff --git a/rc/rc.h b/rc/rc.h
@@ -26,7 +26,7 @@
#define YYMAXDEPTH 500
#ifndef PAREN
#ifndef YYMAJOR
-#include "y.tab.h"
+#include "x.tab.h"
#endif
#endif
@@ -80,6 +80,7 @@ char tok[NTOK];
#define HERE 4
#define DUPFD 5
#define CLOSE 6
+#define RDWR 7
struct var{
char *name; /* ascii name */
word *val; /* value */
diff --git a/rc/simple.c b/rc/simple.c
@@ -15,22 +15,24 @@ exitnext(void){
while(c->f==Xpopredir) c++;
return c->f==Xexit;
}
-void Xsimple(void){
+
+void
+Xsimple(void)
+{
word *a;
- thread *p=runq;
+ thread *p = runq;
var *v;
struct builtin *bp;
- int pid, n;
- char buf[ERRMAX];
+ int pid;
globlist();
- a=runq->argv->words;
+ a = runq->argv->words;
if(a==0){
Xerror1("empty argument list");
return;
}
if(flag['x'])
pfmt(err, "%v\n", p->argv->words); /* wrong, should do redirs …
- v=gvlook(a->word);
+ v = gvlook(a->word);
if(v->fn)
execfunc(v);
else{
@@ -41,10 +43,10 @@ void Xsimple(void){
poplist();
return;
}
- a=a->next;
+ a = a->next;
popword();
}
- for(bp=Builtin;bp->name;bp++)
+ for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
(*bp->fnc)();
return;
@@ -58,30 +60,22 @@ void Xsimple(void){
else{
flush(err);
Updenv(); /* necessary so changes don't go out …
- switch(pid=fork()){
- case -1:
+ if((pid = execforkexec()) < 0){
Xerror("try again");
return;
- case 0:
- pushword("exec");
- execexec();
- strcpy(buf, "can't exec: ");
- n = strlen(buf);
- errstr(buf+n, ERRMAX-n);
- Exit(buf);
- default:
- kidpid = pid;
- poplist();
- /* interrupts don't get us out */
- while(Waitfor(pid, 1) < 0)
- ;
- kidpid = 0;
}
+
+ /* interrupts don't get us out */
+ poplist();
+ while(Waitfor(pid, 1) < 0)
+ ;
}
}
}
-struct word nullpath={ "", 0};
-void doredir(redir *rp)
+struct word nullpath = { "", 0};
+
+void
+doredir(redir *rp)
{
if(rp){
doredir(rp->next);
@@ -92,22 +86,32 @@ void doredir(redir *rp)
close(rp->from);
}
break;
- case RDUP: Dup(rp->from, rp->to); break;
- case RCLOSE: close(rp->from); break;
+ case RDUP:
+ Dup(rp->from, rp->to);
+ break;
+ case RCLOSE:
+ close(rp->from);
+ break;
}
}
}
-word *searchpath(char *w){
+
+word*
+searchpath(char *w)
+{
word *path;
if(strncmp(w, "/", 1)==0
/* || strncmp(w, "#", 1)==0 */
|| strncmp(w, "./", 2)==0
|| strncmp(w, "../", 3)==0
- || (path=vlook("path")->val)==0)
+ || (path = vlook("path")->val)==0)
path=&nullpath;
return path;
}
-void execexec(void){
+
+void
+execexec(void)
+{
popword(); /* "exec" */
if(runq->argv->words==0){
Xerror1("empty argument list");
@@ -117,19 +121,24 @@ void execexec(void){
Execute(runq->argv->words, searchpath(runq->argv->words->word));
poplist();
}
-void execfunc(var *func)
+
+void
+execfunc(var *func)
{
word *starval;
popword();
- starval=runq->argv->words;
- runq->argv->words=0;
+ starval = runq->argv->words;
+ runq->argv->words = 0;
poplist();
- start(func->fn, func->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=starval;
- runq->local->changed=1;
+ start(func->fn, func->pc, runq->local);
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = starval;
+ runq->local->changed = 1;
}
-int dochdir(char *word){
+
+int
+dochdir(char *word)
+{
/* report to /dev/wdir if it exists and we're interactive */
static int wdirfd = -2;
if(chdir(word)<0) return -1;
@@ -141,21 +150,26 @@ int dochdir(char *word){
}
return 1;
}
-void execcd(void){
- word *a=runq->argv->words;
+
+void
+execcd(void)
+{
+ word *a = runq->argv->words;
word *cdpath;
char dir[512];
setstatus("can't cd");
- cdpath=vlook("cdpath")->val;
+ cdpath = vlook("cdpath")->val;
switch(count(a)){
default:
pfmt(err, "Usage: cd [directory]\n");
break;
case 2:
- if(a->next->word[0]=='/' || cdpath==0) cdpath=&nullpath;
- for(;cdpath;cdpath=cdpath->next){
+ if(a->next->word[0]=='/' || cdpath==0)
+ cdpath=&nullpath;
+ for(;cdpath;cdpath = cdpath->next){
strcpy(dir, cdpath->word);
- if(dir[0]) strcat(dir, "/");
+ if(dir[0])
+ strcat(dir, "/");
strcat(dir, a->next->word);
if(dochdir(dir)>=0){
if(strlen(cdpath->word)
@@ -165,10 +179,11 @@ void execcd(void){
break;
}
}
- if(cdpath==0) pfmt(err, "Can't cd %s: %r\n", a->next->word);
+ if(cdpath==0)
+ pfmt(err, "Can't cd %s: %r\n", a->next->word);
break;
case 1:
- a=vlook("HOME")->val;
+ a = vlook("home")->val;
if(count(a)>=1){
if(dochdir(a->word)>=0)
setstatus("");
@@ -181,14 +196,22 @@ void execcd(void){
}
poplist();
}
-void execexit(void){
+
+void
+execexit(void)
+{
switch(count(runq->argv->words)){
- default: pfmt(err, "Usage: exit [status]\nExiting anyway\n");
- case 2: setstatus(runq->argv->words->next->word);
+ default:
+ pfmt(err, "Usage: exit [status]\nExiting anyway\n");
+ case 2:
+ setstatus(runq->argv->words->next->word);
case 1: Xexit();
}
}
-void execshift(void){
+
+void
+execshift(void)
+{
int n;
word *a;
var *star;
@@ -198,72 +221,87 @@ void execshift(void){
setstatus("shift usage");
poplist();
return;
- case 2: n=atoi(runq->argv->words->next->word); break;
- case 1: n=1; break;
+ case 2:
+ n = atoi(runq->argv->words->next->word);
+ break;
+ case 1:
+ n = 1;
+ break;
}
- star=vlook("*");
+ star = vlook("*");
for(;n && star->val;--n){
- a=star->val->next;
+ a = star->val->next;
efree(star->val->word);
efree((char *)star->val);
- star->val=a;
- star->changed=1;
+ star->val = a;
+ star->changed = 1;
}
setstatus("");
poplist();
}
-int octal(char *s)
+
+int
+octal(char *s)
{
- int n=0;
+ int n = 0;
while(*s==' ' || *s=='\t' || *s=='\n') s++;
- while('0'<=*s && *s<='7') n=n*8+*s++-'0';
+ while('0'<=*s && *s<='7') n = n*8+*s++-'0';
return n;
}
-int mapfd(int fd)
+
+int
+mapfd(int fd)
{
redir *rp;
- for(rp=runq->redir;rp;rp=rp->next){
+ for(rp = runq->redir;rp;rp = rp->next){
switch(rp->type){
case RCLOSE:
- if(rp->from==fd) fd=-1;
+ if(rp->from==fd)
+ fd=-1;
break;
case RDUP:
case ROPEN:
- if(rp->to==fd) fd=rp->from;
+ if(rp->to==fd)
+ fd = rp->from;
break;
}
}
return fd;
}
union code rdcmds[4];
-void execcmds(io *f)
+
+void
+execcmds(io *f)
{
- static int first=1;
+ static int first = 1;
if(first){
- rdcmds[0].i=1;
- rdcmds[1].f=Xrdcmds;
- rdcmds[2].f=Xreturn;
- first=0;
+ rdcmds[0].i = 1;
+ rdcmds[1].f = Xrdcmds;
+ rdcmds[2].f = Xreturn;
+ first = 0;
}
start(rdcmds, 1, runq->local);
- runq->cmdfd=f;
- runq->iflast=0;
+ runq->cmdfd = f;
+ runq->iflast = 0;
}
-void execeval(void){
+
+void
+execeval(void)
+{
char *cmdline, *s, *t;
- int len=0;
+ int len = 0;
word *ap;
if(count(runq->argv->words)<=1){
Xerror1("Usage: eval cmd ...");
return;
}
- eflagok=1;
- for(ap=runq->argv->words->next;ap;ap=ap->next)
+ eflagok = 1;
+ for(ap = runq->argv->words->next;ap;ap = ap->next)
len+=1+strlen(ap->word);
- cmdline=emalloc(len);
- s=cmdline;
- for(ap=runq->argv->words->next;ap;ap=ap->next){
- for(t=ap->word;*t;) *s++=*t++;
+ cmdline = emalloc(len);
+ s = cmdline;
+ for(ap = runq->argv->words->next;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
*s++=' ';
}
s[-1]='\n';
@@ -272,36 +310,39 @@ void execeval(void){
efree(cmdline);
}
union code dotcmds[14];
-void execdot(void){
- int iflag=0;
+
+void
+execdot(void)
+{
+ int iflag = 0;
int fd;
list *av;
- thread *p=runq;
+ thread *p = runq;
char *zero;
- static int first=1;
+ static int first = 1;
char file[512];
word *path;
if(first){
- dotcmds[0].i=1;
- dotcmds[1].f=Xmark;
- dotcmds[2].f=Xword;
+ dotcmds[0].i = 1;
+ dotcmds[1].f = Xmark;
+ dotcmds[2].f = Xword;
dotcmds[3].s="0";
- dotcmds[4].f=Xlocal;
- dotcmds[5].f=Xmark;
- dotcmds[6].f=Xword;
+ dotcmds[4].f = Xlocal;
+ dotcmds[5].f = Xmark;
+ dotcmds[6].f = Xword;
dotcmds[7].s="*";
- dotcmds[8].f=Xlocal;
- dotcmds[9].f=Xrdcmds;
- dotcmds[10].f=Xunlocal;
- dotcmds[11].f=Xunlocal;
- dotcmds[12].f=Xreturn;
- first=0;
+ dotcmds[8].f = Xlocal;
+ dotcmds[9].f = Xrdcmds;
+ dotcmds[10].f = Xunlocal;
+ dotcmds[11].f = Xunlocal;
+ dotcmds[12].f = Xreturn;
+ first = 0;
}
else
- eflagok=1;
+ eflagok = 1;
popword();
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
- iflag=1;
+ iflag = 1;
popword();
}
/* get input file */
@@ -309,18 +350,20 @@ void execdot(void){
Xerror1("Usage: . [-i] file [arg ...]");
return;
}
- zero=strdup(p->argv->words->word);
+ zero = strdup(p->argv->words->word);
popword();
fd=-1;
- for(path=searchpath(zero);path;path=path->next){
+ for(path = searchpath(zero);path;path = path->next){
strcpy(file, path->word);
- if(file[0]) strcat(file, "/");
+ if(file[0])
+ strcat(file, "/");
strcat(file, zero);
+ if((fd = open(file, 0))>=0) break;
if(strcmp(file, "/dev/stdin")==0){ /* for sun & ucb */
- fd=Dup1(0);
- if(fd>=0) break;
+ fd = Dup1(0);
+ if(fd>=0)
+ break;
}
- if((fd=open(file, 0))>=0) break;
}
if(fd<0){
pfmt(err, "%s: ", zero);
@@ -331,38 +374,41 @@ void execdot(void){
/* set up for a new command loop */
start(dotcmds, 1, (struct var *)0);
pushredir(RCLOSE, fd, 0);
- runq->cmdfile=zero;
- runq->cmdfd=openfd(fd);
- runq->iflag=iflag;
- runq->iflast=0;
+ runq->cmdfile = zero;
+ runq->cmdfd = openfd(fd);
+ runq->iflag = iflag;
+ runq->iflast = 0;
/* push $* value */
pushlist();
- runq->argv->words=p->argv->words;
+ runq->argv->words = p->argv->words;
/* free caller's copy of $* */
- av=p->argv;
- p->argv=av->next;
+ av = p->argv;
+ p->argv = av->next;
efree((char *)av);
/* push $0 value */
pushlist();
pushword(zero);
ndot++;
}
-void execflag(void){
+
+void
+execflag(void)
+{
char *letter, *val;
switch(count(runq->argv->words)){
case 2:
setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"fl…
break;
case 3:
- letter=runq->argv->words->next->word;
- val=runq->argv->words->next->next->word;
+ letter = runq->argv->words->next->word;
+ val = runq->argv->words->next->next->word;
if(strlen(letter)==1){
if(strcmp(val, "+")==0){
- flag[(uchar)letter[0]]=flagset;
+ flag[(uchar)letter[0]] = flagset;
break;
}
if(strcmp(val, "-")==0){
- flag[(uchar)letter[0]]=0;
+ flag[(uchar)letter[0]] = 0;
break;
}
}
@@ -372,53 +418,57 @@ void execflag(void){
}
poplist();
}
-void execwhatis(void){ /* mildly wrong -- should fork before writing */
+
+void
+execwhatis(void){ /* mildly wrong -- should fork before writing */
word *a, *b, *path;
var *v;
struct builtin *bp;
char file[512];
struct io out[1];
int found, sep;
- a=runq->argv->words->next;
+ a = runq->argv->words->next;
if(a==0){
Xerror1("Usage: whatis name ...");
return;
}
setstatus("");
- out->fd=mapfd(1);
- out->bufp=out->buf;
- out->ebuf=&out->buf[NBUF];
- out->strp=0;
- for(;a;a=a->next){
- v=vlook(a->word);
+ out->fd = mapfd(1);
+ out->bufp = out->buf;
+ out->ebuf = &out->buf[NBUF];
+ out->strp = 0;
+ for(;a;a = a->next){
+ v = vlook(a->word);
if(v->val){
pfmt(out, "%s=", a->word);
if(v->val->next==0)
pfmt(out, "%q\n", v->val->word);
else{
sep='(';
- for(b=v->val;b && b->word;b=b->next){
+ for(b = v->val;b && b->word;b = b->next){
pfmt(out, "%c%q", sep, b->word);
sep=' ';
}
pfmt(out, ")\n");
}
- found=1;
+ found = 1;
}
else
- found=0;
- v=gvlook(a->word);
- if(v->fn) pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
+ found = 0;
+ v = gvlook(a->word);
+ if(v->fn)
+ pfmt(out, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
else{
- for(bp=Builtin;bp->name;bp++)
+ for(bp = Builtin;bp->name;bp++)
if(strcmp(a->word, bp->name)==0){
pfmt(out, "builtin %s\n", a->word);
break;
}
if(!bp->name){
- for(path=searchpath(a->word);path;path=path->n…
+ for(path = searchpath(a->word);path;path = pat…
strcpy(file, path->word);
- if(file[0]) strcat(file, "/");
+ if(file[0])
+ strcat(file, "/");
strcat(file, a->word);
if(Executable(file)){
pfmt(out, "%s\n", file);
@@ -435,11 +485,20 @@ void execwhatis(void){ /* mildly wrong -- should f…
poplist();
flush(err);
}
-void execwait(void){
+
+void
+execwait(void)
+{
switch(count(runq->argv->words)){
- default: Xerror1("Usage: wait [pid]"); return;
- case 2: Waitfor(atoi(runq->argv->words->next->word), 0); break;
- case 1: Waitfor(-1, 0); break;
+ default:
+ Xerror1("Usage: wait [pid]");
+ return;
+ case 2:
+ Waitfor(atoi(runq->argv->words->next->word), 0);
+ break;
+ case 1:
+ Waitfor(-1, 0);
+ break;
}
poplist();
}
diff --git a/rc/subr.c b/rc/subr.c
@@ -2,20 +2,30 @@
#include "exec.h"
#include "io.h"
#include "fns.h"
-char *emalloc(long n){
- char *p=(char *)Malloc(n);
- if(p==0) panic("Can't malloc %d bytes", n);
-/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } *//**/
+
+char*
+emalloc(long n)
+{
+ char *p = (char *)Malloc(n);
+ if(p==0)
+ panic("Can't malloc %d bytes", n);
+/* if(err){ pfmt(err, "malloc %d->%p\n", n, p); flush(err); } /**/
+ memset(p, 0, n);
return p;
}
-void efree(char *p)
+
+void
+efree(char *p)
{
-/* pfmt(err, "free %p\n", p); flush(err); *//**/
- if(p) free(p);
+/* pfmt(err, "free %p\n", p); flush(err); /**/
+ if(p)
+ free(p);
else pfmt(err, "free 0\n");
}
extern int lastword, lastdol;
-void yyerror(char *m)
+
+void
+yyerror(char *m)
{
pfmt(err, "rc: ");
if(runq->cmdfile && !runq->iflag)
@@ -24,17 +34,21 @@ void yyerror(char *m)
pfmt(err, "%s: ", runq->cmdfile);
else if(!runq->iflag)
pfmt(err, "line %d: ", runq->lineno);
- if(tok[0] && tok[0]!='\n') pfmt(err, "token %q: ", tok);
+ if(tok[0] && tok[0]!='\n')
+ pfmt(err, "token %q: ", tok);
pfmt(err, "%s\n", m);
flush(err);
- lastword=0;
- lastdol=0;
+ lastword = 0;
+ lastdol = 0;
while(lastc!='\n' && lastc!=EOF) advance();
nerror++;
setvar("status", newword(m, (word *)0));
}
char *bp;
-void iacvt(int n){
+
+static void
+iacvt(int n)
+{
if(n<0){
*bp++='-';
n=-n; /* doesn't work for n==-inf */
@@ -43,13 +57,17 @@ void iacvt(int n){
iacvt(n/10);
*bp++=n%10+'0';
}
-void itoa(char *s, long n)
+
+void
+inttoascii(char *s, long n)
{
- bp=s;
+ bp = s;
iacvt(n);
*bp='\0';
}
-void panic(char *s, int n)
+
+void
+panic(char *s, int n)
{
pfmt(err, "rc: ");
pfmt(err, s, n);
diff --git a/rc/trap.c b/rc/trap.c
@@ -3,22 +3,25 @@
#include "fns.h"
#include "io.h"
extern char *Signame[];
-void dotrap(void){
- register int i;
- register struct var *trapreq;
- register struct word *starval;
- starval=vlook("*")->val;
- while(ntrap) for(i=0;i!=NSIG;i++) while(trap[i]){
+
+void
+dotrap(void)
+{
+ int i;
+ struct var *trapreq;
+ struct word *starval;
+ starval = vlook("*")->val;
+ while(ntrap) for(i = 0;i!=NSIG;i++) while(trap[i]){
--trap[i];
--ntrap;
if(getpid()!=mypid) Exit(getstatus());
- trapreq=vlook(Signame[i]);
+ trapreq = vlook(Signame[i]);
if(trapreq->fn){
start(trapreq->fn, trapreq->pc, (struct var *)0);
- runq->local=newvar(strdup("*"), runq->local);
- runq->local->val=copywords(starval, (struct word *)0);
- runq->local->changed=1;
- runq->redir=runq->startredir=0;
+ runq->local = newvar(strdup("*"), runq->local);
+ runq->local->val = copywords(starval, (struct word *)0…
+ runq->local->changed = 1;
+ runq->redir = runq->startredir = 0;
}
else if(i==SIGINT || i==SIGQUIT){
/*
diff --git a/rc/tree.c b/rc/tree.c
@@ -7,108 +7,140 @@ tree *treenodes;
* create and clear a new tree node, and add it
* to the node list.
*/
-tree *newtree(void){
- tree *t=new(tree);
- t->iskw=0;
- t->str=0;
- t->child[0]=t->child[1]=t->child[2]=0;
- t->next=treenodes;
- treenodes=t;
+
+tree*
+newtree(void)
+{
+ tree *t = new(tree);
+ t->iskw = 0;
+ t->str = 0;
+ t->child[0] = t->child[1] = t->child[2] = 0;
+ t->next = treenodes;
+ treenodes = t;
return t;
}
-void freenodes(void){
+
+void
+freenodes(void)
+{
tree *t, *u;
- for(t=treenodes;t;t=u){
- u=t->next;
- if(t->str) efree(t->str);
+ for(t = treenodes;t;t = u){
+ u = t->next;
+ if(t->str)
+ efree(t->str);
efree((char *)t);
}
- treenodes=0;
+ treenodes = 0;
}
-tree *tree1(int type, tree *c0)
+
+tree*
+tree1(int type, tree *c0)
{
return tree3(type, c0, (tree *)0, (tree *)0);
}
-tree *tree2(int type, tree *c0, tree *c1)
+
+tree*
+tree2(int type, tree *c0, tree *c1)
{
return tree3(type, c0, c1, (tree *)0);
}
-tree *tree3(int type, tree *c0, tree *c1, tree *c2)
+
+tree*
+tree3(int type, tree *c0, tree *c1, tree *c2)
{
tree *t;
if(type==';'){
- if(c0==0) return c1;
- if(c1==0) return c0;
+ if(c0==0)
+ return c1;
+ if(c1==0)
+ return c0;
}
- t=newtree();
- t->type=type;
- t->child[0]=c0;
- t->child[1]=c1;
- t->child[2]=c2;
+ t = newtree();
+ t->type = type;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ t->child[2] = c2;
return t;
}
-tree *mung1(tree *t, tree *c0)
+
+tree*
+mung1(tree *t, tree *c0)
{
- t->child[0]=c0;
+ t->child[0] = c0;
return t;
}
-tree *mung2(tree *t, tree *c0, tree *c1)
+
+tree*
+mung2(tree *t, tree *c0, tree *c1)
{
- t->child[0]=c0;
- t->child[1]=c1;
+ t->child[0] = c0;
+ t->child[1] = c1;
return t;
}
-tree *mung3(tree *t, tree *c0, tree *c1, tree *c2)
+
+tree*
+mung3(tree *t, tree *c0, tree *c1, tree *c2)
{
- t->child[0]=c0;
- t->child[1]=c1;
- t->child[2]=c2;
+ t->child[0] = c0;
+ t->child[1] = c1;
+ t->child[2] = c2;
return t;
}
-tree *epimung(tree *comp, tree *epi)
+
+tree*
+epimung(tree *comp, tree *epi)
{
tree *p;
- if(epi==0) return comp;
- for(p=epi;p->child[1];p=p->child[1]);
- p->child[1]=comp;
+ if(epi==0)
+ return comp;
+ for(p = epi;p->child[1];p = p->child[1]);
+ p->child[1] = comp;
return epi;
}
/*
* Add a SIMPLE node at the root of t and percolate all the redirections
* up to the root.
*/
-tree *simplemung(tree *t)
+
+tree*
+simplemung(tree *t)
{
tree *u;
struct io *s;
- t=tree1(SIMPLE, t);
- s=openstr();
+ t = tree1(SIMPLE, t);
+ s = openstr();
pfmt(s, "%t", t);
- t->str=strdup(s->strp);
+ t->str = strdup(s->strp);
closeio(s);
- for(u=t->child[0];u->type==ARGLIST;u=u->child[0]){
+ for(u = t->child[0];u->type==ARGLIST;u = u->child[0]){
if(u->child[1]->type==DUP
|| u->child[1]->type==REDIR){
- u->child[1]->child[1]=t;
- t=u->child[1];
- u->child[1]=0;
+ u->child[1]->child[1] = t;
+ t = u->child[1];
+ u->child[1] = 0;
}
}
return t;
}
-tree *token(char *str, int type)
+
+tree*
+token(char *str, int type)
{
- tree *t=newtree();
- t->type=type;
- t->str=strdup(str);
+ tree *t = newtree();
+ t->type = type;
+ t->str = strdup(str);
return t;
}
-void freetree(tree *p)
+
+void
+freetree(tree *p)
{
- if(p==0) return;
+ if(p==0)
+ return;
freetree(p->child[0]);
freetree(p->child[1]);
freetree(p->child[2]);
- if(p->str) efree(p->str);
+ if(p->str)
+ efree(p->str);
efree((char *)p);
}
diff --git a/rc/unixcrap.c b/rc/unixcrap.c
@@ -2,6 +2,8 @@
#include <sys/time.h>
#include <sys/stat.h>
#include <sys/resource.h>
+#include <errno.h>
+#include <fcntl.h>
#include <libc.h>
#include "rc.h"
#include "exec.h"
@@ -209,3 +211,26 @@ out:
poplist();
flush(err);
}
+
+/*
+ * Cope with non-blocking read.
+ */
+long
+readnb(int fd, char *buf, long cnt)
+{
+ int n, didreset;
+ int flgs;
+
+ didreset = 0;
+ while((n = read(fd, buf, cnt)) == -1)
+ if(!didreset && errno == EAGAIN){
+ if((flgs = fcntl(fd, F_GETFL, 0)) == -1)
+ return -1;
+ flgs &= ~O_NONBLOCK;
+ if(fcntl(fd, F_SETFL, flgs) == -1)
+ return -1;
+ didreset = 1;
+ }
+
+ return n;
+}
diff --git a/rc/var.c b/rc/var.c
@@ -1,9 +1,11 @@
#include "rc.h"
#include "exec.h"
#include "fns.h"
-int hash(char *s, int n)
+
+int
+hash(char *s, int n)
{
- register int h=0, i=1;
+ int h = 0, i = 1;
while(*s) h+=*s++*i++;
h%=n;
return h<0?h+n:h;
@@ -14,16 +16,21 @@ struct kw{
int type;
struct kw *next;
}*kw[NKW];
-void kenter(int type, char *name)
+
+void
+kenter(int type, char *name)
{
- register int h=hash(name, NKW);
- register struct kw *p=new(struct kw);
- p->type=type;
- p->name=name;
- p->next=kw[h];
- kw[h]=p;
+ int h = hash(name, NKW);
+ struct kw *p = new(struct kw);
+ p->type = type;
+ p->name = name;
+ p->next = kw[h];
+ kw[h] = p;
}
-void kinit(void){
+
+void
+kinit(void)
+{
kenter(FOR, "for");
kenter(IN, "in");
kenter(WHILE, "while");
@@ -35,47 +42,59 @@ void kinit(void){
kenter(SWITCH, "switch");
kenter(FN, "fn");
}
-tree *klook(char *name)
+
+tree*
+klook(char *name)
{
struct kw *p;
- tree *t=token(name, WORD);
- for(p=kw[hash(name, NKW)];p;p=p->next)
+ tree *t = token(name, WORD);
+ for(p = kw[hash(name, NKW)];p;p = p->next)
if(strcmp(p->name, name)==0){
- t->type=p->type;
- t->iskw=1;
+ t->type = p->type;
+ t->iskw = 1;
break;
}
return t;
}
-var *gvlook(char *name)
+
+var*
+gvlook(char *name)
{
- int h=hash(name, NVAR);
+ int h = hash(name, NVAR);
var *v;
- for(v=gvar[h];v;v=v->next) if(strcmp(v->name, name)==0) return v;
- return gvar[h]=newvar(strdup(name), gvar[h]);
+ for(v = gvar[h];v;v = v->next) if(strcmp(v->name, name)==0) return v;
+ return gvar[h] = newvar(strdup(name), gvar[h]);
}
-var *vlook(char *name)
+
+var*
+vlook(char *name)
{
var *v;
if(runq)
- for(v=runq->local;v;v=v->next)
+ for(v = runq->local;v;v = v->next)
if(strcmp(v->name, name)==0) return v;
return gvlook(name);
}
-void _setvar(char *name, word *val, int callfn)
+
+void
+_setvar(char *name, word *val, int callfn)
{
- register struct var *v=vlook(name);
+ struct var *v = vlook(name);
freewords(v->val);
v->val=val;
v->changed=1;
if(callfn && v->changefn)
v->changefn(v);
}
-void setvar(char *name, word *val)
+
+void
+setvar(char *name, word *val)
{
_setvar(name, val, 1);
}
-void bigpath(var *v)
+
+void
+bigpath(var *v)
{
/* convert $PATH to $path */
char *p, *q;
@@ -107,19 +126,42 @@ void bigpath(var *v)
}
_setvar("path", w, 0);
}
-void littlepath(var *v)
+
+char*
+list2strcolon(word *words)
+{
+ char *value, *s, *t;
+ int len = 0;
+ word *ap;
+ for(ap = words;ap;ap = ap->next)
+ len+=1+strlen(ap->word);
+ value = emalloc(len+1);
+ s = value;
+ for(ap = words;ap;ap = ap->next){
+ for(t = ap->word;*t;) *s++=*t++;
+ *s++=':';
+ }
+ if(s==value)
+ *s='\0';
+ else s[-1]='\0';
+ return value;
+}
+void
+littlepath(var *v)
{
/* convert $path to $PATH */
char *p;
word *w;
- p = _list2str(v->val, ':');
+ p = list2strcolon(v->val);
w = new(word);
w->word = p;
w->next = nil;
_setvar("PATH", w, 1); /* 1: recompute $path to expose colon pr…
}
-void pathinit(void)
+
+void
+pathinit(void)
{
var *v;
diff --git a/sed/sed.1 b/sed/sed.1
@@ -4,10 +4,7 @@ sed \- stream editor
.SH SYNOPSIS
.B sed
[
-.B -n
-]
-[
-.B -g
+.B -gln
]
[
.B -e
@@ -44,6 +41,11 @@ option suppresses the default output;
.B -g
causes all substitutions to be global, as if suffixed
.BR g .
+The
+.B -l
+option causes
+.I sed
+to flush its output buffer after every newline.
.PP
A script consists of editing commands, one per line,
of the following form:
diff --git a/sed/sed.c b/sed/sed.c
@@ -16,7 +16,7 @@ enum {
LBSIZE = 8192, /* input line size */
LABSIZE = 50, /* max label name size */
MAXSUB = 10, /* max number of sub reg ex…
- MAXFILES = 120, /* max output files */
+ MAXFILES = 120 /* max output files */
};
/* An address is a line #, a R.E., "$", a reference to the last
* R.E., or nothing.
@@ -27,7 +27,7 @@ typedef struct {
A_DOL,
A_LINE,
A_RE,
- A_LAST,
+ A_LAST
}type;
union {
long line; /* Line # */
@@ -137,6 +137,7 @@ Rune *hspend = holdsp; /* End of hold…
int nflag; /* Command line flags */
int gflag;
+int lflag;
int dolflag; /* Set when at true EOF */
int sflag; /* Set when substitution done…
@@ -234,6 +235,9 @@ main(int argc, char **argv)
case 'g':
gflag++;
continue;
+ case 'l':
+ lflag++;
+ continue;
default:
fprint(2, "sed: Unknown flag: %c\n", ARGC());
continue;
@@ -990,7 +994,7 @@ match(Reprog *pattern, Rune *buf)
return 0;
subexp[0].s.rsp = buf;
subexp[0].e.rep = 0;
- if (rregexec(pattern, linebuf, subexp, MAXSUB)) {
+ if (rregexec(pattern, linebuf, subexp, MAXSUB) > 0) {
loc1 = subexp[0].s.rsp;
loc2 = subexp[0].e.rep;
return 1;
@@ -1315,6 +1319,8 @@ putline(Biobuf *bp, Rune *buf, int n)
while (n--)
Bputrune(bp, *buf++);
Bputc(bp, '\n');
+ if(lflag)
+ Bflush(bp);
}
int
diff --git a/sort/sort.c b/sort/sort.c
@@ -34,7 +34,7 @@ enum
NSzerofract,
NSexp,
NSexpsign,
- NSexpdigit,
+ NSexpdigit
};
typedef struct Line Line;
@@ -243,8 +243,7 @@ notifyf(void *a, char *s)
done(0);
if(strncmp(s, "sys: write on closed pipe", 25) == 0)
done(0);
- fprint(2, "sort: note: %s\n", s);
- abort();
+ noted(NDFLT);
}
Line*
@@ -1583,7 +1582,7 @@ Rune* month[12] =
enum
{
- Threshold = 14,
+ Threshold = 14
};
void rsort4(Key***, ulong, int);
diff --git a/test/test.1 b/test/test.1
@@ -17,7 +17,7 @@ The following primitives are used to construct
.TP "\w'\fIn1 \fL-eq \fIn2\fLXX'u"
.BI -r " file"
True if the file exists (is accessible) and is readable.
-.PD
+.PD0
.TP
.BI -w " file"
True if the file exists and is writable.
@@ -146,7 +146,7 @@ following operators:
.TP "\w'\fL( \fIexpr\fL )XX'u"
.B !
unary negation operator
-.PD
+.PD0
.TP
.B -o
binary
diff --git a/test/test.c b/test/test.c
@@ -6,13 +6,15 @@
* Plan 9 additions:
* -A file exists and is append-only
* -L file exists and is exclusive-use
+ * -T file exists and is temporary
*/
#include <u.h>
#include <libc.h>
-#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
-extern int isatty(int); /* <unistd.h> */
+#define isatty plan9_isatty
+
+#define EQ(a,b) ((tmp=a)==0?0:(strcmp(tmp,b)==0))
int ap;
int ac;
@@ -23,14 +25,21 @@ void synbad(char *, char *);
int fsizep(char *);
int isdir(char *);
int isreg(char *);
+int isatty(int);
int isint(char *, int *);
+int isolder(char *, char *);
+int isolderthan(char *, char *);
+int isnewerthan(char *, char *);
int hasmode(char *, ulong);
int tio(char *, int);
int e(void), e1(void), e2(void), e3(void);
+char *nxtarg(int);
void
main(int argc, char *argv[])
{
+ int r;
+ char *c;
ac = argc; av = argv; ap = 1;
if(EQ(argv[0],"[")) {
@@ -38,8 +47,16 @@ main(int argc, char *argv[])
synbad("] missing","");
}
argv[ac] = 0;
- if (ac<=1) exits("usage");
- exits(e()?0:"false");
+ if (ac<=1)
+ exits("usage");
+ r = e();
+ /*
+ * nice idea but short-circuit -o and -a operators may have
+ * not consumed their right-hand sides.
+ */
+ if(0 && (c = nxtarg(1)) != nil)
+ synbad("unexpected operator/operand: ", c);
+ exits(r?0:"false");
}
char *
@@ -66,27 +83,32 @@ nxtintarg(int *pans)
}
int
-e(void) {
+e(void)
+{
int p1;
p1 = e1();
- if (EQ(nxtarg(1), "-o")) return(p1 || e());
+ if (EQ(nxtarg(1), "-o"))
+ return(p1 || e());
ap--;
return(p1);
}
int
-e1(void) {
+e1(void)
+{
int p1;
p1 = e2();
- if (EQ(nxtarg(1), "-a")) return (p1 && e1());
+ if (EQ(nxtarg(1), "-a"))
+ return (p1 && e1());
ap--;
return(p1);
}
int
-e2(void) {
+e2(void)
+{
if (EQ(nxtarg(0), "!"))
return(!e2());
ap--;
@@ -94,16 +116,16 @@ e2(void) {
}
int
-e3(void) {
- int p1;
- char *a;
- char *p2;
- int int1, int2;
+e3(void)
+{
+ int p1, int1, int2;
+ char *a, *p2;
a = nxtarg(0);
if(EQ(a, "(")) {
p1 = e();
- if(!EQ(nxtarg(0), ")")) synbad(") expected","");
+ if(!EQ(nxtarg(0), ")"))
+ synbad(") expected","");
return(p1);
}
@@ -113,6 +135,9 @@ e3(void) {
if(EQ(a, "-L"))
return(hasmode(nxtarg(0), DMEXCL));
+ if(EQ(a, "-T"))
+ return(hasmode(nxtarg(0), DMTMP));
+
if(EQ(a, "-f"))
return(isreg(nxtarg(0)));
@@ -147,10 +172,12 @@ e3(void) {
return(fsizep(nxtarg(0)));
if(EQ(a, "-t"))
- if(ap>=ac || !nxtintarg(&int1))
+ if(ap>=ac)
return(isatty(1));
- else
+ else if(nxtintarg(&int1))
return(isatty(int1));
+ else
+ synbad("not a valid file descriptor number ", "");
if(EQ(a, "-n"))
return(!EQ(nxtarg(0), ""));
@@ -166,8 +193,17 @@ e3(void) {
if(EQ(p2, "!="))
return(!EQ(nxtarg(0), a));
+ if(EQ(p2, "-older"))
+ return(isolder(nxtarg(0), a));
+
+ if(EQ(p2, "-ot"))
+ return(isolderthan(nxtarg(0), a));
+
+ if(EQ(p2, "-nt"))
+ return(isnewerthan(nxtarg(0), a));
+
if(!isint(a, &int1))
- return(!EQ(a,""));
+ synbad("unexpected operator/operand: ", p2);
if(nxtintarg(&int2)){
if(EQ(p2, "-eq"))
@@ -201,9 +237,10 @@ localstat(char *f, Dir *dir)
Dir *d;
d = dirstat(f);
- if(d == 0)
+ if(d == nil)
return(-1);
*dir = *d;
+ free(d);
dir->name = 0;
dir->uid = 0;
dir->gid = 0;
@@ -218,9 +255,10 @@ localfstat(int f, Dir *dir)
Dir *d;
d = dirfstat(f);
- if(d == 0)
+ if(d == nil)
return(-1);
*dir = *d;
+ free(d);
dir->name = 0;
dir->uid = 0;
dir->gid = 0;
@@ -259,6 +297,18 @@ isreg(char *f)
}
int
+isatty(int fd)
+{
+ Dir d1, d2;
+
+ if(localfstat(fd, &d1) < 0)
+ return 0;
+ if(localstat("/dev/cons", &d2) < 0)
+ return 0;
+ return d1.type==d2.type && d1.dev==d2.dev && d1.qid.path==d2.qid.path;
+}
+
+int
fsizep(char *f)
{
Dir dir;
@@ -290,3 +340,72 @@ isint(char *s, int *pans)
*pans = strtol(s, &ep, 0);
return (*ep == 0);
}
+
+int
+isolder(char *pin, char *f)
+{
+ char *p = pin;
+ ulong n, m;
+ Dir dir;
+
+ if(localstat(f,&dir)<0)
+ return(0);
+
+ /* parse time */
+ n = 0;
+ while(*p){
+ m = strtoul(p, &p, 0);
+ switch(*p){
+ case 0:
+ n = m;
+ break;
+ case 'y':
+ m *= 12;
+ /* fall through */
+ case 'M':
+ m *= 30;
+ /* fall through */
+ case 'd':
+ m *= 24;
+ /* fall through */
+ case 'h':
+ m *= 60;
+ /* fall through */
+ case 'm':
+ m *= 60;
+ /* fall through */
+ case 's':
+ n += m;
+ p++;
+ break;
+ default:
+ synbad("bad time syntax, ", pin);
+ }
+ }
+
+ return(dir.mtime+n < time(0));
+}
+
+int
+isolderthan(char *a, char *b)
+{
+ Dir ad, bd;
+
+ if(localstat(a, &ad)<0)
+ return(0);
+ if(localstat(b, &bd)<0)
+ return(0);
+ return ad.mtime > bd.mtime;
+}
+
+int
+isnewerthan(char *a, char *b)
+{
+ Dir ad, bd;
+
+ if(localstat(a, &ad)<0)
+ return(0);
+ if(localstat(b, &bd)<0)
+ return(0);
+ return ad.mtime < bd.mtime;
+}
diff --git a/touch/touch.c b/touch/touch.c
@@ -3,6 +3,7 @@
int touch(int, char *);
ulong now;
+int tflag;
void
usage(void)
@@ -20,6 +21,7 @@ main(int argc, char **argv)
now = time(0);
ARGBEGIN{
case 't':
+ tflag = 1;
now = strtoul(EARGF(usage()), 0, 0);
break;
case 'c':
@@ -52,11 +54,15 @@ touch(int nocreate, char *name)
fprint(2, "touch: %s: cannot wstat: %r\n", name);
return 1;
}
- if ((fd = create(name, OREAD, 0666)) < 0) {
+ if((fd = create(name, OREAD, 0666)) < 0) {
fprint(2, "touch: %s: cannot create: %r\n", name);
return 1;
}
- dirfwstat(fd, &stbuff);
+ if(tflag && dirfwstat(fd, &stbuff) < 0){
+ fprint(2, "touch: %s: cannot wstat: %r\n", name);
+ close(fd);
+ return 1;
+ }
close(fd);
return 0;
}
diff --git a/yacc/yacc.c b/yacc/yacc.c
@@ -98,7 +98,7 @@ enum
EMPTY = 1,
WHOKNOWS = 0,
OK = 1,
- NOMORE = -1000,
+ NOMORE = -1000
};
/* macros for getting associativity and precedence levels */
@@ -1223,7 +1223,7 @@ setup(int argc, char *argv[])
openup(stemc, dflag, vflag, ytab, ytabc);
fout = dflag?fdefine:ftable;
if(yyarg){
- Bprint(fdefine, "#define\tYYARG\t1\n\n");
+ Bprint(ftable, "#define\tYYARG\t1\n\n");
}
if((fd = mkstemp(ttempname)) >= 0){
tempname = ttempname;
You are viewing proxied material from suckless.org. The copyright of proxied material belongs to its original authors. Any comments or complaints in relation to proxied material should be directed to the original authors of the content concerned. Please see the disclaimer for more details.