minimal plan9port to cross-build Jehanne
This commit is contained in:
commit
c43269a19e
|
@ -0,0 +1 @@
|
||||||
|
*.o
|
|
@ -0,0 +1,21 @@
|
||||||
|
Copyright © 2021 Plan 9 Foundation
|
||||||
|
Portions Copyright © 2005 Russ Cox, MIT
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining
|
||||||
|
a copy of this software and associated documentation files (the
|
||||||
|
"Software"), to deal in the Software without restriction, including
|
||||||
|
without limitation the rights to use, copy, modify, merge, publish,
|
||||||
|
distribute, sublicense, and/or sell copies of the Software, and to
|
||||||
|
permit persons to whom the Software is furnished to do so, subject to
|
||||||
|
the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be
|
||||||
|
included in all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
||||||
|
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
||||||
|
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.
|
||||||
|
IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY
|
||||||
|
CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT,
|
||||||
|
TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE
|
||||||
|
SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
|
@ -0,0 +1,27 @@
|
||||||
|
A minimal plan9port fork designed just to cross-build Jehanne
|
||||||
|
=============================================================
|
||||||
|
|
||||||
|
The sole goal of these tools is to cross-build Jehanne in a way
|
||||||
|
that can be more easily ported to Jehanne itself.
|
||||||
|
|
||||||
|
|
||||||
|
Tools available
|
||||||
|
---------------
|
||||||
|
- lib
|
||||||
|
- lib9: stripped down lib9 from plan9port
|
||||||
|
uses $JEHANNE/hacking instead of $PLAN9 to not mess with
|
||||||
|
more useful plan9port installation
|
||||||
|
- bio: plan9port libbio
|
||||||
|
- yaccpar and yaccpars (parts of "yacc runtime")
|
||||||
|
|
||||||
|
- cmd
|
||||||
|
- yacc (9yacc in $JEHANNE/hacking/bin)
|
||||||
|
- rc
|
||||||
|
|
||||||
|
Commands will be installed in $JEHANNE/hacking/bin
|
||||||
|
Libraries will be installed in $JEHANNE/hacking/lib
|
||||||
|
|
||||||
|
WARNING
|
||||||
|
-------
|
||||||
|
|
||||||
|
Do not use these tools for anything else.
|
|
@ -0,0 +1,12 @@
|
||||||
|
#!/bin/sh -e
|
||||||
|
|
||||||
|
TARGET=$JEHANNE/hacking/bin/
|
||||||
|
TRAMPOLINE=$JEHANNE/hacking/src/trampoline
|
||||||
|
|
||||||
|
|
||||||
|
(cd $TRAMPOLINE/lib/lib9/ && ./lib9.sh.build)
|
||||||
|
(cd $TRAMPOLINE/lib/bio/ && ./libbio.sh.build)
|
||||||
|
(cd $TRAMPOLINE/cmd/ && \
|
||||||
|
cc yacc.c -DPLAN9PORT -I$TRAMPOLINE/include -L$JEHANNE/hacking/lib -O0 -lbio -l9 -o $TARGET/9yacc)
|
||||||
|
(cp lib/yacc* $TARGET/../lib)
|
||||||
|
(cd $TRAMPOLINE/cmd/rc/ && ./rc.sh.build)
|
|
@ -0,0 +1,496 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#define c0 t->child[0]
|
||||||
|
#define c1 t->child[1]
|
||||||
|
#define c2 t->child[2]
|
||||||
|
int codep, ncode;
|
||||||
|
#define emitf(x) ((void)(codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
|
||||||
|
#define emiti(x) ((void)(codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
|
||||||
|
#define emits(x) ((void)(codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
|
||||||
|
void stuffdot(int);
|
||||||
|
char *fnstr(tree*);
|
||||||
|
void outcode(tree*, int);
|
||||||
|
void codeswitch(tree*, int);
|
||||||
|
int iscase(tree*);
|
||||||
|
code *codecopy(code*);
|
||||||
|
void codefree(code*);
|
||||||
|
|
||||||
|
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!",
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
compile(tree *t)
|
||||||
|
{
|
||||||
|
if(flag['D']) {
|
||||||
|
struct io *s;
|
||||||
|
s = openstr();
|
||||||
|
pfmt(s, "compile: %u\n", t);
|
||||||
|
write(2, s->strp, strlen(s->strp));
|
||||||
|
closeio(s);
|
||||||
|
if(eflagok) // made it out of rcmain - stop executing commands, just print them
|
||||||
|
t = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
ncode = 100;
|
||||||
|
codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
|
||||||
|
codep = 0;
|
||||||
|
emiti(0); /* reference count */
|
||||||
|
outcode(t, flag['e']?1:0);
|
||||||
|
if(nerror){
|
||||||
|
efree((char *)codebuf);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
readhere();
|
||||||
|
emitf(Xreturn);
|
||||||
|
emitf(0);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
cleanhere(char *f)
|
||||||
|
{
|
||||||
|
emitf(Xdelhere);
|
||||||
|
emits(strdup(f));
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
fnstr(tree *t)
|
||||||
|
{
|
||||||
|
io *f = openstr();
|
||||||
|
char *v;
|
||||||
|
extern char nl;
|
||||||
|
char svnl = nl;
|
||||||
|
nl=';';
|
||||||
|
pfmt(f, "%t", t);
|
||||||
|
nl = svnl;
|
||||||
|
v = f->strp;
|
||||||
|
f->strp = 0;
|
||||||
|
closeio(f);
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
outcode(tree *t, int eflag)
|
||||||
|
{
|
||||||
|
int p, q;
|
||||||
|
tree *tt;
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
case '$':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xdol);
|
||||||
|
break;
|
||||||
|
case '"':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xqdol);
|
||||||
|
break;
|
||||||
|
case SUB:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xsub);
|
||||||
|
break;
|
||||||
|
case '&':
|
||||||
|
emitf(Xasync);
|
||||||
|
if(havefork){
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
} else
|
||||||
|
emits(fnstr(c0));
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
outcode(c0, eflag);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
break;
|
||||||
|
case '^':
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xconc);
|
||||||
|
break;
|
||||||
|
case '`':
|
||||||
|
emitf(Xbackq);
|
||||||
|
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);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case ARGLIST:
|
||||||
|
outcode(c1, eflag);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case BANG:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xbang);
|
||||||
|
break;
|
||||||
|
case PCMD:
|
||||||
|
case BRACE:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case COUNT:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xcount);
|
||||||
|
break;
|
||||||
|
case FN:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
if(c1){
|
||||||
|
emitf(Xfn);
|
||||||
|
p = emiti(0);
|
||||||
|
emits(fnstr(c1));
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xunlocal); /* get rid of $* */
|
||||||
|
emitf(Xreturn);
|
||||||
|
stuffdot(p);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
emitf(Xdelfn);
|
||||||
|
break;
|
||||||
|
case IF:
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xif);
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xwastrue);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case NOT:
|
||||||
|
if(!runq->iflast)
|
||||||
|
yyerror("`if not' does not follow `if(...)'");
|
||||||
|
emitf(Xifnot);
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case OROR:
|
||||||
|
outcode(c0, 0);
|
||||||
|
emitf(Xfalse);
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case PAREN:
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case SIMPLE:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xsimple);
|
||||||
|
if(eflag)
|
||||||
|
emitf(Xeflag);
|
||||||
|
break;
|
||||||
|
case SUBSHELL:
|
||||||
|
emitf(Xsubshell);
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
case TWIDDLE:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xmatch);
|
||||||
|
if(eflag)
|
||||||
|
emitf(Xeflag);
|
||||||
|
break;
|
||||||
|
case WHILE:
|
||||||
|
q = codep;
|
||||||
|
outcode(c0, 0);
|
||||||
|
if(q==codep)
|
||||||
|
emitf(Xsettrue); /* empty condition == while(true) */
|
||||||
|
emitf(Xtrue);
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(q);
|
||||||
|
stuffdot(p);
|
||||||
|
break;
|
||||||
|
case WORDS:
|
||||||
|
outcode(c1, eflag);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
emitf(Xmark);
|
||||||
|
if(c1){
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xglob);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
emitf(Xmark);
|
||||||
|
emitf(Xword);
|
||||||
|
emits(strdup("*"));
|
||||||
|
emitf(Xdol);
|
||||||
|
}
|
||||||
|
emitf(Xmark); /* dummy value for Xlocal */
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xlocal);
|
||||||
|
p = emitf(Xfor);
|
||||||
|
q = emiti(0);
|
||||||
|
outcode(c2, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(p);
|
||||||
|
stuffdot(q);
|
||||||
|
emitf(Xunlocal);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
emitf(Xword);
|
||||||
|
emits(strdup(t->str));
|
||||||
|
break;
|
||||||
|
case DUP:
|
||||||
|
if(t->rtype==DUPFD){
|
||||||
|
emitf(Xdup);
|
||||||
|
emiti(t->fd0);
|
||||||
|
emiti(t->fd1);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
emitf(Xclose);
|
||||||
|
emiti(t->fd0);
|
||||||
|
}
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xpopredir);
|
||||||
|
break;
|
||||||
|
case PIPEFD:
|
||||||
|
emitf(Xpipefd);
|
||||||
|
emiti(t->rtype);
|
||||||
|
if(havefork){
|
||||||
|
p = emiti(0);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xexit);
|
||||||
|
stuffdot(p);
|
||||||
|
} else {
|
||||||
|
emits(fnstr(c0));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case REDIR:
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xglob);
|
||||||
|
switch(t->rtype){
|
||||||
|
case APPEND:
|
||||||
|
emitf(Xappend);
|
||||||
|
break;
|
||||||
|
case WRITE:
|
||||||
|
emitf(Xwrite);
|
||||||
|
break;
|
||||||
|
case READ:
|
||||||
|
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);
|
||||||
|
if(t){
|
||||||
|
for(t = tt;t->type=='=';t = c2){
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xlocal);
|
||||||
|
}
|
||||||
|
outcode(t, eflag);
|
||||||
|
for(t = tt; t->type=='='; t = c2)
|
||||||
|
emitf(Xunlocal);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
for(t = tt;t;t = c2){
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c1, eflag);
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xassign);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
t = tt; /* so tests below will work */
|
||||||
|
break;
|
||||||
|
case PIPE:
|
||||||
|
emitf(Xpipe);
|
||||||
|
emiti(t->fd0);
|
||||||
|
emiti(t->fd1);
|
||||||
|
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);
|
||||||
|
emitf(Xpipewait);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(t->type!=NOT && t->type!=';')
|
||||||
|
runq->iflast = t->type==IF;
|
||||||
|
else if(c0) runq->iflast = c0->type==IF;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* switch code looks like this:
|
||||||
|
* Xmark
|
||||||
|
* (get switch value)
|
||||||
|
* Xjump 1f
|
||||||
|
* out: Xjump leave
|
||||||
|
* 1: Xmark
|
||||||
|
* (get case values)
|
||||||
|
* Xcase 1f
|
||||||
|
* (commands)
|
||||||
|
* Xjump out
|
||||||
|
* 1: Xmark
|
||||||
|
* (get case values)
|
||||||
|
* Xcase 1f
|
||||||
|
* (commands)
|
||||||
|
* Xjump out
|
||||||
|
* 1:
|
||||||
|
* leave:
|
||||||
|
* Xpopm
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
codeswitch(tree *t, int eflag)
|
||||||
|
{
|
||||||
|
int leave; /* patch jump address to leave switch */
|
||||||
|
int out; /* jump here to leave switch */
|
||||||
|
int nextcase; /* patch jump address to next case */
|
||||||
|
tree *tt;
|
||||||
|
if(c1->child[0]==nil
|
||||||
|
|| c1->child[0]->type!=';'
|
||||||
|
|| !iscase(c1->child[0]->child[0])){
|
||||||
|
yyerror("case missing in switch");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
emitf(Xmark);
|
||||||
|
outcode(c0, eflag);
|
||||||
|
emitf(Xjump);
|
||||||
|
nextcase = emiti(0);
|
||||||
|
out = emitf(Xjump);
|
||||||
|
leave = emiti(0);
|
||||||
|
stuffdot(nextcase);
|
||||||
|
t = c1->child[0];
|
||||||
|
while(t->type==';'){
|
||||||
|
tt = c1;
|
||||||
|
emitf(Xmark);
|
||||||
|
for(t = c0->child[0];t->type==ARGLIST;t = c0) outcode(c1, eflag);
|
||||||
|
emitf(Xcase);
|
||||||
|
nextcase = emiti(0);
|
||||||
|
t = tt;
|
||||||
|
for(;;){
|
||||||
|
if(t->type==';'){
|
||||||
|
if(iscase(c0)) break;
|
||||||
|
outcode(c0, eflag);
|
||||||
|
t = c1;
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(!iscase(t)) outcode(t, eflag);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
emitf(Xjump);
|
||||||
|
emiti(out);
|
||||||
|
stuffdot(nextcase);
|
||||||
|
}
|
||||||
|
stuffdot(leave);
|
||||||
|
emitf(Xpopm);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
iscase(tree *t)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
cp[0].i++;
|
||||||
|
return cp;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
codefree(code *cp)
|
||||||
|
{
|
||||||
|
code *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++;
|
||||||
|
else if(p->f==Xdup || p->f==Xpipefd) p+=2;
|
||||||
|
else if(p->f==Xpipe) p+=4;
|
||||||
|
else if(p->f==Xword || p->f==Xdelhere) efree((++p)->s);
|
||||||
|
else if(p->f==Xfn){
|
||||||
|
efree(p[2].s);
|
||||||
|
p+=2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
efree((char *)cp);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,76 @@
|
||||||
|
/*
|
||||||
|
* Definitions used in the interpreter
|
||||||
|
*/
|
||||||
|
extern void Xappend(void), Xasync(void), Xbackq(void), Xbang(void), Xclose(void);
|
||||||
|
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqdol(void), Xdup(void);
|
||||||
|
extern void Xexit(void), Xfalse(void), Xfn(void), Xfor(void), Xglob(void);
|
||||||
|
extern void Xjump(void), Xmark(void), Xmatch(void), Xpipe(void), Xread(void);
|
||||||
|
extern void Xrdwr(void);
|
||||||
|
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
|
||||||
|
extern void Xtrue(void), Xword(void), Xwrite(void), Xpipefd(void), Xcase(void);
|
||||||
|
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
|
||||||
|
extern void Xrdcmds(void), Xwastrue(void), Xif(void), Xifnot(void), Xpipewait(void);
|
||||||
|
extern void Xdelhere(void), Xpopredir(void), Xsub(void), Xeflag(void), Xsettrue(void);
|
||||||
|
extern void Xerror(char*);
|
||||||
|
extern void Xerror1(char*);
|
||||||
|
/*
|
||||||
|
* word lists are in correct order,
|
||||||
|
* i.e. word0->word1->word2->word3->0
|
||||||
|
*/
|
||||||
|
struct word{
|
||||||
|
char *word;
|
||||||
|
word *next;
|
||||||
|
};
|
||||||
|
struct list{
|
||||||
|
word *words;
|
||||||
|
list *next;
|
||||||
|
};
|
||||||
|
word *newword(char *, word *), *copywords(word *, word *);
|
||||||
|
struct redir{
|
||||||
|
char type; /* what to do */
|
||||||
|
short from, to; /* what to do it to */
|
||||||
|
struct redir *next; /* what else to do (reverse order) */
|
||||||
|
};
|
||||||
|
#define NSTATUS ERRMAX /* length of status (from plan 9) */
|
||||||
|
/*
|
||||||
|
* redir types
|
||||||
|
*/
|
||||||
|
#define ROPEN 1 /* dup2(from, to); close(from); */
|
||||||
|
#define RDUP 2 /* dup2(from, to); */
|
||||||
|
#define RCLOSE 3 /* close(from); */
|
||||||
|
struct thread{
|
||||||
|
union code *code; /* code for this thread */
|
||||||
|
int pc; /* code[pc] is the next instruction */
|
||||||
|
struct list *argv; /* argument stack */
|
||||||
|
struct redir *redir; /* redirection stack */
|
||||||
|
struct redir *startredir; /* redir inheritance point */
|
||||||
|
struct var *local; /* list of local variables */
|
||||||
|
char *cmdfile; /* file name in Xrdcmd */
|
||||||
|
struct io *cmdfd; /* file descriptor for Xrdcmd */
|
||||||
|
int iflast; /* static `if not' checking */
|
||||||
|
int eof; /* is cmdfd at eof? */
|
||||||
|
int iflag; /* interactive? */
|
||||||
|
int lineno; /* linenumber */
|
||||||
|
int pid; /* process for Xpipewait to wait for */
|
||||||
|
char status[NSTATUS]; /* status for Xpipewait */
|
||||||
|
tree *treenodes; /* tree nodes created by this process */
|
||||||
|
thread *ret; /* who continues when this finishes */
|
||||||
|
};
|
||||||
|
thread *runq;
|
||||||
|
code *codecopy(code*);
|
||||||
|
code *codebuf; /* compiler output */
|
||||||
|
int ntrap; /* number of outstanding traps */
|
||||||
|
int trap[NSIG]; /* number of outstanding traps per type */
|
||||||
|
struct builtin{
|
||||||
|
char *name;
|
||||||
|
void (*fnc)(void);
|
||||||
|
};
|
||||||
|
extern struct builtin Builtin[];
|
||||||
|
int eflagok; /* kludge flag so that -e doesn't exit in startup */
|
||||||
|
extern 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 *);
|
|
@ -0,0 +1,162 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include "fmt.h"
|
||||||
|
#include "fmtdef.h"
|
||||||
|
|
||||||
|
extern int (*doquote)(int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* How many bytes of output UTF will be produced by quoting (if necessary) this string?
|
||||||
|
* How many runes? How much of the input will be consumed?
|
||||||
|
* The parameter q is filled in by _quotesetup.
|
||||||
|
* The string may be UTF or Runes (s or r).
|
||||||
|
* Return count does not include NUL.
|
||||||
|
* Terminate the scan at the first of:
|
||||||
|
* NUL in input
|
||||||
|
* count exceeded in input
|
||||||
|
* count exceeded on output
|
||||||
|
* *ninp is set to number of input bytes accepted.
|
||||||
|
* nin may be <0 initially, to avoid checking input by count.
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
__quotesetup(char *s, int nin, int nout, Quoteinfo *q, int sharp)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
|
||||||
|
q->quoted = 0;
|
||||||
|
q->nbytesout = 0;
|
||||||
|
q->nrunesout = 0;
|
||||||
|
q->nbytesin = 0;
|
||||||
|
q->nrunesin = 0;
|
||||||
|
if(sharp || nin==0 || *s=='\0'){
|
||||||
|
if(nout < 2)
|
||||||
|
return;
|
||||||
|
q->quoted = 1;
|
||||||
|
q->nbytesout = 2;
|
||||||
|
q->nrunesout = 2;
|
||||||
|
}
|
||||||
|
for(; nin!=0; nin-=1){
|
||||||
|
c = *s;
|
||||||
|
|
||||||
|
if(c == '\0')
|
||||||
|
break;
|
||||||
|
if(q->nrunesout+1 > nout)
|
||||||
|
break;
|
||||||
|
|
||||||
|
if((c <= L' ') || (c == L'\'') || (doquote!=nil && doquote(c))){
|
||||||
|
if(!q->quoted){
|
||||||
|
if(1+q->nrunesout+1+1 > nout) /* no room for quotes */
|
||||||
|
break;
|
||||||
|
q->nrunesout += 2; /* include quotes */
|
||||||
|
q->nbytesout += 2; /* include quotes */
|
||||||
|
q->quoted = 1;
|
||||||
|
}
|
||||||
|
if(c == '\'') {
|
||||||
|
q->nbytesout++;
|
||||||
|
q->nrunesout++; /* quotes reproduce as two characters */
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* advance input */
|
||||||
|
s++;
|
||||||
|
q->nbytesin++;
|
||||||
|
q->nrunesin++;
|
||||||
|
|
||||||
|
/* advance output */
|
||||||
|
q->nbytesout++;
|
||||||
|
q->nrunesout++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
qstrfmt(char *sin, Quoteinfo *q, Fmt *f)
|
||||||
|
{
|
||||||
|
int r;
|
||||||
|
char *t, *s, *m, *me;
|
||||||
|
ulong fl;
|
||||||
|
int nc, w;
|
||||||
|
|
||||||
|
m = sin;
|
||||||
|
me = m + q->nbytesin;
|
||||||
|
|
||||||
|
w = f->width;
|
||||||
|
fl = f->flags;
|
||||||
|
if(!(fl & FmtLeft) && __fmtpad(f, w - q->nbytesout) < 0)
|
||||||
|
return -1;
|
||||||
|
t = f->to;
|
||||||
|
s = f->stop;
|
||||||
|
FMTCHAR(f, t, s, '\'');
|
||||||
|
for(nc = q->nrunesin; nc > 0; nc--){
|
||||||
|
r = *(uchar*)m++;
|
||||||
|
FMTCHAR(f, t, s, r);
|
||||||
|
if(r == '\'')
|
||||||
|
FMTCHAR(f, t, s, r);
|
||||||
|
}
|
||||||
|
|
||||||
|
FMTCHAR(f, t, s, '\'');
|
||||||
|
f->nfmt += t - (char *)f->to;
|
||||||
|
f->to = t;
|
||||||
|
if(fl & FmtLeft && __fmtpad(f, w - q->nbytesout) < 0)
|
||||||
|
return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__quotestrfmt(int runesin, Fmt *f)
|
||||||
|
{
|
||||||
|
int outlen;
|
||||||
|
char *s;
|
||||||
|
Quoteinfo q;
|
||||||
|
|
||||||
|
f->flags &= ~FmtPrec; /* ignored for %q %Q, so disable for %s %S in easy case */
|
||||||
|
s = va_arg(f->args, char *);
|
||||||
|
if(!s)
|
||||||
|
return __fmtcpy(f, "<nil>", 5, 5);
|
||||||
|
|
||||||
|
if(f->flush)
|
||||||
|
outlen = 0x7FFFFFFF; /* if we can flush, no output limit */
|
||||||
|
else
|
||||||
|
outlen = (char*)f->stop - (char*)f->to;
|
||||||
|
|
||||||
|
__quotesetup(s, -1, outlen, &q, f->flags&FmtSharp);
|
||||||
|
|
||||||
|
if(!q.quoted)
|
||||||
|
return __fmtcpy(f, s, q.nrunesin, q.nbytesin);
|
||||||
|
return qstrfmt(s, &q, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
quotestrfmt(Fmt *f)
|
||||||
|
{
|
||||||
|
return __quotestrfmt(0, f);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
quotefmtinstall(void)
|
||||||
|
{
|
||||||
|
fmtinstall('q', quotestrfmt);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
__needsquotes(char *s, int *quotelenp)
|
||||||
|
{
|
||||||
|
Quoteinfo q;
|
||||||
|
|
||||||
|
__quotesetup(s, -1, 0x7FFFFFFF, &q, 0);
|
||||||
|
*quotelenp = q.nbytesout;
|
||||||
|
|
||||||
|
return q.quoted;
|
||||||
|
}
|
|
@ -0,0 +1,68 @@
|
||||||
|
void Abort(void);
|
||||||
|
void Closedir(int);
|
||||||
|
int Creat(char*);
|
||||||
|
int Dup(int, int);
|
||||||
|
int Dup1(int);
|
||||||
|
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);
|
||||||
|
long Seek(int, long, long);
|
||||||
|
void Trapinit(void);
|
||||||
|
void Unlink(char*);
|
||||||
|
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*);
|
||||||
|
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 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);
|
||||||
|
void popword(void);
|
||||||
|
void pprompt(void);
|
||||||
|
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 skipnl(void);
|
||||||
|
void start(code*, int, var*);
|
||||||
|
int truestatus(void);
|
||||||
|
void usage(char*);
|
||||||
|
int wordchr(int);
|
||||||
|
void yyerror(char*);
|
||||||
|
int yylex(void);
|
||||||
|
int yyparse(void);
|
||||||
|
int parse(void);
|
|
@ -0,0 +1,244 @@
|
||||||
|
/*% cyntax -DTEST % && cc -DTEST -go # %
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char *flagset[] = {"<flag>"};
|
||||||
|
char **flag[NFLAG];
|
||||||
|
char cmdline[NCMDLINE+1];
|
||||||
|
char *cmdname;
|
||||||
|
static char *flagarg="";
|
||||||
|
static void reverse(char**, char**);
|
||||||
|
static int scanflag(int, char*);
|
||||||
|
static void errn(char*, int);
|
||||||
|
static void errs(char*);
|
||||||
|
static void errc(int);
|
||||||
|
static int reason;
|
||||||
|
#define RESET 1
|
||||||
|
#define FEWARGS 2
|
||||||
|
#define FLAGSYN 3
|
||||||
|
#define BADFLAG 4
|
||||||
|
static int badflag;
|
||||||
|
|
||||||
|
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++)
|
||||||
|
if(s!=&cmdline[NCMDLINE])
|
||||||
|
*s++=*t;
|
||||||
|
if(i!=argc-1 && s!=&cmdline[NCMDLINE])
|
||||||
|
*s++=' ';
|
||||||
|
}
|
||||||
|
*s='\0';
|
||||||
|
i = 1;
|
||||||
|
while(i!=argc){
|
||||||
|
if(argv[i][0]!='-' || argv[i][1]=='\0'){
|
||||||
|
if(stop)
|
||||||
|
return argc;
|
||||||
|
i++;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
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; }
|
||||||
|
if(count==0){
|
||||||
|
flag[c] = flagset;
|
||||||
|
if(*s=='\0'){
|
||||||
|
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];
|
||||||
|
--argc;
|
||||||
|
s = argv[i];
|
||||||
|
}
|
||||||
|
if(argc-i<count){
|
||||||
|
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;
|
||||||
|
s="";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return argc;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
reverse(char **p, char **q)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
for(;p<q;p++,--q){ t=*p; *p=*q; *q = t; }
|
||||||
|
}
|
||||||
|
|
||||||
|
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{
|
||||||
|
f++;
|
||||||
|
if(*f=='\0'){ reason = FLAGSYN; return -1; }
|
||||||
|
}while(*f!=']');
|
||||||
|
f++;
|
||||||
|
}
|
||||||
|
if(c==fc)
|
||||||
|
return count;
|
||||||
|
}
|
||||||
|
reason = BADFLAG;
|
||||||
|
badflag = c;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
usage(char *tail)
|
||||||
|
{
|
||||||
|
char *s, *t, c;
|
||||||
|
int count, nflag = 0;
|
||||||
|
switch(reason){
|
||||||
|
case RESET:
|
||||||
|
errs("Flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errs(": set twice\n");
|
||||||
|
break;
|
||||||
|
case FEWARGS:
|
||||||
|
errs("Flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errs(": too few arguments\n");
|
||||||
|
break;
|
||||||
|
case FLAGSYN:
|
||||||
|
errs("Bad argument to getflags!\n");
|
||||||
|
break;
|
||||||
|
case BADFLAG:
|
||||||
|
errs("Illegal flag -");
|
||||||
|
errc(badflag);
|
||||||
|
errc('\n');
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
errs("Usage: ");
|
||||||
|
errs(cmdname);
|
||||||
|
for(s = flagarg;*s;){
|
||||||
|
c=*s;
|
||||||
|
if(*s++==' ')
|
||||||
|
continue;
|
||||||
|
if(*s==':'){
|
||||||
|
s++;
|
||||||
|
count = 0;
|
||||||
|
while('0'<=*s && *s<='9') count = count*10+*s++-'0';
|
||||||
|
}
|
||||||
|
else count = 0;
|
||||||
|
if(count==0){
|
||||||
|
if(nflag==0)
|
||||||
|
errs(" [-");
|
||||||
|
nflag++;
|
||||||
|
errc(c);
|
||||||
|
}
|
||||||
|
if(*s=='['){
|
||||||
|
s++;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
if(*s==']')
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(nflag)
|
||||||
|
errs("]");
|
||||||
|
for(s = flagarg;*s;){
|
||||||
|
c=*s;
|
||||||
|
if(*s++==' ')
|
||||||
|
continue;
|
||||||
|
if(*s==':'){
|
||||||
|
s++;
|
||||||
|
count = 0;
|
||||||
|
while('0'<=*s && *s<='9') count = count*10+*s++-'0';
|
||||||
|
}
|
||||||
|
else count = 0;
|
||||||
|
if(count!=0){
|
||||||
|
errs(" [-");
|
||||||
|
errc(c);
|
||||||
|
if(*s=='['){
|
||||||
|
s++;
|
||||||
|
t = s;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
errs(" ");
|
||||||
|
errn(t, s-t);
|
||||||
|
if(*s==']')
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
while(count--) errs(" arg");
|
||||||
|
errs("]");
|
||||||
|
}
|
||||||
|
else if(*s=='['){
|
||||||
|
s++;
|
||||||
|
while(*s!=']' && *s!='\0') s++;
|
||||||
|
if(*s==']')
|
||||||
|
s++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tail){
|
||||||
|
errs(" ");
|
||||||
|
errs(tail);
|
||||||
|
}
|
||||||
|
errs("\n");
|
||||||
|
Exit("bad flags");
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
errn(char *s, int count)
|
||||||
|
{
|
||||||
|
while(count){ errc(*s++); --count; }
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
errs(char *s)
|
||||||
|
{
|
||||||
|
while(*s) errc(*s++);
|
||||||
|
}
|
||||||
|
#define NBUF 80
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,7 @@
|
||||||
|
#define NFLAG 128
|
||||||
|
#define NCMDLINE 512
|
||||||
|
extern char **flag[NFLAG];
|
||||||
|
extern char cmdline[NCMDLINE+1];
|
||||||
|
extern char *cmdname;
|
||||||
|
extern char *flagset[];
|
||||||
|
int getflags(int, char*[], char*, int);
|
|
@ -0,0 +1,267 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char *globname;
|
||||||
|
struct word *globv;
|
||||||
|
/*
|
||||||
|
* delete all the GLOB marks from s, in place
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
deglob(char *s)
|
||||||
|
{
|
||||||
|
char *t = s;
|
||||||
|
do{
|
||||||
|
if(*t==GLOB)
|
||||||
|
t++;
|
||||||
|
*s++=*t;
|
||||||
|
}while(*t++);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
globcmp(const void *s, const void *t)
|
||||||
|
{
|
||||||
|
return strcmp(*(char**)s, *(char**)t);
|
||||||
|
}
|
||||||
|
|
||||||
|
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((void *)list, n, sizeof(void *), globcmp);
|
||||||
|
for(a = left,n = 0;a!=right;a = a->next,n++) a->word = list[n];
|
||||||
|
efree((char *)list);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Push names prefixed by globname and suffixed by a match of p onto the astack.
|
||||||
|
* namep points to the end of the prefix in globname.
|
||||||
|
*/
|
||||||
|
|
||||||
|
void
|
||||||
|
globdir(char *p, char *namep)
|
||||||
|
{
|
||||||
|
char *t, *newp;
|
||||||
|
int f;
|
||||||
|
/* scan the pattern looking for a component with a metacharacter in it */
|
||||||
|
if(*p=='\0'){
|
||||||
|
globv = newword(globname, globv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
t = namep;
|
||||||
|
newp = p;
|
||||||
|
while(*newp){
|
||||||
|
if(*newp==GLOB)
|
||||||
|
break;
|
||||||
|
*t=*newp++;
|
||||||
|
if(*t++=='/'){
|
||||||
|
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);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* read the directory and recur for any entry that matches */
|
||||||
|
*namep='\0';
|
||||||
|
if((f = Opendir(globname[0]?globname:"."))<0) return;
|
||||||
|
while(*newp!='/' && *newp!='\0') newp++;
|
||||||
|
while(Readdir(f, namep, *newp=='/')){
|
||||||
|
if(matchfn(namep, p)){
|
||||||
|
for(t = namep;*t;t++);
|
||||||
|
globdir(newp, t);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
Closedir(f);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* 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)
|
||||||
|
{
|
||||||
|
word *svglobv = globv;
|
||||||
|
int globlen = Globsize(p);
|
||||||
|
if(!globlen){
|
||||||
|
deglob(p);
|
||||||
|
globv = newword(p, globv);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
globname = emalloc(globlen);
|
||||||
|
globname[0]='\0';
|
||||||
|
globdir(p, globname);
|
||||||
|
efree(globname);
|
||||||
|
if(svglobv==globv){
|
||||||
|
deglob(p);
|
||||||
|
globv = newword(p, globv);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
globsort(globv, svglobv);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Do p and q point at equal utf codes
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
equtf(char *p, char *q)
|
||||||
|
{
|
||||||
|
if(*p!=*q)
|
||||||
|
return 0;
|
||||||
|
if(twobyte(*p)) return p[1]==q[1];
|
||||||
|
if(threebyte(*p)){
|
||||||
|
if(p[1]!=q[1])
|
||||||
|
return 0;
|
||||||
|
if(p[1]=='\0')
|
||||||
|
return 1; /* broken code at end of string! */
|
||||||
|
return p[2]==q[2];
|
||||||
|
}
|
||||||
|
if(fourbyte(*p)){
|
||||||
|
if(p[1]!=q[1])
|
||||||
|
return 0;
|
||||||
|
if(p[1]=='\0')
|
||||||
|
return 1;
|
||||||
|
if(p[2]!=q[2])
|
||||||
|
return 0;
|
||||||
|
if(p[2]=='\0')
|
||||||
|
return 1;
|
||||||
|
return p[3]==q[3];
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Return a pointer to the next utf code in the string,
|
||||||
|
* not jumping past nuls in broken utf codes!
|
||||||
|
*/
|
||||||
|
|
||||||
|
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;
|
||||||
|
if(fourbyte(*p)) return p[1]=='\0'?p+1:p[2]=='\0'?p+2:p[3]=='\0'?p+3:p+4;
|
||||||
|
return p+1;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Convert the utf code at *p to a unicode value
|
||||||
|
*/
|
||||||
|
|
||||||
|
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);
|
||||||
|
if(fourbyte(u)) return (u<<18)|((p[1]&0x3f)<<12)|((p[2]&0x3f)<<6)|(p[3]&0x3f);
|
||||||
|
return u;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Does the string s match the pattern p
|
||||||
|
* . and .. are only matched by patterns starting with .
|
||||||
|
* * matches any sequence of characters
|
||||||
|
* ? matches any single character
|
||||||
|
* [...] matches the enclosed list of characters
|
||||||
|
*/
|
||||||
|
|
||||||
|
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 compl, hit, lo, hi, t, c;
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
case '*':
|
||||||
|
for(;;){
|
||||||
|
if(match(s, nextutf(p), stop)) return 1;
|
||||||
|
if(!*s)
|
||||||
|
break;
|
||||||
|
s = nextutf(s);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
case '?':
|
||||||
|
if(*s=='\0')
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
if(*s=='\0')
|
||||||
|
return 0;
|
||||||
|
c = unicode(s);
|
||||||
|
p++;
|
||||||
|
compl=*p=='~';
|
||||||
|
if(compl)
|
||||||
|
p++;
|
||||||
|
hit = 0;
|
||||||
|
while(*p!=']'){
|
||||||
|
if(*p=='\0')
|
||||||
|
return 0; /* syntax error */
|
||||||
|
lo = unicode(p);
|
||||||
|
p = nextutf(p);
|
||||||
|
if(*p!='-')
|
||||||
|
hi = lo;
|
||||||
|
else{
|
||||||
|
p++;
|
||||||
|
if(*p=='\0')
|
||||||
|
return 0; /* syntax error */
|
||||||
|
hi = unicode(p);
|
||||||
|
p = nextutf(p);
|
||||||
|
if(hi<lo){ t = lo; lo = hi; hi = t; }
|
||||||
|
}
|
||||||
|
if(lo<=c && c<=hi)
|
||||||
|
hit = 1;
|
||||||
|
}
|
||||||
|
if(compl)
|
||||||
|
hit=!hit;
|
||||||
|
if(!hit)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return *s=='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
globlist1(word *gl)
|
||||||
|
{
|
||||||
|
if(gl){
|
||||||
|
globlist1(gl->next);
|
||||||
|
glob(gl->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
globlist(void)
|
||||||
|
{
|
||||||
|
word *a;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,298 @@
|
||||||
|
#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"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int havefork = 1;
|
||||||
|
|
||||||
|
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:
|
||||||
|
clearwaitpids();
|
||||||
|
/*
|
||||||
|
* 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:
|
||||||
|
addwaitpid(pid);
|
||||||
|
close(null);
|
||||||
|
runq->pc = runq->code[runq->pc].i;
|
||||||
|
inttoascii(npid, pid);
|
||||||
|
setvar("apid", newword(npid, (word *)0));
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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:
|
||||||
|
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);
|
||||||
|
p->pc = p->code[pc+1].i;
|
||||||
|
p->pid = forkid;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Who should wait for the exit from the fork?
|
||||||
|
*/
|
||||||
|
void
|
||||||
|
Xbackq(void)
|
||||||
|
{
|
||||||
|
struct thread *p = runq;
|
||||||
|
char wd[8193];
|
||||||
|
int c, n;
|
||||||
|
char *s, *ewd=&wd[8192], *stop, *q;
|
||||||
|
struct io *f;
|
||||||
|
var *ifs = vlook("ifs");
|
||||||
|
word *v, *nextv;
|
||||||
|
int pfd[2];
|
||||||
|
int pid;
|
||||||
|
Rune r;
|
||||||
|
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:
|
||||||
|
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;
|
||||||
|
v = 0;
|
||||||
|
while((c = rchr(f))!=EOF){
|
||||||
|
if(s != ewd) {
|
||||||
|
*s++ = c;
|
||||||
|
for(q=stop; *q; q+=n) {
|
||||||
|
n = chartorune(&r, q);
|
||||||
|
if(s-wd >= n && memcmp(s-n, q, n) == 0) {
|
||||||
|
s -= n;
|
||||||
|
goto stop;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
stop:
|
||||||
|
if(s != wd) {
|
||||||
|
*s = '\0';
|
||||||
|
v = newword(wd, v);
|
||||||
|
}
|
||||||
|
s = wd;
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
p->pc = p->code[p->pc].i;
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xpipefd(void)
|
||||||
|
{
|
||||||
|
struct thread *p = runq;
|
||||||
|
int pc = p->pc, pid;
|
||||||
|
char name[40];
|
||||||
|
int pfd[2];
|
||||||
|
struct { int sidefd, mainfd; } fd[2], *r, *w;
|
||||||
|
|
||||||
|
r = &fd[0];
|
||||||
|
w = &fd[1];
|
||||||
|
switch(p->code[pc].i){
|
||||||
|
case READ:
|
||||||
|
w = nil;
|
||||||
|
break;
|
||||||
|
case WRITE:
|
||||||
|
r = nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(r){
|
||||||
|
if(pipe(pfd)<0){
|
||||||
|
Xerror("can't get pipe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
r->sidefd = pfd[PWR];
|
||||||
|
r->mainfd = pfd[PRD];
|
||||||
|
}
|
||||||
|
if(w){
|
||||||
|
if(pipe(pfd)<0){
|
||||||
|
Xerror("can't get pipe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
w->sidefd = pfd[PRD];
|
||||||
|
w->mainfd = pfd[PWR];
|
||||||
|
}
|
||||||
|
switch(pid = fork()){
|
||||||
|
case -1:
|
||||||
|
Xerror("try again");
|
||||||
|
break;
|
||||||
|
case 0:
|
||||||
|
clearwaitpids();
|
||||||
|
start(p->code, pc+2, runq->local);
|
||||||
|
if(r){
|
||||||
|
close(r->mainfd);
|
||||||
|
pushredir(ROPEN, r->sidefd, 1);
|
||||||
|
}
|
||||||
|
if(w){
|
||||||
|
close(w->mainfd);
|
||||||
|
pushredir(ROPEN, w->sidefd, 0);
|
||||||
|
}
|
||||||
|
runq->ret = 0;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
addwaitpid(pid);
|
||||||
|
if(w){
|
||||||
|
close(w->sidefd);
|
||||||
|
pushredir(ROPEN, w->mainfd, w->mainfd); /* so that Xpopredir can close it later */
|
||||||
|
strcpy(name, Fdprefix);
|
||||||
|
inttoascii(name+strlen(name), w->mainfd);
|
||||||
|
pushword(name);
|
||||||
|
}
|
||||||
|
if(r){
|
||||||
|
close(r->sidefd);
|
||||||
|
pushredir(ROPEN, r->mainfd, r->mainfd);
|
||||||
|
strcpy(name, Fdprefix);
|
||||||
|
inttoascii(name+strlen(name), r->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:
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
execforkexec(void)
|
||||||
|
{
|
||||||
|
int pid;
|
||||||
|
int n;
|
||||||
|
char buf[ERRMAX];
|
||||||
|
|
||||||
|
switch(pid = fork()){
|
||||||
|
case -1:
|
||||||
|
return -1;
|
||||||
|
case 0:
|
||||||
|
clearwaitpids();
|
||||||
|
pushword("exec");
|
||||||
|
execexec();
|
||||||
|
strcpy(buf, "can't exec: ");
|
||||||
|
n = strlen(buf);
|
||||||
|
errstr(buf+n, ERRMAX-n);
|
||||||
|
Exit(buf);
|
||||||
|
}
|
||||||
|
addwaitpid(pid);
|
||||||
|
return pid;
|
||||||
|
}
|
|
@ -0,0 +1,211 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int havefork = 0;
|
||||||
|
|
||||||
|
static char **
|
||||||
|
rcargv(char *s)
|
||||||
|
{
|
||||||
|
int argc;
|
||||||
|
char **argv;
|
||||||
|
word *p;
|
||||||
|
|
||||||
|
p = vlook("*")->val;
|
||||||
|
argv = malloc((count(p)+6)*sizeof(char*));
|
||||||
|
argc = 0;
|
||||||
|
argv[argc++] = argv0;
|
||||||
|
if(flag['e'])
|
||||||
|
argv[argc++] = "-Se";
|
||||||
|
else
|
||||||
|
argv[argc++] = "-S";
|
||||||
|
argv[argc++] = "-c";
|
||||||
|
argv[argc++] = s;
|
||||||
|
for(p = vlook("*")->val; p; p = p->next)
|
||||||
|
argv[argc++] = p->word;
|
||||||
|
argv[argc] = 0;
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xasync(void)
|
||||||
|
{
|
||||||
|
uint pid;
|
||||||
|
char buf[20], **argv;
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
runq->pc++;
|
||||||
|
sprint(buf, "%d", pid);
|
||||||
|
setvar("apid", newword(buf, (word *)0));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xbackq(void)
|
||||||
|
{
|
||||||
|
char wd[8193], **argv;
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, pfd[1], 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
close(pfd[1]);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
close(pfd[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
f = openfd(pfd[0]);
|
||||||
|
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, 1);
|
||||||
|
/* 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++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xpipe(void)
|
||||||
|
{
|
||||||
|
thread *p=runq;
|
||||||
|
int pc=p->pc, pid;
|
||||||
|
int rfd=p->code[pc+1].i;
|
||||||
|
int pfd[2];
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
if(pipe(pfd)<0){
|
||||||
|
Xerror1("can't get pipe");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[pc+2].s);
|
||||||
|
pid = ForkExecute(argv0, argv, 0, pfd[1], 2);
|
||||||
|
free(argv);
|
||||||
|
close(pfd[1]);
|
||||||
|
|
||||||
|
if(pid == 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
close(pfd[0]);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
start(p->code, pc+4, runq->local);
|
||||||
|
pushredir(ROPEN, pfd[0], rfd);
|
||||||
|
p->pc=p->code[pc+3].i;
|
||||||
|
p->pid=pid;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xpipefd(void)
|
||||||
|
{
|
||||||
|
Abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xsubshell(void)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
Updenv();
|
||||||
|
|
||||||
|
argv = rcargv(runq->code[runq->pc].s);
|
||||||
|
pid = ForkExecute(argv0, argv, -1, 1, 2);
|
||||||
|
free(argv);
|
||||||
|
|
||||||
|
if(pid < 0) {
|
||||||
|
Xerror("proc failed");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
Waitfor(pid, 1);
|
||||||
|
runq->pc++;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* start a process running the cmd on the stack and return its pid.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
execforkexec(void)
|
||||||
|
{
|
||||||
|
char **argv;
|
||||||
|
char file[1024];
|
||||||
|
int nc;
|
||||||
|
word *path;
|
||||||
|
int pid;
|
||||||
|
|
||||||
|
if(runq->argv->words==0)
|
||||||
|
return -1;
|
||||||
|
argv = mkargv(runq->argv->words);
|
||||||
|
|
||||||
|
for(path = searchpath(runq->argv->words->word);path;path = path->next){
|
||||||
|
nc = strlen(path->word);
|
||||||
|
if(nc<sizeof(file)){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]){
|
||||||
|
strcat(file, "/");
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
if(nc+strlen(argv[1])<sizeof(file)){
|
||||||
|
strcat(file, argv[1]);
|
||||||
|
pid = ForkExecute(file, argv+1, mapfd(0), mapfd(1), mapfd(2));
|
||||||
|
if(pid >= 0){
|
||||||
|
free(argv);
|
||||||
|
return pid;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(argv);
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,150 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
struct here *here, **ehere;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
*p++=hex[(n>>12)&0xF];
|
||||||
|
*p++=hex[(n>>8)&0xF];
|
||||||
|
*p++=hex[(n>>4)&0xF];
|
||||||
|
*p = hex[n&0xF];
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
heredoc(tree *tag)
|
||||||
|
{
|
||||||
|
struct here *h = new(struct here);
|
||||||
|
if(tag->type!=WORD)
|
||||||
|
yyerror("Bad here tag");
|
||||||
|
h->next = 0;
|
||||||
|
if(here)
|
||||||
|
*ehere = h;
|
||||||
|
else
|
||||||
|
here = h;
|
||||||
|
ehere=&h->next;
|
||||||
|
h->tag = tag;
|
||||||
|
hexnum(&tmp[9], getpid());
|
||||||
|
hexnum(&tmp[14], ser++);
|
||||||
|
h->name = strdup(tmp);
|
||||||
|
return token(tmp, WORD);
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* bug: lines longer than NLINE get split -- this can cause spurious
|
||||||
|
* missubstitution, or a misrecognized EOF marker.
|
||||||
|
*/
|
||||||
|
#define NLINE 4096
|
||||||
|
|
||||||
|
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){
|
||||||
|
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;
|
||||||
|
pprompt();
|
||||||
|
while((c = rchr(runq->cmdfd))!=EOF){
|
||||||
|
if(c=='\n' || s==&line[NLINE]){
|
||||||
|
*s='\0';
|
||||||
|
if(tag && strcmp(line, tag)==0) break;
|
||||||
|
if(subst)
|
||||||
|
psubst(f, line);
|
||||||
|
else pstr(f, line);
|
||||||
|
s = line;
|
||||||
|
if(c=='\n'){
|
||||||
|
pprompt();
|
||||||
|
pchr(f, c);
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
|
}
|
||||||
|
else *s++=c;
|
||||||
|
}
|
||||||
|
flush(f);
|
||||||
|
closeio(f);
|
||||||
|
cleanhere(h->name);
|
||||||
|
nexth = h->next;
|
||||||
|
efree((char *)h);
|
||||||
|
}
|
||||||
|
here = 0;
|
||||||
|
doprompt = 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
psubst(io *f, char *s)
|
||||||
|
{
|
||||||
|
char *t, *u;
|
||||||
|
int savec, n;
|
||||||
|
word *star;
|
||||||
|
while(*s){
|
||||||
|
if(*s!='$'){
|
||||||
|
if(0xa0<=(*s&0xff) && (*s&0xff)<=0xf5){
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
else if(0xf6<=(*s&0xff) && (*s&0xff)<=0xf7){
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0')
|
||||||
|
break;
|
||||||
|
pchr(f, *s++);
|
||||||
|
if(*s=='\0')
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pchr(f, *s++);
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
t=++s;
|
||||||
|
if(*t=='$')
|
||||||
|
pchr(f, *t++);
|
||||||
|
else{
|
||||||
|
while(*t && idchr(*t)) t++;
|
||||||
|
savec=*t;
|
||||||
|
*t='\0';
|
||||||
|
n = 0;
|
||||||
|
for(u = s;*u && '0'<=*u && *u<='9';u++) n = n*10+*u-'0';
|
||||||
|
if(n && *u=='\0'){
|
||||||
|
star = vlook("*")->val;
|
||||||
|
if(star && 1<=n && n<=count(star)){
|
||||||
|
while(--n) star = star->next;
|
||||||
|
pstr(f, star->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pstrs(f, vlook(s)->val);
|
||||||
|
*t = savec;
|
||||||
|
if(savec=='^')
|
||||||
|
t++;
|
||||||
|
}
|
||||||
|
s = t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pstrs(io *f, word *a)
|
||||||
|
{
|
||||||
|
if(a){
|
||||||
|
while(a->next && a->next->word){
|
||||||
|
pstr(f, a->word);
|
||||||
|
pchr(f, ' ');
|
||||||
|
a = a->next;
|
||||||
|
}
|
||||||
|
pstr(f, a->word);
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,273 @@
|
||||||
|
#include <limits.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
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);
|
||||||
|
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':
|
||||||
|
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, tree *));
|
||||||
|
break;
|
||||||
|
case 'u':
|
||||||
|
pcmdu(f, va_arg(ap, 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);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pchr(io *b, int c)
|
||||||
|
{
|
||||||
|
if(b->bufp==b->ebuf)
|
||||||
|
fullbuf(b, c);
|
||||||
|
else *b->bufp++=c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
rchr(io *b)
|
||||||
|
{
|
||||||
|
if(b->bufp==b->ebuf)
|
||||||
|
return emptybuf(b);
|
||||||
|
return *b->bufp++ & 0xFF;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pquo(io *f, char *s)
|
||||||
|
{
|
||||||
|
pchr(f, '\'');
|
||||||
|
for(;*s;s++)
|
||||||
|
if(*s=='\'')
|
||||||
|
pfmt(f, "''");
|
||||||
|
else pchr(f, *s);
|
||||||
|
pchr(f, '\'');
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pwrd(io *f, char *s)
|
||||||
|
{
|
||||||
|
char *t;
|
||||||
|
for(t = s;*t;t++) if(!wordchr(*t)) break;
|
||||||
|
if(t==s || *t)
|
||||||
|
pquo(f, s);
|
||||||
|
else pstr(f, s);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pptr(io *f, void *v)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
if(s==0)
|
||||||
|
s="(null)";
|
||||||
|
while(*s) pchr(f, *s++);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pdec(io *f, int n)
|
||||||
|
{
|
||||||
|
if(n<0){
|
||||||
|
if(n!=INT_MIN){
|
||||||
|
pchr(f, '-');
|
||||||
|
pdec(f, -n);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* n is two's complement minimum integer */
|
||||||
|
n = -(INT_MIN+1);
|
||||||
|
pchr(f, '-');
|
||||||
|
pdec(f, n/10);
|
||||||
|
pchr(f, n%10+'1');
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(n>9)
|
||||||
|
pdec(f, n/10);
|
||||||
|
pchr(f, n%10+'0');
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
poct(io *f, unsigned n)
|
||||||
|
{
|
||||||
|
if(n>7)
|
||||||
|
poct(f, n>>3);
|
||||||
|
pchr(f, (n&7)+'0');
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pval(io *f, word *a)
|
||||||
|
{
|
||||||
|
if(a){
|
||||||
|
while(a->next && a->next->word){
|
||||||
|
pwrd(f, a->word);
|
||||||
|
pchr(f, ' ');
|
||||||
|
a = a->next;
|
||||||
|
}
|
||||||
|
pwrd(f, a->word);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
fullbuf(io *f, int c)
|
||||||
|
{
|
||||||
|
flush(f);
|
||||||
|
return *f->bufp++=c;
|
||||||
|
}
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
n = f->bufp-f->buf;
|
||||||
|
if(n && Write(f->fd, f->buf, n) < 0){
|
||||||
|
Write(3, "Write error\n", 12);
|
||||||
|
if(ntrap)
|
||||||
|
dotrap();
|
||||||
|
}
|
||||||
|
f->bufp = f->buf;
|
||||||
|
f->ebuf = f->buf+NBUF;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
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';
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Open a corebuffer to read. EOF occurs after reading len
|
||||||
|
* characters from buf.
|
||||||
|
*/
|
||||||
|
|
||||||
|
io*
|
||||||
|
opencore(char *s, int 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;
|
||||||
|
Memcpy(buf, s, len);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
iorewind(io *io)
|
||||||
|
{
|
||||||
|
if(io->fd==-1)
|
||||||
|
io->bufp = io->strp;
|
||||||
|
else{
|
||||||
|
io->bufp = io->ebuf = io->buf;
|
||||||
|
Seek(io->fd, 0L, 0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
closeio(io *io)
|
||||||
|
{
|
||||||
|
if(io->fd>=0)
|
||||||
|
close(io->fd);
|
||||||
|
if(io->strp)
|
||||||
|
efree(io->strp);
|
||||||
|
efree((char *)io);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
emptybuf(io *f)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
if(f->fd==-1)
|
||||||
|
return EOF;
|
||||||
|
Loop:
|
||||||
|
errno = 0;
|
||||||
|
n = Read(f->fd, f->buf, NBUF);
|
||||||
|
if(n < 0 && errno == EINTR)
|
||||||
|
goto Loop;
|
||||||
|
if(n <= 0)
|
||||||
|
return EOF;
|
||||||
|
f->bufp = f->buf;
|
||||||
|
f->ebuf = f->buf+n;
|
||||||
|
return *f->bufp++&0xff;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
/*
|
||||||
|
* on Mac OS X, err is something else,
|
||||||
|
* and assigning to it causes a bus error.
|
||||||
|
* what a crappy linker.
|
||||||
|
*/
|
||||||
|
#define err rc_err
|
||||||
|
#define EOF (-1)
|
||||||
|
#define NBUF 512
|
||||||
|
struct io{
|
||||||
|
int fd;
|
||||||
|
char *bufp, *ebuf, *strp, buf[NBUF];
|
||||||
|
};
|
||||||
|
io *err;
|
||||||
|
io *openfd(int), *openstr(void), *opencore(char *, int);
|
||||||
|
int emptybuf(io*);
|
||||||
|
void pchr(io*, int);
|
||||||
|
int rchr(io*);
|
||||||
|
void closeio(io*);
|
||||||
|
void flush(io*);
|
||||||
|
int fullbuf(io*, int);
|
||||||
|
void pdec(io*, int);
|
||||||
|
void poct(io*, unsigned);
|
||||||
|
void pptr(io*, void*);
|
||||||
|
void pquo(io*, char*);
|
||||||
|
void pwrd(io*, char*);
|
||||||
|
void pstr(io*, char*);
|
||||||
|
void pcmd(io*, tree*);
|
||||||
|
void pcmdu(io*, tree*);
|
||||||
|
void pval(io*, word*);
|
||||||
|
void pfnc(io*, thread*);
|
||||||
|
void pfmt(io*, char*, ...);
|
|
@ -0,0 +1,396 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "fns.h"
|
||||||
|
int getnext(void);
|
||||||
|
|
||||||
|
int
|
||||||
|
wordchr(int c)
|
||||||
|
{
|
||||||
|
return !strchr("\n \t#;&|^$=`'{}()<>", c) && c!=EOF;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
idchr(int c)
|
||||||
|
{
|
||||||
|
/*
|
||||||
|
* Formerly:
|
||||||
|
* return 'a'<=c && c<='z' || 'A'<=c && c<='Z' || '0'<=c && c<='9'
|
||||||
|
* || c=='_' || c=='*';
|
||||||
|
*/
|
||||||
|
return c>' ' && !strchr("!\"#$%&'()+,-./:;<=>?@[\\]^`{|}~", c);
|
||||||
|
}
|
||||||
|
int future = EOF;
|
||||||
|
int doprompt = 1;
|
||||||
|
int inquote;
|
||||||
|
int incomm;
|
||||||
|
/*
|
||||||
|
* Look ahead in the input stream
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
nextc(void)
|
||||||
|
{
|
||||||
|
if(future==EOF)
|
||||||
|
future = getnext();
|
||||||
|
return future;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* Consume the lookahead character.
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
advance(void)
|
||||||
|
{
|
||||||
|
int c = nextc();
|
||||||
|
lastc = future;
|
||||||
|
future = EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* read a character from the input stream
|
||||||
|
*/
|
||||||
|
|
||||||
|
int
|
||||||
|
getnext(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
static int peekc = EOF;
|
||||||
|
if(peekc!=EOF){
|
||||||
|
c = peekc;
|
||||||
|
peekc = EOF;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
if(runq->eof)
|
||||||
|
return EOF;
|
||||||
|
if(doprompt)
|
||||||
|
pprompt();
|
||||||
|
c = rchr(runq->cmdfd);
|
||||||
|
if(!inquote && c=='\\'){
|
||||||
|
c = rchr(runq->cmdfd);
|
||||||
|
if(c=='\n' && !incomm){ /* don't continue a comment */
|
||||||
|
doprompt = 1;
|
||||||
|
c=' ';
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
peekc = c;
|
||||||
|
c='\\';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
var *prompt;
|
||||||
|
if(runq->iflag){
|
||||||
|
pstr(err, promptstr);
|
||||||
|
flush(err);
|
||||||
|
prompt = vlook("prompt");
|
||||||
|
if(prompt->val && prompt->val->next)
|
||||||
|
promptstr = prompt->val->next->word;
|
||||||
|
else
|
||||||
|
promptstr="\t";
|
||||||
|
}
|
||||||
|
runq->lineno++;
|
||||||
|
doprompt = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
skipwhite(void)
|
||||||
|
{
|
||||||
|
int c, skipped;
|
||||||
|
skipped = 0;
|
||||||
|
for(;;){
|
||||||
|
c = nextc();
|
||||||
|
/* Why did this used to be if(!inquote && c=='#') ?? */
|
||||||
|
if(c=='#'){
|
||||||
|
incomm = 1;
|
||||||
|
skipped = 1;
|
||||||
|
for(;;){
|
||||||
|
c = nextc();
|
||||||
|
if(c=='\n' || c==EOF) {
|
||||||
|
incomm = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c==' ' || c=='\t') {
|
||||||
|
skipped = 1;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
else
|
||||||
|
return skipped;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
skipnl(void)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
for(;;){
|
||||||
|
skipwhite();
|
||||||
|
c = nextc();
|
||||||
|
if(c!='\n')
|
||||||
|
return;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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-1]){
|
||||||
|
*p = 0;
|
||||||
|
yyerror("token buffer too short");
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
*p++=val;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
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());
|
||||||
|
return addtok(p, advance());
|
||||||
|
}
|
||||||
|
if(fourbyte(c)){ /* 4-byte escape */
|
||||||
|
p = addtok(p, advance());
|
||||||
|
p = addtok(p, advance());
|
||||||
|
return addtok(p, advance());
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
int lastdol; /* was the last token read '$' or '$#' or '"'? */
|
||||||
|
int lastword; /* was the last token read a word or compound word terminator? */
|
||||||
|
|
||||||
|
int
|
||||||
|
yylex(void)
|
||||||
|
{
|
||||||
|
int c, d = nextc();
|
||||||
|
char *w = tok;
|
||||||
|
tree *t;
|
||||||
|
yylval.tree = 0;
|
||||||
|
/*
|
||||||
|
* Embarassing sneakiness: if the last token read was a quoted or unquoted
|
||||||
|
* WORD then we alter the meaning of what follows. If the next character
|
||||||
|
* is `(', we return SUB (a subscript paren) and consume the `('. Otherwise,
|
||||||
|
* if the next character is the first character of a simple or compound word,
|
||||||
|
* we insert a `^' before it.
|
||||||
|
*/
|
||||||
|
if(lastword && flag['Y']){
|
||||||
|
lastword = 0;
|
||||||
|
if(d=='('){
|
||||||
|
advance();
|
||||||
|
strcpy(tok, "(");
|
||||||
|
return SUB;
|
||||||
|
}
|
||||||
|
if(wordchr(d) || d=='\'' || d=='`' || d=='$' || d=='"'){
|
||||||
|
strcpy(tok, "^");
|
||||||
|
return '^';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
inquote = 0;
|
||||||
|
if(skipwhite() && !flag['Y'])
|
||||||
|
return ' ';
|
||||||
|
switch(c = advance()){
|
||||||
|
case EOF:
|
||||||
|
lastdol = 0;
|
||||||
|
strcpy(tok, "EOF");
|
||||||
|
return EOF;
|
||||||
|
case '$':
|
||||||
|
lastdol = 1;
|
||||||
|
if(nextis('#')){
|
||||||
|
strcpy(tok, "$#");
|
||||||
|
return COUNT;
|
||||||
|
}
|
||||||
|
if(nextis('"')){
|
||||||
|
strcpy(tok, "$\"");
|
||||||
|
return '"';
|
||||||
|
}
|
||||||
|
strcpy(tok, "$");
|
||||||
|
return '$';
|
||||||
|
case '&':
|
||||||
|
lastdol = 0;
|
||||||
|
if(nextis('&')){
|
||||||
|
if(flag['Y'])
|
||||||
|
skipnl();
|
||||||
|
strcpy(tok, "&&");
|
||||||
|
return ANDAND;
|
||||||
|
}
|
||||||
|
strcpy(tok, "&");
|
||||||
|
return '&';
|
||||||
|
case '|':
|
||||||
|
lastdol = 0;
|
||||||
|
if(nextis(c)){
|
||||||
|
if(flag['Y'])
|
||||||
|
skipnl();
|
||||||
|
strcpy(tok, "||");
|
||||||
|
return OROR;
|
||||||
|
}
|
||||||
|
case '<':
|
||||||
|
case '>':
|
||||||
|
lastdol = 0;
|
||||||
|
/*
|
||||||
|
* funny redirection tokens:
|
||||||
|
* redir: arrow | arrow '[' fd ']'
|
||||||
|
* arrow: '<' | '<<' | '>' | '>>' | '|'
|
||||||
|
* fd: digit | digit '=' | digit '=' digit
|
||||||
|
* digit: '0'|'1'|'2'|'3'|'4'|'5'|'6'|'7'|'8'|'9'
|
||||||
|
* some possibilities are nonsensical and get a message.
|
||||||
|
*/
|
||||||
|
*w++=c;
|
||||||
|
t = newtree();
|
||||||
|
switch(c){
|
||||||
|
case '|':
|
||||||
|
t->type = PIPE;
|
||||||
|
t->fd0 = 1;
|
||||||
|
t->fd1 = 0;
|
||||||
|
break;
|
||||||
|
case '>':
|
||||||
|
t->type = REDIR;
|
||||||
|
if(nextis(c)){
|
||||||
|
t->rtype = APPEND;
|
||||||
|
*w++=c;
|
||||||
|
}
|
||||||
|
else t->rtype = WRITE;
|
||||||
|
t->fd0 = 1;
|
||||||
|
break;
|
||||||
|
case '<':
|
||||||
|
t->type = REDIR;
|
||||||
|
if(nextis(c)){
|
||||||
|
t->rtype = HERE;
|
||||||
|
*w++=c;
|
||||||
|
} else if (nextis('>')){
|
||||||
|
t->rtype = RDWR;
|
||||||
|
*w++=c;
|
||||||
|
} else t->rtype = READ;
|
||||||
|
t->fd0 = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(nextis('[')){
|
||||||
|
*w++='[';
|
||||||
|
c = advance();
|
||||||
|
*w++=c;
|
||||||
|
if(c<'0' || '9'<c){
|
||||||
|
RedirErr:
|
||||||
|
*w = 0;
|
||||||
|
yyerror(t->type==PIPE?"pipe syntax"
|
||||||
|
:"redirection syntax");
|
||||||
|
return EOF;
|
||||||
|
}
|
||||||
|
t->fd0 = 0;
|
||||||
|
do{
|
||||||
|
t->fd0 = t->fd0*10+c-'0';
|
||||||
|
*w++=c;
|
||||||
|
c = advance();
|
||||||
|
}while('0'<=c && c<='9');
|
||||||
|
if(c=='='){
|
||||||
|
*w++='=';
|
||||||
|
if(t->type==REDIR)
|
||||||
|
t->type = DUP;
|
||||||
|
c = advance();
|
||||||
|
if('0'<=c && c<='9'){
|
||||||
|
t->rtype = DUPFD;
|
||||||
|
t->fd1 = t->fd0;
|
||||||
|
t->fd0 = 0;
|
||||||
|
do{
|
||||||
|
t->fd0 = t->fd0*10+c-'0';
|
||||||
|
*w++=c;
|
||||||
|
c = advance();
|
||||||
|
}while('0'<=c && c<='9');
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
if(t->type==PIPE)
|
||||||
|
goto RedirErr;
|
||||||
|
t->rtype = CLOSE;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(c!=']'
|
||||||
|
|| t->type==DUP && (t->rtype==HERE || t->rtype==APPEND))
|
||||||
|
goto RedirErr;
|
||||||
|
*w++=']';
|
||||||
|
}
|
||||||
|
*w='\0';
|
||||||
|
yylval.tree = t;
|
||||||
|
if(t->type==PIPE && flag['Y'])
|
||||||
|
skipnl();
|
||||||
|
if(t->type==REDIR) {
|
||||||
|
skipwhite();
|
||||||
|
if(nextc() == '{')
|
||||||
|
t->type = REDIRW;
|
||||||
|
}
|
||||||
|
return t->type;
|
||||||
|
case '\'':
|
||||||
|
lastdol = 0;
|
||||||
|
lastword = 1;
|
||||||
|
inquote = 1;
|
||||||
|
for(;;){
|
||||||
|
c = advance();
|
||||||
|
if(c==EOF)
|
||||||
|
break;
|
||||||
|
if(c=='\''){
|
||||||
|
if(nextc()!='\'')
|
||||||
|
break;
|
||||||
|
advance();
|
||||||
|
}
|
||||||
|
w = addutf(w, c);
|
||||||
|
}
|
||||||
|
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;
|
||||||
|
tok[1]='\0';
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
for(;;){
|
||||||
|
/* next line should have (char)c==GLOB, but ken's compiler is broken */
|
||||||
|
if(c=='*' || c=='[' || c=='?' || c==(unsigned char)GLOB)
|
||||||
|
w = addtok(w, GLOB);
|
||||||
|
w = addutf(w, c);
|
||||||
|
c = nextc();
|
||||||
|
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;
|
||||||
|
return t->type;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
TARG=rc
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
code.$O\
|
||||||
|
exec.$O\
|
||||||
|
getflags.$O\
|
||||||
|
glob.$O\
|
||||||
|
here.$O\
|
||||||
|
io.$O\
|
||||||
|
lex.$O\
|
||||||
|
parse.$O\
|
||||||
|
pcmd.$O\
|
||||||
|
pfnc.$O\
|
||||||
|
simple.$O\
|
||||||
|
subr.$O\
|
||||||
|
trap.$O\
|
||||||
|
tree.$O\
|
||||||
|
unixcrap.$O\
|
||||||
|
var.$O\
|
||||||
|
y.tab.$O\
|
||||||
|
plan9ish.$O\
|
||||||
|
havefork.$O\
|
||||||
|
|
||||||
|
HFILES=\
|
||||||
|
rc.h\
|
||||||
|
x.tab.h\
|
||||||
|
io.h\
|
||||||
|
exec.h\
|
||||||
|
fns.h\
|
||||||
|
|
||||||
|
YFILES=syn.y
|
||||||
|
|
||||||
|
<$PLAN9/src/mkone
|
||||||
|
|
||||||
|
x.tab.h: y.tab.h
|
||||||
|
cmp -s x.tab.h y.tab.h || cp y.tab.h x.tab.h
|
|
@ -0,0 +1,552 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
static tree* body(int tok, int *ptok);
|
||||||
|
static tree* brace(int tok);
|
||||||
|
static tree* cmd(int tok, int *ptok);
|
||||||
|
static tree* cmd2(int tok, int *ptok);
|
||||||
|
static tree* cmd3(int tok, int *ptok);
|
||||||
|
static tree* cmds(int tok, int *ptok, int nlok);
|
||||||
|
static tree* epilog(int tok, int *ptok);
|
||||||
|
static int iswordtok(int tok);
|
||||||
|
static tree* line(int tok, int *ptok);
|
||||||
|
static tree* paren(int tok);
|
||||||
|
static tree* yyredir(int tok, int *ptok);
|
||||||
|
static tree* yyword(int tok, int *ptok, int eqok);
|
||||||
|
static tree* word1(int tok, int *ptok);
|
||||||
|
static tree* words(int tok, int *ptok);
|
||||||
|
|
||||||
|
static jmp_buf yyjmp;
|
||||||
|
|
||||||
|
static int
|
||||||
|
dropnl(int tok)
|
||||||
|
{
|
||||||
|
while(tok == ' ' || tok == '\n')
|
||||||
|
tok = yylex();
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
dropsp(int tok)
|
||||||
|
{
|
||||||
|
while(tok == ' ')
|
||||||
|
tok = yylex();
|
||||||
|
return tok;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
syntax(int tok)
|
||||||
|
{
|
||||||
|
USED(tok);
|
||||||
|
yyerror("syntax error");
|
||||||
|
longjmp(yyjmp, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
parse(void)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
int tok;
|
||||||
|
|
||||||
|
if(setjmp(yyjmp))
|
||||||
|
return 1;
|
||||||
|
|
||||||
|
// rc: { return 1;}
|
||||||
|
// | line '\n' {return !compile($1);}
|
||||||
|
|
||||||
|
tok = dropsp(yylex());
|
||||||
|
if(tok == EOF)
|
||||||
|
return 1;
|
||||||
|
t = line(tok, &tok);
|
||||||
|
if(tok != '\n')
|
||||||
|
yyerror("missing newline at end of line");
|
||||||
|
yylval.tree = t;
|
||||||
|
return !compile(t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
line(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
return cmds(tok, ptok, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
body(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
return cmds(tok, ptok, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
cmds(int tok, int *ptok, int nlok)
|
||||||
|
{
|
||||||
|
tree *t, **last, *t2;
|
||||||
|
|
||||||
|
// line: cmd
|
||||||
|
// | cmdsa line {$$=tree2(';', $1, $2);}
|
||||||
|
// cmdsa: cmd ';'
|
||||||
|
// | cmd '&' {$$=tree1('&', $1);}
|
||||||
|
|
||||||
|
// body: cmd
|
||||||
|
// | cmdsan body {$$=tree2(';', $1, $2);}
|
||||||
|
// cmdsan: cmdsa
|
||||||
|
// | cmd '\n'
|
||||||
|
|
||||||
|
t = nil;
|
||||||
|
last = nil;
|
||||||
|
for(;;) {
|
||||||
|
t2 = cmd(tok, &tok);
|
||||||
|
if(tok == '&')
|
||||||
|
t2 = tree1('&', t2);
|
||||||
|
if(t2 != nil) {
|
||||||
|
// slot into list t
|
||||||
|
if(last == nil) {
|
||||||
|
t = t2;
|
||||||
|
last = &t;
|
||||||
|
} else {
|
||||||
|
*last = tree2(';', *last, t2);
|
||||||
|
last = &(*last)->child[1];
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(tok != ';' && tok != '&' && (!nlok || tok != '\n'))
|
||||||
|
break;
|
||||||
|
tok = yylex();
|
||||||
|
}
|
||||||
|
*ptok = tok;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
brace(int tok)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
|
||||||
|
// brace: '{' body '}' {$$=tree1(BRACE, $2);}
|
||||||
|
|
||||||
|
tok = dropsp(tok);
|
||||||
|
if(tok != '{')
|
||||||
|
syntax(tok);
|
||||||
|
t = body(yylex(), &tok);
|
||||||
|
if(tok != '}')
|
||||||
|
syntax(tok);
|
||||||
|
return tree1(BRACE, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
paren(int tok)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
|
||||||
|
// paren: '(' body ')' {$$=tree1(PCMD, $2);}
|
||||||
|
|
||||||
|
tok = dropsp(tok);
|
||||||
|
if(tok != '(')
|
||||||
|
syntax(tok);
|
||||||
|
t = body(yylex(), &tok);
|
||||||
|
if(tok != ')')
|
||||||
|
syntax(tok);
|
||||||
|
return tree1(PCMD, t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
epilog(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *t, *r;
|
||||||
|
|
||||||
|
// epilog: {$$=0;}
|
||||||
|
// | redir epilog {$$=mung2($1, $1->child[0], $2);}
|
||||||
|
|
||||||
|
if(tok != REDIR && tok != DUP) {
|
||||||
|
*ptok = tok;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
r = yyredir(tok, &tok);
|
||||||
|
t = epilog(tok, &tok);
|
||||||
|
*ptok = tok;
|
||||||
|
return mung2(r, r->child[0], t);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
yyredir(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *r, *w;
|
||||||
|
|
||||||
|
// redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
|
||||||
|
// | DUP
|
||||||
|
|
||||||
|
switch(tok) {
|
||||||
|
default:
|
||||||
|
syntax(tok);
|
||||||
|
case DUP:
|
||||||
|
r = yylval.tree;
|
||||||
|
*ptok = dropsp(yylex());
|
||||||
|
break;
|
||||||
|
case REDIR:
|
||||||
|
r = yylval.tree;
|
||||||
|
w = yyword(yylex(), &tok, 1);
|
||||||
|
*ptok = dropsp(tok);
|
||||||
|
r = mung1(r, r->rtype==HERE?heredoc(w):w);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return r;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
cmd(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
int op;
|
||||||
|
tree *t1, *t2;
|
||||||
|
|
||||||
|
// | cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
|
||||||
|
// | cmd OROR cmd {$$=tree2(OROR, $1, $3);}
|
||||||
|
|
||||||
|
tok = dropsp(tok);
|
||||||
|
t1 = cmd2(tok, &tok);
|
||||||
|
while(tok == ANDAND || tok == OROR) {
|
||||||
|
op = tok;
|
||||||
|
t2 = cmd2(dropnl(yylex()), &tok);
|
||||||
|
t1 = tree2(op, t1, t2);
|
||||||
|
}
|
||||||
|
*ptok = tok;
|
||||||
|
return t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
cmd2(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *t1, *t2, *t3;
|
||||||
|
|
||||||
|
// | cmd PIPE cmd {$$=mung2($2, $1, $3);}
|
||||||
|
t1 = cmd3(tok, &tok);
|
||||||
|
while(tok == PIPE) {
|
||||||
|
t2 = yylval.tree;
|
||||||
|
t3 = cmd3(dropnl(yylex()), &tok);
|
||||||
|
t1 = mung2(t2, t1, t3);
|
||||||
|
}
|
||||||
|
*ptok = tok;
|
||||||
|
return t1;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
cmd3(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *t1, *t2, *t3, *t4;
|
||||||
|
|
||||||
|
tok = dropsp(tok);
|
||||||
|
switch(tok) {
|
||||||
|
case ';':
|
||||||
|
case '&':
|
||||||
|
case '\n':
|
||||||
|
*ptok = tok;
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
case IF:
|
||||||
|
// | IF paren {skipnl();} cmd {$$=mung2($1, $2, $4);}
|
||||||
|
// | IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
|
||||||
|
t1 = yylval.tree;
|
||||||
|
tok = dropsp(yylex());
|
||||||
|
if(tok == NOT) {
|
||||||
|
t1 = yylval.tree;
|
||||||
|
t2 = cmd(dropnl(yylex()), ptok);
|
||||||
|
return mung1(t1, t2);
|
||||||
|
}
|
||||||
|
t2 = paren(tok);
|
||||||
|
t3 = cmd(dropnl(yylex()), ptok);
|
||||||
|
return mung2(t1, t2, t3);
|
||||||
|
|
||||||
|
case FOR:
|
||||||
|
// | FOR '(' word IN words ')' {skipnl();} cmd
|
||||||
|
// {$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
|
||||||
|
// | FOR '(' word ')' {skipnl();} cmd
|
||||||
|
// {$$=mung3($1, $3, (tree *)0, $6);}
|
||||||
|
t1 = yylval.tree;
|
||||||
|
tok = dropsp(yylex());
|
||||||
|
if(tok != '(')
|
||||||
|
syntax(tok);
|
||||||
|
t2 = yyword(yylex(), &tok, 1);
|
||||||
|
switch(tok) {
|
||||||
|
default:
|
||||||
|
syntax(tok);
|
||||||
|
case ')':
|
||||||
|
t3 = nil;
|
||||||
|
break;
|
||||||
|
case IN:
|
||||||
|
t3 = words(yylex(), &tok);
|
||||||
|
if(t3 == nil)
|
||||||
|
t3 = tree1(PAREN, nil);
|
||||||
|
if(tok != ')')
|
||||||
|
syntax(tok);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
t4 = cmd(dropnl(yylex()), ptok);
|
||||||
|
return mung3(t1, t2, t3, t4);
|
||||||
|
|
||||||
|
case WHILE:
|
||||||
|
// | WHILE paren {skipnl();} cmd
|
||||||
|
// {$$=mung2($1, $2, $4);}
|
||||||
|
t1 = yylval.tree;
|
||||||
|
t2 = paren(yylex());
|
||||||
|
t3 = cmd(dropnl(yylex()), ptok);
|
||||||
|
return mung2(t1, t2, t3);
|
||||||
|
|
||||||
|
case SWITCH:
|
||||||
|
// | SWITCH word {skipnl();} brace
|
||||||
|
// {$$=tree2(SWITCH, $2, $4);}
|
||||||
|
t1 = yyword(yylex(), &tok, 1);
|
||||||
|
tok = dropnl(tok); // doesn't work in yacc grammar but works here!
|
||||||
|
t2 = brace(tok);
|
||||||
|
*ptok = dropsp(yylex());
|
||||||
|
return tree2(SWITCH, t1, t2);
|
||||||
|
// Note: cmd: a && for(x) y && b is a && {for (x) {y && b}}.
|
||||||
|
return cmd(tok, ptok);
|
||||||
|
|
||||||
|
case FN:
|
||||||
|
// | FN words brace {$$=tree2(FN, $2, $3);}
|
||||||
|
// | FN words {$$=tree1(FN, $2);}
|
||||||
|
t1 = words(yylex(), &tok);
|
||||||
|
if(tok != '{') {
|
||||||
|
*ptok = tok;
|
||||||
|
return tree1(FN, t1);
|
||||||
|
}
|
||||||
|
t2 = brace(tok);
|
||||||
|
*ptok = dropsp(yylex());
|
||||||
|
return tree2(FN, t1, t2);
|
||||||
|
|
||||||
|
case TWIDDLE:
|
||||||
|
// | TWIDDLE word words {$$=mung2($1, $2, $3);}
|
||||||
|
t1 = yylval.tree;
|
||||||
|
t2 = yyword(yylex(), &tok, 1);
|
||||||
|
t3 = words(tok, ptok);
|
||||||
|
return mung2(t1, t2, t3);
|
||||||
|
|
||||||
|
case BANG:
|
||||||
|
case SUBSHELL:
|
||||||
|
// | BANG cmd {$$=mung1($1, $2);}
|
||||||
|
// | SUBSHELL cmd {$$=mung1($1, $2);}
|
||||||
|
// Note: cmd2: ! x | y is !{x | y} not {!x} | y.
|
||||||
|
t1 = yylval.tree;
|
||||||
|
return mung1(t1, cmd2(yylex(), ptok));
|
||||||
|
|
||||||
|
case REDIR:
|
||||||
|
case DUP:
|
||||||
|
// | redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
|
||||||
|
// Note: cmd2: {>x echo a | tr a-z A-Z} writes A to x.
|
||||||
|
t1 = yyredir(tok, &tok);
|
||||||
|
t2 = cmd2(tok, ptok);
|
||||||
|
return mung2(t1, t1->child[0], t2);
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
// | brace epilog {$$=epimung($1, $2);}
|
||||||
|
t1 = brace(tok);
|
||||||
|
tok = dropsp(yylex());
|
||||||
|
t2 = epilog(tok, ptok);
|
||||||
|
return epimung(t1, t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(!iswordtok(tok)) {
|
||||||
|
*ptok = tok;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
|
||||||
|
// cmd: ...
|
||||||
|
// | simple {$$=simplemung($1);}
|
||||||
|
// | assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
|
||||||
|
// assign: first '=' word {$$=tree2('=', $1, $3);}
|
||||||
|
// Note: first is same as word except for disallowing all the leading keywords,
|
||||||
|
// but all those keywords have been picked off in the switch above.
|
||||||
|
// Except NOT, but disallowing that in yacc was likely a mistake anyway:
|
||||||
|
// there's no ambiguity in not=1 or not x y z.
|
||||||
|
t1 = yyword(tok, &tok, 0);
|
||||||
|
if(tok == '=') {
|
||||||
|
// assignment
|
||||||
|
// Note: cmd2: {x=1 true | echo $x} echoes 1.
|
||||||
|
t1 = tree2('=', t1, yyword(yylex(), &tok, 1));
|
||||||
|
t2 = cmd2(tok, ptok);
|
||||||
|
return mung3(t1, t1->child[0], t1->child[1], t2);
|
||||||
|
}
|
||||||
|
|
||||||
|
// simple: first
|
||||||
|
// | simple word {$$=tree2(ARGLIST, $1, $2);}
|
||||||
|
// | simple redir {$$=tree2(ARGLIST, $1, $2);}
|
||||||
|
for(;;) {
|
||||||
|
if(tok == REDIR || tok == DUP) {
|
||||||
|
t1 = tree2(ARGLIST, t1, yyredir(tok, &tok));
|
||||||
|
} else if(iswordtok(tok)) {
|
||||||
|
t1 = tree2(ARGLIST, t1, yyword(tok, &tok, 1));
|
||||||
|
} else {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ptok = tok;
|
||||||
|
return simplemung(t1);
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
words(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
|
||||||
|
// words: {$$=(tree*)0;}
|
||||||
|
// | words word {$$=tree2(WORDS, $1, $2);}
|
||||||
|
|
||||||
|
t = nil;
|
||||||
|
tok = dropsp(tok);
|
||||||
|
while(iswordtok(tok))
|
||||||
|
t = tree2(WORDS, t, yyword(tok, &tok, 1));
|
||||||
|
*ptok = tok;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
yyword(int tok, int *ptok, int eqok)
|
||||||
|
{
|
||||||
|
tree *t;
|
||||||
|
|
||||||
|
// word: keyword {lastword=1; $1->type=WORD;}
|
||||||
|
// | comword
|
||||||
|
// | word '^' word {$$=tree2('^', $1, $3);}
|
||||||
|
// comword: '$' word {$$=tree1('$', $2);}
|
||||||
|
// | '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
|
||||||
|
// | '"' word {$$=tree1('"', $2);}
|
||||||
|
// | COUNT word {$$=tree1(COUNT, $2);}
|
||||||
|
// | WORD
|
||||||
|
// | '`' brace {$$=tree1('`', $2);}
|
||||||
|
// | '(' words ')' {$$=tree1(PAREN, $2);}
|
||||||
|
// | REDIR brace {$$=mung1($1, $2); $$->type=PIPEFD;}
|
||||||
|
// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
|
||||||
|
//
|
||||||
|
// factored into:
|
||||||
|
//
|
||||||
|
// word: word1
|
||||||
|
// | word '^' word1
|
||||||
|
//
|
||||||
|
// word1: keyword | comword
|
||||||
|
|
||||||
|
t = word1(tok, &tok);
|
||||||
|
if(tok == '=' && !eqok)
|
||||||
|
goto out;
|
||||||
|
for(;;) {
|
||||||
|
if(iswordtok(tok)) {
|
||||||
|
// No free carats around parens.
|
||||||
|
if(t->type == PAREN || tok == '(')
|
||||||
|
syntax(tok);
|
||||||
|
t = tree2('^', t, word1(tok, &tok));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
tok = dropsp(tok);
|
||||||
|
if(tok == '^') {
|
||||||
|
t = tree2('^', t, word1(yylex(), &tok));
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
out:
|
||||||
|
*ptok = dropsp(tok);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
static tree*
|
||||||
|
word1(int tok, int *ptok)
|
||||||
|
{
|
||||||
|
tree *w, *sub, *t;
|
||||||
|
|
||||||
|
tok = dropsp(tok);
|
||||||
|
switch(tok) {
|
||||||
|
default:
|
||||||
|
syntax(tok);
|
||||||
|
|
||||||
|
case WORD:
|
||||||
|
case FOR:
|
||||||
|
case IN:
|
||||||
|
case WHILE:
|
||||||
|
case IF:
|
||||||
|
case NOT:
|
||||||
|
case TWIDDLE:
|
||||||
|
case BANG:
|
||||||
|
case SUBSHELL:
|
||||||
|
case SWITCH:
|
||||||
|
case FN:
|
||||||
|
// | WORD
|
||||||
|
// keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
|
||||||
|
t = yylval.tree;
|
||||||
|
t->type = WORD;
|
||||||
|
*ptok = yylex();
|
||||||
|
return t;
|
||||||
|
|
||||||
|
case '=':
|
||||||
|
*ptok = yylex();
|
||||||
|
return token("=", WORD);
|
||||||
|
|
||||||
|
case '$':
|
||||||
|
// comword: '$' word1 {$$=tree1('$', $2);}
|
||||||
|
// | '$' word1 SUB words ')' {$$=tree2(SUB, $2, $4);}
|
||||||
|
w = word1(yylex(), &tok);
|
||||||
|
if(tok == '(') {
|
||||||
|
sub = words(yylex(), &tok);
|
||||||
|
if(tok != ')')
|
||||||
|
syntax(tok);
|
||||||
|
*ptok = yylex();
|
||||||
|
return tree2(SUB, w, sub);
|
||||||
|
}
|
||||||
|
*ptok = tok;
|
||||||
|
return tree1('$', w);
|
||||||
|
|
||||||
|
case '"':
|
||||||
|
// | '"' word1 {$$=tree1('"', $2);}
|
||||||
|
return tree1('"', word1(yylex(), ptok));
|
||||||
|
|
||||||
|
case COUNT:
|
||||||
|
// | COUNT word1 {$$=tree1(COUNT, $2);}
|
||||||
|
return tree1(COUNT, word1(yylex(), ptok));
|
||||||
|
|
||||||
|
case '`':
|
||||||
|
// | '`' brace {$$=tree1('`', $2);}
|
||||||
|
t = tree1('`', brace(yylex()));
|
||||||
|
*ptok = yylex();
|
||||||
|
return t;
|
||||||
|
|
||||||
|
case '(':
|
||||||
|
// | '(' words ')' {$$=tree1(PAREN, $2);}
|
||||||
|
t = tree1(PAREN, words(yylex(), &tok));
|
||||||
|
if(tok != ')')
|
||||||
|
syntax(tok);
|
||||||
|
*ptok = yylex();
|
||||||
|
return t;
|
||||||
|
|
||||||
|
case REDIRW:
|
||||||
|
// | REDIRW brace {$$=mung1($1, $2); $$->type=PIPEFD;}
|
||||||
|
t = yylval.tree;
|
||||||
|
t = mung1(t, brace(yylex()));
|
||||||
|
t->type = PIPEFD;
|
||||||
|
*ptok = yylex();
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
iswordtok(int tok)
|
||||||
|
{
|
||||||
|
switch(tok) {
|
||||||
|
case FOR:
|
||||||
|
case IN:
|
||||||
|
case WHILE:
|
||||||
|
case IF:
|
||||||
|
case NOT:
|
||||||
|
case TWIDDLE:
|
||||||
|
case BANG:
|
||||||
|
case SUBSHELL:
|
||||||
|
case SWITCH:
|
||||||
|
case FN:
|
||||||
|
case '$':
|
||||||
|
case '"':
|
||||||
|
case COUNT:
|
||||||
|
case WORD:
|
||||||
|
case '`':
|
||||||
|
case '(':
|
||||||
|
case REDIRW:
|
||||||
|
case '=':
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,265 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
char nl='\n'; /* change to semicolon for bourne-proofing */
|
||||||
|
#define c0 t->child[0]
|
||||||
|
#define c1 t->child[1]
|
||||||
|
#define c2 t->child[2]
|
||||||
|
|
||||||
|
void
|
||||||
|
pdeglob(io *f, char *s)
|
||||||
|
{
|
||||||
|
while(*s){
|
||||||
|
if(*s==GLOB)
|
||||||
|
s++;
|
||||||
|
pchr(f, *s++);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pcmd(io *f, tree *t)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
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 ARGLIST:
|
||||||
|
if(c0==0)
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
else if(c1==0)
|
||||||
|
pfmt(f, "%t", c0);
|
||||||
|
else
|
||||||
|
pfmt(f, "%t %t", c0, c1);
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
if(c0){
|
||||||
|
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);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
pfmt(f, "for(%t", c0);
|
||||||
|
if(c1)
|
||||||
|
pfmt(f, " in %t", c1);
|
||||||
|
pfmt(f, ")%t", c2);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
if(t->quoted)
|
||||||
|
pfmt(f, "%Q", t->str);
|
||||||
|
else pdeglob(f, t->str);
|
||||||
|
break;
|
||||||
|
case DUP:
|
||||||
|
if(t->rtype==DUPFD)
|
||||||
|
pfmt(f, ">[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
|
||||||
|
else
|
||||||
|
pfmt(f, ">[%d=]", t->fd0);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
case PIPEFD:
|
||||||
|
case REDIR:
|
||||||
|
switch(t->rtype){
|
||||||
|
case HERE:
|
||||||
|
pchr(f, '<');
|
||||||
|
case READ:
|
||||||
|
case RDWR:
|
||||||
|
pchr(f, '<');
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
pfmt(f, "%t", c0);
|
||||||
|
if(c1)
|
||||||
|
pfmt(f, " %t", c1);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
pfmt(f, "%t=%t", c0, c1);
|
||||||
|
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);
|
||||||
|
}
|
||||||
|
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
|
||||||
|
pfmt(f, "%t", c1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pcmdu(io *f, tree *t) /* unambiguous */
|
||||||
|
{
|
||||||
|
if(t==0) {
|
||||||
|
pfmt(f, "<nil>");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
switch(t->type){
|
||||||
|
default: pfmt(f, "(bad %d %p %p %p)", t->type, c0, c1, c2);
|
||||||
|
break;
|
||||||
|
case '$': pfmt(f, "($ %u)", c0);
|
||||||
|
break;
|
||||||
|
case '"': pfmt(f, "($\" %u)", c0);
|
||||||
|
break;
|
||||||
|
case '&': pfmt(f, "(& %u)", c0);
|
||||||
|
break;
|
||||||
|
case '^': pfmt(f, "(^ %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case '`': pfmt(f, "(` %u)", c0);
|
||||||
|
break;
|
||||||
|
case ANDAND: pfmt(f, "(&& %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case BANG: pfmt(f, "(! %u)", c0);
|
||||||
|
break;
|
||||||
|
case BRACE: pfmt(f, "(brace %u)", c0);
|
||||||
|
break;
|
||||||
|
case COUNT: pfmt(f, "($# %u)", c0);
|
||||||
|
break;
|
||||||
|
case FN: pfmt(f, "(fn %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case IF: pfmt(f, "(if %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case NOT: pfmt(f, "(if not %u)", c0);
|
||||||
|
break;
|
||||||
|
case OROR: pfmt(f, "(|| %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case PCMD:
|
||||||
|
case PAREN: pfmt(f, "(paren %u)", c0);
|
||||||
|
break;
|
||||||
|
case SUB: pfmt(f, "($sub %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case SIMPLE: pfmt(f, "(simple %u)", c0);
|
||||||
|
break;
|
||||||
|
case SUBSHELL: pfmt(f, "(@ %u)", c0);
|
||||||
|
break;
|
||||||
|
case SWITCH: pfmt(f, "(switch %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case TWIDDLE: pfmt(f, "(~ %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case WHILE: pfmt(f, "(while %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case ARGLIST:
|
||||||
|
pfmt(f, "(arglist %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case ';':
|
||||||
|
pfmt(f, "(; %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case WORDS:
|
||||||
|
pfmt(f, "(words %u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case FOR:
|
||||||
|
pfmt(f, "(for %u %u %u)", c0, c1, c2);
|
||||||
|
break;
|
||||||
|
case WORD:
|
||||||
|
if(t->quoted)
|
||||||
|
pfmt(f, "%Q", t->str);
|
||||||
|
else pdeglob(f, t->str);
|
||||||
|
break;
|
||||||
|
case DUP:
|
||||||
|
if(t->rtype==DUPFD)
|
||||||
|
pfmt(f, "(>[%d=%d]", t->fd1, t->fd0); /* yes, fd1, then fd0; read lex.c */
|
||||||
|
else
|
||||||
|
pfmt(f, "(>[%d=]", t->fd0); /*)*/
|
||||||
|
pfmt(f, " %u)", c1);
|
||||||
|
break;
|
||||||
|
case PIPEFD:
|
||||||
|
case REDIR:
|
||||||
|
pfmt(f, "(");
|
||||||
|
switch(t->rtype){
|
||||||
|
case HERE:
|
||||||
|
pchr(f, '<');
|
||||||
|
case READ:
|
||||||
|
case RDWR:
|
||||||
|
pchr(f, '<');
|
||||||
|
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);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(t->rtype == HERE)
|
||||||
|
pfmt(f, "HERE %u)", c1);
|
||||||
|
else
|
||||||
|
pfmt(f, "%u %u)", c0, c1);
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
pfmt(f, "(%u=%u %u)", c0, c1, c2);
|
||||||
|
break;
|
||||||
|
case PIPE:
|
||||||
|
pfmt(f, "(|");
|
||||||
|
if(t->fd1==0){
|
||||||
|
if(t->fd0!=1)
|
||||||
|
pfmt(f, "[%d]", t->fd0);
|
||||||
|
}
|
||||||
|
else pfmt(f, "[%d=%d]", t->fd0, t->fd1);
|
||||||
|
pfmt(f, " %u %u", c0, c1);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,71 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
struct{
|
||||||
|
void (*f)(void);
|
||||||
|
char *name;
|
||||||
|
}fname[] = {
|
||||||
|
Xappend, "Xappend",
|
||||||
|
Xasync, "Xasync",
|
||||||
|
Xbang, "Xbang",
|
||||||
|
Xclose, "Xclose",
|
||||||
|
Xdup, "Xdup",
|
||||||
|
Xeflag, "Xeflag",
|
||||||
|
Xexit, "Xexit",
|
||||||
|
Xfalse, "Xfalse",
|
||||||
|
Xifnot, "Xifnot",
|
||||||
|
Xjump, "Xjump",
|
||||||
|
Xmark, "Xmark",
|
||||||
|
Xpopm, "Xpopm",
|
||||||
|
Xrdwr, "Xrdwr",
|
||||||
|
Xread, "Xread",
|
||||||
|
Xreturn, "Xreturn",
|
||||||
|
Xtrue, "Xtrue",
|
||||||
|
Xif, "Xif",
|
||||||
|
Xwastrue, "Xwastrue",
|
||||||
|
Xword, "Xword",
|
||||||
|
Xwrite, "Xwrite",
|
||||||
|
Xmatch, "Xmatch",
|
||||||
|
Xcase, "Xcase",
|
||||||
|
Xconc, "Xconc",
|
||||||
|
Xassign, "Xassign",
|
||||||
|
Xdol, "Xdol",
|
||||||
|
Xcount, "Xcount",
|
||||||
|
Xlocal, "Xlocal",
|
||||||
|
Xunlocal, "Xunlocal",
|
||||||
|
Xfn, "Xfn",
|
||||||
|
Xdelfn, "Xdelfn",
|
||||||
|
Xpipe, "Xpipe",
|
||||||
|
Xpipewait, "Xpipewait",
|
||||||
|
Xrdcmds, "Xrdcmds",
|
||||||
|
(void (*)(void))Xerror, "Xerror",
|
||||||
|
Xbackq, "Xbackq",
|
||||||
|
Xpipefd, "Xpipefd",
|
||||||
|
Xsubshell, "Xsubshell",
|
||||||
|
Xdelhere, "Xdelhere",
|
||||||
|
Xfor, "Xfor",
|
||||||
|
Xglob, "Xglob",
|
||||||
|
Xrdfn, "Xrdfn",
|
||||||
|
Xsimple, "Xsimple",
|
||||||
|
Xrdfn, "Xrdfn",
|
||||||
|
Xqdol, "Xqdol",
|
||||||
|
0};
|
||||||
|
|
||||||
|
void
|
||||||
|
pfnc(io *fd, thread *t)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
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){
|
||||||
|
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);
|
||||||
|
pchr(fd, '\n');
|
||||||
|
flush(fd);
|
||||||
|
}
|
|
@ -0,0 +1,604 @@
|
||||||
|
/*
|
||||||
|
* Plan 9 versions of system-specific functions
|
||||||
|
* By convention, exported routines herein have names beginning with an
|
||||||
|
* upper case letter.
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
char *Signame[]={
|
||||||
|
"sigexit", "sighup", "sigint", "sigquit",
|
||||||
|
"sigalrm", "sigkill", "sigfpe", "sigterm",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
char *syssigname[]={
|
||||||
|
"exit", /* can't happen */
|
||||||
|
"hangup",
|
||||||
|
"interrupt",
|
||||||
|
"quit", /* can't happen */
|
||||||
|
"alarm",
|
||||||
|
"kill",
|
||||||
|
"sys: fp: ",
|
||||||
|
"term",
|
||||||
|
0
|
||||||
|
};
|
||||||
|
char*
|
||||||
|
Rcmain(void)
|
||||||
|
{
|
||||||
|
return unsharp("#9/rcmain");
|
||||||
|
}
|
||||||
|
|
||||||
|
char Fdprefix[]="/dev/fd/";
|
||||||
|
long readnb(int, char *, long);
|
||||||
|
void execfinit(void);
|
||||||
|
void execbind(void);
|
||||||
|
void execmount(void);
|
||||||
|
void execulimit(void);
|
||||||
|
void execumask(void);
|
||||||
|
void execrfork(void);
|
||||||
|
builtin Builtin[]={
|
||||||
|
"cd", execcd,
|
||||||
|
"whatis", execwhatis,
|
||||||
|
"eval", execeval,
|
||||||
|
"exec", execexec, /* but with popword first */
|
||||||
|
"exit", execexit,
|
||||||
|
"shift", execshift,
|
||||||
|
"wait", execwait,
|
||||||
|
".", execdot,
|
||||||
|
"finit", execfinit,
|
||||||
|
"flag", execflag,
|
||||||
|
"ulimit", execulimit,
|
||||||
|
"umask", execumask,
|
||||||
|
"rfork", execrfork,
|
||||||
|
0
|
||||||
|
};
|
||||||
|
|
||||||
|
void
|
||||||
|
execrfork(void)
|
||||||
|
{
|
||||||
|
int arg;
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
case 1:
|
||||||
|
arg = RFENVG|RFNOTEG|RFNAMEG;
|
||||||
|
break;
|
||||||
|
case 2:
|
||||||
|
arg = 0;
|
||||||
|
for(s = runq->argv->words->next->word;*s;s++) switch(*s){
|
||||||
|
default:
|
||||||
|
goto Usage;
|
||||||
|
case 'n':
|
||||||
|
arg|=RFNAMEG; break;
|
||||||
|
case 'N':
|
||||||
|
arg|=RFCNAMEG;
|
||||||
|
break;
|
||||||
|
case 'e':
|
||||||
|
/* arg|=RFENVG; */ break;
|
||||||
|
case 'E':
|
||||||
|
arg|=RFCENVG; break;
|
||||||
|
case 's':
|
||||||
|
arg|=RFNOTEG; break;
|
||||||
|
case 'f':
|
||||||
|
arg|=RFFDG; break;
|
||||||
|
case 'F':
|
||||||
|
arg|=RFCFDG; break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
Usage:
|
||||||
|
pfmt(err, "Usage: %s [nNeEsfF]\n", runq->argv->words->word);
|
||||||
|
setstatus("rfork usage");
|
||||||
|
poplist();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(rfork(arg)==-1){
|
||||||
|
pfmt(err, "rc: %s failed\n", runq->argv->words->word);
|
||||||
|
setstatus("rfork failed");
|
||||||
|
}
|
||||||
|
else
|
||||||
|
setstatus("");
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
#define SEP '\1'
|
||||||
|
char **environp;
|
||||||
|
struct word *enval(s)
|
||||||
|
register char *s;
|
||||||
|
{
|
||||||
|
register char *t, c;
|
||||||
|
register struct word *v;
|
||||||
|
for(t=s;*t && *t!=SEP;t++);
|
||||||
|
c=*t;
|
||||||
|
*t='\0';
|
||||||
|
v=newword(s, c=='\0'?(struct word *)0:enval(t+1));
|
||||||
|
*t=c;
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
void Vinit(void){
|
||||||
|
extern char **environ;
|
||||||
|
register char *s;
|
||||||
|
register char **env=environ;
|
||||||
|
environp=env;
|
||||||
|
for(;*env;env++){
|
||||||
|
for(s=*env;*s && *s!='(' && *s!='=';s++);
|
||||||
|
switch(*s){
|
||||||
|
case '\0':
|
||||||
|
/* pfmt(err, "rc: odd environment %q?\n", *env); */
|
||||||
|
break;
|
||||||
|
case '=':
|
||||||
|
*s='\0';
|
||||||
|
setvar(*env, enval(s+1));
|
||||||
|
*s='=';
|
||||||
|
break;
|
||||||
|
case '(': /* ignore functions for now */
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
char **envp;
|
||||||
|
void Xrdfn(void){
|
||||||
|
char *p;
|
||||||
|
register char *s;
|
||||||
|
register int len;
|
||||||
|
for(;*envp;envp++){
|
||||||
|
s = *envp;
|
||||||
|
if(strncmp(s, "fn#", 3) == 0){
|
||||||
|
p = strchr(s, '=');
|
||||||
|
if(p == nil)
|
||||||
|
continue;
|
||||||
|
*p = ' ';
|
||||||
|
s[2] = ' ';
|
||||||
|
len = strlen(s);
|
||||||
|
execcmds(opencore(s, len));
|
||||||
|
s[len] = '\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#if 0
|
||||||
|
for(s=*envp;*s && *s!='(' && *s!='=';s++);
|
||||||
|
switch(*s){
|
||||||
|
case '\0':
|
||||||
|
pfmt(err, "environment %q?\n", *envp);
|
||||||
|
break;
|
||||||
|
case '=': /* ignore variables */
|
||||||
|
break;
|
||||||
|
case '(': /* Bourne again */
|
||||||
|
s=*envp+3;
|
||||||
|
envp++;
|
||||||
|
len=strlen(s);
|
||||||
|
s[len]='\n';
|
||||||
|
execcmds(opencore(s, len+1));
|
||||||
|
s[len]='\0';
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
Xreturn();
|
||||||
|
}
|
||||||
|
union code rdfns[4];
|
||||||
|
void execfinit(void){
|
||||||
|
static int first=1;
|
||||||
|
if(first){
|
||||||
|
rdfns[0].i=1;
|
||||||
|
rdfns[1].f=Xrdfn;
|
||||||
|
rdfns[2].f=Xjump;
|
||||||
|
rdfns[3].i=1;
|
||||||
|
first=0;
|
||||||
|
}
|
||||||
|
Xpopm();
|
||||||
|
envp=environp;
|
||||||
|
start(rdfns, 1, runq->local);
|
||||||
|
}
|
||||||
|
extern int mapfd(int);
|
||||||
|
int Waitfor(int pid, int unused0){
|
||||||
|
thread *p;
|
||||||
|
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);
|
||||||
|
setstatus(w->msg);
|
||||||
|
free(w);
|
||||||
|
return 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){
|
||||||
|
p->pid=-1;
|
||||||
|
strcpy(p->status, w->msg);
|
||||||
|
}
|
||||||
|
free(w);
|
||||||
|
}
|
||||||
|
|
||||||
|
rerrstr(errbuf, sizeof errbuf);
|
||||||
|
if(strcmp(errbuf, "interrupted")==0) return -1;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
char **mkargv(word *a)
|
||||||
|
{
|
||||||
|
char **argv=(char **)emalloc((count(a)+2)*sizeof(char *));
|
||||||
|
char **argp=argv+1; /* leave one at front for runcoms */
|
||||||
|
for(;a;a=a->next) *argp++=a->word;
|
||||||
|
*argp=0;
|
||||||
|
return argv;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
void addenv(var *v)
|
||||||
|
{
|
||||||
|
char envname[256];
|
||||||
|
word *w;
|
||||||
|
int f;
|
||||||
|
io *fd;
|
||||||
|
if(v->changed){
|
||||||
|
v->changed=0;
|
||||||
|
snprint(envname, sizeof envname, "/env/%s", v->name);
|
||||||
|
if((f=Creat(envname))<0)
|
||||||
|
pfmt(err, "rc: can't open %s: %r\n", envname);
|
||||||
|
else{
|
||||||
|
for(w=v->val;w;w=w->next)
|
||||||
|
write(f, w->word, strlen(w->word)+1L);
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(v->fnchanged){
|
||||||
|
v->fnchanged=0;
|
||||||
|
snprint(envname, sizeof envname, "/env/fn#%s", v->name);
|
||||||
|
if((f=Creat(envname))<0)
|
||||||
|
pfmt(err, "rc: can't open %s: %r\n", envname);
|
||||||
|
else{
|
||||||
|
if(v->fn){
|
||||||
|
fd=openfd(f);
|
||||||
|
pfmt(fd, "fn %s %s\n", v->name, v->fn[v->pc-1].s);
|
||||||
|
closeio(fd);
|
||||||
|
}
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void updenvlocal(var *v)
|
||||||
|
{
|
||||||
|
if(v){
|
||||||
|
updenvlocal(v->next);
|
||||||
|
addenv(v);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
void Updenv(void){
|
||||||
|
var *v, **h;
|
||||||
|
for(h=gvar;h!=&gvar[NVAR];h++)
|
||||||
|
for(v=*h;v;v=v->next)
|
||||||
|
addenv(v);
|
||||||
|
if(runq) updenvlocal(runq->local);
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
cmpenv(const void *a, const void *b)
|
||||||
|
{
|
||||||
|
return strcmp(*(char**)a, *(char**)b);
|
||||||
|
}
|
||||||
|
char **mkenv(){
|
||||||
|
register char **env, **ep, *p, *q;
|
||||||
|
register struct var **h, *v;
|
||||||
|
register struct word *a;
|
||||||
|
register int nvar=0, nchr=0, sep;
|
||||||
|
/*
|
||||||
|
* Slightly kludgy loops look at locals then globals
|
||||||
|
*/
|
||||||
|
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
|
||||||
|
if((v==vlook(v->name)) && v->val){
|
||||||
|
nvar++;
|
||||||
|
nchr+=strlen(v->name)+1;
|
||||||
|
for(a=v->val;a;a=a->next)
|
||||||
|
nchr+=strlen(a->word)+1;
|
||||||
|
}
|
||||||
|
if(v->fn){
|
||||||
|
nvar++;
|
||||||
|
nchr+=strlen(v->name)+strlen(v->fn[v->pc-1].s)+8;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
env=(char **)emalloc((nvar+1)*sizeof(char *)+nchr);
|
||||||
|
ep=env;
|
||||||
|
p=(char *)&env[nvar+1];
|
||||||
|
for(h=gvar-1;h!=&gvar[NVAR];h++) for(v=h>=gvar?*h:runq->local;v;v=v->next){
|
||||||
|
if((v==vlook(v->name)) && v->val){
|
||||||
|
*ep++=p;
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
sep='=';
|
||||||
|
for(a=v->val;a;a=a->next){
|
||||||
|
*p++=sep;
|
||||||
|
sep=SEP;
|
||||||
|
q=a->word;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
}
|
||||||
|
*p++='\0';
|
||||||
|
}
|
||||||
|
if(v->fn){
|
||||||
|
*ep++=p;
|
||||||
|
#if 0
|
||||||
|
*p++='#'; *p++='('; *p++=')'; /* to fool Bourne */
|
||||||
|
*p++='f'; *p++='n'; *p++=' ';
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++=' ';
|
||||||
|
#endif
|
||||||
|
*p++='f'; *p++='n'; *p++='#';
|
||||||
|
q=v->name;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++='=';
|
||||||
|
q=v->fn[v->pc-1].s;
|
||||||
|
while(*q) *p++=*q++;
|
||||||
|
*p++='\n';
|
||||||
|
*p++='\0';
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*ep=0;
|
||||||
|
qsort((char *)env, nvar, sizeof ep[0], cmpenv);
|
||||||
|
return env;
|
||||||
|
}
|
||||||
|
void Updenv(void){}
|
||||||
|
void Execute(word *args, word *path)
|
||||||
|
{
|
||||||
|
char **argv=mkargv(args);
|
||||||
|
char **env=mkenv();
|
||||||
|
char file[1024];
|
||||||
|
int nc;
|
||||||
|
Updenv();
|
||||||
|
for(;path;path=path->next){
|
||||||
|
nc=strlen(path->word);
|
||||||
|
if(nc<1024){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0]){
|
||||||
|
strcat(file, "/");
|
||||||
|
nc++;
|
||||||
|
}
|
||||||
|
if(nc+strlen(argv[1])<1024){
|
||||||
|
strcat(file, argv[1]);
|
||||||
|
execve(file, argv+1, env);
|
||||||
|
}
|
||||||
|
else werrstr("command name too long");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
rerrstr(file, sizeof file);
|
||||||
|
pfmt(err, "%s: %s\n", argv[1], file);
|
||||||
|
efree((char *)argv);
|
||||||
|
}
|
||||||
|
#define NDIR 256 /* shoud be a better way */
|
||||||
|
int Globsize(char *p)
|
||||||
|
{
|
||||||
|
ulong isglob=0, globlen=NDIR+1;
|
||||||
|
for(;*p;p++){
|
||||||
|
if(*p==GLOB){
|
||||||
|
p++;
|
||||||
|
if(*p!=GLOB) isglob++;
|
||||||
|
globlen+=*p=='*'?NDIR:1;
|
||||||
|
}
|
||||||
|
else
|
||||||
|
globlen++;
|
||||||
|
}
|
||||||
|
return isglob?globlen:0;
|
||||||
|
}
|
||||||
|
#define NFD 50
|
||||||
|
#define NDBUF 32
|
||||||
|
struct{
|
||||||
|
Dir *dbuf;
|
||||||
|
int i;
|
||||||
|
int n;
|
||||||
|
}dir[NFD];
|
||||||
|
int Opendir(char *name)
|
||||||
|
{
|
||||||
|
Dir *db;
|
||||||
|
int f;
|
||||||
|
f=open(name, 0);
|
||||||
|
if(f==-1)
|
||||||
|
return f;
|
||||||
|
db = dirfstat(f);
|
||||||
|
if(db!=nil && (db->mode&DMDIR)){
|
||||||
|
if(f<NFD){
|
||||||
|
dir[f].i=0;
|
||||||
|
dir[f].n=0;
|
||||||
|
}
|
||||||
|
free(db);
|
||||||
|
return f;
|
||||||
|
}
|
||||||
|
free(db);
|
||||||
|
close(f);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
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 */
|
||||||
|
free(dir[f].dbuf);
|
||||||
|
dir[f].dbuf=0;
|
||||||
|
n=dirread(f, &dir[f].dbuf);
|
||||||
|
if(n>=0)
|
||||||
|
dir[f].n=n;
|
||||||
|
else
|
||||||
|
dir[f].n=0;
|
||||||
|
dir[f].i=0;
|
||||||
|
}
|
||||||
|
if(dir[f].i==dir[f].n)
|
||||||
|
return 0;
|
||||||
|
strcpy(p, dir[f].dbuf[dir[f].i].name);
|
||||||
|
dir[f].i++;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
void Closedir(int f){
|
||||||
|
if(f>=0 && f<NFD){
|
||||||
|
free(dir[f].dbuf);
|
||||||
|
dir[f].i=0;
|
||||||
|
dir[f].n=0;
|
||||||
|
dir[f].dbuf=0;
|
||||||
|
}
|
||||||
|
close(f);
|
||||||
|
}
|
||||||
|
int interrupted = 0;
|
||||||
|
void
|
||||||
|
notifyf(void *unused0, char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
for(i=0;syssigname[i];i++)
|
||||||
|
if(strncmp(s, syssigname[i], strlen(syssigname[i]))==0){
|
||||||
|
if(strncmp(s, "sys: ", 5)!=0){
|
||||||
|
if(kidpid && !interrupted){
|
||||||
|
interrupted=1;
|
||||||
|
postnote(PNGROUP, kidpid, s);
|
||||||
|
}
|
||||||
|
interrupted = 1;
|
||||||
|
}
|
||||||
|
goto Out;
|
||||||
|
}
|
||||||
|
if(strcmp(s, "sys: window size change") != 0)
|
||||||
|
if(strcmp(s, "sys: write on closed pipe") != 0)
|
||||||
|
if(strcmp(s, "sys: child") != 0)
|
||||||
|
pfmt(err, "rc: note: %s\n", s);
|
||||||
|
noted(NDFLT);
|
||||||
|
return;
|
||||||
|
Out:
|
||||||
|
if(strcmp(s, "interrupt")!=0 || trap[i]==0){
|
||||||
|
trap[i]++;
|
||||||
|
ntrap++;
|
||||||
|
}
|
||||||
|
if(ntrap>=32){ /* rc is probably in a trap loop */
|
||||||
|
pfmt(err, "rc: Too many traps (trap %s), aborting\n", s);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
noted(NCONT);
|
||||||
|
}
|
||||||
|
void Trapinit(void){
|
||||||
|
notify(notifyf);
|
||||||
|
}
|
||||||
|
void Unlink(char *name)
|
||||||
|
{
|
||||||
|
remove(name);
|
||||||
|
}
|
||||||
|
long Write(int fd, char *buf, long cnt)
|
||||||
|
{
|
||||||
|
return write(fd, buf, (long)cnt);
|
||||||
|
}
|
||||||
|
long Read(int fd, char *buf, long cnt)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
i = readnb(fd, buf, cnt);
|
||||||
|
if(ntrap) dotrap();
|
||||||
|
return i;
|
||||||
|
}
|
||||||
|
long Seek(int fd, long cnt, long whence)
|
||||||
|
{
|
||||||
|
return seek(fd, cnt, whence);
|
||||||
|
}
|
||||||
|
int Executable(char *file)
|
||||||
|
{
|
||||||
|
Dir *statbuf;
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
statbuf = dirstat(file);
|
||||||
|
if(statbuf == nil) return 0;
|
||||||
|
ret = ((statbuf->mode&0111)!=0 && (statbuf->mode&DMDIR)==0);
|
||||||
|
free(statbuf);
|
||||||
|
return ret;
|
||||||
|
}
|
||||||
|
int Creat(char *file)
|
||||||
|
{
|
||||||
|
return create(file, 1, 0666L);
|
||||||
|
}
|
||||||
|
int Dup(int a, int b){
|
||||||
|
return dup(a, b);
|
||||||
|
}
|
||||||
|
int Dup1(int a){
|
||||||
|
return dup(a, -1);
|
||||||
|
}
|
||||||
|
void Exit(char *stat)
|
||||||
|
{
|
||||||
|
Updenv();
|
||||||
|
setstatus(stat);
|
||||||
|
exits(truestatus()?"":getstatus());
|
||||||
|
}
|
||||||
|
int Eintr(void){
|
||||||
|
return interrupted;
|
||||||
|
}
|
||||||
|
void Noerror(void){
|
||||||
|
interrupted=0;
|
||||||
|
}
|
||||||
|
int
|
||||||
|
Isatty(int fd){
|
||||||
|
return isatty(fd);
|
||||||
|
}
|
||||||
|
void Abort(void){
|
||||||
|
pfmt(err, "aborting\n");
|
||||||
|
flush(err);
|
||||||
|
Exit("aborting");
|
||||||
|
}
|
||||||
|
void Memcpy(char *a, char *b, long n)
|
||||||
|
{
|
||||||
|
memmove(a, 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;
|
||||||
|
}
|
|
@ -0,0 +1,153 @@
|
||||||
|
/*
|
||||||
|
* Plan9 is defined for plan 9
|
||||||
|
* V9 is defined for 9th edition
|
||||||
|
* Sun is defined for sun-os
|
||||||
|
* Please don't litter the code with ifdefs. The three below (and one in
|
||||||
|
* getflags) should be enough.
|
||||||
|
*/
|
||||||
|
#define Plan9
|
||||||
|
#ifdef Plan9
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#undef NSIG
|
||||||
|
#undef SIGINT
|
||||||
|
#undef SIGQUIT
|
||||||
|
#define NSIG 32
|
||||||
|
#define SIGINT 2
|
||||||
|
#define SIGQUIT 3
|
||||||
|
#endif
|
||||||
|
#ifdef V9
|
||||||
|
#include <signal.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#endif
|
||||||
|
#ifdef Sun
|
||||||
|
#include <signal.h>
|
||||||
|
#endif
|
||||||
|
#define YYMAXDEPTH 500
|
||||||
|
#ifndef PAREN
|
||||||
|
#ifndef YYMAJOR
|
||||||
|
#include "x.tab.h"
|
||||||
|
#endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#undef pipe /* so that /dev/fd works */
|
||||||
|
#define searchpath rcsearchpath /* avoid new libc function */
|
||||||
|
|
||||||
|
/* some systems define a global "var", "thread" */
|
||||||
|
#undef var
|
||||||
|
#define var rcvar
|
||||||
|
#undef thread
|
||||||
|
#define thread rcthread
|
||||||
|
|
||||||
|
typedef struct tree tree;
|
||||||
|
typedef struct word word;
|
||||||
|
typedef struct io io;
|
||||||
|
typedef union code code;
|
||||||
|
typedef struct var var;
|
||||||
|
typedef struct list list;
|
||||||
|
typedef struct redir redir;
|
||||||
|
typedef struct thread thread;
|
||||||
|
typedef struct builtin builtin;
|
||||||
|
|
||||||
|
struct tree{
|
||||||
|
int type;
|
||||||
|
int rtype, fd0, fd1; /* details of REDIR PIPE DUP tokens */
|
||||||
|
char *str;
|
||||||
|
int quoted;
|
||||||
|
int iskw;
|
||||||
|
tree *child[3];
|
||||||
|
tree *next;
|
||||||
|
};
|
||||||
|
tree *newtree(void);
|
||||||
|
tree *token(char*, int), *klook(char*), *tree1(int, tree*);
|
||||||
|
tree *tree2(int, tree*, tree*), *tree3(int, tree*, tree*, tree*);
|
||||||
|
tree *mung1(tree*, tree*), *mung2(tree*, tree*, tree*);
|
||||||
|
tree *mung3(tree*, tree*, tree*, tree*), *epimung(tree*, tree*);
|
||||||
|
tree *simplemung(tree*), *heredoc(tree*);
|
||||||
|
void freetree(tree*);
|
||||||
|
tree *cmdtree;
|
||||||
|
/*
|
||||||
|
* The first word of any code vector is a reference count.
|
||||||
|
* Always create a new reference to a code vector by calling codecopy(.).
|
||||||
|
* Always call codefree(.) when deleting a reference.
|
||||||
|
*/
|
||||||
|
union code{
|
||||||
|
void (*f)(void);
|
||||||
|
int i;
|
||||||
|
char *s;
|
||||||
|
};
|
||||||
|
char *promptstr;
|
||||||
|
#define NTOK 8192
|
||||||
|
char tok[NTOK];
|
||||||
|
#define APPEND 1
|
||||||
|
#define WRITE 2
|
||||||
|
#define READ 3
|
||||||
|
#define HERE 4
|
||||||
|
#define DUPFD 5
|
||||||
|
#define CLOSE 6
|
||||||
|
#define RDWR 7
|
||||||
|
struct var{
|
||||||
|
char *name; /* ascii name */
|
||||||
|
word *val; /* value */
|
||||||
|
int changed;
|
||||||
|
code *fn; /* pointer to function's code vector */
|
||||||
|
int fnchanged;
|
||||||
|
int pc; /* pc of start of function */
|
||||||
|
var *next; /* next on hash or local list */
|
||||||
|
void (*changefn)(var*);
|
||||||
|
};
|
||||||
|
var *vlook(char*), *gvlook(char*), *newvar(char*, var*);
|
||||||
|
#define NVAR 521
|
||||||
|
var *gvar[NVAR]; /* hash for globals */
|
||||||
|
#define new(type) ((type *)emalloc(sizeof(type)))
|
||||||
|
char *emalloc(long);
|
||||||
|
void *Malloc(ulong);
|
||||||
|
void efree(char*);
|
||||||
|
#define NOFILE 128 /* should come from <param.h> */
|
||||||
|
struct here{
|
||||||
|
tree *tag;
|
||||||
|
char *name;
|
||||||
|
struct here *next;
|
||||||
|
};
|
||||||
|
int mypid;
|
||||||
|
/*
|
||||||
|
* Glob character escape in strings:
|
||||||
|
* In a string, GLOB must be followed by *?[ or GLOB.
|
||||||
|
* GLOB* matches any string
|
||||||
|
* GLOB? matches any single character
|
||||||
|
* GLOB[...] matches anything in the brackets
|
||||||
|
* GLOBGLOB matches GLOB
|
||||||
|
*/
|
||||||
|
#define GLOB ((char)0x01)
|
||||||
|
/*
|
||||||
|
* onebyte(c), twobyte(c), threebyte(c)
|
||||||
|
* Is c the first character of a one- two- or three-byte utf sequence?
|
||||||
|
*/
|
||||||
|
#define onebyte(c) ((c&0x80)==0x00)
|
||||||
|
#define twobyte(c) ((c&0xe0)==0xc0)
|
||||||
|
#define threebyte(c) ((c&0xf0)==0xe0)
|
||||||
|
#define fourbyte(c) ((c&0xf8)==0xf0)
|
||||||
|
|
||||||
|
char **argp;
|
||||||
|
char **args;
|
||||||
|
int nerror; /* number of errors encountered during compilation */
|
||||||
|
extern int doprompt; /* is it time for a prompt? */
|
||||||
|
/*
|
||||||
|
* Which fds are the reading/writing end of a pipe?
|
||||||
|
* Unfortunately, this can vary from system to system.
|
||||||
|
* 9th edition Unix doesn't care, the following defines
|
||||||
|
* work on plan 9.
|
||||||
|
*/
|
||||||
|
#define PRD 0
|
||||||
|
#define PWR 1
|
||||||
|
extern char *Rcmain(), Fdprefix[];
|
||||||
|
#define register
|
||||||
|
/*
|
||||||
|
* How many dot commands have we executed?
|
||||||
|
* Used to ensure that -v flag doesn't print rcmain.
|
||||||
|
*/
|
||||||
|
int ndot;
|
||||||
|
char *getstatus(void);
|
||||||
|
int lastc;
|
||||||
|
int lastword;
|
||||||
|
int kidpid;
|
|
@ -0,0 +1,80 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
mkdir -p $JEHANNE/hacking/bin/
|
||||||
|
TARGET=rc #$JEHANNE/hacking/bin/rc
|
||||||
|
|
||||||
|
git clean -xdf .
|
||||||
|
|
||||||
|
9yacc -d syn.y
|
||||||
|
cp y.tab.h x.tab.h
|
||||||
|
|
||||||
|
cc -c \
|
||||||
|
-DPLAN9PORT \
|
||||||
|
-I$JEHANNE/hacking/src/trampoline/include \
|
||||||
|
-O2 \
|
||||||
|
-c \
|
||||||
|
-Wall \
|
||||||
|
-Wno-parentheses \
|
||||||
|
-Wno-missing-braces \
|
||||||
|
-Wno-switch \
|
||||||
|
-Wno-comment \
|
||||||
|
-Wno-sign-compare \
|
||||||
|
-Wno-unknown-pragmas \
|
||||||
|
-Wno-misleading-indentation \
|
||||||
|
-Wno-stringop-truncation \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-format-truncation \
|
||||||
|
-fno-omit-frame-pointer \
|
||||||
|
-fsigned-char \
|
||||||
|
-fcommon \
|
||||||
|
-ggdb \
|
||||||
|
code.c \
|
||||||
|
exec.c \
|
||||||
|
getflags.c \
|
||||||
|
glob.c \
|
||||||
|
havefork.c \
|
||||||
|
here.c \
|
||||||
|
io.c \
|
||||||
|
plan9ish.c \
|
||||||
|
unixcrap.c \
|
||||||
|
lex.c \
|
||||||
|
parse.c \
|
||||||
|
pcmd.c \
|
||||||
|
pfnc.c \
|
||||||
|
simple.c \
|
||||||
|
subr.c \
|
||||||
|
trap.c \
|
||||||
|
tree.c \
|
||||||
|
var.c \
|
||||||
|
y.tab.c
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
|
gcc -pie -o $TARGET \
|
||||||
|
code.o \
|
||||||
|
exec.o \
|
||||||
|
getflags.o \
|
||||||
|
glob.o \
|
||||||
|
here.o \
|
||||||
|
io.o \
|
||||||
|
lex.o \
|
||||||
|
parse.o \
|
||||||
|
pcmd.o \
|
||||||
|
pfnc.o \
|
||||||
|
simple.o \
|
||||||
|
subr.o \
|
||||||
|
trap.o \
|
||||||
|
tree.o \
|
||||||
|
unixcrap.o \
|
||||||
|
var.o \
|
||||||
|
y.tab.o \
|
||||||
|
plan9ish.o \
|
||||||
|
havefork.o \
|
||||||
|
-L$JEHANNE/hacking/lib -lutil -lresolv -lpthread -l9 -lm \
|
||||||
|
-lutil \
|
||||||
|
-lresolv \
|
||||||
|
-lpthread \
|
||||||
|
-lc
|
||||||
|
|
||||||
|
|
||||||
|
#git clean -xdf .
|
|
@ -0,0 +1,505 @@
|
||||||
|
/*
|
||||||
|
* Maybe `simple' is a misnomer.
|
||||||
|
*/
|
||||||
|
#include "rc.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
/*
|
||||||
|
* Search through the following code to see if we're just going to exit.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
exitnext(void){
|
||||||
|
union code *c=&runq->code[runq->pc];
|
||||||
|
while(c->f==Xpopredir) c++;
|
||||||
|
return c->f==Xexit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
Xsimple(void)
|
||||||
|
{
|
||||||
|
word *a;
|
||||||
|
thread *p = runq;
|
||||||
|
var *v;
|
||||||
|
struct builtin *bp;
|
||||||
|
int pid;
|
||||||
|
globlist();
|
||||||
|
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);
|
||||||
|
if(v->fn)
|
||||||
|
execfunc(v);
|
||||||
|
else{
|
||||||
|
if(strcmp(a->word, "builtin")==0){
|
||||||
|
if(count(a)==1){
|
||||||
|
pfmt(err, "builtin: empty argument list\n");
|
||||||
|
setstatus("empty arg list");
|
||||||
|
poplist();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
a = a->next;
|
||||||
|
popword();
|
||||||
|
}
|
||||||
|
for(bp = Builtin;bp->name;bp++)
|
||||||
|
if(strcmp(a->word, bp->name)==0){
|
||||||
|
(*bp->fnc)();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
if(exitnext()){
|
||||||
|
/* fork and wait is redundant */
|
||||||
|
pushword("exec");
|
||||||
|
execexec();
|
||||||
|
Xexit();
|
||||||
|
}
|
||||||
|
else{
|
||||||
|
flush(err);
|
||||||
|
Updenv(); /* necessary so changes don't go out again */
|
||||||
|
if((pid = execforkexec()) < 0){
|
||||||
|
Xerror("try again");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* interrupts don't get us out */
|
||||||
|
poplist();
|
||||||
|
while(Waitfor(pid, 1) < 0)
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
struct word nullpath = { "", 0};
|
||||||
|
|
||||||
|
void
|
||||||
|
doredir(redir *rp)
|
||||||
|
{
|
||||||
|
if(rp){
|
||||||
|
doredir(rp->next);
|
||||||
|
switch(rp->type){
|
||||||
|
case ROPEN:
|
||||||
|
if(rp->from!=rp->to){
|
||||||
|
Dup(rp->from, rp->to);
|
||||||
|
close(rp->from);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case RDUP:
|
||||||
|
Dup(rp->from, rp->to);
|
||||||
|
break;
|
||||||
|
case RCLOSE:
|
||||||
|
close(rp->from);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
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=&nullpath;
|
||||||
|
return path;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execexec(void)
|
||||||
|
{
|
||||||
|
popword(); /* "exec" */
|
||||||
|
if(runq->argv->words==0){
|
||||||
|
Xerror1("empty argument list");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
doredir(runq->redir);
|
||||||
|
Execute(runq->argv->words, searchpath(runq->argv->words->word));
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execfunc(var *func)
|
||||||
|
{
|
||||||
|
word *starval;
|
||||||
|
popword();
|
||||||
|
starval = runq->argv->words;
|
||||||
|
runq->argv->words = 0;
|
||||||
|
poplist();
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
/* report to /dev/wdir if it exists and we're interactive */
|
||||||
|
static int wdirfd = -2;
|
||||||
|
if(chdir(word)<0) return -1;
|
||||||
|
if(flag['i']!=0){
|
||||||
|
if(wdirfd==-2) /* try only once */
|
||||||
|
wdirfd = open("/dev/wdir", OWRITE|OCEXEC);
|
||||||
|
if(wdirfd>=0)
|
||||||
|
write(wdirfd, word, strlen(word));
|
||||||
|
}
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execcd(void)
|
||||||
|
{
|
||||||
|
word *a = runq->argv->words;
|
||||||
|
word *cdpath;
|
||||||
|
char dir[512];
|
||||||
|
setstatus("can't cd");
|
||||||
|
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){
|
||||||
|
strcpy(dir, cdpath->word);
|
||||||
|
if(dir[0])
|
||||||
|
strcat(dir, "/");
|
||||||
|
strcat(dir, a->next->word);
|
||||||
|
if(dochdir(dir)>=0){
|
||||||
|
if(strlen(cdpath->word)
|
||||||
|
&& strcmp(cdpath->word, ".")!=0)
|
||||||
|
pfmt(err, "%s\n", dir);
|
||||||
|
setstatus("");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(cdpath==0)
|
||||||
|
pfmt(err, "Can't cd %s: %r\n", a->next->word);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
a = vlook("home")->val;
|
||||||
|
if(count(a)>=1){
|
||||||
|
if(dochdir(a->word)>=0)
|
||||||
|
setstatus("");
|
||||||
|
else
|
||||||
|
pfmt(err, "Can't cd %s: %r\n", a->word);
|
||||||
|
}
|
||||||
|
else
|
||||||
|
pfmt(err, "Can't cd -- $home empty\n");
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
|
case 1: Xexit();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execshift(void)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
word *a;
|
||||||
|
var *star;
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
default:
|
||||||
|
pfmt(err, "Usage: shift [n]\n");
|
||||||
|
setstatus("shift usage");
|
||||||
|
poplist();
|
||||||
|
return;
|
||||||
|
case 2:
|
||||||
|
n = atoi(runq->argv->words->next->word);
|
||||||
|
break;
|
||||||
|
case 1:
|
||||||
|
n = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
star = vlook("*");
|
||||||
|
for(;n && star->val;--n){
|
||||||
|
a = star->val->next;
|
||||||
|
efree(star->val->word);
|
||||||
|
efree((char *)star->val);
|
||||||
|
star->val = a;
|
||||||
|
star->changed = 1;
|
||||||
|
}
|
||||||
|
setstatus("");
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
octal(char *s)
|
||||||
|
{
|
||||||
|
int n = 0;
|
||||||
|
while(*s==' ' || *s=='\t' || *s=='\n') s++;
|
||||||
|
while('0'<=*s && *s<='7') n = n*8+*s++-'0';
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
mapfd(int fd)
|
||||||
|
{
|
||||||
|
redir *rp;
|
||||||
|
for(rp = runq->redir;rp;rp = rp->next){
|
||||||
|
switch(rp->type){
|
||||||
|
case RCLOSE:
|
||||||
|
if(rp->from==fd)
|
||||||
|
fd=-1;
|
||||||
|
break;
|
||||||
|
case RDUP:
|
||||||
|
case ROPEN:
|
||||||
|
if(rp->to==fd)
|
||||||
|
fd = rp->from;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
union code rdcmds[4];
|
||||||
|
|
||||||
|
void
|
||||||
|
execcmds(io *f)
|
||||||
|
{
|
||||||
|
static int first = 1;
|
||||||
|
if(first){
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execeval(void)
|
||||||
|
{
|
||||||
|
char *cmdline, *s, *t;
|
||||||
|
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)
|
||||||
|
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++;
|
||||||
|
*s++=' ';
|
||||||
|
}
|
||||||
|
s[-1]='\n';
|
||||||
|
poplist();
|
||||||
|
execcmds(opencore(cmdline, len));
|
||||||
|
efree(cmdline);
|
||||||
|
}
|
||||||
|
union code dotcmds[14];
|
||||||
|
|
||||||
|
void
|
||||||
|
execdot(void)
|
||||||
|
{
|
||||||
|
int iflag = 0;
|
||||||
|
int fd;
|
||||||
|
list *av;
|
||||||
|
thread *p = runq;
|
||||||
|
char *zero;
|
||||||
|
static int first = 1;
|
||||||
|
char file[512];
|
||||||
|
word *path;
|
||||||
|
|
||||||
|
if(first){
|
||||||
|
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[7].s="*";
|
||||||
|
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;
|
||||||
|
popword();
|
||||||
|
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
|
||||||
|
iflag = 1;
|
||||||
|
popword();
|
||||||
|
}
|
||||||
|
/* get input file */
|
||||||
|
if(p->argv->words==0){
|
||||||
|
Xerror1("Usage: . [-i] file [arg ...]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
zero = strdup(p->argv->words->word);
|
||||||
|
popword();
|
||||||
|
fd=-1;
|
||||||
|
for(path = searchpath(zero);path;path = path->next){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(fd<0){
|
||||||
|
pfmt(err, "%s: ", zero);
|
||||||
|
setstatus("can't open");
|
||||||
|
Xerror(".: can't open");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
/* 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;
|
||||||
|
/* push $* value */
|
||||||
|
pushlist();
|
||||||
|
runq->argv->words = p->argv->words;
|
||||||
|
/* free caller's copy of $* */
|
||||||
|
av = p->argv;
|
||||||
|
p->argv = av->next;
|
||||||
|
efree((char *)av);
|
||||||
|
/* push $0 value */
|
||||||
|
pushlist();
|
||||||
|
pushword(zero);
|
||||||
|
ndot++;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execflag(void)
|
||||||
|
{
|
||||||
|
char *letter, *val;
|
||||||
|
switch(count(runq->argv->words)){
|
||||||
|
case 2:
|
||||||
|
setstatus(flag[(uchar)runq->argv->words->next->word[0]]?"":"flag not set");
|
||||||
|
break;
|
||||||
|
case 3:
|
||||||
|
letter = runq->argv->words->next->word;
|
||||||
|
val = runq->argv->words->next->next->word;
|
||||||
|
if(strlen(letter)==1){
|
||||||
|
if(strcmp(val, "+")==0){
|
||||||
|
flag[(uchar)letter[0]] = flagset;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(strcmp(val, "-")==0){
|
||||||
|
flag[(uchar)letter[0]] = 0;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
default:
|
||||||
|
Xerror1("Usage: flag [letter] [+-]");
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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);
|
||||||
|
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){
|
||||||
|
pfmt(out, "%c%q", sep, b->word);
|
||||||
|
sep=' ';
|
||||||
|
}
|
||||||
|
pfmt(out, ")\n");
|
||||||
|
}
|
||||||
|
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);
|
||||||
|
else{
|
||||||
|
for(bp = Builtin;bp->name;bp++)
|
||||||
|
if(strcmp(a->word, bp->name)==0){
|
||||||
|
pfmt(out, "builtin %s\n", a->word);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(!bp->name){
|
||||||
|
for(path = searchpath(a->word);path;path = path->next){
|
||||||
|
strcpy(file, path->word);
|
||||||
|
if(file[0])
|
||||||
|
strcat(file, "/");
|
||||||
|
strcat(file, a->word);
|
||||||
|
if(Executable(file)){
|
||||||
|
pfmt(out, "%s\n", file);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(!path && !found){
|
||||||
|
pfmt(err, "%s: not found\n", a->word);
|
||||||
|
setstatus("not found");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
flush(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
poplist();
|
||||||
|
}
|
|
@ -0,0 +1,77 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#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); } /**/
|
||||||
|
memset(p, 0, n);
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
efree(char *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)
|
||||||
|
{
|
||||||
|
pfmt(err, "rc: ");
|
||||||
|
if(runq->cmdfile && !runq->iflag)
|
||||||
|
pfmt(err, "%s:%d: ", runq->cmdfile, runq->lineno);
|
||||||
|
else if(runq->cmdfile)
|
||||||
|
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);
|
||||||
|
pfmt(err, "%s\n", m);
|
||||||
|
flush(err);
|
||||||
|
lastword = 0;
|
||||||
|
lastdol = 0;
|
||||||
|
while(lastc!='\n' && lastc!=EOF) advance();
|
||||||
|
nerror++;
|
||||||
|
setvar("status", newword(m, (word *)0));
|
||||||
|
}
|
||||||
|
char *bp;
|
||||||
|
|
||||||
|
static void
|
||||||
|
iacvt(int n)
|
||||||
|
{
|
||||||
|
if(n<0){
|
||||||
|
*bp++='-';
|
||||||
|
n=-n; /* doesn't work for n==-inf */
|
||||||
|
}
|
||||||
|
if(n/10)
|
||||||
|
iacvt(n/10);
|
||||||
|
*bp++=n%10+'0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
inttoascii(char *s, long n)
|
||||||
|
{
|
||||||
|
bp = s;
|
||||||
|
iacvt(n);
|
||||||
|
*bp='\0';
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
panic(char *s, int n)
|
||||||
|
{
|
||||||
|
pfmt(err, "rc: ");
|
||||||
|
pfmt(err, s, n);
|
||||||
|
pchr(err, '\n');
|
||||||
|
flush(err);
|
||||||
|
Abort();
|
||||||
|
}
|
|
@ -0,0 +1,91 @@
|
||||||
|
%term FOR IN WHILE IF NOT TWIDDLE BANG SUBSHELL SWITCH FN
|
||||||
|
%term WORD REDIR REDIRW DUP PIPE SUB
|
||||||
|
%term SIMPLE ARGLIST WORDS BRACE PAREN PCMD PIPEFD /* not used in syntax */
|
||||||
|
/* operator priorities -- lowest first */
|
||||||
|
%left IF WHILE FOR SWITCH ')' NOT
|
||||||
|
%left ANDAND OROR
|
||||||
|
%left BANG SUBSHELL
|
||||||
|
%left PIPE
|
||||||
|
%left '^'
|
||||||
|
%right '$' COUNT '"'
|
||||||
|
%left SUB
|
||||||
|
%{
|
||||||
|
#include "rc.h"
|
||||||
|
#include "fns.h"
|
||||||
|
%}
|
||||||
|
%union{
|
||||||
|
struct tree *tree;
|
||||||
|
};
|
||||||
|
%type<tree> line paren brace body cmdsa cmdsan assign epilog redir
|
||||||
|
%type<tree> cmd simple first word comword keyword words
|
||||||
|
%type<tree> NOT FOR IN WHILE IF TWIDDLE BANG SUBSHELL SWITCH FN
|
||||||
|
%type<tree> WORD REDIR REDIRW DUP PIPE
|
||||||
|
%%
|
||||||
|
rc: { return 1;}
|
||||||
|
| line '\n' {return !compile($1);}
|
||||||
|
line: cmd
|
||||||
|
| cmdsa line {$$=tree2(';', $1, $2);}
|
||||||
|
body: cmd
|
||||||
|
| cmdsan body {$$=tree2(';', $1, $2);}
|
||||||
|
cmdsa: cmd ';'
|
||||||
|
| cmd '&' {$$=tree1('&', $1);}
|
||||||
|
cmdsan: cmdsa
|
||||||
|
| cmd '\n'
|
||||||
|
brace: '{' body '}' {$$=tree1(BRACE, $2);}
|
||||||
|
paren: '(' body ')' {$$=tree1(PCMD, $2);}
|
||||||
|
assign: first '=' word {$$=tree2('=', $1, $3);}
|
||||||
|
epilog: {$$=0;}
|
||||||
|
| redir epilog {$$=mung2($1, $1->child[0], $2);}
|
||||||
|
redir: REDIR word {$$=mung1($1, $1->rtype==HERE?heredoc($2):$2);}
|
||||||
|
| DUP
|
||||||
|
cmd: {$$=0;}
|
||||||
|
| brace epilog {$$=epimung($1, $2);}
|
||||||
|
| IF paren {skipnl();} cmd
|
||||||
|
{$$=mung2($1, $2, $4);}
|
||||||
|
| IF NOT {skipnl();} cmd {$$=mung1($2, $4);}
|
||||||
|
| FOR '(' word IN words ')' {skipnl();} cmd
|
||||||
|
/*
|
||||||
|
* if ``words'' is nil, we need a tree element to distinguish between
|
||||||
|
* for(i in ) and for(i), the former being a loop over the empty set
|
||||||
|
* and the latter being the implicit argument loop. so if $5 is nil
|
||||||
|
* (the empty set), we represent it as "()". don't parenthesize non-nil
|
||||||
|
* functions, to avoid growing parentheses every time we reread the
|
||||||
|
* definition.
|
||||||
|
*/
|
||||||
|
{$$=mung3($1, $3, $5 ? $5 : tree1(PAREN, $5), $8);}
|
||||||
|
| FOR '(' word ')' {skipnl();} cmd
|
||||||
|
{$$=mung3($1, $3, (struct tree *)0, $6);}
|
||||||
|
| WHILE paren {skipnl();} cmd
|
||||||
|
{$$=mung2($1, $2, $4);}
|
||||||
|
| SWITCH word {skipnl();} brace
|
||||||
|
{$$=tree2(SWITCH, $2, $4);}
|
||||||
|
| simple {$$=simplemung($1);}
|
||||||
|
| TWIDDLE word words {$$=mung2($1, $2, $3);}
|
||||||
|
| cmd ANDAND cmd {$$=tree2(ANDAND, $1, $3);}
|
||||||
|
| cmd OROR cmd {$$=tree2(OROR, $1, $3);}
|
||||||
|
| cmd PIPE cmd {$$=mung2($2, $1, $3);}
|
||||||
|
| redir cmd %prec BANG {$$=mung2($1, $1->child[0], $2);}
|
||||||
|
| assign cmd %prec BANG {$$=mung3($1, $1->child[0], $1->child[1], $2);}
|
||||||
|
| BANG cmd {$$=mung1($1, $2);}
|
||||||
|
| SUBSHELL cmd {$$=mung1($1, $2);}
|
||||||
|
| FN words brace {$$=tree2(FN, $2, $3);}
|
||||||
|
| FN words {$$=tree1(FN, $2);}
|
||||||
|
simple: first
|
||||||
|
| simple word {$$=tree2(ARGLIST, $1, $2);}
|
||||||
|
| simple redir {$$=tree2(ARGLIST, $1, $2);}
|
||||||
|
first: comword
|
||||||
|
| first '^' word {$$=tree2('^', $1, $3);}
|
||||||
|
word: keyword {lastword=1; $1->type=WORD;}
|
||||||
|
| comword
|
||||||
|
| word '^' word {$$=tree2('^', $1, $3);}
|
||||||
|
comword: '$' word {$$=tree1('$', $2);}
|
||||||
|
| '$' word SUB words ')' {$$=tree2(SUB, $2, $4);}
|
||||||
|
| '"' word {$$=tree1('"', $2);}
|
||||||
|
| COUNT word {$$=tree1(COUNT, $2);}
|
||||||
|
| WORD
|
||||||
|
| '`' brace {$$=tree1('`', $2);}
|
||||||
|
| '(' words ')' {$$=tree1(PAREN, $2);}
|
||||||
|
| REDIRW brace {$$=mung1($1, $2); $$->type=PIPEFD;}
|
||||||
|
keyword: FOR|IN|WHILE|IF|NOT|TWIDDLE|BANG|SUBSHELL|SWITCH|FN
|
||||||
|
words: {$$=(struct tree*)0;}
|
||||||
|
| words word {$$=tree2(WORDS, $1, $2);}
|
|
@ -0,0 +1,37 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "io.h"
|
||||||
|
extern char *Signame[];
|
||||||
|
|
||||||
|
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]);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
else if(i==SIGINT || i==SIGQUIT){
|
||||||
|
/*
|
||||||
|
* run the stack down until we uncover the
|
||||||
|
* command reading loop. Xreturn will exit
|
||||||
|
* if there is none (i.e. if this is not
|
||||||
|
* an interactive rc.)
|
||||||
|
*/
|
||||||
|
while(!runq->iflag) Xreturn();
|
||||||
|
}
|
||||||
|
else Exit(getstatus());
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,146 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
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;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freenodes(void)
|
||||||
|
{
|
||||||
|
tree *t, *u;
|
||||||
|
for(t = treenodes;t;t = u){
|
||||||
|
u = t->next;
|
||||||
|
if(t->str)
|
||||||
|
efree(t->str);
|
||||||
|
efree((char *)t);
|
||||||
|
}
|
||||||
|
treenodes = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
tree1(int type, tree *c0)
|
||||||
|
{
|
||||||
|
return tree3(type, c0, (tree *)0, (tree *)0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 *t;
|
||||||
|
if(type==';'){
|
||||||
|
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;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
mung1(tree *t, tree *c0)
|
||||||
|
{
|
||||||
|
t->child[0] = c0;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
mung2(tree *t, tree *c0, tree *c1)
|
||||||
|
{
|
||||||
|
t->child[0] = c0;
|
||||||
|
t->child[1] = c1;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
mung3(tree *t, tree *c0, tree *c1, tree *c2)
|
||||||
|
{
|
||||||
|
t->child[0] = c0;
|
||||||
|
t->child[1] = c1;
|
||||||
|
t->child[2] = c2;
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
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 *u;
|
||||||
|
struct io *s;
|
||||||
|
t = tree1(SIMPLE, t);
|
||||||
|
s = openstr();
|
||||||
|
pfmt(s, "%t", t);
|
||||||
|
t->str = strdup(s->strp);
|
||||||
|
closeio(s);
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
token(char *str, int type)
|
||||||
|
{
|
||||||
|
tree *t = newtree();
|
||||||
|
t->type = type;
|
||||||
|
t->str = strdup(str);
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
freetree(tree *p)
|
||||||
|
{
|
||||||
|
if(p==0)
|
||||||
|
return;
|
||||||
|
freetree(p->child[0]);
|
||||||
|
freetree(p->child[1]);
|
||||||
|
freetree(p->child[2]);
|
||||||
|
if(p->str)
|
||||||
|
efree(p->str);
|
||||||
|
efree((char *)p);
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
#include <u.h>
|
||||||
|
#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"
|
||||||
|
#include "io.h"
|
||||||
|
#include "fns.h"
|
||||||
|
#include "getflags.h"
|
||||||
|
|
||||||
|
extern char **mkargv(word*);
|
||||||
|
extern int mapfd(int);
|
||||||
|
|
||||||
|
static char *eargs = "cdflmnstuv";
|
||||||
|
static int rlx[] = {
|
||||||
|
RLIMIT_CORE,
|
||||||
|
RLIMIT_DATA,
|
||||||
|
RLIMIT_FSIZE,
|
||||||
|
#ifdef RLIMIT_MEMLOCK
|
||||||
|
RLIMIT_MEMLOCK,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_RSS
|
||||||
|
RLIMIT_RSS,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
RLIMIT_NOFILE,
|
||||||
|
RLIMIT_STACK,
|
||||||
|
RLIMIT_CPU,
|
||||||
|
#ifdef RLIMIT_NPROC
|
||||||
|
RLIMIT_NPROC,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
#ifdef RLIMIT_RSS
|
||||||
|
RLIMIT_RSS,
|
||||||
|
#else
|
||||||
|
0,
|
||||||
|
#endif
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
eusage(void)
|
||||||
|
{
|
||||||
|
fprint(mapfd(2), "usage: ulimit [-SHa%s [limit]]\n", eargs);
|
||||||
|
}
|
||||||
|
|
||||||
|
#define Notset -4
|
||||||
|
#define Unlimited -3
|
||||||
|
#define Hard -2
|
||||||
|
#define Soft -1
|
||||||
|
|
||||||
|
void
|
||||||
|
execulimit(void)
|
||||||
|
{
|
||||||
|
rlim_t n;
|
||||||
|
int fd, argc, sethard, setsoft, limit;
|
||||||
|
int flag[256];
|
||||||
|
char **argv, **oargv, *p;
|
||||||
|
char *argv0;
|
||||||
|
struct rlimit rl;
|
||||||
|
|
||||||
|
argv0 = nil;
|
||||||
|
setstatus("");
|
||||||
|
oargv = mkargv(runq->argv->words);
|
||||||
|
argv = oargv+1;
|
||||||
|
for(argc=0; argv[argc]; argc++)
|
||||||
|
;
|
||||||
|
|
||||||
|
memset(flag, 0, sizeof flag);
|
||||||
|
ARGBEGIN{
|
||||||
|
default:
|
||||||
|
if(strchr(eargs, ARGC()) == nil){
|
||||||
|
eusage();
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
case 'S':
|
||||||
|
case 'H':
|
||||||
|
case 'a':
|
||||||
|
flag[ARGC()] = 1;
|
||||||
|
break;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(argc > 1){
|
||||||
|
eusage();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fd = mapfd(1);
|
||||||
|
|
||||||
|
sethard = 1;
|
||||||
|
setsoft = 1;
|
||||||
|
if(flag['S'] && flag['H'])
|
||||||
|
;
|
||||||
|
else if(flag['S'])
|
||||||
|
sethard = 0;
|
||||||
|
else if(flag['H'])
|
||||||
|
setsoft = 0;
|
||||||
|
|
||||||
|
limit = Notset;
|
||||||
|
if(argc>0){
|
||||||
|
if(strcmp(argv[0], "unlimited") == 0)
|
||||||
|
limit = Unlimited;
|
||||||
|
else if(strcmp(argv[0], "hard") == 0)
|
||||||
|
limit = Hard;
|
||||||
|
else if(strcmp(argv[0], "soft") == 0)
|
||||||
|
limit = Soft;
|
||||||
|
else if((limit = strtol(argv[0], &p, 0)) < 0 || *p != 0){
|
||||||
|
eusage();
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(flag['a']){
|
||||||
|
for(p=eargs; *p; p++){
|
||||||
|
getrlimit(rlx[p-eargs], &rl);
|
||||||
|
n = flag['H'] ? rl.rlim_max : rl.rlim_cur;
|
||||||
|
if(n == RLIM_INFINITY)
|
||||||
|
fprint(fd, "ulimit -%c unlimited\n", *p);
|
||||||
|
else
|
||||||
|
fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n);
|
||||||
|
}
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
for(p=eargs; *p; p++){
|
||||||
|
if(flag[(uchar)*p]){
|
||||||
|
n = 0;
|
||||||
|
getrlimit(rlx[p-eargs], &rl);
|
||||||
|
switch(limit){
|
||||||
|
case Notset:
|
||||||
|
n = flag['H'] ? rl.rlim_max : rl.rlim_cur;
|
||||||
|
if(n == RLIM_INFINITY)
|
||||||
|
fprint(fd, "ulimit -%c unlimited\n", *p);
|
||||||
|
else
|
||||||
|
fprint(fd, "ulimit -%c %llud\n", *p, (uvlong)n);
|
||||||
|
break;
|
||||||
|
case Hard:
|
||||||
|
n = rl.rlim_max;
|
||||||
|
goto set;
|
||||||
|
case Soft:
|
||||||
|
n = rl.rlim_cur;
|
||||||
|
goto set;
|
||||||
|
case Unlimited:
|
||||||
|
n = RLIM_INFINITY;
|
||||||
|
goto set;
|
||||||
|
default:
|
||||||
|
n = limit;
|
||||||
|
set:
|
||||||
|
if(setsoft)
|
||||||
|
rl.rlim_cur = n;
|
||||||
|
if(sethard)
|
||||||
|
rl.rlim_max = n;
|
||||||
|
if(setrlimit(rlx[p-eargs], &rl) < 0)
|
||||||
|
fprint(mapfd(2), "setrlimit: %r\n");
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(oargv);
|
||||||
|
poplist();
|
||||||
|
flush(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
execumask(void)
|
||||||
|
{
|
||||||
|
int n, argc;
|
||||||
|
char **argv, **oargv, *p;
|
||||||
|
char *argv0;
|
||||||
|
|
||||||
|
argv0 = nil;
|
||||||
|
setstatus("");
|
||||||
|
oargv = mkargv(runq->argv->words);
|
||||||
|
argv = oargv+1;
|
||||||
|
for(argc=0; argv[argc]; argc++)
|
||||||
|
;
|
||||||
|
|
||||||
|
ARGBEGIN{
|
||||||
|
default:
|
||||||
|
usage:
|
||||||
|
fprint(mapfd(2), "usage: umask [mode]\n");
|
||||||
|
goto out;
|
||||||
|
}ARGEND
|
||||||
|
|
||||||
|
if(argc > 1)
|
||||||
|
goto usage;
|
||||||
|
|
||||||
|
if(argc == 1){
|
||||||
|
n = strtol(argv[0], &p, 8);
|
||||||
|
if(*p != 0 || p == argv[0])
|
||||||
|
goto usage;
|
||||||
|
umask(n);
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = umask(0);
|
||||||
|
umask(n);
|
||||||
|
if(n < 0){
|
||||||
|
fprint(mapfd(2), "umask: %r\n");
|
||||||
|
goto out;
|
||||||
|
}
|
||||||
|
|
||||||
|
fprint(mapfd(1), "umask %03o\n", n);
|
||||||
|
|
||||||
|
out:
|
||||||
|
free(oargv);
|
||||||
|
poplist();
|
||||||
|
flush(err);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Cope with non-blocking read.
|
||||||
|
*/
|
||||||
|
long
|
||||||
|
readnb(int fd, char *buf, long cnt)
|
||||||
|
{
|
||||||
|
int n, didreset;
|
||||||
|
int flgs;
|
||||||
|
|
||||||
|
didreset = 0;
|
||||||
|
again:
|
||||||
|
n = read(fd, buf, cnt);
|
||||||
|
if(n == -1)
|
||||||
|
if(errno == EAGAIN){
|
||||||
|
if(!didreset){
|
||||||
|
if((flgs = fcntl(fd, F_GETFL, 0)) == -1)
|
||||||
|
return -1;
|
||||||
|
flgs &= ~O_NONBLOCK;
|
||||||
|
if(fcntl(fd, F_SETFL, flgs) == -1)
|
||||||
|
return -1;
|
||||||
|
didreset = 1;
|
||||||
|
}
|
||||||
|
goto again;
|
||||||
|
}
|
||||||
|
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,173 @@
|
||||||
|
#include "rc.h"
|
||||||
|
#include "exec.h"
|
||||||
|
#include "fns.h"
|
||||||
|
|
||||||
|
int
|
||||||
|
hash(char *s, int n)
|
||||||
|
{
|
||||||
|
int h = 0, i = 1;
|
||||||
|
while(*s) h+=*s++*i++;
|
||||||
|
h%=n;
|
||||||
|
return h<0?h+n:h;
|
||||||
|
}
|
||||||
|
#define NKW 30
|
||||||
|
struct kw{
|
||||||
|
char *name;
|
||||||
|
int type;
|
||||||
|
struct kw *next;
|
||||||
|
}*kw[NKW];
|
||||||
|
|
||||||
|
void
|
||||||
|
kenter(int type, char *name)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
kenter(FOR, "for");
|
||||||
|
kenter(IN, "in");
|
||||||
|
kenter(WHILE, "while");
|
||||||
|
kenter(IF, "if");
|
||||||
|
kenter(NOT, "not");
|
||||||
|
kenter(TWIDDLE, "~");
|
||||||
|
kenter(BANG, "!");
|
||||||
|
kenter(SUBSHELL, "@");
|
||||||
|
kenter(SWITCH, "switch");
|
||||||
|
kenter(FN, "fn");
|
||||||
|
}
|
||||||
|
|
||||||
|
tree*
|
||||||
|
klook(char *name)
|
||||||
|
{
|
||||||
|
struct kw *p;
|
||||||
|
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;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return t;
|
||||||
|
}
|
||||||
|
|
||||||
|
var*
|
||||||
|
gvlook(char *name)
|
||||||
|
{
|
||||||
|
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]);
|
||||||
|
}
|
||||||
|
|
||||||
|
var*
|
||||||
|
vlook(char *name)
|
||||||
|
{
|
||||||
|
var *v;
|
||||||
|
if(runq)
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
_setvar(name, val, 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
bigpath(var *v)
|
||||||
|
{
|
||||||
|
/* convert $PATH to $path */
|
||||||
|
char *p, *q;
|
||||||
|
word **l, *w;
|
||||||
|
|
||||||
|
if(v->val == nil){
|
||||||
|
_setvar("path", nil, 0);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
p = v->val->word;
|
||||||
|
w = nil;
|
||||||
|
l = &w;
|
||||||
|
/*
|
||||||
|
* Doesn't handle escaped colon nonsense.
|
||||||
|
*/
|
||||||
|
if(p[0] == 0)
|
||||||
|
p = nil;
|
||||||
|
while(p){
|
||||||
|
q = strchr(p, ':');
|
||||||
|
if(q)
|
||||||
|
*q = 0;
|
||||||
|
*l = newword(p[0] ? p : ".", nil);
|
||||||
|
l = &(*l)->next;
|
||||||
|
if(q){
|
||||||
|
*q = ':';
|
||||||
|
p = q+1;
|
||||||
|
}else
|
||||||
|
p = nil;
|
||||||
|
}
|
||||||
|
_setvar("path", w, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
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 = list2strcolon(v->val);
|
||||||
|
w = new(word);
|
||||||
|
w->word = p;
|
||||||
|
w->next = nil;
|
||||||
|
_setvar("PATH", w, 1); /* 1: recompute $path to expose colon problems */
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
pathinit(void)
|
||||||
|
{
|
||||||
|
var *v;
|
||||||
|
|
||||||
|
v = gvlook("path");
|
||||||
|
v->changefn = littlepath;
|
||||||
|
v = gvlook("PATH");
|
||||||
|
v->changefn = bigpath;
|
||||||
|
bigpath(v);
|
||||||
|
}
|
File diff suppressed because it is too large
Load Diff
|
@ -0,0 +1,91 @@
|
||||||
|
#ifndef _BIO_H_
|
||||||
|
#define _BIO_H_ 1
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef AUTOLIB
|
||||||
|
AUTOLIB(bio)
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <fcntl.h> /* for O_RDONLY, O_WRONLY */
|
||||||
|
|
||||||
|
typedef struct Biobuf Biobuf;
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
Bsize = 8*1024,
|
||||||
|
Bungetsize = 4, /* space for ungetc */
|
||||||
|
Bmagic = 0x314159,
|
||||||
|
Beof = -1,
|
||||||
|
Bbad = -2,
|
||||||
|
|
||||||
|
Binactive = 0, /* states */
|
||||||
|
Bractive,
|
||||||
|
Bwactive,
|
||||||
|
Bracteof,
|
||||||
|
|
||||||
|
Bend
|
||||||
|
};
|
||||||
|
|
||||||
|
struct Biobuf
|
||||||
|
{
|
||||||
|
int icount; /* neg num of bytes at eob */
|
||||||
|
int ocount; /* num of bytes at bob */
|
||||||
|
int rdline; /* num of bytes after rdline */
|
||||||
|
int runesize; /* num of bytes of last getrune */
|
||||||
|
int state; /* r/w/inactive */
|
||||||
|
int fid; /* open file */
|
||||||
|
int flag; /* magic if malloc'ed */
|
||||||
|
long long offset; /* offset of buffer in file */
|
||||||
|
int bsize; /* size of buffer */
|
||||||
|
unsigned char* bbuf; /* pointer to beginning of buffer */
|
||||||
|
unsigned char* ebuf; /* pointer to end of buffer */
|
||||||
|
unsigned char* gbuf; /* pointer to good data in buf */
|
||||||
|
unsigned char b[Bungetsize+Bsize];
|
||||||
|
};
|
||||||
|
|
||||||
|
#define BGETC(bp)\
|
||||||
|
((bp)->icount?(bp)->bbuf[(bp)->bsize+(bp)->icount++]:Bgetc((bp)))
|
||||||
|
#define BPUTC(bp,c)\
|
||||||
|
((bp)->ocount?(bp)->bbuf[(bp)->bsize+(bp)->ocount++]=(c),0:Bputc((bp),(c)))
|
||||||
|
#define BOFFSET(bp)\
|
||||||
|
(((bp)->state==Bractive)?\
|
||||||
|
(bp)->offset + (bp)->icount:\
|
||||||
|
(((bp)->state==Bwactive)?\
|
||||||
|
(bp)->offset + ((bp)->bsize + (bp)->ocount):\
|
||||||
|
-1))
|
||||||
|
#define BLINELEN(bp)\
|
||||||
|
(bp)->rdline
|
||||||
|
#define BFILDES(bp)\
|
||||||
|
(bp)->fid
|
||||||
|
|
||||||
|
int Bbuffered(Biobuf*);
|
||||||
|
Biobuf* Bfdopen(int, int);
|
||||||
|
int Bfildes(Biobuf*);
|
||||||
|
int Bflush(Biobuf*);
|
||||||
|
int Bgetc(Biobuf*);
|
||||||
|
int Bgetd(Biobuf*, double*);
|
||||||
|
long Bgetrune(Biobuf*);
|
||||||
|
int Binit(Biobuf*, int, int);
|
||||||
|
int Binits(Biobuf*, int, int, unsigned char*, int);
|
||||||
|
int Blinelen(Biobuf*);
|
||||||
|
long long Boffset(Biobuf*);
|
||||||
|
Biobuf* Bopen(char*, int);
|
||||||
|
int Bprint(Biobuf*, char*, ...);
|
||||||
|
int Bputc(Biobuf*, int);
|
||||||
|
int Bputrune(Biobuf*, long);
|
||||||
|
void* Brdline(Biobuf*, int);
|
||||||
|
char* Brdstr(Biobuf*, int, int);
|
||||||
|
long Bread(Biobuf*, void*, long);
|
||||||
|
long long Bseek(Biobuf*, long long, int);
|
||||||
|
int Bterm(Biobuf*);
|
||||||
|
int Bungetc(Biobuf*);
|
||||||
|
int Bungetrune(Biobuf*);
|
||||||
|
long Bwrite(Biobuf*, void*, long);
|
||||||
|
int Bvprint(Biobuf*, char*, va_list);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,116 @@
|
||||||
|
#ifndef _FMT_H_
|
||||||
|
#define _FMT_H_ 1
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <utf.h>
|
||||||
|
|
||||||
|
typedef struct Fmt Fmt;
|
||||||
|
struct Fmt{
|
||||||
|
unsigned char runes; /* output buffer is runes or chars? */
|
||||||
|
void *start; /* of buffer */
|
||||||
|
void *to; /* current place in the buffer */
|
||||||
|
void *stop; /* end of the buffer; overwritten if flush fails */
|
||||||
|
int (*flush)(Fmt *); /* called when to == stop */
|
||||||
|
void *farg; /* to make flush a closure */
|
||||||
|
int nfmt; /* num chars formatted so far */
|
||||||
|
va_list args; /* args passed to dofmt */
|
||||||
|
Rune r; /* % format Rune */
|
||||||
|
int width;
|
||||||
|
int prec;
|
||||||
|
unsigned long flags;
|
||||||
|
char *decimal; /* decimal point; cannot be "" */
|
||||||
|
|
||||||
|
/* For %'d */
|
||||||
|
char *thousands; /* separator for thousands */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Each char is an integer indicating #digits before next separator. Values:
|
||||||
|
* \xFF: no more grouping (or \x7F; defined to be CHAR_MAX in POSIX)
|
||||||
|
* \x00: repeat previous indefinitely
|
||||||
|
* \x**: count that many
|
||||||
|
*/
|
||||||
|
char *grouping; /* descriptor of separator placement */
|
||||||
|
};
|
||||||
|
|
||||||
|
enum{
|
||||||
|
FmtWidth = 1,
|
||||||
|
FmtLeft = FmtWidth << 1,
|
||||||
|
FmtPrec = FmtLeft << 1,
|
||||||
|
FmtSharp = FmtPrec << 1,
|
||||||
|
FmtSpace = FmtSharp << 1,
|
||||||
|
FmtSign = FmtSpace << 1,
|
||||||
|
FmtApost = FmtSign << 1,
|
||||||
|
FmtZero = FmtApost << 1,
|
||||||
|
FmtUnsigned = FmtZero << 1,
|
||||||
|
FmtShort = FmtUnsigned << 1,
|
||||||
|
FmtLong = FmtShort << 1,
|
||||||
|
FmtVLong = FmtLong << 1,
|
||||||
|
FmtComma = FmtVLong << 1,
|
||||||
|
FmtByte = FmtComma << 1,
|
||||||
|
FmtLDouble = FmtByte << 1,
|
||||||
|
|
||||||
|
FmtFlag = FmtLDouble << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int (*fmtdoquote)(int);
|
||||||
|
|
||||||
|
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/fmt/?*.c | grep -v static |grep -v __ */
|
||||||
|
int dofmt(Fmt *f, char *fmt);
|
||||||
|
int dorfmt(Fmt *f, const Rune *fmt);
|
||||||
|
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);
|
||||||
|
int fmtstrcpy(Fmt *f, char *s);
|
||||||
|
char* fmtstrflush(Fmt *f);
|
||||||
|
int fmtstrinit(Fmt *f);
|
||||||
|
double fmtstrtod(const char *as, char **aas);
|
||||||
|
int fmtvprint(Fmt *f, char *fmt, va_list args);
|
||||||
|
int fprint(int fd, char *fmt, ...);
|
||||||
|
int print(char *fmt, ...);
|
||||||
|
void quotefmtinstall(void);
|
||||||
|
int quoterunestrfmt(Fmt *f);
|
||||||
|
int quotestrfmt(Fmt *f);
|
||||||
|
Rune* runefmtstrflush(Fmt *f);
|
||||||
|
int runefmtstrinit(Fmt *f);
|
||||||
|
Rune* runeseprint(Rune *buf, Rune *e, char *fmt, ...);
|
||||||
|
Rune* runesmprint(char *fmt, ...);
|
||||||
|
int runesnprint(Rune *buf, int len, char *fmt, ...);
|
||||||
|
int runesprint(Rune *buf, char *fmt, ...);
|
||||||
|
Rune* runevseprint(Rune *buf, Rune *e, char *fmt, va_list args);
|
||||||
|
Rune* runevsmprint(char *fmt, va_list args);
|
||||||
|
int runevsnprint(Rune *buf, int len, char *fmt, va_list args);
|
||||||
|
char* seprint(char *buf, char *e, char *fmt, ...);
|
||||||
|
char* smprint(char *fmt, ...);
|
||||||
|
int snprint(char *buf, int len, char *fmt, ...);
|
||||||
|
int sprint(char *buf, char *fmt, ...);
|
||||||
|
int vfprint(int fd, char *fmt, va_list args);
|
||||||
|
char* vseprint(char *buf, char *e, char *fmt, va_list args);
|
||||||
|
char* vsmprint(char *fmt, va_list args);
|
||||||
|
int vsnprint(char *buf, int len, char *fmt, va_list args);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,2 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
|
@ -0,0 +1,950 @@
|
||||||
|
// This file originated as Plan 9's /sys/include/libc.h.
|
||||||
|
// The plan9port-specific changes may be distributed
|
||||||
|
// using the license in ../src/lib9/LICENSE.
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Lib9 is miscellany from the Plan 9 C library that doesn't
|
||||||
|
* fit into libutf or into libfmt, but is still missing from traditional
|
||||||
|
* Unix C libraries.
|
||||||
|
*/
|
||||||
|
#ifndef _LIBC_H_
|
||||||
|
#define _LIBC_H_ 1
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#include <utf.h>
|
||||||
|
#include <fmt.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Begin usual libc.h
|
||||||
|
*/
|
||||||
|
|
||||||
|
#ifndef nil
|
||||||
|
#define nil ((void*)0)
|
||||||
|
#endif
|
||||||
|
#define nelem(x) (sizeof(x)/sizeof((x)[0]))
|
||||||
|
|
||||||
|
#ifndef offsetof
|
||||||
|
#define offsetof(s, m) (ulong)(&(((s*)0)->m))
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* mem routines (provided by system <string.h>)
|
||||||
|
*
|
||||||
|
extern void* memccpy(void*, void*, int, ulong);
|
||||||
|
extern void* memset(void*, int, ulong);
|
||||||
|
extern int memcmp(void*, void*, ulong);
|
||||||
|
extern void* memcpy(void*, void*, ulong);
|
||||||
|
extern void* memmove(void*, void*, ulong);
|
||||||
|
extern void* memchr(void*, int, ulong);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* string routines (provided by system <string.h>)
|
||||||
|
*
|
||||||
|
extern char* strcat(char*, char*);
|
||||||
|
extern char* strchr(char*, int);
|
||||||
|
extern int strcmp(char*, char*);
|
||||||
|
extern char* strcpy(char*, char*);
|
||||||
|
*/
|
||||||
|
extern char* strecpy(char*, char*, char*);
|
||||||
|
extern char* p9strdup(char*);
|
||||||
|
/*
|
||||||
|
extern char* strncat(char*, char*, long);
|
||||||
|
extern char* strncpy(char*, char*, long);
|
||||||
|
extern int strncmp(char*, char*, long);
|
||||||
|
extern char* strpbrk(char*, char*);
|
||||||
|
extern char* strrchr(char*, int);
|
||||||
|
extern char* strtok(char*, char*);
|
||||||
|
extern long strlen(char*);
|
||||||
|
extern long strspn(char*, char*);
|
||||||
|
extern long strcspn(char*, char*);
|
||||||
|
extern char* strstr(char*, char*);
|
||||||
|
*/
|
||||||
|
extern int cistrncmp(char*, char*, int);
|
||||||
|
extern int cistrcmp(char*, char*);
|
||||||
|
extern char* cistrstr(char*, char*);
|
||||||
|
extern int tokenize(char*, char**, int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UTFmax = 4,
|
||||||
|
Runesync = 0x80,
|
||||||
|
Runeself = 0x80,
|
||||||
|
Runeerror = 0xFFFD,
|
||||||
|
Runemax = 0x10FFFF,
|
||||||
|
};
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* rune routines (provided by <utf.h>
|
||||||
|
*
|
||||||
|
extern int runetochar(char*, Rune*);
|
||||||
|
extern int chartorune(Rune*, char*);
|
||||||
|
extern int runelen(long);
|
||||||
|
extern int runenlen(Rune*, int);
|
||||||
|
extern int fullrune(char*, int);
|
||||||
|
extern int utflen(char*);
|
||||||
|
extern int utfnlen(char*, long);
|
||||||
|
extern char* utfrune(char*, long);
|
||||||
|
extern char* utfrrune(char*, long);
|
||||||
|
extern char* utfutf(char*, char*);
|
||||||
|
extern char* utfecpy(char*, char*, char*);
|
||||||
|
|
||||||
|
extern Rune* runestrcat(Rune*, Rune*);
|
||||||
|
extern Rune* runestrchr(Rune*, Rune);
|
||||||
|
extern int runestrcmp(Rune*, Rune*);
|
||||||
|
extern Rune* runestrcpy(Rune*, Rune*);
|
||||||
|
extern Rune* runestrncpy(Rune*, Rune*, long);
|
||||||
|
extern Rune* runestrecpy(Rune*, Rune*, Rune*);
|
||||||
|
extern Rune* runestrdup(Rune*);
|
||||||
|
extern Rune* runestrncat(Rune*, Rune*, long);
|
||||||
|
extern int runestrncmp(Rune*, Rune*, long);
|
||||||
|
extern Rune* runestrrchr(Rune*, Rune);
|
||||||
|
extern long runestrlen(Rune*);
|
||||||
|
extern Rune* runestrstr(Rune*, Rune*);
|
||||||
|
|
||||||
|
extern Rune tolowerrune(Rune);
|
||||||
|
extern Rune totitlerune(Rune);
|
||||||
|
extern Rune toupperrune(Rune);
|
||||||
|
extern int isalpharune(Rune);
|
||||||
|
extern int islowerrune(Rune);
|
||||||
|
extern int isspacerune(Rune);
|
||||||
|
extern int istitlerune(Rune);
|
||||||
|
extern int isupperrune(Rune);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* malloc (provied by system <stdlib.h>)
|
||||||
|
*
|
||||||
|
extern void* malloc(ulong);
|
||||||
|
*/
|
||||||
|
extern void* p9malloc(ulong);
|
||||||
|
extern void* mallocz(ulong, int);
|
||||||
|
extern void p9free(void*);
|
||||||
|
extern void* p9calloc(ulong, ulong);
|
||||||
|
extern void* p9realloc(void*, ulong);
|
||||||
|
extern void setmalloctag(void*, ulong);
|
||||||
|
extern void setrealloctag(void*, ulong);
|
||||||
|
extern ulong getmalloctag(void*);
|
||||||
|
extern ulong getrealloctag(void*);
|
||||||
|
/*
|
||||||
|
extern void* malloctopoolblock(void*);
|
||||||
|
*/
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define malloc p9malloc
|
||||||
|
#define realloc p9realloc
|
||||||
|
#define calloc p9calloc
|
||||||
|
#define free p9free
|
||||||
|
#undef strdup
|
||||||
|
#define strdup p9strdup
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* print routines (provided by <fmt.h>)
|
||||||
|
*
|
||||||
|
typedef struct Fmt Fmt;
|
||||||
|
struct Fmt{
|
||||||
|
uchar runes;
|
||||||
|
void *start;
|
||||||
|
void *to;
|
||||||
|
void *stop;
|
||||||
|
int (*flush)(Fmt *);
|
||||||
|
void *farg;
|
||||||
|
int nfmt;
|
||||||
|
va_list args;
|
||||||
|
int r;
|
||||||
|
int width;
|
||||||
|
int prec;
|
||||||
|
ulong flags;
|
||||||
|
};
|
||||||
|
|
||||||
|
enum{
|
||||||
|
FmtWidth = 1,
|
||||||
|
FmtLeft = FmtWidth << 1,
|
||||||
|
FmtPrec = FmtLeft << 1,
|
||||||
|
FmtSharp = FmtPrec << 1,
|
||||||
|
FmtSpace = FmtSharp << 1,
|
||||||
|
FmtSign = FmtSpace << 1,
|
||||||
|
FmtZero = FmtSign << 1,
|
||||||
|
FmtUnsigned = FmtZero << 1,
|
||||||
|
FmtShort = FmtUnsigned << 1,
|
||||||
|
FmtLong = FmtShort << 1,
|
||||||
|
FmtVLong = FmtLong << 1,
|
||||||
|
FmtComma = FmtVLong << 1,
|
||||||
|
FmtByte = FmtComma << 1,
|
||||||
|
|
||||||
|
FmtFlag = FmtByte << 1
|
||||||
|
};
|
||||||
|
|
||||||
|
extern int print(char*, ...);
|
||||||
|
extern char* seprint(char*, char*, char*, ...);
|
||||||
|
extern char* vseprint(char*, char*, char*, va_list);
|
||||||
|
extern int snprint(char*, int, char*, ...);
|
||||||
|
extern int vsnprint(char*, int, char*, va_list);
|
||||||
|
extern char* smprint(char*, ...);
|
||||||
|
extern char* vsmprint(char*, va_list);
|
||||||
|
extern int sprint(char*, char*, ...);
|
||||||
|
extern int fprint(int, char*, ...);
|
||||||
|
extern int vfprint(int, char*, va_list);
|
||||||
|
|
||||||
|
extern int runesprint(Rune*, char*, ...);
|
||||||
|
extern int runesnprint(Rune*, int, char*, ...);
|
||||||
|
extern int runevsnprint(Rune*, int, char*, va_list);
|
||||||
|
extern Rune* runeseprint(Rune*, Rune*, char*, ...);
|
||||||
|
extern Rune* runevseprint(Rune*, Rune*, char*, va_list);
|
||||||
|
extern Rune* runesmprint(char*, ...);
|
||||||
|
extern Rune* runevsmprint(char*, va_list);
|
||||||
|
|
||||||
|
extern int fmtfdinit(Fmt*, int, char*, int);
|
||||||
|
extern int fmtfdflush(Fmt*);
|
||||||
|
extern int fmtstrinit(Fmt*);
|
||||||
|
extern char* fmtstrflush(Fmt*);
|
||||||
|
extern int runefmtstrinit(Fmt*);
|
||||||
|
extern Rune* runefmtstrflush(Fmt*);
|
||||||
|
|
||||||
|
extern int fmtinstall(int, int (*)(Fmt*));
|
||||||
|
extern int dofmt(Fmt*, char*);
|
||||||
|
extern int dorfmt(Fmt*, Rune*);
|
||||||
|
extern int fmtprint(Fmt*, char*, ...);
|
||||||
|
extern int fmtvprint(Fmt*, char*, va_list);
|
||||||
|
extern int fmtrune(Fmt*, int);
|
||||||
|
extern int fmtstrcpy(Fmt*, char*);
|
||||||
|
extern int fmtrunestrcpy(Fmt*, Rune*);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* error string for %r
|
||||||
|
* supplied on per os basis, not part of fmt library
|
||||||
|
*
|
||||||
|
* (provided by lib9, but declared in fmt.h)
|
||||||
|
*
|
||||||
|
extern int errfmt(Fmt *f);
|
||||||
|
*/
|
||||||
|
|
||||||
|
/*
|
||||||
|
* quoted strings
|
||||||
|
*/
|
||||||
|
extern char *unquotestrdup(char*);
|
||||||
|
extern Rune *unquoterunestrdup(Rune*);
|
||||||
|
extern char *quotestrdup(char*);
|
||||||
|
extern Rune *quoterunestrdup(Rune*);
|
||||||
|
/*
|
||||||
|
* in fmt.h
|
||||||
|
*
|
||||||
|
extern void quotefmtinstall(void);
|
||||||
|
extern int quotestrfmt(Fmt*);
|
||||||
|
extern int quoterunestrfmt(Fmt*);
|
||||||
|
*/
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define doquote fmtdoquote
|
||||||
|
#endif
|
||||||
|
extern int needsrcquote(int);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* random number
|
||||||
|
*/
|
||||||
|
extern void p9srand(long);
|
||||||
|
extern int p9rand(void);
|
||||||
|
|
||||||
|
extern int p9nrand(int);
|
||||||
|
extern long p9lrand(void);
|
||||||
|
extern long p9lnrand(long);
|
||||||
|
extern double p9frand(void);
|
||||||
|
extern ulong truerand(void); /* uses /dev/random */
|
||||||
|
extern ulong ntruerand(ulong); /* uses /dev/random */
|
||||||
|
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define srand p9srand
|
||||||
|
#define rand p9rand
|
||||||
|
#define nrand p9nrand
|
||||||
|
#define lrand p9lrand
|
||||||
|
#define lnrand p9lnrand
|
||||||
|
#define frand p9frand
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* math
|
||||||
|
*/
|
||||||
|
extern ulong getfcr(void);
|
||||||
|
extern void setfsr(ulong);
|
||||||
|
extern ulong getfsr(void);
|
||||||
|
extern void setfcr(ulong);
|
||||||
|
extern double NaN(void);
|
||||||
|
extern double Inf(int);
|
||||||
|
extern int isNaN(double);
|
||||||
|
extern int isInf(double, int);
|
||||||
|
extern ulong umuldiv(ulong, ulong, ulong);
|
||||||
|
extern long muldiv(long, long, long);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* provided by math.h
|
||||||
|
*
|
||||||
|
extern double pow(double, double);
|
||||||
|
extern double atan2(double, double);
|
||||||
|
extern double fabs(double);
|
||||||
|
extern double atan(double);
|
||||||
|
extern double log(double);
|
||||||
|
extern double log10(double);
|
||||||
|
extern double exp(double);
|
||||||
|
extern double floor(double);
|
||||||
|
extern double ceil(double);
|
||||||
|
extern double hypot(double, double);
|
||||||
|
extern double sin(double);
|
||||||
|
extern double cos(double);
|
||||||
|
extern double tan(double);
|
||||||
|
extern double asin(double);
|
||||||
|
extern double acos(double);
|
||||||
|
extern double sinh(double);
|
||||||
|
extern double cosh(double);
|
||||||
|
extern double tanh(double);
|
||||||
|
extern double sqrt(double);
|
||||||
|
extern double fmod(double, double);
|
||||||
|
#define HUGE 3.4028234e38
|
||||||
|
#define PIO2 1.570796326794896619231e0
|
||||||
|
#define PI (PIO2+PIO2)
|
||||||
|
*/
|
||||||
|
#define PI M_PI
|
||||||
|
#define PIO2 M_PI_2
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Time-of-day
|
||||||
|
*/
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct Tm
|
||||||
|
{
|
||||||
|
int sec;
|
||||||
|
int min;
|
||||||
|
int hour;
|
||||||
|
int mday;
|
||||||
|
int mon;
|
||||||
|
int year;
|
||||||
|
int wday;
|
||||||
|
int yday;
|
||||||
|
char zone[4];
|
||||||
|
int tzoff;
|
||||||
|
} Tm;
|
||||||
|
|
||||||
|
extern Tm* p9gmtime(long);
|
||||||
|
extern Tm* p9localtime(long);
|
||||||
|
extern char* p9asctime(Tm*);
|
||||||
|
extern char* p9ctime(long);
|
||||||
|
extern double p9cputime(void);
|
||||||
|
extern long p9times(long*);
|
||||||
|
extern long p9tm2sec(Tm*);
|
||||||
|
extern vlong p9nsec(void);
|
||||||
|
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define gmtime p9gmtime
|
||||||
|
#define localtime p9localtime
|
||||||
|
#define asctime p9asctime
|
||||||
|
#define ctime p9ctime
|
||||||
|
#define cputime p9cputime
|
||||||
|
#define times p9times
|
||||||
|
#define tm2sec p9tm2sec
|
||||||
|
#define nsec p9nsec
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* one-of-a-kind
|
||||||
|
*/
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
PNPROC = 1,
|
||||||
|
PNGROUP = 2
|
||||||
|
};
|
||||||
|
|
||||||
|
/* extern int abs(int); <stdlib.h> */
|
||||||
|
extern int p9atexit(void(*)(void));
|
||||||
|
extern void p9atexitdont(void(*)(void));
|
||||||
|
extern int atnotify(int(*)(void*, char*), int);
|
||||||
|
/*
|
||||||
|
* <stdlib.h>
|
||||||
|
extern double atof(char*); <stdlib.h>
|
||||||
|
*/
|
||||||
|
extern int p9atoi(char*);
|
||||||
|
extern long p9atol(char*);
|
||||||
|
extern vlong p9atoll(char*);
|
||||||
|
extern double fmtcharstod(int(*)(void*), void*);
|
||||||
|
extern char* cleanname(char*);
|
||||||
|
extern int p9decrypt(void*, void*, int);
|
||||||
|
extern int p9encrypt(void*, void*, int);
|
||||||
|
extern int netcrypt(void*, void*);
|
||||||
|
extern int dec64(uchar*, int, char*, int);
|
||||||
|
extern int enc64(char*, int, uchar*, int);
|
||||||
|
extern int dec32(uchar*, int, char*, int);
|
||||||
|
extern int enc32(char*, int, uchar*, int);
|
||||||
|
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 p9frexp(double, int*);
|
||||||
|
extern ulong getcallerpc(void*);
|
||||||
|
#if defined(__GNUC__) || defined(__clang__) || defined(__IBMC__)
|
||||||
|
#define getcallerpc(x) ((ulong)__builtin_return_address(0))
|
||||||
|
#endif
|
||||||
|
extern char* p9getenv(char*);
|
||||||
|
extern int p9putenv(char*, char*);
|
||||||
|
extern int getfields(char*, char**, int, int, char*);
|
||||||
|
extern int gettokens(char *, char **, int, char *);
|
||||||
|
extern char* getuser(void);
|
||||||
|
extern char* p9getwd(char*, int);
|
||||||
|
extern int iounit(int);
|
||||||
|
/* extern long labs(long); <math.h> */
|
||||||
|
/* extern double ldexp(double, int); <math.h> */
|
||||||
|
extern void p9longjmp(p9jmp_buf, int);
|
||||||
|
extern char* mktemp(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*);
|
||||||
|
extern int postnote(int, int, char *);
|
||||||
|
extern double p9pow10(int);
|
||||||
|
/* extern int putenv(char*, char*); <stdlib.h. */
|
||||||
|
/* extern void qsort(void*, long, long, int (*)(void*, void*)); <stdlib.h> */
|
||||||
|
extern char* searchpath(char*);
|
||||||
|
/* extern int p9setjmp(p9jmp_buf); */
|
||||||
|
#define p9setjmp(b) sigsetjmp((void*)(b), 1)
|
||||||
|
/*
|
||||||
|
* <stdlib.h>
|
||||||
|
extern long strtol(char*, char**, int);
|
||||||
|
extern ulong strtoul(char*, char**, int);
|
||||||
|
extern vlong strtoll(char*, char**, int);
|
||||||
|
extern uvlong strtoull(char*, char**, int);
|
||||||
|
*/
|
||||||
|
extern void sysfatal(char*, ...);
|
||||||
|
extern void p9syslog(int, char*, char*, ...);
|
||||||
|
extern long p9time(long*);
|
||||||
|
/* extern int tolower(int); <ctype.h> */
|
||||||
|
/* extern int toupper(int); <ctype.h> */
|
||||||
|
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
|
||||||
|
#define atoi p9atoi
|
||||||
|
#define atol p9atol
|
||||||
|
#define atoll p9atoll
|
||||||
|
#define encrypt p9encrypt
|
||||||
|
#define decrypt p9decrypt
|
||||||
|
#undef frexp
|
||||||
|
#define frexp p9frexp
|
||||||
|
#define getenv p9getenv
|
||||||
|
#define getwd p9getwd
|
||||||
|
#define longjmp p9longjmp
|
||||||
|
#undef setjmp
|
||||||
|
#define setjmp p9setjmp
|
||||||
|
#define putenv p9putenv
|
||||||
|
#define notejmp p9notejmp
|
||||||
|
#define jmp_buf p9jmp_buf
|
||||||
|
#define time p9time
|
||||||
|
#define pow10 p9pow10
|
||||||
|
#define strtod fmtstrtod
|
||||||
|
#define charstod fmtcharstod
|
||||||
|
#define syslog p9syslog
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* just enough information so that libc can be
|
||||||
|
* properly locked without dragging in all of libthread
|
||||||
|
*/
|
||||||
|
typedef struct _Thread _Thread;
|
||||||
|
typedef struct _Threadlist _Threadlist;
|
||||||
|
struct _Threadlist
|
||||||
|
{
|
||||||
|
_Thread *head;
|
||||||
|
_Thread *tail;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern _Thread *(*threadnow)(void);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* synchronization
|
||||||
|
*/
|
||||||
|
typedef struct Lock Lock;
|
||||||
|
struct Lock
|
||||||
|
{
|
||||||
|
int init;
|
||||||
|
pthread_mutex_t mutex;
|
||||||
|
int held;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void lock(Lock*);
|
||||||
|
extern void unlock(Lock*);
|
||||||
|
extern int canlock(Lock*);
|
||||||
|
extern int (*_lock)(Lock*, int, ulong);
|
||||||
|
extern void (*_unlock)(Lock*, ulong);
|
||||||
|
|
||||||
|
typedef struct QLock QLock;
|
||||||
|
struct QLock
|
||||||
|
{
|
||||||
|
Lock l;
|
||||||
|
_Thread *owner;
|
||||||
|
_Threadlist waiting;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void qlock(QLock*);
|
||||||
|
extern void qunlock(QLock*);
|
||||||
|
extern int canqlock(QLock*);
|
||||||
|
extern int (*_qlock)(QLock*, int, ulong); /* do not use */
|
||||||
|
extern void (*_qunlock)(QLock*, ulong);
|
||||||
|
|
||||||
|
typedef struct Rendez Rendez;
|
||||||
|
struct Rendez
|
||||||
|
{
|
||||||
|
QLock *l;
|
||||||
|
_Threadlist waiting;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void rsleep(Rendez*); /* unlocks r->l, sleeps, locks r->l again */
|
||||||
|
extern int rwakeup(Rendez*);
|
||||||
|
extern int rwakeupall(Rendez*);
|
||||||
|
extern void (*_rsleep)(Rendez*, ulong); /* do not use */
|
||||||
|
extern int (*_rwakeup)(Rendez*, int, ulong);
|
||||||
|
|
||||||
|
typedef struct RWLock RWLock;
|
||||||
|
struct RWLock
|
||||||
|
{
|
||||||
|
Lock l;
|
||||||
|
int readers;
|
||||||
|
_Thread *writer;
|
||||||
|
_Threadlist rwaiting;
|
||||||
|
_Threadlist wwaiting;
|
||||||
|
};
|
||||||
|
|
||||||
|
extern void rlock(RWLock*);
|
||||||
|
extern void runlock(RWLock*);
|
||||||
|
extern int canrlock(RWLock*);
|
||||||
|
extern void wlock(RWLock*);
|
||||||
|
extern void wunlock(RWLock*);
|
||||||
|
extern int canwlock(RWLock*);
|
||||||
|
extern int (*_rlock)(RWLock*, int, ulong); /* do not use */
|
||||||
|
extern int (*_wlock)(RWLock*, int, ulong);
|
||||||
|
extern void (*_runlock)(RWLock*, ulong);
|
||||||
|
extern void (*_wunlock)(RWLock*, ulong);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* per-process private data
|
||||||
|
*/
|
||||||
|
extern void** privalloc(void);
|
||||||
|
extern void privfree(void**);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* network dialing
|
||||||
|
*/
|
||||||
|
#define NETPATHLEN 40
|
||||||
|
extern int p9accept(int, char*);
|
||||||
|
extern int p9announce(char*, char*);
|
||||||
|
extern int p9dial(char*, char*, char*, int*);
|
||||||
|
extern int p9dialparse(char *ds, char **net, char **unixa, void *ip, int *port);
|
||||||
|
extern void p9setnetmtpt(char*, int, char*);
|
||||||
|
extern int p9listen(char*, char*);
|
||||||
|
extern char* p9netmkaddr(char*, char*, char*);
|
||||||
|
extern int p9reject(int, char*, char*);
|
||||||
|
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define accept p9accept
|
||||||
|
#define announce p9announce
|
||||||
|
#define dial p9dial
|
||||||
|
#define setnetmtpt p9setnetmtpt
|
||||||
|
#define listen p9listen
|
||||||
|
#define netmkaddr p9netmkaddr
|
||||||
|
#define reject p9reject
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/*
|
||||||
|
* encryption
|
||||||
|
*/
|
||||||
|
extern int pushssl(int, char*, char*, char*, int*);
|
||||||
|
extern int pushtls(int, char*, char*, int, char*, char*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* network services
|
||||||
|
*/
|
||||||
|
typedef struct NetConnInfo NetConnInfo;
|
||||||
|
struct NetConnInfo
|
||||||
|
{
|
||||||
|
char *dir; /* connection directory */
|
||||||
|
char *root; /* network root */
|
||||||
|
char *spec; /* binding spec */
|
||||||
|
char *lsys; /* local system */
|
||||||
|
char *lserv; /* local service */
|
||||||
|
char *rsys; /* remote system */
|
||||||
|
char *rserv; /* remote service */
|
||||||
|
char *laddr;
|
||||||
|
char *raddr;
|
||||||
|
};
|
||||||
|
extern NetConnInfo* getnetconninfo(char*, int);
|
||||||
|
extern void freenetconninfo(NetConnInfo*);
|
||||||
|
|
||||||
|
/*
|
||||||
|
* system calls
|
||||||
|
*
|
||||||
|
*/
|
||||||
|
#define STATMAX 65535U /* max length of machine-independent stat structure */
|
||||||
|
#define DIRMAX (sizeof(Dir)+STATMAX) /* max length of Dir structure */
|
||||||
|
#define ERRMAX 128 /* max length of error string */
|
||||||
|
|
||||||
|
#define MORDER 0x0003 /* mask for bits defining order of mounting */
|
||||||
|
#define MREPL 0x0000 /* mount replaces object */
|
||||||
|
#define MBEFORE 0x0001 /* mount goes before others in union directory */
|
||||||
|
#define MAFTER 0x0002 /* mount goes after others in union directory */
|
||||||
|
#define MCREATE 0x0004 /* permit creation in mounted directory */
|
||||||
|
#define MCACHE 0x0010 /* cache some data */
|
||||||
|
#define MMASK 0x0017 /* all bits on */
|
||||||
|
|
||||||
|
#define OREAD 0 /* open for read */
|
||||||
|
#define OWRITE 1 /* write */
|
||||||
|
#define ORDWR 2 /* read and write */
|
||||||
|
#define OEXEC 3 /* execute, == read but check execute permission */
|
||||||
|
#define OTRUNC 16 /* or'ed in (except for exec), truncate file first */
|
||||||
|
#define OCEXEC 32 /* or'ed in, close on exec */
|
||||||
|
#define ORCLOSE 64 /* or'ed in, remove on close */
|
||||||
|
#define ODIRECT 128 /* or'ed in, direct access */
|
||||||
|
#define ONONBLOCK 256 /* or'ed in, non-blocking call */
|
||||||
|
#define OEXCL 0x1000 /* or'ed in, exclusive use (create only) */
|
||||||
|
#define OLOCK 0x2000 /* or'ed in, lock after opening */
|
||||||
|
#define OAPPEND 0x4000 /* or'ed in, append only */
|
||||||
|
|
||||||
|
#define AEXIST 0 /* accessible: exists */
|
||||||
|
#define AEXEC 1 /* execute access */
|
||||||
|
#define AWRITE 2 /* write access */
|
||||||
|
#define AREAD 4 /* read access */
|
||||||
|
|
||||||
|
/* Segattch */
|
||||||
|
#define SG_RONLY 0040 /* read only */
|
||||||
|
#define SG_CEXEC 0100 /* detach on exec */
|
||||||
|
|
||||||
|
#define NCONT 0 /* continue after note */
|
||||||
|
#define NDFLT 1 /* terminate after note */
|
||||||
|
#define NSAVE 2 /* clear note but hold state */
|
||||||
|
#define NRSTR 3 /* restore saved state */
|
||||||
|
|
||||||
|
/* bits in Qid.type */
|
||||||
|
#define QTDIR 0x80 /* type bit for directories */
|
||||||
|
#define QTAPPEND 0x40 /* type bit for append only files */
|
||||||
|
#define QTEXCL 0x20 /* type bit for exclusive use files */
|
||||||
|
#define QTMOUNT 0x10 /* type bit for mounted channel */
|
||||||
|
#define QTAUTH 0x08 /* type bit for authentication file */
|
||||||
|
#define QTTMP 0x04 /* type bit for non-backed-up file */
|
||||||
|
#define QTSYMLINK 0x02 /* type bit for symbolic link */
|
||||||
|
#define QTFILE 0x00 /* type bits for plain file */
|
||||||
|
|
||||||
|
/* bits in Dir.mode */
|
||||||
|
#define DMDIR 0x80000000 /* mode bit for directories */
|
||||||
|
#define DMAPPEND 0x40000000 /* mode bit for append only files */
|
||||||
|
#define DMEXCL 0x20000000 /* mode bit for exclusive use files */
|
||||||
|
#define DMMOUNT 0x10000000 /* mode bit for mounted channel */
|
||||||
|
#define DMAUTH 0x08000000 /* mode bit for authentication file */
|
||||||
|
#define DMTMP 0x04000000 /* mode bit for non-backed-up file */
|
||||||
|
#define DMSYMLINK 0x02000000 /* mode bit for symbolic link (Unix, 9P2000.u) */
|
||||||
|
#define DMDEVICE 0x00800000 /* mode bit for device file (Unix, 9P2000.u) */
|
||||||
|
#define DMNAMEDPIPE 0x00200000 /* mode bit for named pipe (Unix, 9P2000.u) */
|
||||||
|
#define DMSOCKET 0x00100000 /* mode bit for socket (Unix, 9P2000.u) */
|
||||||
|
#define DMSETUID 0x00080000 /* mode bit for setuid (Unix, 9P2000.u) */
|
||||||
|
#define DMSETGID 0x00040000 /* mode bit for setgid (Unix, 9P2000.u) */
|
||||||
|
|
||||||
|
#define DMREAD 0x4 /* mode bit for read permission */
|
||||||
|
#define DMWRITE 0x2 /* mode bit for write permission */
|
||||||
|
#define DMEXEC 0x1 /* mode bit for execute permission */
|
||||||
|
|
||||||
|
#ifdef RFMEM /* FreeBSD, OpenBSD */
|
||||||
|
#undef RFFDG
|
||||||
|
#undef RFNOTEG
|
||||||
|
#undef RFPROC
|
||||||
|
#undef RFMEM
|
||||||
|
#undef RFNOWAIT
|
||||||
|
#undef RFCFDG
|
||||||
|
#undef RFNAMEG
|
||||||
|
#undef RFENVG
|
||||||
|
#undef RFCENVG
|
||||||
|
#undef RFCFDG
|
||||||
|
#undef RFCNAMEG
|
||||||
|
#endif
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
RFNAMEG = (1<<0),
|
||||||
|
RFENVG = (1<<1),
|
||||||
|
RFFDG = (1<<2),
|
||||||
|
RFNOTEG = (1<<3),
|
||||||
|
RFPROC = (1<<4),
|
||||||
|
RFMEM = (1<<5),
|
||||||
|
RFNOWAIT = (1<<6),
|
||||||
|
RFCNAMEG = (1<<10),
|
||||||
|
RFCENVG = (1<<11),
|
||||||
|
RFCFDG = (1<<12)
|
||||||
|
/* RFREND = (1<<13), */
|
||||||
|
/* RFNOMNT = (1<<14) */
|
||||||
|
};
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct Qid
|
||||||
|
{
|
||||||
|
uvlong path;
|
||||||
|
ulong vers;
|
||||||
|
uchar type;
|
||||||
|
} Qid;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct Dir {
|
||||||
|
/* system-modified data */
|
||||||
|
ushort type; /* server type */
|
||||||
|
uint dev; /* server subtype */
|
||||||
|
/* file data */
|
||||||
|
Qid qid; /* unique id from server */
|
||||||
|
ulong mode; /* permissions */
|
||||||
|
ulong atime; /* last read time */
|
||||||
|
ulong mtime; /* last write time */
|
||||||
|
vlong length; /* file length */
|
||||||
|
char *name; /* last element of path */
|
||||||
|
char *uid; /* owner name */
|
||||||
|
char *gid; /* group name */
|
||||||
|
char *muid; /* last modifier name */
|
||||||
|
|
||||||
|
/* 9P2000.u extensions */
|
||||||
|
uint uidnum; /* numeric uid */
|
||||||
|
uint gidnum; /* numeric gid */
|
||||||
|
uint muidnum; /* numeric muid */
|
||||||
|
char *ext; /* extended info */
|
||||||
|
} Dir;
|
||||||
|
|
||||||
|
/* keep /sys/src/ape/lib/ap/plan9/sys9.h in sync with this -rsc */
|
||||||
|
typedef
|
||||||
|
struct Waitmsg
|
||||||
|
{
|
||||||
|
int pid; /* of loved one */
|
||||||
|
ulong time[3]; /* of loved one & descendants */
|
||||||
|
char *msg;
|
||||||
|
} Waitmsg;
|
||||||
|
|
||||||
|
typedef
|
||||||
|
struct IOchunk
|
||||||
|
{
|
||||||
|
void *addr;
|
||||||
|
ulong len;
|
||||||
|
} IOchunk;
|
||||||
|
|
||||||
|
extern void _exits(char*);
|
||||||
|
|
||||||
|
extern void abort(void);
|
||||||
|
/* extern int access(char*, int); */
|
||||||
|
extern long p9alarm(ulong);
|
||||||
|
extern int await(char*, int);
|
||||||
|
extern int awaitfor(int, char*, int);
|
||||||
|
extern int awaitnohang(char*, int);
|
||||||
|
/* extern int bind(char*, char*, int); give up */
|
||||||
|
/* extern int brk(void*); <unistd.h> */
|
||||||
|
extern int p9chdir(char*);
|
||||||
|
extern int p9close(int);
|
||||||
|
extern int p9create(char*, int, ulong);
|
||||||
|
extern int p9dup(int, int);
|
||||||
|
extern int errstr(char*, uint);
|
||||||
|
extern int p9exec(char*, char*[]);
|
||||||
|
extern int p9execl(char*, ...);
|
||||||
|
/* extern int p9fork(void); */
|
||||||
|
extern int p9rfork(int);
|
||||||
|
/* not implemented
|
||||||
|
extern int fauth(int, char*);
|
||||||
|
extern int fstat(int, uchar*, int);
|
||||||
|
extern int fwstat(int, uchar*, int);
|
||||||
|
extern int fversion(int, int, char*, int);
|
||||||
|
extern int mount(int, int, char*, int, char*);
|
||||||
|
extern int unmount(char*, char*);
|
||||||
|
*/
|
||||||
|
extern int noted(int);
|
||||||
|
extern int notify(void(*)(void*, char*));
|
||||||
|
extern int noteenable(char*);
|
||||||
|
extern int notedisable(char*);
|
||||||
|
extern int notifyon(char*);
|
||||||
|
extern int notifyoff(char*);
|
||||||
|
extern int p9open(char*, int);
|
||||||
|
extern int fd2path(int, char*, int);
|
||||||
|
extern int p9pipe(int*);
|
||||||
|
/*
|
||||||
|
* use defs from <unistd.h>
|
||||||
|
extern long pread(int, void*, long, vlong);
|
||||||
|
extern long preadv(int, IOchunk*, int, vlong);
|
||||||
|
extern long pwrite(int, void*, long, vlong);
|
||||||
|
extern long pwritev(int, IOchunk*, int, vlong);
|
||||||
|
extern long read(int, void*, long);
|
||||||
|
*/
|
||||||
|
extern long readn(int, void*, long);
|
||||||
|
/* extern long readv(int, IOchunk*, int); <unistd.h> */
|
||||||
|
extern int remove(const char*);
|
||||||
|
/* extern void* sbrk(ulong); <unistd.h> */
|
||||||
|
/* extern long oseek(int, long, int); */
|
||||||
|
extern vlong p9seek(int, vlong, int);
|
||||||
|
/* give up
|
||||||
|
extern long segattach(int, char*, void*, ulong);
|
||||||
|
extern int segbrk(void*, void*);
|
||||||
|
extern int segdetach(void*);
|
||||||
|
extern int segflush(void*, ulong);
|
||||||
|
extern int segfree(void*, ulong);
|
||||||
|
*/
|
||||||
|
extern int p9sleep(long);
|
||||||
|
/* extern int stat(char*, uchar*, int); give up */
|
||||||
|
extern Waitmsg* p9wait(void);
|
||||||
|
extern Waitmsg* p9waitfor(int);
|
||||||
|
extern Waitmsg* waitnohang(void);
|
||||||
|
extern int p9waitpid(void);
|
||||||
|
/* <unistd.h>
|
||||||
|
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);
|
||||||
|
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define alarm p9alarm
|
||||||
|
#define dup p9dup
|
||||||
|
#define exec p9exec
|
||||||
|
#define execl p9execl
|
||||||
|
#define seek p9seek
|
||||||
|
#define sleep p9sleep
|
||||||
|
#define wait p9wait
|
||||||
|
#define waitpid p9waitpid
|
||||||
|
/* #define fork p9fork */
|
||||||
|
#define rfork p9rfork
|
||||||
|
/* #define access p9access */
|
||||||
|
#define create p9create
|
||||||
|
#undef open
|
||||||
|
#define open p9open
|
||||||
|
#undef close
|
||||||
|
#define close p9close
|
||||||
|
#define pipe p9pipe
|
||||||
|
#define waitfor p9waitfor
|
||||||
|
#define write p9write
|
||||||
|
#endif
|
||||||
|
|
||||||
|
extern Dir* dirstat(char*);
|
||||||
|
extern Dir* dirfstat(int);
|
||||||
|
extern int dirwstat(char*, Dir*);
|
||||||
|
extern int dirfwstat(int, Dir*);
|
||||||
|
extern long dirread(int, Dir**);
|
||||||
|
extern void nulldir(Dir*);
|
||||||
|
extern long dirreadall(int, Dir**);
|
||||||
|
/* extern int getpid(void); <unistd.h> */
|
||||||
|
/* extern int getppid(void); */
|
||||||
|
extern void rerrstr(char*, uint);
|
||||||
|
extern char* sysname(void);
|
||||||
|
extern void werrstr(char*, ...);
|
||||||
|
extern char* getns(void);
|
||||||
|
extern char* get9root(void);
|
||||||
|
extern char* unsharp(char*);
|
||||||
|
extern int sendfd(int, int);
|
||||||
|
extern int recvfd(int);
|
||||||
|
extern int post9pservice(int, char*, char*);
|
||||||
|
extern int chattyfuse;
|
||||||
|
|
||||||
|
/* external names that we don't want to step on */
|
||||||
|
#ifndef NOPLAN9DEFINES
|
||||||
|
#define main p9main
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifdef VARARGCK
|
||||||
|
#pragma varargck type "lld" vlong
|
||||||
|
#pragma varargck type "llx" vlong
|
||||||
|
#pragma varargck type "lld" uvlong
|
||||||
|
#pragma varargck type "llx" uvlong
|
||||||
|
#pragma varargck type "ld" long
|
||||||
|
#pragma varargck type "lx" long
|
||||||
|
#pragma varargck type "ld" ulong
|
||||||
|
#pragma varargck type "lx" ulong
|
||||||
|
#pragma varargck type "d" int
|
||||||
|
#pragma varargck type "x" int
|
||||||
|
#pragma varargck type "c" int
|
||||||
|
#pragma varargck type "C" int
|
||||||
|
#pragma varargck type "d" uint
|
||||||
|
#pragma varargck type "x" uint
|
||||||
|
#pragma varargck type "c" uint
|
||||||
|
#pragma varargck type "C" uint
|
||||||
|
#pragma varargck type "f" double
|
||||||
|
#pragma varargck type "e" double
|
||||||
|
#pragma varargck type "g" double
|
||||||
|
#pragma varargck type "lf" long double
|
||||||
|
#pragma varargck type "le" long double
|
||||||
|
#pragma varargck type "lg" long double
|
||||||
|
#pragma varargck type "s" char*
|
||||||
|
#pragma varargck type "q" char*
|
||||||
|
#pragma varargck type "S" Rune*
|
||||||
|
#pragma varargck type "Q" Rune*
|
||||||
|
#pragma varargck type "r" void
|
||||||
|
#pragma varargck type "%" void
|
||||||
|
#pragma varargck type "n" int*
|
||||||
|
#pragma varargck type "p" void*
|
||||||
|
#pragma varargck type "<" void*
|
||||||
|
#pragma varargck type "[" void*
|
||||||
|
#pragma varargck type "H" void*
|
||||||
|
#pragma varargck type "lH" void*
|
||||||
|
|
||||||
|
#pragma varargck flag ' '
|
||||||
|
#pragma varargck flag '#'
|
||||||
|
#pragma varargck flag '+'
|
||||||
|
#pragma varargck flag ','
|
||||||
|
#pragma varargck flag '-'
|
||||||
|
#pragma varargck flag 'u'
|
||||||
|
|
||||||
|
#pragma varargck argpos fmtprint 2
|
||||||
|
#pragma varargck argpos fprint 2
|
||||||
|
#pragma varargck argpos print 1
|
||||||
|
#pragma varargck argpos runeseprint 3
|
||||||
|
#pragma varargck argpos runesmprint 1
|
||||||
|
#pragma varargck argpos runesnprint 3
|
||||||
|
#pragma varargck argpos runesprint 2
|
||||||
|
#pragma varargck argpos seprint 3
|
||||||
|
#pragma varargck argpos smprint 1
|
||||||
|
#pragma varargck argpos snprint 3
|
||||||
|
#pragma varargck argpos sprint 2
|
||||||
|
#pragma varargck argpos sysfatal 1
|
||||||
|
#pragma varargck argpos p9syslog 3
|
||||||
|
#pragma varargck argpos werrstr 1
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* compiler directives on plan 9 */
|
||||||
|
#define SET(x) ((x)=0)
|
||||||
|
#define USED(x) if(x){}else{}
|
||||||
|
#ifdef __GNUC__
|
||||||
|
# if __GNUC__ >= 3
|
||||||
|
# undef USED
|
||||||
|
# define USED(x) ((void)(x))
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
/* command line */
|
||||||
|
extern char *argv0;
|
||||||
|
extern void __fixargv0(void);
|
||||||
|
#define ARGBEGIN for((argv0?0:(argv0=(__fixargv0(),*argv))),argv++,argc--;\
|
||||||
|
argv[0] && argv[0][0]=='-' && argv[0][1];\
|
||||||
|
argc--, argv++) {\
|
||||||
|
char *_args, *_argt;\
|
||||||
|
Rune _argc;\
|
||||||
|
_args = &argv[0][1];\
|
||||||
|
if(_args[0]=='-' && _args[1]==0){\
|
||||||
|
argc--; argv++; break;\
|
||||||
|
}\
|
||||||
|
_argc = 0;\
|
||||||
|
while(*_args && (_args += chartorune(&_argc, _args)))\
|
||||||
|
switch(_argc)
|
||||||
|
#define ARGEND SET(_argt);USED(_argt);USED(_argc);USED(_args);}USED(argv);USED(argc);
|
||||||
|
#define ARGF() (_argt=_args, _args="",\
|
||||||
|
(*_argt? _argt: argv[1]? (argc--, *++argv): 0))
|
||||||
|
#define EARGF(x) (_argt=_args, _args="",\
|
||||||
|
(*_argt? _argt: argv[1]? (argc--, *++argv): ((x), abort(), (char*)0)))
|
||||||
|
|
||||||
|
#define ARGC() _argc
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif /* _LIB9_H_ */
|
|
@ -0,0 +1,195 @@
|
||||||
|
// See ../src/lib9/LICENSE
|
||||||
|
|
||||||
|
#ifndef _U_H_
|
||||||
|
#define _U_H_ 1
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#define HAS_SYS_TERMIOS 1
|
||||||
|
|
||||||
|
#define __BSD_VISIBLE 1 /* FreeBSD 5.x */
|
||||||
|
#if defined(__sun__)
|
||||||
|
# define __EXTENSIONS__ 1 /* SunOS */
|
||||||
|
# if defined(__SunOS5_6__) || defined(__SunOS5_7__) || defined(__SunOS5_8__) || defined(__SunOS5_9__) || defined(__SunOS5_10__)
|
||||||
|
/* NOT USING #define __MAKECONTEXT_V2_SOURCE 1 / * SunOS */
|
||||||
|
# else
|
||||||
|
/* What's left? */
|
||||||
|
# define __MAKECONTEXT_V2_SOURCE 1
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
#define _BSD_SOURCE 1
|
||||||
|
#define _NETBSD_SOURCE 1 /* NetBSD */
|
||||||
|
#define _SVID_SOURCE 1
|
||||||
|
#define _DEFAULT_SOURCE 1
|
||||||
|
#if !defined(__APPLE__) && !defined(__OpenBSD__) && !defined(__AIX__)
|
||||||
|
# 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 _ALL_SOURCE
|
||||||
|
# undef HAS_SYS_TERMIOS
|
||||||
|
#endif
|
||||||
|
#define _LARGEFILE64_SOURCE 1
|
||||||
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
|
||||||
|
#include <inttypes.h>
|
||||||
|
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
#include <stdarg.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <assert.h>
|
||||||
|
#include <setjmp.h>
|
||||||
|
#include <stddef.h>
|
||||||
|
#include <math.h>
|
||||||
|
#include <ctype.h> /* for tolower */
|
||||||
|
|
||||||
|
/*
|
||||||
|
* OS-specific crap
|
||||||
|
*/
|
||||||
|
#define _NEEDUCHAR 1
|
||||||
|
#define _NEEDUSHORT 1
|
||||||
|
#define _NEEDUINT 1
|
||||||
|
#define _NEEDULONG 1
|
||||||
|
|
||||||
|
typedef long p9jmp_buf[sizeof(sigjmp_buf)/sizeof(long)];
|
||||||
|
|
||||||
|
#if defined(__linux__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# if defined(__USE_MISC)
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# undef _NEEDULONG
|
||||||
|
# endif
|
||||||
|
#elif defined(__sun__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# undef _NEEDULONG
|
||||||
|
# define nil 0 /* no cast to void* */
|
||||||
|
#elif defined(__FreeBSD__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <osreldate.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# if !defined(_POSIX_SOURCE)
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# endif
|
||||||
|
#elif defined(__APPLE__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# if __GNUC__ < 4
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# endif
|
||||||
|
# undef _ANSI_SOURCE
|
||||||
|
# undef _POSIX_C_SOURCE
|
||||||
|
# undef _XOPEN_SOURCE
|
||||||
|
# if !defined(NSIG)
|
||||||
|
# define NSIG 32
|
||||||
|
# endif
|
||||||
|
# define _NEEDLL 1
|
||||||
|
#elif defined(__NetBSD__)
|
||||||
|
# include <sched.h>
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# undef _NEEDULONG
|
||||||
|
#elif defined(__OpenBSD__)
|
||||||
|
# include <sys/types.h>
|
||||||
|
# include <pthread.h>
|
||||||
|
# undef _NEEDUSHORT
|
||||||
|
# undef _NEEDUINT
|
||||||
|
# undef _NEEDULONG
|
||||||
|
#else
|
||||||
|
/* No idea what system this is -- try some defaults */
|
||||||
|
# include <pthread.h>
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#ifndef O_DIRECT
|
||||||
|
#define O_DIRECT 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef signed char schar;
|
||||||
|
|
||||||
|
#ifdef _NEEDUCHAR
|
||||||
|
typedef unsigned char uchar;
|
||||||
|
#endif
|
||||||
|
#ifdef _NEEDUSHORT
|
||||||
|
typedef unsigned short ushort;
|
||||||
|
#endif
|
||||||
|
#ifdef _NEEDUINT
|
||||||
|
typedef unsigned int uint;
|
||||||
|
#endif
|
||||||
|
#ifdef _NEEDULONG
|
||||||
|
typedef unsigned long ulong;
|
||||||
|
#endif
|
||||||
|
typedef unsigned long long uvlong;
|
||||||
|
typedef long long vlong;
|
||||||
|
|
||||||
|
typedef uvlong u64int;
|
||||||
|
typedef vlong s64int;
|
||||||
|
typedef uint8_t u8int;
|
||||||
|
typedef int8_t s8int;
|
||||||
|
typedef uint16_t u16int;
|
||||||
|
typedef int16_t s16int;
|
||||||
|
typedef uintptr_t uintptr;
|
||||||
|
typedef intptr_t intptr;
|
||||||
|
typedef uint u32int;
|
||||||
|
typedef int s32int;
|
||||||
|
|
||||||
|
typedef u32int uint32;
|
||||||
|
typedef s32int int32;
|
||||||
|
typedef u16int uint16;
|
||||||
|
typedef s16int int16;
|
||||||
|
typedef u64int uint64;
|
||||||
|
typedef s64int int64;
|
||||||
|
typedef u8int uint8;
|
||||||
|
typedef s8int int8;
|
||||||
|
|
||||||
|
#undef _NEEDUCHAR
|
||||||
|
#undef _NEEDUSHORT
|
||||||
|
#undef _NEEDUINT
|
||||||
|
#undef _NEEDULONG
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Funny-named symbols to tip off 9l to autolink.
|
||||||
|
*/
|
||||||
|
#define AUTOLIB(x) static int __p9l_autolib_ ## x = 1;
|
||||||
|
#define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x = 1;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Gcc is too smart for its own good.
|
||||||
|
*/
|
||||||
|
#if defined(__GNUC__)
|
||||||
|
# undef strcmp /* causes way too many warnings */
|
||||||
|
# if __GNUC__ >= 4 || (__GNUC__==3 && !defined(__APPLE_CC__))
|
||||||
|
# undef AUTOLIB
|
||||||
|
# define AUTOLIB(x) int __p9l_autolib_ ## x __attribute__ ((weak));
|
||||||
|
# undef AUTOFRAMEWORK
|
||||||
|
# define AUTOFRAMEWORK(x) int __p9l_autoframework_ ## x __attribute__ ((weak));
|
||||||
|
# else
|
||||||
|
# undef AUTOLIB
|
||||||
|
# define AUTOLIB(x) static int __p9l_autolib_ ## x __attribute__ ((unused));
|
||||||
|
# undef AUTOFRAMEWORK
|
||||||
|
# define AUTOFRAMEWORK(x) static int __p9l_autoframework_ ## x __attribute__ ((unused));
|
||||||
|
# endif
|
||||||
|
#endif
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,54 @@
|
||||||
|
#ifndef _UTF_H_
|
||||||
|
#define _UTF_H_ 1
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
extern "C" {
|
||||||
|
#endif
|
||||||
|
|
||||||
|
typedef unsigned int Rune; /* 32 bits */
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
UTFmax = 4, /* maximum bytes per rune */
|
||||||
|
Runesync = 0x80, /* cannot represent part of a UTF sequence (<) */
|
||||||
|
Runeself = 0x80, /* rune and UTF sequences are the same (<) */
|
||||||
|
Runeerror = 0xFFFD, /* decoding error in UTF */
|
||||||
|
Runemax = 0x10FFFF /* maximum rune value */
|
||||||
|
};
|
||||||
|
|
||||||
|
/* Edit .+1,/^$/ | cfn $PLAN9/src/lib9/utf/?*.c | grep -v static |grep -v __ */
|
||||||
|
int chartorune(Rune *rune, char *str);
|
||||||
|
int fullrune(char *str, int n);
|
||||||
|
int isalpharune(Rune c);
|
||||||
|
int islowerrune(Rune c);
|
||||||
|
int isspacerune(Rune c);
|
||||||
|
int istitlerune(Rune c);
|
||||||
|
int isupperrune(Rune c);
|
||||||
|
int runelen(long c);
|
||||||
|
int runenlen(Rune *r, int nrune);
|
||||||
|
Rune* runestrcat(Rune *s1, Rune *s2);
|
||||||
|
Rune* runestrchr(Rune *s, Rune c);
|
||||||
|
int runestrcmp(Rune *s1, Rune *s2);
|
||||||
|
Rune* runestrcpy(Rune *s1, Rune *s2);
|
||||||
|
Rune* runestrdup(Rune *s) ;
|
||||||
|
Rune* runestrecpy(Rune *s1, Rune *es1, Rune *s2);
|
||||||
|
long runestrlen(Rune *s);
|
||||||
|
Rune* runestrncat(Rune *s1, Rune *s2, long n);
|
||||||
|
int runestrncmp(Rune *s1, Rune *s2, long n);
|
||||||
|
Rune* runestrncpy(Rune *s1, Rune *s2, long n);
|
||||||
|
Rune* runestrrchr(Rune *s, Rune c);
|
||||||
|
Rune* runestrstr(Rune *s1, Rune *s2);
|
||||||
|
int runetochar(char *str, Rune *rune);
|
||||||
|
Rune tolowerrune(Rune c);
|
||||||
|
Rune totitlerune(Rune c);
|
||||||
|
Rune toupperrune(Rune c);
|
||||||
|
char* utfecpy(char *to, char *e, char *from);
|
||||||
|
int utflen(char *s);
|
||||||
|
int utfnlen(char *s, long m);
|
||||||
|
char* utfrrune(char *s, long c);
|
||||||
|
char* utfrune(char *s, long c);
|
||||||
|
char* utfutf(char *s1, char *s2);
|
||||||
|
|
||||||
|
#if defined(__cplusplus)
|
||||||
|
}
|
||||||
|
#endif
|
||||||
|
#endif
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <fmt.h>
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define OREAD O_RDONLY
|
||||||
|
#define OWRITE O_WRONLY
|
||||||
|
|
||||||
|
#include <utf.h>
|
||||||
|
|
||||||
|
#define nil ((void*)0)
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bbuffered(Biobuf *bp)
|
||||||
|
{
|
||||||
|
switch(bp->state) {
|
||||||
|
case Bracteof:
|
||||||
|
case Bractive:
|
||||||
|
return -bp->icount;
|
||||||
|
|
||||||
|
case Bwactive:
|
||||||
|
return bp->bsize + bp->ocount;
|
||||||
|
|
||||||
|
case Binactive:
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
fprint(2, "Bbuffered: unknown state %d\n", bp->state);
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,46 @@
|
||||||
|
#include <fmt.h>
|
||||||
|
#include "bio.h"
|
||||||
|
|
||||||
|
Biobuf bout;
|
||||||
|
|
||||||
|
void
|
||||||
|
bcat(Biobuf *b, char *name)
|
||||||
|
{
|
||||||
|
char buf[1000];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
while((n = Bread(b, buf, sizeof buf)) > 0){
|
||||||
|
if(Bwrite(&bout, buf, n) < 0)
|
||||||
|
fprint(2, "writing during %s: %r\n", name);
|
||||||
|
}
|
||||||
|
if(n < 0)
|
||||||
|
fprint(2, "reading %s: %r\n", name);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
main(int argc, char **argv)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
Biobuf b, *bp;
|
||||||
|
Fmt fmt;
|
||||||
|
|
||||||
|
Binit(&bout, 1, O_WRONLY);
|
||||||
|
Bfmtinit(&fmt, &bout);
|
||||||
|
fmtprint(&fmt, "hello, world\n");
|
||||||
|
Bfmtflush(&fmt);
|
||||||
|
|
||||||
|
if(argc == 1){
|
||||||
|
Binit(&b, 0, O_RDONLY);
|
||||||
|
bcat(&b, "<stdin>");
|
||||||
|
}else{
|
||||||
|
for(i=1; i<argc; i++){
|
||||||
|
if((bp = Bopen(argv[i], O_RDONLY)) == 0){
|
||||||
|
fprint(2, "Bopen %s: %r\n", argv[i]);
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
bcat(bp, argv[i]);
|
||||||
|
Bterm(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
exit(0);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bfildes(Biobuf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
return bp->fid;
|
||||||
|
}
|
|
@ -0,0 +1,33 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bflush(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int n, c;
|
||||||
|
|
||||||
|
switch(bp->state) {
|
||||||
|
case Bwactive:
|
||||||
|
n = bp->bsize+bp->ocount;
|
||||||
|
if(n == 0)
|
||||||
|
return 0;
|
||||||
|
c = write(bp->fid, bp->bbuf, n);
|
||||||
|
if(n == c) {
|
||||||
|
bp->offset += n;
|
||||||
|
bp->ocount = -bp->bsize;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bp->state = Binactive;
|
||||||
|
bp->ocount = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bracteof:
|
||||||
|
bp->state = Bractive;
|
||||||
|
|
||||||
|
case Bractive:
|
||||||
|
bp->icount = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return Beof;
|
||||||
|
}
|
|
@ -0,0 +1,53 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bgetc(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
loop:
|
||||||
|
i = bp->icount;
|
||||||
|
if(i != 0) {
|
||||||
|
bp->icount = i+1;
|
||||||
|
return bp->ebuf[i];
|
||||||
|
}
|
||||||
|
if(bp->state != Bractive) {
|
||||||
|
if(bp->state == Bracteof)
|
||||||
|
bp->state = Bractive;
|
||||||
|
return Beof;
|
||||||
|
}
|
||||||
|
/*
|
||||||
|
* get next buffer, try to keep Bungetsize
|
||||||
|
* characters pre-catenated from the previous
|
||||||
|
* buffer to allow that many ungets.
|
||||||
|
*/
|
||||||
|
memmove(bp->bbuf-Bungetsize, bp->ebuf-Bungetsize, Bungetsize);
|
||||||
|
i = read(bp->fid, bp->bbuf, bp->bsize);
|
||||||
|
bp->gbuf = bp->bbuf;
|
||||||
|
if(i <= 0) {
|
||||||
|
bp->state = Bracteof;
|
||||||
|
if(i < 0)
|
||||||
|
bp->state = Binactive;
|
||||||
|
return Beof;
|
||||||
|
}
|
||||||
|
if(i < bp->bsize) {
|
||||||
|
memmove(bp->ebuf-i-Bungetsize, bp->bbuf-Bungetsize, i+Bungetsize);
|
||||||
|
bp->gbuf = bp->ebuf-i;
|
||||||
|
}
|
||||||
|
bp->icount = -i;
|
||||||
|
bp->offset += i;
|
||||||
|
goto loop;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Bungetc(Biobuf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(bp->state == Bracteof)
|
||||||
|
bp->state = Bractive;
|
||||||
|
if(bp->state != Bractive)
|
||||||
|
return Beof;
|
||||||
|
bp->icount--;
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,36 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
struct bgetd
|
||||||
|
{
|
||||||
|
Biobuf* b;
|
||||||
|
int eof;
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
Bgetdf(void *vp)
|
||||||
|
{
|
||||||
|
int c;
|
||||||
|
struct bgetd *bg = vp;
|
||||||
|
|
||||||
|
c = Bgetc(bg->b);
|
||||||
|
if(c == Beof)
|
||||||
|
bg->eof = 1;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Bgetd(Biobuf *bp, double *dp)
|
||||||
|
{
|
||||||
|
double d;
|
||||||
|
struct bgetd b;
|
||||||
|
|
||||||
|
b.b = bp;
|
||||||
|
b.eof = 0;
|
||||||
|
d = fmtcharstod(Bgetdf, &b);
|
||||||
|
if(b.eof)
|
||||||
|
return -1;
|
||||||
|
Bungetc(bp);
|
||||||
|
*dp = d;
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,47 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
#include <utf.h>
|
||||||
|
|
||||||
|
long
|
||||||
|
Bgetrune(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int c, i;
|
||||||
|
Rune rune;
|
||||||
|
char str[UTFmax];
|
||||||
|
|
||||||
|
c = Bgetc(bp);
|
||||||
|
if(c < Runeself) { /* one char */
|
||||||
|
bp->runesize = 1;
|
||||||
|
return c;
|
||||||
|
}
|
||||||
|
str[0] = c;
|
||||||
|
|
||||||
|
for(i=1;;) {
|
||||||
|
c = Bgetc(bp);
|
||||||
|
if(c < 0)
|
||||||
|
return c;
|
||||||
|
str[i++] = c;
|
||||||
|
|
||||||
|
if(fullrune(str, i)) {
|
||||||
|
bp->runesize = chartorune(&rune, str);
|
||||||
|
while(i > bp->runesize) {
|
||||||
|
Bungetc(bp);
|
||||||
|
i--;
|
||||||
|
}
|
||||||
|
return rune;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Bungetrune(Biobuf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
if(bp->state == Bracteof)
|
||||||
|
bp->state = Bractive;
|
||||||
|
if(bp->state != Bractive)
|
||||||
|
return Beof;
|
||||||
|
bp->icount -= bp->runesize;
|
||||||
|
bp->runesize = 0;
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
MAXBUFS = 20
|
||||||
|
};
|
||||||
|
|
||||||
|
static Biobuf* wbufs[MAXBUFS];
|
||||||
|
static int atexitflag;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
batexit(void)
|
||||||
|
{
|
||||||
|
Biobuf *bp;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<MAXBUFS; i++) {
|
||||||
|
bp = wbufs[i];
|
||||||
|
if(bp != 0) {
|
||||||
|
wbufs[i] = 0;
|
||||||
|
Bflush(bp);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
deinstall(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<MAXBUFS; i++)
|
||||||
|
if(wbufs[i] == bp)
|
||||||
|
wbufs[i] = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
install(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
deinstall(bp);
|
||||||
|
for(i=0; i<MAXBUFS; i++)
|
||||||
|
if(wbufs[i] == 0) {
|
||||||
|
wbufs[i] = bp;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(atexitflag == 0) {
|
||||||
|
atexitflag = 1;
|
||||||
|
atexit(batexit);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Binits(Biobuf *bp, int f, int mode, unsigned char *p, int size)
|
||||||
|
{
|
||||||
|
|
||||||
|
p += Bungetsize; /* make room for Bungets */
|
||||||
|
size -= Bungetsize;
|
||||||
|
|
||||||
|
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
|
||||||
|
default:
|
||||||
|
fprint(2, "Bopen: unknown mode %d\n", mode);
|
||||||
|
return Beof;
|
||||||
|
|
||||||
|
case OREAD:
|
||||||
|
bp->state = Bractive;
|
||||||
|
bp->ocount = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OWRITE:
|
||||||
|
install(bp);
|
||||||
|
bp->state = Bwactive;
|
||||||
|
bp->ocount = -size;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp->bbuf = p;
|
||||||
|
bp->ebuf = p+size;
|
||||||
|
bp->bsize = size;
|
||||||
|
bp->icount = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
bp->fid = f;
|
||||||
|
bp->flag = 0;
|
||||||
|
bp->rdline = 0;
|
||||||
|
bp->offset = 0;
|
||||||
|
bp->runesize = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
int
|
||||||
|
Binit(Biobuf *bp, int f, int mode)
|
||||||
|
{
|
||||||
|
return Binits(bp, f, mode, bp->b, sizeof(bp->b));
|
||||||
|
}
|
||||||
|
|
||||||
|
Biobuf*
|
||||||
|
Bfdopen(int f, int mode)
|
||||||
|
{
|
||||||
|
Biobuf *bp;
|
||||||
|
|
||||||
|
bp = malloc(sizeof(Biobuf));
|
||||||
|
if(bp == 0)
|
||||||
|
return 0;
|
||||||
|
Binits(bp, f, mode, bp->b, sizeof(bp->b));
|
||||||
|
bp->flag = Bmagic;
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
Biobuf*
|
||||||
|
Bopen(char *name, int mode)
|
||||||
|
{
|
||||||
|
Biobuf *bp;
|
||||||
|
int f;
|
||||||
|
|
||||||
|
switch(mode&~(OCEXEC|ORCLOSE|OTRUNC)) {
|
||||||
|
default:
|
||||||
|
fprint(2, "Bopen: unknown mode %d\n", mode);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case OREAD:
|
||||||
|
f = open(name, mode);
|
||||||
|
if(f < 0)
|
||||||
|
return 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case OWRITE:
|
||||||
|
f = create(name, mode, 0666);
|
||||||
|
if(f < 0)
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bp = Bfdopen(f, mode);
|
||||||
|
if(bp == 0)
|
||||||
|
close(f);
|
||||||
|
return bp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Bterm(Biobuf *bp)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
|
||||||
|
deinstall(bp);
|
||||||
|
ret = Bflush(bp);
|
||||||
|
if(bp->flag == Bmagic) {
|
||||||
|
bp->flag = 0;
|
||||||
|
if(close(bp->fid) < 0)
|
||||||
|
ret = -1;
|
||||||
|
free(bp);
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
vlong
|
||||||
|
Boffset(Biobuf *bp)
|
||||||
|
{
|
||||||
|
vlong n;
|
||||||
|
|
||||||
|
switch(bp->state) {
|
||||||
|
default:
|
||||||
|
fprint(2, "Boffset: unknown state %d\n", bp->state);
|
||||||
|
n = Beof;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bracteof:
|
||||||
|
case Bractive:
|
||||||
|
n = bp->offset + bp->icount;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bwactive:
|
||||||
|
n = bp->offset + (bp->bsize + bp->ocount);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,14 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bprint(Biobuf *bp, char *fmt, ...)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
va_list arg;
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
n = Bvprint(bp, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,20 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bputc(Biobuf *bp, int c)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(;;) {
|
||||||
|
i = bp->ocount;
|
||||||
|
if(i) {
|
||||||
|
bp->ebuf[i++] = c;
|
||||||
|
bp->ocount = i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
if(Bflush(bp) == Beof)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return Beof;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
#include <utf.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
Bputrune(Biobuf *bp, long c)
|
||||||
|
{
|
||||||
|
Rune rune;
|
||||||
|
char str[UTFmax];
|
||||||
|
int n;
|
||||||
|
|
||||||
|
rune = c;
|
||||||
|
if(rune < Runeself) {
|
||||||
|
Bputc(bp, rune);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
n = runetochar(str, &rune);
|
||||||
|
if(n == 0)
|
||||||
|
return Bbad;
|
||||||
|
if(Bwrite(bp, str, n) != n)
|
||||||
|
return Beof;
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,94 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
void*
|
||||||
|
Brdline(Biobuf *bp, int delim)
|
||||||
|
{
|
||||||
|
char *ip, *ep;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
i = -bp->icount;
|
||||||
|
if(i == 0) {
|
||||||
|
/*
|
||||||
|
* eof or other error
|
||||||
|
*/
|
||||||
|
if(bp->state != Bractive) {
|
||||||
|
if(bp->state == Bracteof)
|
||||||
|
bp->state = Bractive;
|
||||||
|
bp->rdline = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first try in remainder of buffer (gbuf doesn't change)
|
||||||
|
*/
|
||||||
|
ip = (char*)bp->ebuf - i;
|
||||||
|
ep = memchr(ip, delim, i);
|
||||||
|
if(ep) {
|
||||||
|
j = (ep - ip) + 1;
|
||||||
|
bp->rdline = j;
|
||||||
|
bp->icount += j;
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy data to beginning of buffer
|
||||||
|
*/
|
||||||
|
if(i < bp->bsize)
|
||||||
|
memmove(bp->bbuf, ip, i);
|
||||||
|
bp->gbuf = bp->bbuf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* append to buffer looking for the delim
|
||||||
|
*/
|
||||||
|
ip = (char*)bp->bbuf + i;
|
||||||
|
while(i < bp->bsize) {
|
||||||
|
j = read(bp->fid, ip, bp->bsize-i);
|
||||||
|
if(j <= 0) {
|
||||||
|
/*
|
||||||
|
* end of file with no delim
|
||||||
|
*/
|
||||||
|
memmove(bp->ebuf-i, bp->bbuf, i);
|
||||||
|
bp->rdline = i;
|
||||||
|
bp->icount = -i;
|
||||||
|
bp->gbuf = bp->ebuf-i;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
bp->offset += j;
|
||||||
|
i += j;
|
||||||
|
ep = memchr(ip, delim, j);
|
||||||
|
if(ep) {
|
||||||
|
/*
|
||||||
|
* found in new piece
|
||||||
|
* copy back up and reset everything
|
||||||
|
*/
|
||||||
|
ip = (char*)bp->ebuf - i;
|
||||||
|
if(i < bp->bsize){
|
||||||
|
memmove(ip, bp->bbuf, i);
|
||||||
|
bp->gbuf = (unsigned char*)ip;
|
||||||
|
}
|
||||||
|
j = (ep - (char*)bp->bbuf) + 1;
|
||||||
|
bp->rdline = j;
|
||||||
|
bp->icount = j - i;
|
||||||
|
return ip;
|
||||||
|
}
|
||||||
|
ip += j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* full buffer without finding
|
||||||
|
*/
|
||||||
|
bp->rdline = bp->bsize;
|
||||||
|
bp->icount = -bp->bsize;
|
||||||
|
bp->gbuf = bp->bbuf;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Blinelen(Biobuf *bp)
|
||||||
|
{
|
||||||
|
|
||||||
|
return bp->rdline;
|
||||||
|
}
|
|
@ -0,0 +1,111 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
static char*
|
||||||
|
badd(char *p, int *np, char *data, int ndata, int delim, int nulldelim)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
|
||||||
|
n = *np;
|
||||||
|
p = realloc(p, n+ndata+1);
|
||||||
|
if(p){
|
||||||
|
memmove(p+n, data, ndata);
|
||||||
|
n += ndata;
|
||||||
|
if(n>0 && nulldelim && p[n-1]==delim)
|
||||||
|
p[--n] = '\0';
|
||||||
|
else
|
||||||
|
p[n] = '\0';
|
||||||
|
*np = n;
|
||||||
|
}
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
char*
|
||||||
|
Brdstr(Biobuf *bp, int delim, int nulldelim)
|
||||||
|
{
|
||||||
|
char *ip, *ep, *p;
|
||||||
|
int i, j;
|
||||||
|
|
||||||
|
i = -bp->icount;
|
||||||
|
bp->rdline = 0;
|
||||||
|
if(i == 0) {
|
||||||
|
/*
|
||||||
|
* eof or other error
|
||||||
|
*/
|
||||||
|
if(bp->state != Bractive) {
|
||||||
|
if(bp->state == Bracteof)
|
||||||
|
bp->state = Bractive;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
return nil;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* first try in remainder of buffer (gbuf doesn't change)
|
||||||
|
*/
|
||||||
|
ip = (char*)bp->ebuf - i;
|
||||||
|
ep = memchr(ip, delim, i);
|
||||||
|
if(ep) {
|
||||||
|
j = (ep - ip) + 1;
|
||||||
|
bp->icount += j;
|
||||||
|
return badd(nil, &bp->rdline, ip, j, delim, nulldelim);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* copy data to beginning of buffer
|
||||||
|
*/
|
||||||
|
if(i < bp->bsize)
|
||||||
|
memmove(bp->bbuf, ip, i);
|
||||||
|
bp->gbuf = bp->bbuf;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* append to buffer looking for the delim
|
||||||
|
*/
|
||||||
|
p = nil;
|
||||||
|
for(;;){
|
||||||
|
ip = (char*)bp->bbuf + i;
|
||||||
|
while(i < bp->bsize) {
|
||||||
|
j = read(bp->fid, ip, bp->bsize-i);
|
||||||
|
if(j <= 0 && i == 0)
|
||||||
|
return p;
|
||||||
|
if(j <= 0 && i > 0){
|
||||||
|
/*
|
||||||
|
* end of file but no delim. pretend we got a delim
|
||||||
|
* by making the delim \0 and smashing it with nulldelim.
|
||||||
|
*/
|
||||||
|
j = 1;
|
||||||
|
ep = ip;
|
||||||
|
delim = '\0';
|
||||||
|
nulldelim = 1;
|
||||||
|
*ep = delim; /* there will be room for this */
|
||||||
|
}else{
|
||||||
|
bp->offset += j;
|
||||||
|
ep = memchr(ip, delim, j);
|
||||||
|
}
|
||||||
|
i += j;
|
||||||
|
if(ep) {
|
||||||
|
/*
|
||||||
|
* found in new piece
|
||||||
|
* copy back up and reset everything
|
||||||
|
*/
|
||||||
|
ip = (char*)bp->ebuf - i;
|
||||||
|
if(i < bp->bsize){
|
||||||
|
memmove(ip, bp->bbuf, i);
|
||||||
|
bp->gbuf = (unsigned char*)ip;
|
||||||
|
}
|
||||||
|
j = (ep - (char*)bp->bbuf) + 1;
|
||||||
|
bp->icount = j - i;
|
||||||
|
return badd(p, &bp->rdline, ip, j, delim, nulldelim);
|
||||||
|
}
|
||||||
|
ip += j;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* full buffer without finding; add to user string and continue
|
||||||
|
*/
|
||||||
|
p = badd(p, &bp->rdline, (char*)bp->bbuf, bp->bsize, 0, 0);
|
||||||
|
i = 0;
|
||||||
|
bp->icount = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,45 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
long
|
||||||
|
Bread(Biobuf *bp, void *ap, long count)
|
||||||
|
{
|
||||||
|
long c;
|
||||||
|
unsigned char *p;
|
||||||
|
int i, n, ic;
|
||||||
|
|
||||||
|
p = ap;
|
||||||
|
c = count;
|
||||||
|
ic = bp->icount;
|
||||||
|
|
||||||
|
while(c > 0) {
|
||||||
|
n = -ic;
|
||||||
|
if(n > c)
|
||||||
|
n = c;
|
||||||
|
if(n == 0) {
|
||||||
|
if(bp->state != Bractive)
|
||||||
|
break;
|
||||||
|
i = read(bp->fid, bp->bbuf, bp->bsize);
|
||||||
|
if(i <= 0) {
|
||||||
|
bp->state = Bracteof;
|
||||||
|
if(i < 0)
|
||||||
|
bp->state = Binactive;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp->gbuf = bp->bbuf;
|
||||||
|
bp->offset += i;
|
||||||
|
if(i < bp->bsize) {
|
||||||
|
memmove(bp->ebuf-i, bp->bbuf, i);
|
||||||
|
bp->gbuf = bp->ebuf-i;
|
||||||
|
}
|
||||||
|
ic = -i;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memmove(p, bp->ebuf+ic, n);
|
||||||
|
c -= n;
|
||||||
|
ic += n;
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
bp->icount = ic;
|
||||||
|
return count-c;
|
||||||
|
}
|
|
@ -0,0 +1,60 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
long long
|
||||||
|
Bseek(Biobuf *bp, long long offset, int base)
|
||||||
|
{
|
||||||
|
vlong n, d;
|
||||||
|
int bufsz;
|
||||||
|
|
||||||
|
switch(bp->state) {
|
||||||
|
default:
|
||||||
|
fprint(2, "Bseek: unknown state %d\n", bp->state);
|
||||||
|
return Beof;
|
||||||
|
|
||||||
|
case Bracteof:
|
||||||
|
bp->state = Bractive;
|
||||||
|
bp->icount = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
|
||||||
|
case Bractive:
|
||||||
|
n = offset;
|
||||||
|
if(base == 1) {
|
||||||
|
n += Boffset(bp);
|
||||||
|
base = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* try to seek within buffer
|
||||||
|
*/
|
||||||
|
if(base == 0) {
|
||||||
|
d = n - Boffset(bp);
|
||||||
|
bufsz = bp->ebuf - bp->gbuf;
|
||||||
|
if(-bufsz <= d && d <= bufsz){
|
||||||
|
bp->icount += d;
|
||||||
|
if(d >= 0) {
|
||||||
|
if(bp->icount <= 0)
|
||||||
|
return n;
|
||||||
|
} else {
|
||||||
|
if(bp->ebuf - bp->gbuf >= -bp->icount)
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* reset the buffer
|
||||||
|
*/
|
||||||
|
n = lseek(bp->fid, n, base);
|
||||||
|
bp->icount = 0;
|
||||||
|
bp->gbuf = bp->ebuf;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Bwactive:
|
||||||
|
Bflush(bp);
|
||||||
|
n = seek(bp->fid, offset, base);
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
bp->offset = n;
|
||||||
|
return n;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
static int
|
||||||
|
fmtBflush(Fmt *f)
|
||||||
|
{
|
||||||
|
Biobuf *bp;
|
||||||
|
|
||||||
|
bp = f->farg;
|
||||||
|
bp->ocount = (char*)f->to - (char*)f->stop;
|
||||||
|
if(Bflush(bp) < 0)
|
||||||
|
return 0;
|
||||||
|
f->stop = bp->ebuf;
|
||||||
|
f->to = (char*)f->stop + bp->ocount;
|
||||||
|
f->start = f->to;
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
Bvprint(Biobuf *bp, char *fmt, va_list arg)
|
||||||
|
{
|
||||||
|
int n;
|
||||||
|
Fmt f;
|
||||||
|
|
||||||
|
f.runes = 0;
|
||||||
|
f.stop = bp->ebuf;
|
||||||
|
f.start = (char*)f.stop + bp->ocount;
|
||||||
|
f.to = f.start;
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,38 @@
|
||||||
|
#include "lib9.h"
|
||||||
|
#include <bio.h>
|
||||||
|
|
||||||
|
long
|
||||||
|
Bwrite(Biobuf *bp, void *ap, long count)
|
||||||
|
{
|
||||||
|
long c;
|
||||||
|
unsigned char *p;
|
||||||
|
int i, n, oc;
|
||||||
|
|
||||||
|
p = ap;
|
||||||
|
c = count;
|
||||||
|
oc = bp->ocount;
|
||||||
|
|
||||||
|
while(c > 0) {
|
||||||
|
n = -oc;
|
||||||
|
if(n > c)
|
||||||
|
n = c;
|
||||||
|
if(n == 0) {
|
||||||
|
if(bp->state != Bwactive)
|
||||||
|
return Beof;
|
||||||
|
i = write(bp->fid, bp->bbuf, bp->bsize);
|
||||||
|
if(i != bp->bsize) {
|
||||||
|
bp->state = Binactive;
|
||||||
|
return Beof;
|
||||||
|
}
|
||||||
|
bp->offset += i;
|
||||||
|
oc = -bp->bsize;
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
memmove(bp->ebuf+oc, p, n);
|
||||||
|
oc += n;
|
||||||
|
c -= n;
|
||||||
|
p += n;
|
||||||
|
}
|
||||||
|
bp->ocount = oc;
|
||||||
|
return count-c;
|
||||||
|
}
|
|
@ -0,0 +1,25 @@
|
||||||
|
#define _FILE_OFFSET_BITS 64
|
||||||
|
#define _LARGEFILE64_SOURCE
|
||||||
|
|
||||||
|
#include <utf.h>
|
||||||
|
#include <fmt.h>
|
||||||
|
|
||||||
|
#include <fcntl.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
#include <stdlib.h>
|
||||||
|
|
||||||
|
#define OREAD O_RDONLY
|
||||||
|
#define OWRITE O_WRONLY
|
||||||
|
|
||||||
|
#define OCEXEC 0
|
||||||
|
#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)
|
|
@ -0,0 +1,47 @@
|
||||||
|
#!/bin/sh
|
||||||
|
|
||||||
|
git clean -xdf .
|
||||||
|
|
||||||
|
cc \
|
||||||
|
-I ../../include\
|
||||||
|
-DPLAN9PORT \
|
||||||
|
-O0 \
|
||||||
|
-c \
|
||||||
|
-g -ggdb \
|
||||||
|
-Wall \
|
||||||
|
-Wno-parentheses \
|
||||||
|
-Wno-missing-braces \
|
||||||
|
-Wno-switch \
|
||||||
|
-Wno-comment \
|
||||||
|
-Wno-sign-compare \
|
||||||
|
-Wno-unknown-pragmas \
|
||||||
|
-Wno-misleading-indentation \
|
||||||
|
-Wno-stringop-truncation \
|
||||||
|
-Wno-stringop-overflow \
|
||||||
|
-Wno-format-truncation \
|
||||||
|
-fno-omit-frame-pointer \
|
||||||
|
-fsigned-char \
|
||||||
|
-fcommon \
|
||||||
|
bbuffered.c\
|
||||||
|
bfildes.c\
|
||||||
|
bflush.c\
|
||||||
|
bgetc.c\
|
||||||
|
bgetrune.c\
|
||||||
|
bgetd.c\
|
||||||
|
binit.c\
|
||||||
|
boffset.c\
|
||||||
|
bprint.c\
|
||||||
|
bputc.c\
|
||||||
|
bputrune.c\
|
||||||
|
brdline.c\
|
||||||
|
brdstr.c\
|
||||||
|
bread.c\
|
||||||
|
bseek.c\
|
||||||
|
bvprint.c\
|
||||||
|
bwrite.c
|
||||||
|
|
||||||
|
mkdir -p $JEHANNE/hacking/lib/
|
||||||
|
ar rcs $JEHANNE/hacking/lib/libbio.a *.o
|
||||||
|
|
||||||
|
git clean -xdf .
|
||||||
|
|
|
@ -0,0 +1,31 @@
|
||||||
|
<$PLAN9/src/mkhdr
|
||||||
|
|
||||||
|
LIB=libbio.a
|
||||||
|
|
||||||
|
OFILES=\
|
||||||
|
bbuffered.$O\
|
||||||
|
bfildes.$O\
|
||||||
|
bflush.$O\
|
||||||
|
bgetc.$O\
|
||||||
|
bgetrune.$O\
|
||||||
|
bgetd.$O\
|
||||||
|
binit.$O\
|
||||||
|
boffset.$O\
|
||||||
|
bprint.$O\
|
||||||
|
bputc.$O\
|
||||||
|
bputrune.$O\
|
||||||
|
brdline.$O\
|
||||||
|
brdstr.$O\
|
||||||
|
bread.$O\
|
||||||
|
bseek.$O\
|
||||||
|
bvprint.$O\
|
||||||
|
bwrite.$O\
|
||||||
|
|
||||||
|
HFILES=\
|
||||||
|
$PLAN9/include/bio.h\
|
||||||
|
|
||||||
|
<$PLAN9/src/mksyslib
|
||||||
|
|
||||||
|
bcat: bcat.$O $PLAN9/lib/$LIB
|
||||||
|
$LD -o bcat bcat.$O -lbio -l9
|
||||||
|
|
|
@ -0,0 +1,18 @@
|
||||||
|
bbuffered.c 2004/1225
|
||||||
|
bcat.c 2004/1225
|
||||||
|
bfildes.c 2004/1225
|
||||||
|
bflush.c 2004/1225
|
||||||
|
bfmt.c 2004/1225
|
||||||
|
bgetc.c 2004/1225
|
||||||
|
bgetd.c 2004/1225
|
||||||
|
bgetrune.c 2004/1225
|
||||||
|
binit.c 2004/1225
|
||||||
|
boffset.c 2004/1225
|
||||||
|
bprint.c 2004/1225
|
||||||
|
bputc.c 2004/1225
|
||||||
|
bputrune.c 2004/1225
|
||||||
|
brdline.c 2004/1225
|
||||||
|
brdstr.c 2004/1225
|
||||||
|
bread.c 2004/1225
|
||||||
|
bseek.c 2004/1225
|
||||||
|
bwrite.c 2004/1225
|
|
@ -0,0 +1,92 @@
|
||||||
|
The files listed below were written from scrach for plan9port
|
||||||
|
and do not derive from the Plan 9 from Bell Labs distribution.
|
||||||
|
They are made available under an MIT-style license, using the
|
||||||
|
same terms as the main distribution.
|
||||||
|
|
||||||
|
../../include/u.h
|
||||||
|
non-Plan 9 code in ../../include/libc.h
|
||||||
|
_exits.c
|
||||||
|
_p9dialparse.c
|
||||||
|
_p9dir.c
|
||||||
|
_p9translate.c
|
||||||
|
announce.c
|
||||||
|
argv0.c
|
||||||
|
atoi.c
|
||||||
|
atol.c
|
||||||
|
atoll.c
|
||||||
|
await.c
|
||||||
|
create.c
|
||||||
|
debugmalloc.c
|
||||||
|
dial.c
|
||||||
|
dirfstat.c
|
||||||
|
dirfwstat.c
|
||||||
|
dirstat.c
|
||||||
|
dirwstat.c
|
||||||
|
dup.c
|
||||||
|
errstr.c
|
||||||
|
exec.c
|
||||||
|
execl.c
|
||||||
|
exitcode.c
|
||||||
|
fmtlock2.c
|
||||||
|
fork.c
|
||||||
|
get9root.c
|
||||||
|
getcallerpc-386.c
|
||||||
|
getcallerpc-arm.c
|
||||||
|
getcallerpc-power.c
|
||||||
|
getcallerpc-sun4u.s
|
||||||
|
getcallerpc-x86_64.c
|
||||||
|
getenv.c
|
||||||
|
getnetconn.c
|
||||||
|
getns.c
|
||||||
|
getuser.c
|
||||||
|
getwd.c
|
||||||
|
jmp.c
|
||||||
|
lock.c
|
||||||
|
main.c
|
||||||
|
malloc.c
|
||||||
|
malloctag.c
|
||||||
|
mallocz.c
|
||||||
|
nan.c
|
||||||
|
needstack.c
|
||||||
|
notify.c
|
||||||
|
open.c
|
||||||
|
opentemp.c
|
||||||
|
pin.c
|
||||||
|
pipe.c
|
||||||
|
post9p.c
|
||||||
|
postnote.c
|
||||||
|
priv.c
|
||||||
|
qlock.c
|
||||||
|
readcons.c
|
||||||
|
rfork.c
|
||||||
|
searchpath.c
|
||||||
|
seek.c
|
||||||
|
sendfd.c
|
||||||
|
sleep.c
|
||||||
|
strdup.c
|
||||||
|
sysfatal.c
|
||||||
|
sysname.c
|
||||||
|
time.c
|
||||||
|
truerand.c
|
||||||
|
udp.c
|
||||||
|
unsharp.c
|
||||||
|
|
||||||
|
Copyright 2001-2007 Russ Cox. All Rights Reserved.
|
||||||
|
|
||||||
|
Permission is hereby granted, free of charge, to any person obtaining a copy
|
||||||
|
of this software and associated documentation files (the "Software"), to deal
|
||||||
|
in the Software without restriction, including without limitation the rights
|
||||||
|
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
||||||
|
copies of the Software, and to permit persons to whom the Software is
|
||||||
|
furnished to do so, subject to the following conditions:
|
||||||
|
|
||||||
|
The above copyright notice and this permission notice shall be included in
|
||||||
|
all copies or substantial portions of the Software.
|
||||||
|
|
||||||
|
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
||||||
|
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
||||||
|
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
||||||
|
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
||||||
|
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
||||||
|
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN
|
||||||
|
THE SOFTWARE.
|
|
@ -0,0 +1,10 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
void
|
||||||
|
_exits(char *s)
|
||||||
|
{
|
||||||
|
if(s == 0 || *s == 0)
|
||||||
|
_exit(0);
|
||||||
|
_exit(exitcode(s));
|
||||||
|
}
|
|
@ -0,0 +1,185 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
|
||||||
|
static char *nets[] = { "tcp", "udp", nil };
|
||||||
|
#define CLASS(p) ((*(uchar*)(p))>>6)
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
char *net;
|
||||||
|
char *service;
|
||||||
|
int port;
|
||||||
|
} porttbl[] = {
|
||||||
|
"tcp", "9fs", 564,
|
||||||
|
"tcp", "whoami", 565,
|
||||||
|
"tcp", "guard", 566,
|
||||||
|
"tcp", "ticket", 567,
|
||||||
|
"tcp", "exportfs", 17007,
|
||||||
|
"tcp", "rexexec", 17009,
|
||||||
|
"tcp", "ncpu", 17010,
|
||||||
|
"tcp", "cpu", 17013,
|
||||||
|
"tcp", "venti", 17034,
|
||||||
|
"tcp", "wiki", 17035,
|
||||||
|
"tcp", "secstore", 5356,
|
||||||
|
"udp", "dns", 53,
|
||||||
|
"tcp", "dns", 53,
|
||||||
|
};
|
||||||
|
|
||||||
|
static int
|
||||||
|
setport(struct sockaddr_storage *ss, int port)
|
||||||
|
{
|
||||||
|
switch(ss->ss_family){
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in*)ss)->sin_port = htons(port);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6*)ss)->sin6_port = htons(port);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errstr("unknown protocol family %d", ss->ss_family);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9dialparse(char *addr, char **pnet, char **punix, void *phost, int *pport)
|
||||||
|
{
|
||||||
|
char *net, *host, *port, *e;
|
||||||
|
int i;
|
||||||
|
struct servent *se;
|
||||||
|
struct hostent *he;
|
||||||
|
struct sockaddr_storage *ss;
|
||||||
|
struct addrinfo *result;
|
||||||
|
|
||||||
|
ss = phost;
|
||||||
|
|
||||||
|
memset(ss, 0, sizeof *ss);
|
||||||
|
|
||||||
|
*punix = nil;
|
||||||
|
net = addr;
|
||||||
|
if((host = strchr(net, '!')) == nil){
|
||||||
|
werrstr("malformed address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*host++ = 0;
|
||||||
|
if((port = strchr(host, '!')) == nil){
|
||||||
|
if(strcmp(net, "unix")==0 || strcmp(net, "net")==0){
|
||||||
|
Unix:
|
||||||
|
if(strlen(host)+1 > sizeof ((struct sockaddr_un*)ss)->sun_path){
|
||||||
|
werrstr("unix socket name too long");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*punix = host;
|
||||||
|
*pnet = "unix";
|
||||||
|
ss->ss_family = AF_UNIX;
|
||||||
|
strcpy(((struct sockaddr_un*)ss)->sun_path, host);
|
||||||
|
*pport = 0;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
werrstr("malformed address");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
*port++ = 0;
|
||||||
|
|
||||||
|
if(*host == 0){
|
||||||
|
werrstr("malformed address (empty host)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(*port == 0){
|
||||||
|
werrstr("malformed address (empty port)");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(net, "unix") == 0)
|
||||||
|
goto Unix;
|
||||||
|
|
||||||
|
if(strcmp(net, "tcp")!=0 && strcmp(net, "udp")!=0 && strcmp(net, "net") != 0){
|
||||||
|
werrstr("bad network %s!%s!%s", net, host, port);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translate host */
|
||||||
|
if(strcmp(host, "*") == 0){
|
||||||
|
ss->ss_family = AF_INET6;
|
||||||
|
((struct sockaddr_in6*)ss)->sin6_addr = in6addr_any;
|
||||||
|
}else if((he = gethostbyname(host)) != nil && he->h_addr_list[0] != nil){
|
||||||
|
ss->ss_family = he->h_addrtype;
|
||||||
|
switch(ss->ss_family){
|
||||||
|
case AF_INET:
|
||||||
|
((struct sockaddr_in*)ss)->sin_addr = *(struct in_addr*) *(he->h_addr_list);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
((struct sockaddr_in6*)ss)->sin6_addr = *(struct in6_addr*) *(he->h_addr_list);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errstr("unknown protocol family %d", ss->ss_family);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else if(getaddrinfo(host, NULL, NULL, &result) == 0) {
|
||||||
|
switch (result->ai_family) {
|
||||||
|
case AF_INET:
|
||||||
|
memmove((struct sockaddr_in*)ss, result->ai_addr, result->ai_addrlen);
|
||||||
|
break;
|
||||||
|
case AF_INET6:
|
||||||
|
memmove((struct sockaddr_in6*)ss, result->ai_addr, result->ai_addrlen);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
errstr("unknown protocol family %d", ss->ss_family);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
werrstr("unknown host %s", host);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
/* translate network and port; should return list rather than first */
|
||||||
|
if(strcmp(net, "net") == 0){
|
||||||
|
for(i=0; nets[i]; i++){
|
||||||
|
if((se = getservbyname(port, nets[i])) != nil){
|
||||||
|
*pnet = nets[i];
|
||||||
|
*pport = ntohs(se->s_port);
|
||||||
|
return setport(ss, *pport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for(i=0; i<nelem(porttbl); i++){
|
||||||
|
if(strcmp(net, "net") == 0 || strcmp(porttbl[i].net, net) == 0)
|
||||||
|
if(strcmp(porttbl[i].service, port) == 0){
|
||||||
|
*pnet = porttbl[i].net;
|
||||||
|
*pport = porttbl[i].port;
|
||||||
|
return setport(ss, *pport);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(net, "net") == 0){
|
||||||
|
werrstr("unknown service net!*!%s", port);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(net, "tcp") != 0 && strcmp(net, "udp") != 0){
|
||||||
|
werrstr("unknown network %s", net);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
*pnet = net;
|
||||||
|
i = strtol(port, &e, 0);
|
||||||
|
if(*e == 0){
|
||||||
|
*pport = i;
|
||||||
|
return setport(ss, *pport);
|
||||||
|
}
|
||||||
|
|
||||||
|
if((se = getservbyname(port, net)) != nil){
|
||||||
|
*pport = ntohs(se->s_port);
|
||||||
|
return setport(ss, *pport);
|
||||||
|
}
|
||||||
|
werrstr("unknown service %s!*!%s", net, port);
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,242 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
#include <dirent.h>
|
||||||
|
#include <pwd.h>
|
||||||
|
#include <grp.h>
|
||||||
|
|
||||||
|
#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>
|
||||||
|
#include <sys/dkio.h>
|
||||||
|
static vlong
|
||||||
|
disksize(int fd, struct stat *st)
|
||||||
|
{
|
||||||
|
struct disklabel lab;
|
||||||
|
int n;
|
||||||
|
|
||||||
|
if(!S_ISCHR(st->st_mode))
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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, struct stat *st)
|
||||||
|
{
|
||||||
|
u64int u64;
|
||||||
|
long l;
|
||||||
|
struct hd_geometry geo;
|
||||||
|
|
||||||
|
memset(&geo, 0, sizeof geo);
|
||||||
|
l = 0;
|
||||||
|
u64 = 0;
|
||||||
|
#ifdef BLKGETSIZE64
|
||||||
|
if(ioctl(fd, BLKGETSIZE64, &u64) >= 0)
|
||||||
|
return u64;
|
||||||
|
#endif
|
||||||
|
if(ioctl(fd, BLKGETSIZE, &l) >= 0)
|
||||||
|
return l*512;
|
||||||
|
if(ioctl(fd, HDIO_GETGEO, &geo) >= 0)
|
||||||
|
return (vlong)geo.heads*geo.sectors*geo.cylinders*512;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
#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.
|
||||||
|
* It's not safe for threaded programs, but neither is using
|
||||||
|
* getpwnam in the first place, so I'm not too worried.
|
||||||
|
*/
|
||||||
|
int
|
||||||
|
_p9dir(struct stat *lst, struct stat *st, char *name, Dir *d, char **str, char *estr)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
char tmp[20];
|
||||||
|
static struct group *g;
|
||||||
|
static struct passwd *p;
|
||||||
|
static int gid, uid;
|
||||||
|
int sz, fd;
|
||||||
|
|
||||||
|
fd = -1;
|
||||||
|
USED(fd);
|
||||||
|
sz = 0;
|
||||||
|
if(d)
|
||||||
|
memset(d, 0, sizeof *d);
|
||||||
|
|
||||||
|
/* name */
|
||||||
|
s = strrchr(name, '/');
|
||||||
|
if(s)
|
||||||
|
s++;
|
||||||
|
if(!s || !*s)
|
||||||
|
s = name;
|
||||||
|
if(*s == '/')
|
||||||
|
s++;
|
||||||
|
if(*s == 0)
|
||||||
|
s = "/";
|
||||||
|
if(d){
|
||||||
|
if(*str + strlen(s)+1 > estr)
|
||||||
|
d->name = "oops";
|
||||||
|
else{
|
||||||
|
strcpy(*str, s);
|
||||||
|
d->name = *str;
|
||||||
|
*str += strlen(*str)+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
sz += strlen(s)+1;
|
||||||
|
|
||||||
|
/* user */
|
||||||
|
if(p && st->st_uid == uid && p->pw_uid == uid)
|
||||||
|
;
|
||||||
|
else if(_p9usepwlibrary){
|
||||||
|
p = getpwuid(st->st_uid);
|
||||||
|
uid = st->st_uid;
|
||||||
|
}
|
||||||
|
if(p == nil || st->st_uid != uid || p->pw_uid != uid){
|
||||||
|
snprint(tmp, sizeof tmp, "%d", (int)st->st_uid);
|
||||||
|
s = tmp;
|
||||||
|
}else
|
||||||
|
s = p->pw_name;
|
||||||
|
sz += strlen(s)+1;
|
||||||
|
if(d){
|
||||||
|
if(*str+strlen(s)+1 > estr)
|
||||||
|
d->uid = "oops";
|
||||||
|
else{
|
||||||
|
strcpy(*str, s);
|
||||||
|
d->uid = *str;
|
||||||
|
*str += strlen(*str)+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
/* group */
|
||||||
|
if(g && st->st_gid == gid && g->gr_gid == gid)
|
||||||
|
;
|
||||||
|
else if(_p9usepwlibrary){
|
||||||
|
g = getgrgid(st->st_gid);
|
||||||
|
gid = st->st_gid;
|
||||||
|
}
|
||||||
|
if(g == nil || st->st_gid != gid || g->gr_gid != gid){
|
||||||
|
snprint(tmp, sizeof tmp, "%d", (int)st->st_gid);
|
||||||
|
s = tmp;
|
||||||
|
}else
|
||||||
|
s = g->gr_name;
|
||||||
|
sz += strlen(s)+1;
|
||||||
|
if(d){
|
||||||
|
if(*str + strlen(s)+1 > estr)
|
||||||
|
d->gid = "oops";
|
||||||
|
else{
|
||||||
|
strcpy(*str, s);
|
||||||
|
d->gid = *str;
|
||||||
|
*str += strlen(*str)+1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if(d){
|
||||||
|
d->type = 'M';
|
||||||
|
|
||||||
|
d->muid = "";
|
||||||
|
d->qid.path = st->st_ino;
|
||||||
|
/*
|
||||||
|
* do not include st->st_dev in path, because
|
||||||
|
* automounters give the same file system different
|
||||||
|
* st_dev values for successive mounts, causing
|
||||||
|
* spurious write warnings in acme and sam.
|
||||||
|
d->qid.path |= (uvlong)st->st_dev<<32;
|
||||||
|
*/
|
||||||
|
#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_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;
|
||||||
|
}
|
||||||
|
else if(S_ISFIFO(st->st_mode))
|
||||||
|
d->mode |= DMNAMEDPIPE;
|
||||||
|
else if(S_ISSOCK(st->st_mode))
|
||||||
|
d->mode |= DMSOCKET;
|
||||||
|
else if(S_ISBLK(st->st_mode)){
|
||||||
|
d->mode |= DMDEVICE;
|
||||||
|
d->qid.path = ('b'<<16)|st->st_rdev;
|
||||||
|
}
|
||||||
|
else if(S_ISCHR(st->st_mode)){
|
||||||
|
d->mode |= DMDEVICE;
|
||||||
|
d->qid.path = ('c'<<16)|st->st_rdev;
|
||||||
|
}
|
||||||
|
/* fetch real size for disks */
|
||||||
|
if(S_ISBLK(lst->st_mode)){
|
||||||
|
if((fd = open(name, O_RDONLY)) >= 0){
|
||||||
|
d->length = disksize(fd, st);
|
||||||
|
close(fd);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return sz;
|
||||||
|
}
|
|
@ -0,0 +1,155 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <errno.h>
|
||||||
|
|
||||||
|
#undef sun
|
||||||
|
#define sun sockun
|
||||||
|
|
||||||
|
int
|
||||||
|
_p9netfd(char *dir)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if(strncmp(dir, "/dev/fd/", 8) != 0)
|
||||||
|
return -1;
|
||||||
|
fd = strtol(dir+8, &dir, 0);
|
||||||
|
if(*dir != 0)
|
||||||
|
return -1;
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
putfd(char *dir, int fd)
|
||||||
|
{
|
||||||
|
snprint(dir, NETPATHLEN, "/dev/fd/%d", fd);
|
||||||
|
}
|
||||||
|
|
||||||
|
#undef unix
|
||||||
|
#define unix sockunix
|
||||||
|
|
||||||
|
static int
|
||||||
|
addrlen(struct sockaddr_storage *ss)
|
||||||
|
{
|
||||||
|
switch(ss->ss_family){
|
||||||
|
case AF_INET:
|
||||||
|
return sizeof(struct sockaddr_in);
|
||||||
|
case AF_INET6:
|
||||||
|
return sizeof(struct sockaddr_in6);
|
||||||
|
case AF_UNIX:
|
||||||
|
return sizeof(struct sockaddr_un);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9announce(char *addr, char *dir)
|
||||||
|
{
|
||||||
|
int proto;
|
||||||
|
char *buf, *unix;
|
||||||
|
char *net;
|
||||||
|
int port, s;
|
||||||
|
int n;
|
||||||
|
socklen_t sn;
|
||||||
|
struct sockaddr_storage ss;
|
||||||
|
|
||||||
|
buf = strdup(addr);
|
||||||
|
if(buf == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strcmp(net, "tcp") == 0)
|
||||||
|
proto = SOCK_STREAM;
|
||||||
|
else if(strcmp(net, "udp") == 0)
|
||||||
|
proto = SOCK_DGRAM;
|
||||||
|
else if(strcmp(net, "unix") == 0)
|
||||||
|
goto Unix;
|
||||||
|
else{
|
||||||
|
werrstr("can only handle tcp, udp, and unix: not %s", net);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if((s = socket(ss.ss_family, proto, 0)) < 0)
|
||||||
|
return -1;
|
||||||
|
sn = sizeof n;
|
||||||
|
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
|
||||||
|
&& n == SOCK_STREAM){
|
||||||
|
n = 1;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
|
||||||
|
}
|
||||||
|
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(proto == SOCK_STREAM){
|
||||||
|
listen(s, 8);
|
||||||
|
putfd(dir, s);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
|
||||||
|
Unix:
|
||||||
|
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
|
||||||
|
return -1;
|
||||||
|
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
|
||||||
|
if(errno == EADDRINUSE
|
||||||
|
&& connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0
|
||||||
|
&& errno == ECONNREFUSED){
|
||||||
|
/* dead socket, so remove it */
|
||||||
|
remove(unix);
|
||||||
|
close(s);
|
||||||
|
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0)
|
||||||
|
return -1;
|
||||||
|
if(bind(s, (struct sockaddr*)&ss, addrlen(&ss)) >= 0)
|
||||||
|
goto Success;
|
||||||
|
}
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
Success:
|
||||||
|
listen(s, 8);
|
||||||
|
putfd(dir, s);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9listen(char *dir, char *newdir)
|
||||||
|
{
|
||||||
|
int fd, one;
|
||||||
|
|
||||||
|
if((fd = _p9netfd(dir)) < 0){
|
||||||
|
werrstr("bad 'directory' in listen: %s", dir);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if((fd = accept(fd, nil, nil)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
one = 1;
|
||||||
|
setsockopt(fd, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
|
||||||
|
|
||||||
|
putfd(newdir, fd);
|
||||||
|
return fd;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9accept(int cfd, char *dir)
|
||||||
|
{
|
||||||
|
int fd;
|
||||||
|
|
||||||
|
if((fd = _p9netfd(dir)) < 0){
|
||||||
|
werrstr("bad 'directory' in accept");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* need to dup because the listen fd will be closed */
|
||||||
|
return dup(fd);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <lib9.h>
|
||||||
|
|
||||||
|
char *argv0;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* Mac OS can't deal with files that only declare data.
|
||||||
|
* ARGBEGIN mentions this function so that this file gets pulled in.
|
||||||
|
*/
|
||||||
|
void __fixargv0(void) { }
|
|
@ -0,0 +1,56 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#define NEXIT 33
|
||||||
|
|
||||||
|
static Lock onexlock;
|
||||||
|
static struct
|
||||||
|
{
|
||||||
|
void (*f)(void);
|
||||||
|
int pid;
|
||||||
|
}onex[NEXIT];
|
||||||
|
|
||||||
|
int
|
||||||
|
atexit(void (*f)(void))
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
lock(&onexlock);
|
||||||
|
for(i=0; i<NEXIT; i++)
|
||||||
|
if(onex[i].f == 0) {
|
||||||
|
onex[i].pid = getpid();
|
||||||
|
onex[i].f = f;
|
||||||
|
unlock(&onexlock);
|
||||||
|
return 1;
|
||||||
|
}
|
||||||
|
unlock(&onexlock);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
atexitdont(void (*f)(void))
|
||||||
|
{
|
||||||
|
int i, pid;
|
||||||
|
|
||||||
|
pid = getpid();
|
||||||
|
for(i=0; i<NEXIT; i++)
|
||||||
|
if(onex[i].f == f && onex[i].pid == pid)
|
||||||
|
onex[i].f = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
exits(char *s)
|
||||||
|
{
|
||||||
|
int i, pid;
|
||||||
|
void (*f)(void);
|
||||||
|
|
||||||
|
pid = getpid();
|
||||||
|
for(i = NEXIT-1; i >= 0; i--)
|
||||||
|
if((f = onex[i].f) && pid == onex[i].pid) {
|
||||||
|
onex[i].f = 0;
|
||||||
|
(*f)();
|
||||||
|
}
|
||||||
|
if(s == 0 || *s == 0)
|
||||||
|
exit(0);
|
||||||
|
exit(exitcode(s));
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#define NFN 33
|
||||||
|
static int (*onnot[NFN])(void*, char*);
|
||||||
|
static Lock onnotlock;
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
notifier(void *v, char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<NFN; i++)
|
||||||
|
if(onnot[i] && ((*onnot[i])(v, s))){
|
||||||
|
noted(NCONT);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
noted(NDFLT);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
atnotify(int (*f)(void*, char*), int in)
|
||||||
|
{
|
||||||
|
int i, n, ret;
|
||||||
|
static int init;
|
||||||
|
|
||||||
|
if(!init){
|
||||||
|
notify(notifier);
|
||||||
|
init = 1; /* assign = */
|
||||||
|
}
|
||||||
|
ret = 0;
|
||||||
|
lock(&onnotlock);
|
||||||
|
if(in){
|
||||||
|
for(i=0; i<NFN; i++)
|
||||||
|
if(onnot[i] == 0) {
|
||||||
|
onnot[i] = f;
|
||||||
|
ret = 1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
n = 0;
|
||||||
|
for(i=0; i<NFN; i++)
|
||||||
|
if(onnot[i]){
|
||||||
|
if(ret==0 && onnot[i]==f){
|
||||||
|
onnot[i] = 0;
|
||||||
|
ret = 1;
|
||||||
|
}else
|
||||||
|
n++;
|
||||||
|
}
|
||||||
|
if(n == 0){
|
||||||
|
init = 0;
|
||||||
|
notify(0);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
unlock(&onnotlock);
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
atoi(char *s)
|
||||||
|
{
|
||||||
|
return strtol(s, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
long
|
||||||
|
atol(char *s)
|
||||||
|
{
|
||||||
|
return strtol(s, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
vlong
|
||||||
|
atoll(char *s)
|
||||||
|
{
|
||||||
|
return strtoll(s, 0, 0);
|
||||||
|
}
|
|
@ -0,0 +1,136 @@
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#include <signal.h>
|
||||||
|
#include <sys/types.h>
|
||||||
|
#include <sys/wait.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/resource.h>
|
||||||
|
|
||||||
|
#ifndef WCOREDUMP /* not on Mac OS X Tiger */
|
||||||
|
#define WCOREDUMP(status) 0
|
||||||
|
#endif
|
||||||
|
|
||||||
|
static struct {
|
||||||
|
int sig;
|
||||||
|
char *str;
|
||||||
|
} tab[] = {
|
||||||
|
SIGHUP, "hangup",
|
||||||
|
SIGINT, "interrupt",
|
||||||
|
SIGQUIT, "quit",
|
||||||
|
SIGILL, "sys: illegal instruction",
|
||||||
|
SIGTRAP, "sys: breakpoint",
|
||||||
|
SIGABRT, "sys: abort",
|
||||||
|
#ifdef SIGEMT
|
||||||
|
SIGEMT, "sys: emulate instruction executed",
|
||||||
|
#endif
|
||||||
|
SIGFPE, "sys: fp: trap",
|
||||||
|
SIGKILL, "sys: kill",
|
||||||
|
SIGBUS, "sys: bus error",
|
||||||
|
SIGSEGV, "sys: segmentation violation",
|
||||||
|
SIGALRM, "alarm",
|
||||||
|
SIGTERM, "kill",
|
||||||
|
SIGURG, "sys: urgent condition on socket",
|
||||||
|
SIGSTOP, "sys: stop",
|
||||||
|
SIGTSTP, "sys: tstp",
|
||||||
|
SIGCONT, "sys: cont",
|
||||||
|
SIGCHLD, "sys: child",
|
||||||
|
SIGTTIN, "sys: ttin",
|
||||||
|
SIGTTOU, "sys: ttou",
|
||||||
|
#ifdef SIGIO /* not on Mac OS X Tiger */
|
||||||
|
SIGIO, "sys: i/o possible on fd",
|
||||||
|
#endif
|
||||||
|
SIGXCPU, "sys: cpu time limit exceeded",
|
||||||
|
SIGXFSZ, "sys: file size limit exceeded",
|
||||||
|
SIGVTALRM, "sys: virtual time alarm",
|
||||||
|
SIGPROF, "sys: profiling timer alarm",
|
||||||
|
#ifdef SIGWINCH /* not on Mac OS X Tiger */
|
||||||
|
SIGWINCH, "sys: window size change",
|
||||||
|
#endif
|
||||||
|
#ifdef SIGINFO
|
||||||
|
SIGINFO, "sys: status request",
|
||||||
|
#endif
|
||||||
|
SIGUSR1, "sys: usr1",
|
||||||
|
SIGUSR2, "sys: usr2",
|
||||||
|
SIGPIPE, "sys: write on closed pipe",
|
||||||
|
};
|
||||||
|
|
||||||
|
char*
|
||||||
|
_p9sigstr(int sig, char *tmp)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(tab); i++)
|
||||||
|
if(tab[i].sig == sig)
|
||||||
|
return tab[i].str;
|
||||||
|
if(tmp == nil)
|
||||||
|
return nil;
|
||||||
|
sprint(tmp, "sys: signal %d", sig);
|
||||||
|
return tmp;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
_p9strsig(char *s)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
|
||||||
|
for(i=0; i<nelem(tab); i++)
|
||||||
|
if(strcmp(s, tab[i].str) == 0)
|
||||||
|
return tab[i].sig;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
_await(int pid4, char *str, int n, int opt)
|
||||||
|
{
|
||||||
|
int pid, status, cd;
|
||||||
|
struct rusage ru;
|
||||||
|
char buf[128], tmp[64];
|
||||||
|
uint64_t u, s;
|
||||||
|
|
||||||
|
for(;;){
|
||||||
|
/* On Linux, pid==-1 means anyone; on SunOS, it's pid==0. */
|
||||||
|
if(pid4 == -1)
|
||||||
|
pid = wait3(&status, opt, &ru);
|
||||||
|
else
|
||||||
|
pid = wait4(pid4, &status, opt, &ru);
|
||||||
|
if(pid <= 0)
|
||||||
|
return -1;
|
||||||
|
u = ru.ru_utime.tv_sec*1000+((ru.ru_utime.tv_usec+500)/1000);
|
||||||
|
s = ru.ru_stime.tv_sec*1000+((ru.ru_stime.tv_usec+500)/1000);
|
||||||
|
if(WIFEXITED(status)){
|
||||||
|
status = WEXITSTATUS(status);
|
||||||
|
if(status)
|
||||||
|
snprint(buf, sizeof buf, "%d %lud %lud %lud %d", pid, u, s, u+s, status);
|
||||||
|
else
|
||||||
|
snprint(buf, sizeof buf, "%d %lud %lud %lud ''", pid, u, s, u+s, status);
|
||||||
|
strecpy(str, str+n, buf);
|
||||||
|
return strlen(str);
|
||||||
|
}
|
||||||
|
if(WIFSIGNALED(status)){
|
||||||
|
cd = WCOREDUMP(status);
|
||||||
|
snprint(buf, sizeof buf, "%d %lud %lud %lud 'signal: %s%s'", pid, u, s, u+s, _p9sigstr(WTERMSIG(status), tmp), cd ? " (core dumped)" : "");
|
||||||
|
strecpy(str, str+n, buf);
|
||||||
|
return strlen(str);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
await(char *str, int n)
|
||||||
|
{
|
||||||
|
return _await(-1, str, n, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
awaitnohang(char *str, int n)
|
||||||
|
{
|
||||||
|
return _await(-1, str, n, WNOHANG);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
awaitfor(int pid, char *str, int n)
|
||||||
|
{
|
||||||
|
return _await(pid, str, n, 0);
|
||||||
|
}
|
|
@ -0,0 +1,26 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
cistrcmp(char *s1, char *s2)
|
||||||
|
{
|
||||||
|
int c1, c2;
|
||||||
|
|
||||||
|
while(*s1){
|
||||||
|
c1 = *(uchar*)s1++;
|
||||||
|
c2 = *(uchar*)s2++;
|
||||||
|
|
||||||
|
if(c1 == c2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(c1 >= 'A' && c1 <= 'Z')
|
||||||
|
c1 -= 'A' - 'a';
|
||||||
|
|
||||||
|
if(c2 >= 'A' && c2 <= 'Z')
|
||||||
|
c2 -= 'A' - 'a';
|
||||||
|
|
||||||
|
if(c1 != c2)
|
||||||
|
return c1 - c2;
|
||||||
|
}
|
||||||
|
return -*s2;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
cistrncmp(char *s1, char *s2, int n)
|
||||||
|
{
|
||||||
|
int c1, c2;
|
||||||
|
|
||||||
|
while(*s1 && n-- > 0){
|
||||||
|
c1 = *(uchar*)s1++;
|
||||||
|
c2 = *(uchar*)s2++;
|
||||||
|
|
||||||
|
if(c1 == c2)
|
||||||
|
continue;
|
||||||
|
|
||||||
|
if(c1 >= 'A' && c1 <= 'Z')
|
||||||
|
c1 -= 'A' - 'a';
|
||||||
|
|
||||||
|
if(c2 >= 'A' && c2 <= 'Z')
|
||||||
|
c2 -= 'A' - 'a';
|
||||||
|
|
||||||
|
if(c1 != c2)
|
||||||
|
return c1 - c2;
|
||||||
|
}
|
||||||
|
if(n <= 0)
|
||||||
|
return 0;
|
||||||
|
return -*s2;
|
||||||
|
}
|
|
@ -0,0 +1,23 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
char*
|
||||||
|
cistrstr(char *s, char *sub)
|
||||||
|
{
|
||||||
|
int c, csub, n;
|
||||||
|
|
||||||
|
csub = *sub;
|
||||||
|
if(csub == '\0')
|
||||||
|
return s;
|
||||||
|
if(csub >= 'A' && csub <= 'Z')
|
||||||
|
csub -= 'A' - 'a';
|
||||||
|
sub++;
|
||||||
|
n = strlen(sub);
|
||||||
|
for(; c = *s; s++){
|
||||||
|
if(c >= 'A' && c <= 'Z')
|
||||||
|
c -= 'A' - 'a';
|
||||||
|
if(c == csub && cistrncmp(s+1, sub, n) == 0)
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
return nil;
|
||||||
|
}
|
|
@ -0,0 +1,52 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* In place, rewrite name to compress multiple /, eliminate ., and process ..
|
||||||
|
*/
|
||||||
|
#define SEP(x) ((x)=='/' || (x) == 0)
|
||||||
|
char*
|
||||||
|
cleanname(char *name)
|
||||||
|
{
|
||||||
|
char *p, *q, *dotdot;
|
||||||
|
int rooted;
|
||||||
|
|
||||||
|
rooted = name[0] == '/';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* invariants:
|
||||||
|
* p points at beginning of path element we're considering.
|
||||||
|
* q points just past the last path element we wrote (no slash).
|
||||||
|
* dotdot points just past the point where .. cannot backtrack
|
||||||
|
* any further (no slash).
|
||||||
|
*/
|
||||||
|
p = q = dotdot = name+rooted;
|
||||||
|
while(*p) {
|
||||||
|
if(p[0] == '/') /* null element */
|
||||||
|
p++;
|
||||||
|
else if(p[0] == '.' && SEP(p[1]))
|
||||||
|
p += 1; /* don't count the separator in case it is nul */
|
||||||
|
else if(p[0] == '.' && p[1] == '.' && SEP(p[2])) {
|
||||||
|
p += 2;
|
||||||
|
if(q > dotdot) { /* can backtrack */
|
||||||
|
while(--q > dotdot && *q != '/')
|
||||||
|
;
|
||||||
|
} else if(!rooted) { /* /.. is / but ./../ is .. */
|
||||||
|
if(q != name)
|
||||||
|
*q++ = '/';
|
||||||
|
*q++ = '.';
|
||||||
|
*q++ = '.';
|
||||||
|
dotdot = q;
|
||||||
|
}
|
||||||
|
} else { /* real path element */
|
||||||
|
if(q != name+rooted)
|
||||||
|
*q++ = '/';
|
||||||
|
while((*q = *p) != '/' && *q != 0)
|
||||||
|
p++, q++;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(q == name) /* empty string is really ``.'' */
|
||||||
|
*q++ = '.';
|
||||||
|
*q = '\0';
|
||||||
|
return name;
|
||||||
|
}
|
|
@ -0,0 +1,101 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
|
||||||
|
uint
|
||||||
|
sizeD2M(Dir *d)
|
||||||
|
{
|
||||||
|
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;
|
||||||
|
|
||||||
|
ns = 0;
|
||||||
|
for(i = 0; i < nstr; i++)
|
||||||
|
if(sv[i])
|
||||||
|
ns += strlen(sv[i]);
|
||||||
|
|
||||||
|
return fixlen + ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
convD2M(Dir *d, uchar *buf, uint nbuf)
|
||||||
|
{
|
||||||
|
uchar *p, *ebuf;
|
||||||
|
char *sv[5];
|
||||||
|
int i, ns, nsv[5], ss, nstr, fixlen;
|
||||||
|
|
||||||
|
if(nbuf < BIT16SZ)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
ebuf = buf + nbuf;
|
||||||
|
|
||||||
|
sv[0] = d->name;
|
||||||
|
sv[1] = d->uid;
|
||||||
|
sv[2] = d->gid;
|
||||||
|
sv[3] = d->muid;
|
||||||
|
|
||||||
|
fixlen = STATFIXLEN;
|
||||||
|
nstr = 4;
|
||||||
|
|
||||||
|
ns = 0;
|
||||||
|
for(i = 0; i < nstr; i++){
|
||||||
|
if(sv[i])
|
||||||
|
nsv[i] = strlen(sv[i]);
|
||||||
|
else
|
||||||
|
nsv[i] = 0;
|
||||||
|
ns += nsv[i];
|
||||||
|
}
|
||||||
|
|
||||||
|
ss = fixlen + ns;
|
||||||
|
|
||||||
|
/* set size befor erroring, so user can know how much is needed */
|
||||||
|
/* note that length excludes count field itself */
|
||||||
|
PBIT16(p, ss-BIT16SZ);
|
||||||
|
p += BIT16SZ;
|
||||||
|
|
||||||
|
if(ss > nbuf)
|
||||||
|
return BIT16SZ;
|
||||||
|
|
||||||
|
PBIT16(p, d->type);
|
||||||
|
p += BIT16SZ;
|
||||||
|
PBIT32(p, d->dev);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT8(p, d->qid.type);
|
||||||
|
p += BIT8SZ;
|
||||||
|
PBIT32(p, d->qid.vers);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT64(p, d->qid.path);
|
||||||
|
p += BIT64SZ;
|
||||||
|
PBIT32(p, d->mode);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT32(p, d->atime);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT32(p, d->mtime);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT64(p, d->length);
|
||||||
|
p += BIT64SZ;
|
||||||
|
|
||||||
|
for(i = 0; i < nstr; i++){
|
||||||
|
ns = nsv[i];
|
||||||
|
if(p + ns + BIT16SZ > ebuf)
|
||||||
|
return 0;
|
||||||
|
PBIT16(p, ns);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(ns)
|
||||||
|
memmove(p, sv[i], ns);
|
||||||
|
p += ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(ss != p - buf)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
return p - buf;
|
||||||
|
}
|
|
@ -0,0 +1,98 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
statcheck(uchar *buf, uint nbuf)
|
||||||
|
{
|
||||||
|
uchar *ebuf;
|
||||||
|
int i, nstr;
|
||||||
|
|
||||||
|
ebuf = buf + nbuf;
|
||||||
|
|
||||||
|
if(nbuf < STATFIXLEN || nbuf != BIT16SZ + GBIT16(buf))
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
buf += STATFIXLEN - 4 * BIT16SZ;
|
||||||
|
|
||||||
|
nstr = 4;
|
||||||
|
for(i = 0; i < nstr; i++){
|
||||||
|
if(buf + BIT16SZ > ebuf)
|
||||||
|
return -1;
|
||||||
|
buf += BIT16SZ + GBIT16(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
if(buf != ebuf)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static char nullstring[] = "";
|
||||||
|
|
||||||
|
uint
|
||||||
|
convM2D(uchar *buf, uint nbuf, Dir *d, char *strs)
|
||||||
|
{
|
||||||
|
uchar *p, *ebuf;
|
||||||
|
char *sv[5];
|
||||||
|
int i, ns, nstr;
|
||||||
|
|
||||||
|
if(nbuf < STATFIXLEN)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = buf;
|
||||||
|
ebuf = buf + nbuf;
|
||||||
|
|
||||||
|
p += BIT16SZ; /* ignore size */
|
||||||
|
d->type = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
d->dev = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
d->qid.type = GBIT8(p);
|
||||||
|
p += BIT8SZ;
|
||||||
|
d->qid.vers = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
d->qid.path = GBIT64(p);
|
||||||
|
p += BIT64SZ;
|
||||||
|
d->mode = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
d->atime = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
d->mtime = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
d->length = GBIT64(p);
|
||||||
|
p += BIT64SZ;
|
||||||
|
|
||||||
|
nstr = 4;
|
||||||
|
for(i = 0; i < nstr; i++){
|
||||||
|
if(p + BIT16SZ > ebuf)
|
||||||
|
return 0;
|
||||||
|
ns = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(p + ns > ebuf)
|
||||||
|
return 0;
|
||||||
|
if(strs){
|
||||||
|
sv[i] = strs;
|
||||||
|
memmove(strs, p, ns);
|
||||||
|
strs += ns;
|
||||||
|
*strs++ = '\0';
|
||||||
|
}
|
||||||
|
p += ns;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strs){
|
||||||
|
d->name = sv[0];
|
||||||
|
d->uid = sv[1];
|
||||||
|
d->gid = sv[2];
|
||||||
|
d->muid = sv[3];
|
||||||
|
d->ext = nullstring;
|
||||||
|
}else{
|
||||||
|
d->name = nullstring;
|
||||||
|
d->uid = nullstring;
|
||||||
|
d->gid = nullstring;
|
||||||
|
d->muid = nullstring;
|
||||||
|
d->ext = nullstring;
|
||||||
|
}
|
||||||
|
|
||||||
|
return p - buf;
|
||||||
|
}
|
|
@ -0,0 +1,326 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
uchar*
|
||||||
|
gstring(uchar *p, uchar *ep, char **s)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
|
||||||
|
if(p+BIT16SZ > ep)
|
||||||
|
return nil;
|
||||||
|
n = GBIT16(p);
|
||||||
|
p += BIT16SZ - 1;
|
||||||
|
if(p+n+1 > ep)
|
||||||
|
return nil;
|
||||||
|
/* move it down, on top of count, to make room for '\0' */
|
||||||
|
memmove(p, p + 1, n);
|
||||||
|
p[n] = '\0';
|
||||||
|
*s = (char*)p;
|
||||||
|
p += n+1;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uchar*
|
||||||
|
gqid(uchar *p, uchar *ep, Qid *q)
|
||||||
|
{
|
||||||
|
if(p+QIDSZ > ep)
|
||||||
|
return nil;
|
||||||
|
q->type = GBIT8(p);
|
||||||
|
p += BIT8SZ;
|
||||||
|
q->vers = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
q->path = GBIT64(p);
|
||||||
|
p += BIT64SZ;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* no syntactic checks.
|
||||||
|
* three causes for error:
|
||||||
|
* 1. message size field is incorrect
|
||||||
|
* 2. input buffer too short for its own data (counts too long, etc.)
|
||||||
|
* 3. too many names or qids
|
||||||
|
* gqid() and gstring() return nil if they would reach beyond buffer.
|
||||||
|
* main switch statement checks range and also can fall through
|
||||||
|
* to test at end of routine.
|
||||||
|
*/
|
||||||
|
uint
|
||||||
|
convM2S(uchar *ap, uint nap, Fcall *f)
|
||||||
|
{
|
||||||
|
uchar *p, *ep;
|
||||||
|
uint i, size;
|
||||||
|
|
||||||
|
p = ap;
|
||||||
|
ep = p + nap;
|
||||||
|
|
||||||
|
if(p+BIT32SZ+BIT8SZ+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
size = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
|
||||||
|
if(size < BIT32SZ+BIT8SZ+BIT16SZ)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
f->type = GBIT8(p);
|
||||||
|
p += BIT8SZ;
|
||||||
|
f->tag = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
|
||||||
|
switch(f->type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case Tversion:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->msize = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = gstring(p, ep, &f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tflush:
|
||||||
|
if(p+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->oldtag = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tauth:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->afid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = gstring(p, ep, &f->uname);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
p = gstring(p, ep, &f->aname);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
f->uidnum = NOUID;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tattach:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->afid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = gstring(p, ep, &f->uname);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
p = gstring(p, ep, &f->aname);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
f->uidnum = NOUID;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twalk:
|
||||||
|
if(p+BIT32SZ+BIT32SZ+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->newfid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->nwname = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(f->nwname > MAXWELEM)
|
||||||
|
return 0;
|
||||||
|
for(i=0; i<f->nwname; i++){
|
||||||
|
p = gstring(p, ep, &f->wname[i]);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Topen:
|
||||||
|
case Topenfd:
|
||||||
|
if(p+BIT32SZ+BIT8SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->mode = GBIT8(p);
|
||||||
|
p += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcreate:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = gstring(p, ep, &f->name);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
if(p+BIT32SZ+BIT8SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->perm = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->mode = GBIT8(p);
|
||||||
|
p += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tread:
|
||||||
|
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->offset = GBIT64(p);
|
||||||
|
p += BIT64SZ;
|
||||||
|
f->count = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twrite:
|
||||||
|
if(p+BIT32SZ+BIT64SZ+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->offset = GBIT64(p);
|
||||||
|
p += BIT64SZ;
|
||||||
|
f->count = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
if(p+f->count > ep)
|
||||||
|
return 0;
|
||||||
|
f->data = (char*)p;
|
||||||
|
p += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tclunk:
|
||||||
|
case Tremove:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tstat:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twstat:
|
||||||
|
if(p+BIT32SZ+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->fid = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
f->nstat = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(p+f->nstat > ep)
|
||||||
|
return 0;
|
||||||
|
f->stat = p;
|
||||||
|
p += f->nstat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
case Rversion:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->msize = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = gstring(p, ep, &f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rerror:
|
||||||
|
p = gstring(p, ep, &f->ename);
|
||||||
|
f->errornum = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rflush:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rauth:
|
||||||
|
p = gqid(p, ep, &f->aqid);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rattach:
|
||||||
|
p = gqid(p, ep, &f->qid);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwalk:
|
||||||
|
if(p+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->nwqid = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(f->nwqid > MAXWELEM)
|
||||||
|
return 0;
|
||||||
|
for(i=0; i<f->nwqid; i++){
|
||||||
|
p = gqid(p, ep, &f->wqid[i]);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Ropen:
|
||||||
|
case Ropenfd:
|
||||||
|
case Rcreate:
|
||||||
|
p = gqid(p, ep, &f->qid);
|
||||||
|
if(p == nil)
|
||||||
|
break;
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->iounit = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
if(f->type == Ropenfd){
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->unixfd = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rread:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->count = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
if(p+f->count > ep)
|
||||||
|
return 0;
|
||||||
|
f->data = (char*)p;
|
||||||
|
p += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwrite:
|
||||||
|
if(p+BIT32SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->count = GBIT32(p);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rclunk:
|
||||||
|
case Rremove:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rstat:
|
||||||
|
if(p+BIT16SZ > ep)
|
||||||
|
return 0;
|
||||||
|
f->nstat = GBIT16(p);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(p+f->nstat > ep)
|
||||||
|
return 0;
|
||||||
|
f->stat = p;
|
||||||
|
p += f->nstat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwstat:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(p==nil || p>ep)
|
||||||
|
return 0;
|
||||||
|
if(ap+size == p)
|
||||||
|
return size;
|
||||||
|
return 0;
|
||||||
|
}
|
|
@ -0,0 +1,399 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
|
||||||
|
static
|
||||||
|
uchar*
|
||||||
|
pstring(uchar *p, char *s)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
|
||||||
|
if(s == nil){
|
||||||
|
PBIT16(p, 0);
|
||||||
|
p += BIT16SZ;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
n = strlen(s);
|
||||||
|
PBIT16(p, n);
|
||||||
|
p += BIT16SZ;
|
||||||
|
memmove(p, s, n);
|
||||||
|
p += n;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uchar*
|
||||||
|
pqid(uchar *p, Qid *q)
|
||||||
|
{
|
||||||
|
PBIT8(p, q->type);
|
||||||
|
p += BIT8SZ;
|
||||||
|
PBIT32(p, q->vers);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT64(p, q->path);
|
||||||
|
p += BIT64SZ;
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
uint
|
||||||
|
stringsz(char *s)
|
||||||
|
{
|
||||||
|
if(s == nil)
|
||||||
|
return BIT16SZ;
|
||||||
|
|
||||||
|
return BIT16SZ+strlen(s);
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
sizeS2M(Fcall *f)
|
||||||
|
{
|
||||||
|
uint n;
|
||||||
|
int i;
|
||||||
|
|
||||||
|
n = 0;
|
||||||
|
n += BIT32SZ; /* size */
|
||||||
|
n += BIT8SZ; /* type */
|
||||||
|
n += BIT16SZ; /* tag */
|
||||||
|
|
||||||
|
switch(f->type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case Tversion:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += stringsz(f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tflush:
|
||||||
|
n += BIT16SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tauth:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += stringsz(f->uname);
|
||||||
|
n += stringsz(f->aname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tattach:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += stringsz(f->uname);
|
||||||
|
n += stringsz(f->aname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twalk:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT16SZ;
|
||||||
|
for(i=0; i<f->nwname; i++)
|
||||||
|
n += stringsz(f->wname[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Topen:
|
||||||
|
case Topenfd:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcreate:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += stringsz(f->name);
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tread:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT64SZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twrite:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT64SZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tclunk:
|
||||||
|
case Tremove:
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tstat:
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twstat:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT16SZ;
|
||||||
|
n += f->nstat;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
case Rversion:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += stringsz(f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rerror:
|
||||||
|
n += stringsz(f->ename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rflush:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rauth:
|
||||||
|
n += QIDSZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rattach:
|
||||||
|
n += QIDSZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwalk:
|
||||||
|
n += BIT16SZ;
|
||||||
|
n += f->nwqid*QIDSZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Ropen:
|
||||||
|
case Rcreate:
|
||||||
|
n += QIDSZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Ropenfd:
|
||||||
|
n += QIDSZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rread:
|
||||||
|
n += BIT32SZ;
|
||||||
|
n += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwrite:
|
||||||
|
n += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rclunk:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rremove:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rstat:
|
||||||
|
n += BIT16SZ;
|
||||||
|
n += f->nstat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwstat:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return n;
|
||||||
|
}
|
||||||
|
|
||||||
|
uint
|
||||||
|
convS2M(Fcall *f, uchar *ap, uint nap)
|
||||||
|
{
|
||||||
|
uchar *p;
|
||||||
|
uint i, size;
|
||||||
|
|
||||||
|
size = sizeS2M(f);
|
||||||
|
if(size == 0)
|
||||||
|
return 0;
|
||||||
|
if(size > nap)
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
p = (uchar*)ap;
|
||||||
|
|
||||||
|
PBIT32(p, size);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT8(p, f->type);
|
||||||
|
p += BIT8SZ;
|
||||||
|
PBIT16(p, f->tag);
|
||||||
|
p += BIT16SZ;
|
||||||
|
|
||||||
|
switch(f->type)
|
||||||
|
{
|
||||||
|
default:
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
case Tversion:
|
||||||
|
PBIT32(p, f->msize);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = pstring(p, f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tflush:
|
||||||
|
PBIT16(p, f->oldtag);
|
||||||
|
p += BIT16SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tauth:
|
||||||
|
PBIT32(p, f->afid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = pstring(p, f->uname);
|
||||||
|
p = pstring(p, f->aname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tattach:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT32(p, f->afid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = pstring(p, f->uname);
|
||||||
|
p = pstring(p, f->aname);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twalk:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT32(p, f->newfid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT16(p, f->nwname);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(f->nwname > MAXWELEM)
|
||||||
|
return 0;
|
||||||
|
for(i=0; i<f->nwname; i++)
|
||||||
|
p = pstring(p, f->wname[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Topen:
|
||||||
|
case Topenfd:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT8(p, f->mode);
|
||||||
|
p += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tcreate:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = pstring(p, f->name);
|
||||||
|
PBIT32(p, f->perm);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT8(p, f->mode);
|
||||||
|
p += BIT8SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tread:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT64(p, f->offset);
|
||||||
|
p += BIT64SZ;
|
||||||
|
PBIT32(p, f->count);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twrite:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT64(p, f->offset);
|
||||||
|
p += BIT64SZ;
|
||||||
|
PBIT32(p, f->count);
|
||||||
|
p += BIT32SZ;
|
||||||
|
memmove(p, f->data, f->count);
|
||||||
|
p += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tclunk:
|
||||||
|
case Tremove:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Tstat:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Twstat:
|
||||||
|
PBIT32(p, f->fid);
|
||||||
|
p += BIT32SZ;
|
||||||
|
PBIT16(p, f->nstat);
|
||||||
|
p += BIT16SZ;
|
||||||
|
memmove(p, f->stat, f->nstat);
|
||||||
|
p += f->nstat;
|
||||||
|
break;
|
||||||
|
/*
|
||||||
|
*/
|
||||||
|
|
||||||
|
case Rversion:
|
||||||
|
PBIT32(p, f->msize);
|
||||||
|
p += BIT32SZ;
|
||||||
|
p = pstring(p, f->version);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rerror:
|
||||||
|
p = pstring(p, f->ename);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rflush:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rauth:
|
||||||
|
p = pqid(p, &f->aqid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rattach:
|
||||||
|
p = pqid(p, &f->qid);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwalk:
|
||||||
|
PBIT16(p, f->nwqid);
|
||||||
|
p += BIT16SZ;
|
||||||
|
if(f->nwqid > MAXWELEM)
|
||||||
|
return 0;
|
||||||
|
for(i=0; i<f->nwqid; i++)
|
||||||
|
p = pqid(p, &f->wqid[i]);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Ropen:
|
||||||
|
case Rcreate:
|
||||||
|
case Ropenfd:
|
||||||
|
p = pqid(p, &f->qid);
|
||||||
|
PBIT32(p, f->iounit);
|
||||||
|
p += BIT32SZ;
|
||||||
|
if(f->type == Ropenfd){
|
||||||
|
PBIT32(p, f->unixfd);
|
||||||
|
p += BIT32SZ;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rread:
|
||||||
|
PBIT32(p, f->count);
|
||||||
|
p += BIT32SZ;
|
||||||
|
memmove(p, f->data, f->count);
|
||||||
|
p += f->count;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwrite:
|
||||||
|
PBIT32(p, f->count);
|
||||||
|
p += BIT32SZ;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rclunk:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rremove:
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rstat:
|
||||||
|
PBIT16(p, f->nstat);
|
||||||
|
p += BIT16SZ;
|
||||||
|
memmove(p, f->stat, f->nstat);
|
||||||
|
p += f->nstat;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case Rwstat:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(size != p-ap)
|
||||||
|
return 0;
|
||||||
|
return size;
|
||||||
|
}
|
|
@ -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;
|
||||||
|
}
|
|
@ -0,0 +1,180 @@
|
||||||
|
/*
|
||||||
|
* 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>
|
||||||
|
|
||||||
|
#include "zoneinfo.h"
|
||||||
|
|
||||||
|
static char dmsize[12] =
|
||||||
|
{
|
||||||
|
31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31
|
||||||
|
};
|
||||||
|
|
||||||
|
#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 - 1);
|
||||||
|
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)
|
||||||
|
{
|
||||||
|
const char *ncp;
|
||||||
|
static char cbuf[30];
|
||||||
|
|
||||||
|
strcpy(cbuf, "Thu Jan 01 00:00:00 GMT 1970\n");
|
||||||
|
ncp = &"SunMonTueWedThuFriSat"[t->wday*3];
|
||||||
|
cbuf[0] = *ncp++;
|
||||||
|
cbuf[1] = *ncp++;
|
||||||
|
cbuf[2] = *ncp;
|
||||||
|
ncp = &"JanFebMarAprMayJunJulAugSepOctNovDec"[t->mon*3];
|
||||||
|
cbuf[4] = *ncp++;
|
||||||
|
cbuf[5] = *ncp++;
|
||||||
|
cbuf[6] = *ncp;
|
||||||
|
ct_numb(cbuf+8, t->mday);
|
||||||
|
ct_numb(cbuf+11, t->hour+100);
|
||||||
|
ct_numb(cbuf+14, t->min+100);
|
||||||
|
ct_numb(cbuf+17, t->sec+100);
|
||||||
|
ncp = t->zone;
|
||||||
|
cbuf[20] = *ncp++;
|
||||||
|
cbuf[21] = *ncp++;
|
||||||
|
cbuf[22] = *ncp;
|
||||||
|
if(t->year >= 100) {
|
||||||
|
cbuf[24] = '2';
|
||||||
|
cbuf[25] = '0';
|
||||||
|
}
|
||||||
|
ct_numb(cbuf+26, t->year+100);
|
||||||
|
return cbuf;
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
dysize(int y)
|
||||||
|
{
|
||||||
|
|
||||||
|
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';
|
||||||
|
}
|
|
@ -0,0 +1,157 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Unix libc routines cannot be trusted to do their own locking.
|
||||||
|
* Sad but apparently true.
|
||||||
|
*/
|
||||||
|
static int mallocpid;
|
||||||
|
|
||||||
|
/*
|
||||||
|
* The Unix mallocs don't do nearly enough error checking
|
||||||
|
* for my tastes. We'll waste another 24 bytes per guy so that
|
||||||
|
* we can. This is severely antisocial, since now free and p9free
|
||||||
|
* are not interchangeable.
|
||||||
|
*/
|
||||||
|
int debugmalloc;
|
||||||
|
|
||||||
|
#define Overhead (debugmalloc ? (6*sizeof(ulong)) : 0)
|
||||||
|
#define MallocMagic 0xA110C09
|
||||||
|
#define ReallocMagic 0xB110C09
|
||||||
|
#define CallocMagic 0xC110C09
|
||||||
|
#define FreeMagic 0xF533F533
|
||||||
|
#define CheckMagic 0
|
||||||
|
#define END "\x7F\x2E\x55\x23"
|
||||||
|
|
||||||
|
static void
|
||||||
|
whoops(void *v)
|
||||||
|
{
|
||||||
|
fprint(2, "bad malloc block %p\n", v);
|
||||||
|
abort();
|
||||||
|
}
|
||||||
|
|
||||||
|
static void*
|
||||||
|
mark(void *v, ulong pc, ulong n, ulong magic)
|
||||||
|
{
|
||||||
|
ulong *u;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if(!debugmalloc)
|
||||||
|
return v;
|
||||||
|
|
||||||
|
if(v == nil)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
if(magic == FreeMagic || magic == CheckMagic){
|
||||||
|
u = (ulong*)((char*)v-4*sizeof(ulong));
|
||||||
|
if(u[0] != MallocMagic && u[0] != ReallocMagic && u[0] != CallocMagic)
|
||||||
|
whoops(v);
|
||||||
|
n = u[1];
|
||||||
|
p = (char*)v+n;
|
||||||
|
if(memcmp(p, END, 4) != 0)
|
||||||
|
whoops(v);
|
||||||
|
if(magic != CheckMagic){
|
||||||
|
u[0] = FreeMagic;
|
||||||
|
u[1] = u[2] = u[3] = pc;
|
||||||
|
if(n > 16){
|
||||||
|
u[4] = u[5] = u[6] = u[7] = pc;
|
||||||
|
memset((char*)v+16, 0xFB, n-16);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
return u;
|
||||||
|
}else{
|
||||||
|
u = v;
|
||||||
|
u[0] = magic;
|
||||||
|
u[1] = n;
|
||||||
|
u[2] = 0;
|
||||||
|
u[3] = 0;
|
||||||
|
if(magic == ReallocMagic)
|
||||||
|
u[3] = pc;
|
||||||
|
else
|
||||||
|
u[2] = pc;
|
||||||
|
p = (char*)(u+4)+n;
|
||||||
|
memmove(p, END, 4);
|
||||||
|
return u+4;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setmalloctag(void *v, ulong t)
|
||||||
|
{
|
||||||
|
ulong *u;
|
||||||
|
|
||||||
|
if(!debugmalloc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(v == nil)
|
||||||
|
return;
|
||||||
|
u = mark(v, 0, 0, 0);
|
||||||
|
u[2] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setrealloctag(void *v, ulong t)
|
||||||
|
{
|
||||||
|
ulong *u;
|
||||||
|
|
||||||
|
if(!debugmalloc)
|
||||||
|
return;
|
||||||
|
|
||||||
|
if(v == nil)
|
||||||
|
return;
|
||||||
|
u = mark(v, 0, 0, 0);
|
||||||
|
u[3] = t;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
p9malloc(ulong n)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
if(n == 0)
|
||||||
|
n++;
|
||||||
|
/*fprint(2, "%s %d malloc\n", argv0, getpid()); */
|
||||||
|
mallocpid = getpid();
|
||||||
|
v = malloc(n+Overhead);
|
||||||
|
v = mark(v, getcallerpc(&n), n, MallocMagic);
|
||||||
|
/*fprint(2, "%s %d donemalloc\n", argv0, getpid()); */
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
p9free(void *v)
|
||||||
|
{
|
||||||
|
if(v == nil)
|
||||||
|
return;
|
||||||
|
|
||||||
|
/*fprint(2, "%s %d free\n", argv0, getpid()); */
|
||||||
|
mallocpid = getpid();
|
||||||
|
v = mark(v, getcallerpc(&v), 0, FreeMagic);
|
||||||
|
free(v);
|
||||||
|
/*fprint(2, "%s %d donefree\n", argv0, getpid()); */
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
p9calloc(ulong a, ulong b)
|
||||||
|
{
|
||||||
|
void *v;
|
||||||
|
|
||||||
|
/*fprint(2, "%s %d calloc\n", argv0, getpid()); */
|
||||||
|
mallocpid = getpid();
|
||||||
|
v = calloc(a*b+Overhead, 1);
|
||||||
|
v = mark(v, getcallerpc(&a), a*b, CallocMagic);
|
||||||
|
/*fprint(2, "%s %d donecalloc\n", argv0, getpid()); */
|
||||||
|
return v;
|
||||||
|
}
|
||||||
|
|
||||||
|
void*
|
||||||
|
p9realloc(void *v, ulong n)
|
||||||
|
{
|
||||||
|
/*fprint(2, "%s %d realloc\n", argv0, getpid()); */
|
||||||
|
mallocpid = getpid();
|
||||||
|
v = mark(v, getcallerpc(&v), 0, CheckMagic);
|
||||||
|
v = realloc(v, n+Overhead);
|
||||||
|
v = mark(v, getcallerpc(&v), n, ReallocMagic);
|
||||||
|
/*fprint(2, "%s %d donerealloc\n", argv0, getpid()); */
|
||||||
|
return v;
|
||||||
|
}
|
|
@ -0,0 +1,159 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#undef accept
|
||||||
|
#undef announce
|
||||||
|
#undef dial
|
||||||
|
#undef setnetmtpt
|
||||||
|
#undef hangup
|
||||||
|
#undef listen
|
||||||
|
#undef netmkaddr
|
||||||
|
#undef reject
|
||||||
|
|
||||||
|
#include <sys/socket.h>
|
||||||
|
#include <netinet/in.h>
|
||||||
|
#include <netinet/tcp.h>
|
||||||
|
#include <sys/un.h>
|
||||||
|
#include <netdb.h>
|
||||||
|
|
||||||
|
#undef unix
|
||||||
|
#define unix xunix
|
||||||
|
|
||||||
|
static int
|
||||||
|
isany(struct sockaddr_storage *ss)
|
||||||
|
{
|
||||||
|
switch(ss->ss_family){
|
||||||
|
case AF_INET:
|
||||||
|
return (((struct sockaddr_in*)ss)->sin_addr.s_addr == INADDR_ANY);
|
||||||
|
case AF_INET6:
|
||||||
|
return (memcmp(((struct sockaddr_in6*)ss)->sin6_addr.s6_addr,
|
||||||
|
in6addr_any.s6_addr, sizeof (struct in6_addr)) == 0);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
static int
|
||||||
|
addrlen(struct sockaddr_storage *ss)
|
||||||
|
{
|
||||||
|
switch(ss->ss_family){
|
||||||
|
case AF_INET:
|
||||||
|
return sizeof(struct sockaddr_in);
|
||||||
|
case AF_INET6:
|
||||||
|
return sizeof(struct sockaddr_in6);
|
||||||
|
case AF_UNIX:
|
||||||
|
return sizeof(struct sockaddr_un);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
p9dial(char *addr, char *local, char *dummy2, int *dummy3)
|
||||||
|
{
|
||||||
|
char *buf;
|
||||||
|
char *net, *unix;
|
||||||
|
int port;
|
||||||
|
int proto;
|
||||||
|
socklen_t sn;
|
||||||
|
int n;
|
||||||
|
struct sockaddr_storage ss, ssl;
|
||||||
|
int s;
|
||||||
|
|
||||||
|
if(dummy2 || dummy3){
|
||||||
|
werrstr("cannot handle extra arguments in dial");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
buf = strdup(addr);
|
||||||
|
if(buf == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(strcmp(net, "unix") != 0 && isany(&ss)){
|
||||||
|
werrstr("invalid dial address 0.0.0.0 (aka *)");
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(strcmp(net, "tcp") == 0)
|
||||||
|
proto = SOCK_STREAM;
|
||||||
|
else if(strcmp(net, "udp") == 0)
|
||||||
|
proto = SOCK_DGRAM;
|
||||||
|
else if(strcmp(net, "unix") == 0)
|
||||||
|
goto Unix;
|
||||||
|
else{
|
||||||
|
werrstr("can only handle tcp, udp, and unix: not %s", net);
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
|
||||||
|
if((s = socket(ss.ss_family, proto, 0)) < 0)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
if(local){
|
||||||
|
buf = strdup(local);
|
||||||
|
if(buf == nil){
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(p9dialparse(buf, &net, &unix, &ss, &port) < 0){
|
||||||
|
badlocal:
|
||||||
|
free(buf);
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(unix){
|
||||||
|
werrstr("bad local address %s for dial %s", local, addr);
|
||||||
|
goto badlocal;
|
||||||
|
}
|
||||||
|
sn = sizeof n;
|
||||||
|
if(port && getsockopt(s, SOL_SOCKET, SO_TYPE, (void*)&n, &sn) >= 0
|
||||||
|
&& n == SOCK_STREAM){
|
||||||
|
n = 1;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&n, sizeof n);
|
||||||
|
}
|
||||||
|
if(bind(s, (struct sockaddr*)&ssl, addrlen(&ssl)) < 0)
|
||||||
|
goto badlocal;
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
n = 1;
|
||||||
|
setsockopt(s, SOL_SOCKET, SO_BROADCAST, &n, sizeof n);
|
||||||
|
if(!isany(&ss)){
|
||||||
|
if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if(proto == SOCK_STREAM){
|
||||||
|
int one = 1;
|
||||||
|
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&one, sizeof one);
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
|
||||||
|
Unix:
|
||||||
|
if(local){
|
||||||
|
werrstr("local address not supported on unix network");
|
||||||
|
free(buf);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
/* Allow regular files in addition to Unix sockets. */
|
||||||
|
if((s = open(unix, ORDWR)) >= 0){
|
||||||
|
free(buf);
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
if((s = socket(ss.ss_family, SOCK_STREAM, 0)) < 0){
|
||||||
|
werrstr("socket: %r");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
if(connect(s, (struct sockaddr*)&ss, addrlen(&ss)) < 0){
|
||||||
|
werrstr("connect %s: %r", ((struct sockaddr_un*)&ss)->sun_path);
|
||||||
|
close(s);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
return s;
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
|
||||||
|
|
||||||
|
Dir*
|
||||||
|
dirfstat(int fd)
|
||||||
|
{
|
||||||
|
struct stat st;
|
||||||
|
int nstr;
|
||||||
|
Dir *d;
|
||||||
|
char *str, tmp[100];
|
||||||
|
|
||||||
|
if(fstat(fd, &st) < 0)
|
||||||
|
return nil;
|
||||||
|
|
||||||
|
snprint(tmp, sizeof tmp, "/dev/fd/%d", fd);
|
||||||
|
nstr = _p9dir(&st, &st, tmp, nil, nil, nil);
|
||||||
|
d = mallocz(sizeof(Dir)+nstr, 1);
|
||||||
|
if(d == nil)
|
||||||
|
return nil;
|
||||||
|
str = (char*)&d[1];
|
||||||
|
_p9dir(&st, &st, tmp, d, &str, str+nstr);
|
||||||
|
return d;
|
||||||
|
}
|
|
@ -0,0 +1,56 @@
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <sys/time.h>
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
#if defined(__FreeBSD__) || defined(__APPLE__) || defined(__OpenBSD__) || defined(__linux__)
|
||||||
|
/* do nothing -- futimes exists and is fine */
|
||||||
|
|
||||||
|
#elif defined(__SunOS5_9__)
|
||||||
|
/* use futimesat */
|
||||||
|
static int
|
||||||
|
futimes(int fd, struct timeval *tv)
|
||||||
|
{
|
||||||
|
return futimesat(fd, 0, tv);
|
||||||
|
}
|
||||||
|
|
||||||
|
#else
|
||||||
|
/* provide dummy */
|
||||||
|
/* rename just in case -- linux provides an unusable one */
|
||||||
|
#undef futimes
|
||||||
|
#define futimes myfutimes
|
||||||
|
static int
|
||||||
|
futimes(int fd, struct timeval *tv)
|
||||||
|
{
|
||||||
|
werrstr("futimes not available");
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
||||||
|
int
|
||||||
|
dirfwstat(int fd, Dir *dir)
|
||||||
|
{
|
||||||
|
int ret;
|
||||||
|
struct timeval tv[2];
|
||||||
|
|
||||||
|
ret = 0;
|
||||||
|
if(~dir->mode != 0){
|
||||||
|
if(fchmod(fd, dir->mode) < 0)
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
if(~dir->mtime != 0){
|
||||||
|
tv[0].tv_sec = dir->mtime;
|
||||||
|
tv[0].tv_usec = 0;
|
||||||
|
tv[1].tv_sec = dir->mtime;
|
||||||
|
tv[1].tv_usec = 0;
|
||||||
|
if(futimes(fd, tv) < 0)
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
if(~dir->length != 0){
|
||||||
|
if(ftruncate(fd, dir->length) < 0)
|
||||||
|
ret = -1;
|
||||||
|
}
|
||||||
|
return ret;
|
||||||
|
}
|
|
@ -0,0 +1,62 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
static char *modes[] =
|
||||||
|
{
|
||||||
|
"---",
|
||||||
|
"--x",
|
||||||
|
"-w-",
|
||||||
|
"-wx",
|
||||||
|
"r--",
|
||||||
|
"r-x",
|
||||||
|
"rw-",
|
||||||
|
"rwx",
|
||||||
|
};
|
||||||
|
|
||||||
|
static void
|
||||||
|
rwx(long m, char *s)
|
||||||
|
{
|
||||||
|
strncpy(s, modes[m], 3);
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dirmodefmt(Fmt *f)
|
||||||
|
{
|
||||||
|
static char buf[16];
|
||||||
|
ulong m;
|
||||||
|
|
||||||
|
m = va_arg(f->args, ulong);
|
||||||
|
|
||||||
|
if(m & DMDIR)
|
||||||
|
buf[0]='d';
|
||||||
|
else if(m & DMAPPEND)
|
||||||
|
buf[0]='a';
|
||||||
|
else if(m & DMAUTH)
|
||||||
|
buf[0]='A';
|
||||||
|
else if(m & DMDEVICE)
|
||||||
|
buf[0] = 'D';
|
||||||
|
else if(m & DMSOCKET)
|
||||||
|
buf[0] = 'S';
|
||||||
|
else if(m & DMNAMEDPIPE)
|
||||||
|
buf[0] = 'P';
|
||||||
|
else
|
||||||
|
buf[0]='-';
|
||||||
|
|
||||||
|
/*
|
||||||
|
* It's a little weird to have DMSYMLINK conflict with DMEXCL
|
||||||
|
* here, but since you can have symlinks to any of the above
|
||||||
|
* things, this is a better display. Especially since we don't do
|
||||||
|
* DMEXCL on any of the supported systems.
|
||||||
|
*/
|
||||||
|
if(m & DMEXCL)
|
||||||
|
buf[1]='l';
|
||||||
|
else if(m & DMSYMLINK)
|
||||||
|
buf[1] = 'L';
|
||||||
|
else
|
||||||
|
buf[1]='-';
|
||||||
|
rwx((m>>6)&7, buf+2);
|
||||||
|
rwx((m>>3)&7, buf+5);
|
||||||
|
rwx((m>>0)&7, buf+8);
|
||||||
|
buf[11] = 0;
|
||||||
|
return fmtstrcpy(f, buf);
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#include <sys/stat.h>
|
||||||
|
|
||||||
|
extern int _p9dir(struct stat*, struct stat*, char*, Dir*, char**, char*);
|
||||||
|
|
||||||
|
Dir*
|
||||||
|
dirstat(char *file)
|
||||||
|
{
|
||||||
|
struct stat lst;
|
||||||
|
struct stat st;
|
||||||
|
int nstr;
|
||||||
|
Dir *d;
|
||||||
|
char *str;
|
||||||
|
|
||||||
|
if(lstat(file, &lst) < 0)
|
||||||
|
return nil;
|
||||||
|
st = lst;
|
||||||
|
if((lst.st_mode&S_IFMT) == S_IFLNK)
|
||||||
|
stat(file, &st);
|
||||||
|
|
||||||
|
nstr = _p9dir(&lst, &st, file, nil, nil, nil);
|
||||||
|
d = mallocz(sizeof(Dir)+nstr, 1);
|
||||||
|
if(d == nil)
|
||||||
|
return nil;
|
||||||
|
str = (char*)&d[1];
|
||||||
|
_p9dir(&lst, &st, file, d, &str, str+nstr);
|
||||||
|
return d;
|
||||||
|
}
|
|
@ -0,0 +1,31 @@
|
||||||
|
#include <u.h>
|
||||||
|
#define NOPLAN9DEFINES
|
||||||
|
#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 */
|
||||||
|
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;
|
||||||
|
}
|
|
@ -0,0 +1,12 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
#undef dup
|
||||||
|
|
||||||
|
int
|
||||||
|
p9dup(int old, int new)
|
||||||
|
{
|
||||||
|
if(new == -1)
|
||||||
|
return dup(old);
|
||||||
|
return dup2(old, new);
|
||||||
|
}
|
|
@ -0,0 +1,76 @@
|
||||||
|
#include <lib9.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
encodefmt(Fmt *f)
|
||||||
|
{
|
||||||
|
char *out;
|
||||||
|
char *buf, *p;
|
||||||
|
int len;
|
||||||
|
int ilen;
|
||||||
|
int rv;
|
||||||
|
uchar *b;
|
||||||
|
char obuf[64]; /* rsc optimization */
|
||||||
|
|
||||||
|
b = va_arg(f->args, uchar*);
|
||||||
|
if(b == 0)
|
||||||
|
return fmtstrcpy(f, "<nil>");
|
||||||
|
|
||||||
|
ilen = f->prec;
|
||||||
|
f->prec = 0;
|
||||||
|
|
||||||
|
if(!(f->flags&FmtPrec) || ilen < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
f->flags &= ~FmtPrec;
|
||||||
|
|
||||||
|
switch(f->r){
|
||||||
|
case '<':
|
||||||
|
len = (8*ilen+4)/5 + 3;
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
len = (8*ilen+5)/6 + 4;
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
len = 2*ilen + 1;
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if(len > sizeof(obuf)){
|
||||||
|
buf = malloc(len);
|
||||||
|
if(buf == nil)
|
||||||
|
goto error;
|
||||||
|
} else
|
||||||
|
buf = obuf;
|
||||||
|
|
||||||
|
/* convert */
|
||||||
|
out = buf;
|
||||||
|
switch(f->r){
|
||||||
|
case '<':
|
||||||
|
rv = enc32(out, len, b, ilen);
|
||||||
|
break;
|
||||||
|
case '[':
|
||||||
|
rv = enc64(out, len, b, ilen);
|
||||||
|
break;
|
||||||
|
case 'H':
|
||||||
|
rv = enc16(out, len, b, ilen);
|
||||||
|
if(rv >= 0 && (f->flags & FmtLong))
|
||||||
|
for(p = buf; *p; p++)
|
||||||
|
*p = tolower((uchar)*p);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
rv = -1;
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
if(rv < 0)
|
||||||
|
goto error;
|
||||||
|
|
||||||
|
fmtstrcpy(f, buf);
|
||||||
|
if(buf != obuf)
|
||||||
|
free(buf);
|
||||||
|
return 0;
|
||||||
|
|
||||||
|
error:
|
||||||
|
return fmtstrcpy(f, "<encodefmt>");
|
||||||
|
}
|
|
@ -0,0 +1,80 @@
|
||||||
|
/*
|
||||||
|
* We assume there's only one error buffer for the whole system.
|
||||||
|
* If you use ffork, you need to provide a _syserrstr. Since most
|
||||||
|
* people will use libthread (which provides a _syserrstr), this is
|
||||||
|
* okay.
|
||||||
|
*/
|
||||||
|
|
||||||
|
#include <u.h>
|
||||||
|
#include <errno.h>
|
||||||
|
#include <string.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
enum
|
||||||
|
{
|
||||||
|
EPLAN9 = 0x19283745
|
||||||
|
};
|
||||||
|
|
||||||
|
char *(*_syserrstr)(void);
|
||||||
|
static char xsyserr[ERRMAX];
|
||||||
|
static char*
|
||||||
|
getsyserr(void)
|
||||||
|
{
|
||||||
|
char *s;
|
||||||
|
|
||||||
|
s = nil;
|
||||||
|
if(_syserrstr)
|
||||||
|
s = (*_syserrstr)();
|
||||||
|
if(s == nil)
|
||||||
|
s = xsyserr;
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
errstr(char *err, uint n)
|
||||||
|
{
|
||||||
|
char tmp[ERRMAX];
|
||||||
|
char *syserr;
|
||||||
|
|
||||||
|
strecpy(tmp, tmp+ERRMAX, err);
|
||||||
|
rerrstr(err, n);
|
||||||
|
syserr = getsyserr();
|
||||||
|
strecpy(syserr, syserr+ERRMAX, tmp);
|
||||||
|
errno = EPLAN9;
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
rerrstr(char *err, uint n)
|
||||||
|
{
|
||||||
|
char *syserr;
|
||||||
|
|
||||||
|
syserr = getsyserr();
|
||||||
|
if(errno == EINTR)
|
||||||
|
strcpy(syserr, "interrupted");
|
||||||
|
else if(errno != EPLAN9)
|
||||||
|
strcpy(syserr, strerror(errno));
|
||||||
|
strecpy(err, err+n, syserr);
|
||||||
|
}
|
||||||
|
|
||||||
|
/* replaces __errfmt in libfmt */
|
||||||
|
|
||||||
|
int
|
||||||
|
__errfmt(Fmt *f)
|
||||||
|
{
|
||||||
|
if(errno == EPLAN9)
|
||||||
|
return fmtstrcpy(f, getsyserr());
|
||||||
|
return fmtstrcpy(f, strerror(errno));
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
werrstr(char *fmt, ...)
|
||||||
|
{
|
||||||
|
va_list arg;
|
||||||
|
char buf[ERRMAX];
|
||||||
|
|
||||||
|
va_start(arg, fmt);
|
||||||
|
vseprint(buf, buf+ERRMAX, fmt, arg);
|
||||||
|
va_end(arg);
|
||||||
|
errstr(buf, ERRMAX);
|
||||||
|
}
|
|
@ -0,0 +1,9 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
exec(char *prog, char *argv[])
|
||||||
|
{
|
||||||
|
/* to mimic plan 9 should be just exec, but execvp is a better fit for unix */
|
||||||
|
return execvp(prog, argv);
|
||||||
|
}
|
|
@ -0,0 +1,28 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
execl(char *prog, ...)
|
||||||
|
{
|
||||||
|
int i;
|
||||||
|
va_list arg;
|
||||||
|
char **argv;
|
||||||
|
|
||||||
|
va_start(arg, prog);
|
||||||
|
for(i=0; va_arg(arg, char*) != nil; i++)
|
||||||
|
;
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
argv = malloc((i+1)*sizeof(char*));
|
||||||
|
if(argv == nil)
|
||||||
|
return -1;
|
||||||
|
|
||||||
|
va_start(arg, prog);
|
||||||
|
for(i=0; (argv[i] = va_arg(arg, char*)) != nil; i++)
|
||||||
|
;
|
||||||
|
va_end(arg);
|
||||||
|
|
||||||
|
exec(prog, argv);
|
||||||
|
free(argv);
|
||||||
|
return -1;
|
||||||
|
}
|
|
@ -0,0 +1,8 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
|
||||||
|
int
|
||||||
|
exitcode(char *s)
|
||||||
|
{
|
||||||
|
return 1;
|
||||||
|
}
|
|
@ -0,0 +1,253 @@
|
||||||
|
#include <u.h>
|
||||||
|
#include <libc.h>
|
||||||
|
#include <fcall.h>
|
||||||
|
|
||||||
|
static uint dumpsome(char*, char*, char*, long);
|
||||||
|
static void fdirconv(char*, char*, Dir*);
|
||||||
|
static char *qidtype(char*, uchar);
|
||||||
|
|
||||||
|
#define QIDFMT "(%.16llux %lud %s)"
|
||||||
|
|
||||||
|
int
|
||||||
|
fcallfmt(Fmt *fmt)
|
||||||
|
{
|
||||||
|
Fcall *f;
|
||||||
|
int fid, type, tag, i;
|
||||||
|
char buf[512], tmp[200];
|
||||||
|
char *p, *e;
|
||||||
|
Dir *d;
|
||||||
|
Qid *q;
|
||||||
|
|
||||||
|
e = buf+sizeof(buf);
|
||||||
|
f = va_arg(fmt->args, Fcall*);
|
||||||
|
type = f->type;
|
||||||
|
fid = f->fid;
|
||||||
|
tag = f->tag;
|
||||||
|
switch(type){
|
||||||
|
case Tversion: /* 100 */
|
||||||
|
seprint(buf, e, "Tversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
|
||||||
|
break;
|
||||||
|
case Rversion:
|
||||||
|
seprint(buf, e, "Rversion tag %ud msize %ud version '%s'", tag, f->msize, f->version);
|
||||||
|
break;
|
||||||
|
case Tauth: /* 102 */
|
||||||
|
seprint(buf, e, "Tauth tag %ud afid %d uname %s aname %s", tag,
|
||||||
|
f->afid, f->uname, f->aname);
|
||||||
|
break;
|
||||||
|
case Rauth:
|
||||||
|
seprint(buf, e, "Rauth tag %ud qid " QIDFMT, tag,
|
||||||
|
f->aqid.path, f->aqid.vers, qidtype(tmp, f->aqid.type));
|
||||||
|
break;
|
||||||
|
case Tattach: /* 104 */
|
||||||
|
seprint(buf, e, "Tattach tag %ud fid %d afid %d uname %s aname %s", tag,
|
||||||
|
fid, f->afid, f->uname, f->aname);
|
||||||
|
break;
|
||||||
|
case Rattach:
|
||||||
|
seprint(buf, e, "Rattach tag %ud qid " QIDFMT, tag,
|
||||||
|
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type));
|
||||||
|
break;
|
||||||
|
case Rerror: /* 107; 106 (Terror) illegal */
|
||||||
|
seprint(buf, e, "Rerror tag %ud ename %s", tag, f->ename);
|
||||||
|
break;
|
||||||
|
case Tflush: /* 108 */
|
||||||
|
seprint(buf, e, "Tflush tag %ud oldtag %ud", tag, f->oldtag);
|
||||||
|
break;
|
||||||
|
case Rflush:
|
||||||
|
seprint(buf, e, "Rflush tag %ud", tag);
|
||||||
|
break;
|
||||||
|
case Twalk: /* 110 */
|
||||||
|
p = seprint(buf, e, "Twalk tag %ud fid %d newfid %d nwname %d ", tag, fid, f->newfid, f->nwname);
|
||||||
|
if(f->nwname <= MAXWELEM)
|
||||||
|
for(i=0; i<f->nwname; i++)
|
||||||
|
p = seprint(p, e, "%d:%s ", i, f->wname[i]);
|
||||||
|
break;
|
||||||
|
case Rwalk:
|
||||||
|
p = seprint(buf, e, "Rwalk tag %ud nwqid %ud ", tag, f->nwqid);
|
||||||
|
if(f->nwqid <= MAXWELEM)
|
||||||
|
for(i=0; i<f->nwqid; i++){
|
||||||
|
q = &f->wqid[i];
|
||||||
|
p = seprint(p, e, "%d:" QIDFMT " ", i,
|
||||||
|
q->path, q->vers, qidtype(tmp, q->type));
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Topen: /* 112 */
|
||||||
|
seprint(buf, e, "Topen tag %ud fid %ud mode %d", tag, fid, f->mode);
|
||||||
|
break;
|
||||||
|
case Ropen:
|
||||||
|
seprint(buf, e, "Ropen tag %ud qid " QIDFMT " iounit %ud", tag,
|
||||||
|
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
|
||||||
|
break;
|
||||||
|
case Topenfd: /* 98 */
|
||||||
|
seprint(buf, e, "Topenfd tag %ud fid %ud mode %d", tag, fid, f->mode);
|
||||||
|
break;
|
||||||
|
case Ropenfd:
|
||||||
|
seprint(buf, e, "Ropenfd tag %ud qid " QIDFMT " iounit %ud unixfd %d", tag,
|
||||||
|
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit, f->unixfd);
|
||||||
|
break;
|
||||||
|
case Tcreate: /* 114 */
|
||||||
|
seprint(buf, e, "Tcreate tag %ud fid %ud name %s perm %M mode %d", tag, fid, f->name, (ulong)f->perm, f->mode);
|
||||||
|
break;
|
||||||
|
case Rcreate:
|
||||||
|
seprint(buf, e, "Rcreate tag %ud qid " QIDFMT " iounit %ud ", tag,
|
||||||
|
f->qid.path, f->qid.vers, qidtype(tmp, f->qid.type), f->iounit);
|
||||||
|
break;
|
||||||
|
case Tread: /* 116 */
|
||||||
|
seprint(buf, e, "Tread tag %ud fid %d offset %lld count %ud",
|
||||||
|
tag, fid, f->offset, f->count);
|
||||||
|
break;
|
||||||
|
case Rread:
|
||||||
|
p = seprint(buf, e, "Rread tag %ud count %ud ", tag, f->count);
|
||||||
|
dumpsome(p, e, f->data, f->count);
|
||||||
|
break;
|
||||||
|
case Twrite: /* 118 */
|
||||||
|
p = seprint(buf, e, "Twrite tag %ud fid %d offset %lld count %ud ",
|
||||||
|
tag, fid, f->offset, f->count);
|
||||||
|
dumpsome(p, e, f->data, f->count);
|
||||||
|
break;
|
||||||
|
case Rwrite:
|
||||||
|
seprint(buf, e, "Rwrite tag %ud count %ud", tag, f->count);
|
||||||
|
break;
|
||||||
|
case Tclunk: /* 120 */
|
||||||
|
seprint(buf, e, "Tclunk tag %ud fid %ud", tag, fid);
|
||||||
|
break;
|
||||||
|
case Rclunk:
|
||||||
|
seprint(buf, e, "Rclunk tag %ud", tag);
|
||||||
|
break;
|
||||||
|
case Tremove: /* 122 */
|
||||||
|
seprint(buf, e, "Tremove tag %ud fid %ud", tag, fid);
|
||||||
|
break;
|
||||||
|
case Rremove:
|
||||||
|
seprint(buf, e, "Rremove tag %ud", tag);
|
||||||
|
break;
|
||||||
|
case Tstat: /* 124 */
|
||||||
|
seprint(buf, e, "Tstat tag %ud fid %ud", tag, fid);
|
||||||
|
break;
|
||||||
|
case Rstat:
|
||||||
|
p = seprint(buf, e, "Rstat tag %ud ", tag);
|
||||||
|
if(f->stat == nil || f->nstat > sizeof tmp)
|
||||||
|
seprint(p, e, " stat(%d bytes)", f->nstat);
|
||||||
|
else{
|
||||||
|
d = (Dir*)tmp;
|
||||||
|
convM2D(f->stat, f->nstat, d, (char*)(d+1));
|
||||||
|
seprint(p, e, " stat ");
|
||||||
|
fdirconv(p+6, e, d);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Twstat: /* 126 */
|
||||||
|
p = seprint(buf, e, "Twstat tag %ud fid %ud", tag, fid);
|
||||||
|
if(f->stat == nil || f->nstat > sizeof tmp)
|
||||||
|
seprint(p, e, " stat(%d bytes)", f->nstat);
|
||||||
|
else{
|
||||||
|
d = (Dir*)tmp;
|
||||||
|
convM2D(f->stat, f->nstat, d, (char*)(d+1));
|
||||||
|
seprint(p, e, " stat ");
|
||||||
|
fdirconv(p+6, e, d);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
case Rwstat:
|
||||||
|
seprint(buf, e, "Rwstat tag %ud", tag);
|
||||||
|
break;
|
||||||
|
default:
|
||||||
|
seprint(buf, e, "unknown type %d", type);
|
||||||
|
}
|
||||||
|
return fmtstrcpy(fmt, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static char*
|
||||||
|
qidtype(char *s, uchar t)
|
||||||
|
{
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
p = s;
|
||||||
|
if(t & QTDIR)
|
||||||
|
*p++ = 'd';
|
||||||
|
if(t & QTAPPEND)
|
||||||
|
*p++ = 'a';
|
||||||
|
if(t & QTEXCL)
|
||||||
|
*p++ = 'l';
|
||||||
|
if(t & QTAUTH)
|
||||||
|
*p++ = 'A';
|
||||||
|
*p = '\0';
|
||||||
|
return s;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
dirfmt(Fmt *fmt)
|
||||||
|
{
|
||||||
|
char buf[160];
|
||||||
|
|
||||||
|
fdirconv(buf, buf+sizeof buf, va_arg(fmt->args, Dir*));
|
||||||
|
return fmtstrcpy(fmt, buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
static void
|
||||||
|
fdirconv(char *buf, char *e, Dir *d)
|
||||||
|
{
|
||||||
|
char tmp[16];
|
||||||
|
|
||||||
|
seprint(buf, e, "'%s' '%s' '%s' '%s' "
|
||||||
|
"q " QIDFMT " m %#luo "
|
||||||
|
"at %ld mt %ld l %lld "
|
||||||
|
"t %d d %d",
|
||||||
|
d->name, d->uid, d->gid, d->muid,
|
||||||
|
d->qid.path, d->qid.vers, qidtype(tmp, d->qid.type), d->mode,
|
||||||
|
d->atime, d->mtime, d->length,
|
||||||
|
d->type, d->dev);
|
||||||
|
}
|
||||||
|
|
||||||
|
/*
|
||||||
|
* dump out count (or DUMPL, if count is bigger) bytes from
|
||||||
|
* buf to ans, as a string if they are all printable,
|
||||||
|
* else as a series of hex bytes
|
||||||
|
*/
|
||||||
|
#define DUMPL 64
|
||||||
|
|
||||||
|
static uint
|
||||||
|
dumpsome(char *ans, char *e, char *buf, long count)
|
||||||
|
{
|
||||||
|
int i, printable;
|
||||||
|
char *p;
|
||||||
|
|
||||||
|
if(buf == nil){
|
||||||
|
seprint(ans, e, "<no data>");
|
||||||
|
return strlen(ans);
|
||||||
|
}
|
||||||
|
printable = 1;
|
||||||
|
if(count > DUMPL)
|
||||||
|
count = DUMPL;
|
||||||
|
for(i=0; i<count && printable; i++)
|
||||||
|
if((buf[i]!=0 && buf[i]<32) || (uchar)buf[i]>127)
|
||||||
|
printable = 0;
|
||||||
|
p = ans;
|
||||||
|
*p++ = '\'';
|
||||||
|
if(printable){
|
||||||
|
if(2*count > e-p-2)
|
||||||
|
count = (e-p-2)/2;
|
||||||
|
for(i=0; i<count; i++){
|
||||||
|
if(buf[i] == 0){
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = '0';
|
||||||
|
}else if(buf[i] == '\t'){
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = 't';
|
||||||
|
}else if(buf[i] == '\n'){
|
||||||
|
*p++ = '\\';
|
||||||
|
*p++ = 'n';
|
||||||
|
}else
|
||||||
|
*p++ = buf[i];
|
||||||
|
}
|
||||||
|
}else{
|
||||||
|
if(2*count > e-p-2)
|
||||||
|
count = (e-p-2)/2;
|
||||||
|
for(i=0; i<count; i++){
|
||||||
|
if(i>0 && i%4==0)
|
||||||
|
*p++ = ' ';
|
||||||
|
sprint(p, "%2.2ux", (uchar)buf[i]);
|
||||||
|
p += 2;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
*p++ = '\'';
|
||||||
|
*p = 0;
|
||||||
|
assert(p < e);
|
||||||
|
return p - ans;
|
||||||
|
}
|
|
@ -0,0 +1,22 @@
|
||||||
|
/*
|
||||||
|
* 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
|
||||||
|
* NOR GOOGLE INC MAKE ANY REPRESENTATION OR WARRANTY OF ANY KIND CONCERNING
|
||||||
|
* THE MERCHANTABILITY OF THIS SOFTWARE OR ITS FITNESS FOR ANY PARTICULAR PURPOSE.
|
||||||
|
*/
|
||||||
|
|
||||||
|
This is a Unix port of the Plan 9 formatted I/O package.
|
||||||
|
|
||||||
|
Please send comments about the packaging to Russ Cox <rsc@swtch.com>.
|
||||||
|
|
|
@ -0,0 +1,19 @@
|
||||||
|
/*
|
||||||
|
* 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.
|
||||||
|
*/
|
||||||
|
|
||||||
|
This is a Unix port of the Plan 9 formatted I/O package.
|
||||||
|
|
||||||
|
Please send comments about the packaging
|
||||||
|
to Russ Cox <rsc@post.harvard.edu>.
|
||||||
|
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue