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