ref: d75d842cf576cb4785f89c5f5b73a4f73170001b
parent: dbd54342fd66fd372f5c2edd1597019814f41c9c
author: Ori Bernstein <[email protected]>
date: Sun Nov 1 06:56:26 EST 2020
rc: show line numbers on error This change provides a location for errors like 'null list in concatenation'.
--- a/sys/src/cmd/rc/code.c
+++ b/sys/src/cmd/rc/code.c
@@ -6,10 +6,12 @@
#define c0 t->child[0]
#define c1 t->child[1]
#define c2 t->child[2]
+code *codebuf;
int codep, ncode;
#define emitf(x) ((codep!=ncode || morecode()), codebuf[codep].f = (x), codep++)
#define emiti(x) ((codep!=ncode || morecode()), codebuf[codep].i = (x), codep++)
#define emits(x) ((codep!=ncode || morecode()), codebuf[codep].s = (x), codep++)
+
void stuffdot(int);
char *fnstr(tree*);
void outcode(tree*, int);
@@ -38,7 +40,7 @@
compile(tree *t)
{
ncode = 100;
- codebuf = (code *)emalloc(ncode*sizeof codebuf[0]);
+ codebuf = emalloc(ncode*sizeof codebuf[0]);
codep = 0;
emiti(0); /* reference count */
outcode(t, flag['e']?1:0);
@@ -64,12 +66,8 @@
{
io *f = openstr();
void *v;
- extern char nl;
- char svnl = nl;
- nl = ';';
pfmt(f, "%t", t);
- nl = svnl;
v = f->strp;
f->strp = 0;
closeio(f);
@@ -79,12 +77,19 @@
void
outcode(tree *t, int eflag)
{
+ static int line;
int p, q;
tree *tt;
+ char *f;
if(t==0)
return;
if(t->type!=NOT && t->type!=';')
runq->iflast = 0;
+ if(t->line != line){
+ line = t->line;
+ emitf(Xsrcline);
+ emiti(line);
+ }
switch(t->type){
default:
pfmt(err, "bad type %d in outcode\n", t->type);
@@ -174,6 +179,12 @@
emitf(Xfn);
p = emiti(0);
emits(fnstr(c1));
+ if((f = curfile(runq)) != nil){
+ emitf(Xsrcfile);
+ emits(strdup(f));
+ }
+ emitf(Xsrcline);
+ emiti(lexline);
outcode(c1, eflag);
emitf(Xunlocal); /* get rid of $* */
emitf(Xreturn);
--- a/sys/src/cmd/rc/exec.c
+++ b/sys/src/cmd/rc/exec.c
@@ -14,11 +14,12 @@
struct thread *p = new(struct thread);
p->code = codecopy(c);
+ p->line = runq?runq->line:0;
p->pc = pc;
p->argv = 0;
- p->redir = p->startredir = runq?runq->redir:0;
+ p->redir = p->startredir = runq?runq->redir:nil;
p->local = local;
- p->cmdfile = 0;
+ p->cmdfile = nil;
p->cmdfd = 0;
p->eof = 0;
p->iflag = 0;
@@ -201,10 +202,14 @@
bootstrap[i++].f = Xexit;
bootstrap[i].i = 0;
start(bootstrap, 1, (var *)0);
+ runq->cmdfile = strdup("rc");
/* prime bootstrap argv */
pushlist();
argv0 = estrdup(argv[0]);
for(i = argc-1;i!=0;--i) pushword(argv[i]);
+
+ lexline = 0;
+
for(;;){
if(flag['r'])
pfnc(err, runq);
@@ -260,6 +265,8 @@
* Xunlocal delete local variable
* Xword[string] push string
* Xwrite(file)[fd] open file to write
+ * Xsrcline[line] set current line number
+ * Xsrcfile[file] set current file name
*/
void
@@ -932,7 +939,7 @@
if(p->cmdfile)
free(p->cmdfile);
closeio(p->cmdfd);
- Xreturn(); /* should this be omitted? */
+ Xreturn();
}
else{
if(Eintr()){
@@ -950,13 +957,22 @@
freenodes();
}
+char*
+curfile(thread *p)
+{
+ for(; p != nil; p = p->ret)
+ if(p->cmdfile != nil)
+ return p->cmdfile;
+ return "unknown";
+}
+
void
Xerror(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
- pfmt(err, "rc: %s: %r\n", s);
+ pfmt(err, "rc:%d: %s: %r\n", runq->line, s);
else
- pfmt(err, "rc (%s): %s: %r\n", argv0, s);
+ pfmt(err, "%s:%d: %s: %r\n", curfile(runq), runq->line, s);
flush(err);
setstatus("error");
while(!runq->iflag) Xreturn();
@@ -966,9 +982,9 @@
Xerror1(char *s)
{
if(strcmp(argv0, "rc")==0 || strcmp(argv0, "/bin/rc")==0)
- pfmt(err, "rc: %s\n", s);
+ pfmt(err, "rc:%d: %s\n", runq->line, s);
else
- pfmt(err, "rc (%s): %s\n", argv0, s);
+ pfmt(err, "%s:%d: %s\n", curfile(runq), runq->line, s);
flush(err);
setstatus("error");
while(!runq->iflag) Xreturn();
@@ -1024,4 +1040,17 @@
Xglob(void)
{
globlist(runq->argv->words);
+}
+
+void
+Xsrcline(void)
+{
+ runq->line = runq->code[runq->pc++].i;
+}
+
+void
+Xsrcfile(void)
+{
+ free(runq->cmdfile);
+ runq->cmdfile = strdup(runq->code[runq->pc++].s);
}
--- a/sys/src/cmd/rc/exec.h
+++ b/sys/src/cmd/rc/exec.h
@@ -5,7 +5,7 @@
extern void Xconc(void), Xcount(void), Xdelfn(void), Xdol(void), Xqw(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 Xrdwr(void), Xsrcline(void), Xsrcfile(void);
extern void Xrdfn(void), Xunredir(void), Xstar(void), Xreturn(void), Xsubshell(void);
extern void Xtrue(void), Xword(void), Xglobs(void), Xwrite(void), Xpipefd(void), Xcase(void);
extern void Xlocal(void), Xunlocal(void), Xassign(void), Xsimple(void), Xpopm(void);
@@ -30,7 +30,7 @@
struct redir{
char type; /* what to do */
short from, to; /* what to do it to */
- struct redir *next; /* what else to do (reverse order) */
+ redir *next; /* what else to do (reverse order) */
};
#define NSTATUS ERRMAX /* length of status (from plan 9) */
/*
@@ -40,14 +40,15 @@
#define RDUP 2 /* dup2(from, to); */
#define RCLOSE 3 /* close(from); */
struct thread{
- union code *code; /* code for this thread */
+ 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 */
+ int line; /* source code line */
+ list *argv; /* argument stack */
+ redir *redir; /* redirection stack */
+ redir *startredir; /* redir inheritance point */
+ var *local; /* list of local variables */
char *cmdfile; /* file name in Xrdcmd */
- struct io *cmdfd; /* file descriptor for Xrdcmd */
+ io *cmdfd; /* file descriptor for Xrdcmd */
int iflast; /* static `if not' checking */
int eof; /* is cmdfd at eof? */
int iflag; /* interactive? */
@@ -55,7 +56,7 @@
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 *ret; /* who continues when this finishes */
};
thread *runq;
code *codecopy(code*);
@@ -74,3 +75,4 @@
void execexit(void), execshift(void);
void execwait(void), execumask(void), execdot(void), execflag(void);
void execfunc(var*), execcmds(io *);
+char *curfile(thread*);
\ No newline at end of file
--- a/sys/src/cmd/rc/lex.c
+++ b/sys/src/cmd/rc/lex.c
@@ -25,6 +25,13 @@
int doprompt = 1;
int inquote;
int incomm;
+int lastc;
+int ndot;
+int nerror;
+int lexline;
+int nlexpath;
+int lexpathsz;
+
/*
* Look ahead in the input stream
*/
@@ -39,7 +46,6 @@
/*
* Consume the lookahead character.
*/
-
int
advance(void)
{
@@ -46,6 +52,8 @@
int c = nextc();
lastc = future;
future = EOF;
+ if(c == '\n')
+ lexline++;
return c;
}
/*
--- a/sys/src/cmd/rc/pcmd.c
+++ b/sys/src/cmd/rc/pcmd.c
@@ -1,7 +1,7 @@
#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]
@@ -76,7 +76,7 @@
case ';':
if(c0){
if(c1)
- pfmt(f, "%t%c%t", c0, nl, c1);
+ pfmt(f, "%t\n%t", c0, c1);
else pfmt(f, "%t", c0);
}
else pfmt(f, "%t", c1);
--- a/sys/src/cmd/rc/pfnc.c
+++ b/sys/src/cmd/rc/pfnc.c
@@ -51,6 +51,7 @@
Xrdfn, "Xrdfn",
Xsimple, "Xsimple",
Xqw, "Xqw",
+ Xsrcline, "Xsrcline",
0};
void
@@ -59,7 +60,8 @@
int i;
void (*fn)(void) = t->code[t->pc].f;
list *a;
- pfmt(fd, "pid %d cycle %p %d ", getpid(), t->code, t->pc);
+
+ pfmt(fd, "%s:%d: pid %d cycle %p %d ", t->cmdfile, t->line, getpid(), t->code, t->pc);
for(i = 0;fname[i].f;i++) if(fname[i].f==fn){
pstr(fd, fname[i].name);
break;
--- a/sys/src/cmd/rc/plan9.c
+++ b/sys/src/cmd/rc/plan9.c
@@ -164,9 +164,12 @@
if(runq->argv->words == 0)
poplist();
else {
+ free(runq->cmdfile);
int f = open(runq->argv->words->word, 0);
- popword();
+ lexline = 0;
+ runq->cmdfile = strdup(runq->argv->words->word);
runq->pc--;
+ popword();
if(f>=0) execcmds(openfd(f));
}
}
--- a/sys/src/cmd/rc/rc.h
+++ b/sys/src/cmd/rc/rc.h
@@ -43,6 +43,7 @@
char *str;
int quoted;
int iskw;
+ int line;
tree *child[3];
tree *next;
};
@@ -54,6 +55,7 @@
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(.).
@@ -126,10 +128,12 @@
*/
#define onebyte(c) ((c&0x80)==0x00)
-char **argp;
-char **args;
-int nerror; /* number of errors encountered during compilation */
-int doprompt; /* is it time for a prompt? */
+extern char **argp;
+extern char **args;
+extern int nerror; /* number of errors encountered during compilation */
+extern int doprompt; /* is it time for a prompt? */
+extern int lexline;
+
/*
* Which fds are the reading/writing end of a pipe?
* Unfortunately, this can vary from system to system.
@@ -143,7 +147,7 @@
* How many dot commands have we executed?
* Used to ensure that -v flag doesn't print rcmain.
*/
-int ndot;
+extern int ndot;
+extern int lastc;
+extern int lastword;
char *getstatus(void);
-int lastc;
-int lastword;
--- a/sys/src/cmd/rc/simple.c
+++ b/sys/src/cmd/rc/simple.c
@@ -11,8 +11,15 @@
*/
int
exitnext(void){
- union code *c=&runq->code[runq->pc];
- while(c->f==Xpopredir || c->f==Xunlocal) c++;
+ code *c=&runq->code[runq->pc];
+ while(1){
+ if(c->f==Xpopredir || c->f==Xunlocal)
+ c++;
+ else if(c->f==Xsrcline || c->f==Xsrcfile)
+ c += 2;
+ else
+ break;
+ }
return c->f==Xexit;
}
@@ -260,6 +267,7 @@
execcmds(io *f)
{
static int first = 1;
+
if(first){
rdcmds[0].i = 1;
rdcmds[1].f = Xrdcmds;
@@ -319,6 +327,7 @@
}
else
eflagok = 1;
+
popword();
if(p->argv->words && strcmp(p->argv->words->word, "-i")==0){
iflag = 1;
@@ -354,6 +363,9 @@
Xerror(".: can't open");
return;
}
+
+ lexline = 1;
+
/* set up for a new command loop */
start(dotcmds, 1, (struct var *)0);
pushredir(RCLOSE, fd, 0);
--- a/sys/src/cmd/rc/tree.c
+++ b/sys/src/cmd/rc/tree.c
@@ -16,6 +16,7 @@
t->str = 0;
t->child[0] = t->child[1] = t->child[2] = 0;
t->next = treenodes;
+ t->line = lexline;
treenodes = t;
return t;
}