diff options
-rw-r--r-- | ChangeLog | 1 | ||||
-rw-r--r-- | src/error.c | 12 | ||||
-rw-r--r-- | src/error.h | 1 | ||||
-rw-r--r-- | src/eval.c | 33 | ||||
-rw-r--r-- | src/exec.c | 2 | ||||
-rw-r--r-- | src/input.c | 10 | ||||
-rw-r--r-- | src/input.h | 1 | ||||
-rw-r--r-- | src/jobs.c | 2 | ||||
-rw-r--r-- | src/nodetypes | 11 | ||||
-rw-r--r-- | src/parser.c | 35 | ||||
-rw-r--r-- | src/parser.h | 1 | ||||
-rw-r--r-- | src/var.c | 9 | ||||
-rw-r--r-- | src/var.h | 7 |
13 files changed, 81 insertions, 44 deletions
diff --git a/ChangeLog b/ChangeLog index 3e7465b..44e5bdf 100644 --- a/ChangeLog +++ b/ChangeLog @@ -1,6 +1,7 @@ 2011-03-15 Harald van Dijk <harald@gigawatt.nl> * Let funcnode refer to a function definition, not its first command. + * Improve LINENO support. 2011-03-15 Brian Koropoff <bkoropoff@gmail.com> diff --git a/src/error.c b/src/error.c index f1a358d..7ad73bc 100644 --- a/src/error.c +++ b/src/error.c @@ -62,6 +62,7 @@ struct jmploc *handler; int exception; int suppressint; volatile sig_atomic_t intpending; +int errlinno; static void exverror(int, const char *, va_list) @@ -116,13 +117,12 @@ exvwarning2(const char *msg, va_list ap) const char *fmt; errs = out2; - name = arg0 ?: "sh"; - fmt = "%s: "; - if (commandname) { - name = commandname; + name = arg0 ? arg0 : "sh"; + if (!commandname) fmt = "%s: %d: "; - } - outfmt(errs, fmt, name, startlinno); + else + fmt = "%s: %d: %s: "; + outfmt(errs, fmt, name, errlinno, commandname); doformat(errs, msg, ap); #if FLUSHERR outc('\n', errs); diff --git a/src/error.h b/src/error.h index f236d9f..9630b56 100644 --- a/src/error.h +++ b/src/error.h @@ -120,6 +120,7 @@ void onint(void) __attribute__((__noreturn__)); #else void onint(void); #endif +extern int errlinno; void sh_error(const char *, ...) __attribute__((__noreturn__)); void exerror(int, const char *, ...) __attribute__((__noreturn__)); const char *errmsg(int, int); diff --git a/src/eval.c b/src/eval.c index 9f4388a..426c03a 100644 --- a/src/eval.c +++ b/src/eval.c @@ -73,7 +73,7 @@ int evalskip; /* set if we are skipping commands */ STATIC int skipcount; /* number of levels to skip */ MKINIT int loopnest; /* current loop nesting level */ -static int funcnest; /* depth of function calls */ +static int funcline; /* starting line number of current function, or 0 if not in a function */ char *commandname; @@ -218,6 +218,9 @@ evaltree(union node *n, int flags) status = !exitstatus; goto setstatus; case NREDIR: + errlinno = lineno = n->nredir.linno; + if (funcline) + lineno -= funcline - 1; expredir(n->nredir.redirect); pushredir(n->nredir.redirect); status = redirectsafe(n->nredir.redirect, REDIR_PUSH); @@ -376,6 +379,10 @@ evalfor(union node *n, int flags) struct strlist *sp; struct stackmark smark; + errlinno = lineno = n->nfor.linno; + if (funcline) + lineno -= funcline - 1; + setstackmark(&smark); arglist.lastp = &arglist.list; for (argp = n->nfor.args ; argp ; argp = argp->narg.next) { @@ -417,6 +424,10 @@ evalcase(union node *n, int flags) struct arglist arglist; struct stackmark smark; + errlinno = lineno = n->ncase.linno; + if (funcline) + lineno -= funcline - 1; + setstackmark(&smark); arglist.lastp = &arglist.list; expandarg(n->ncase.expr, &arglist, EXP_TILDE); @@ -448,6 +459,10 @@ evalsubshell(union node *n, int flags) int backgnd = (n->type == NBACKGND); int status; + errlinno = lineno = n->nredir.linno; + if (funcline) + lineno -= funcline - 1; + expredir(n->nredir.redirect); if (!backgnd && flags & EV_EXIT && !have_traps()) goto nofork; @@ -704,6 +719,10 @@ evalcommand(union node *cmd, int flags) int status; char **nargv; + errlinno = lineno = cmd->ncmd.linno; + if (funcline) + lineno -= funcline - 1; + /* First expand the arguments. */ TRACE(("evalcommand(0x%lx, %d) called\n", (long)cmd, flags)); setstackmark(&smark); @@ -737,7 +756,7 @@ evalcommand(union node *cmd, int flags) *nargv = NULL; lastarg = NULL; - if (iflag && funcnest == 0 && argc > 0) + if (iflag && funcline == 0 && argc > 0) lastarg = nargv[-1]; preverrout.fd = 2; @@ -937,8 +956,10 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) struct jmploc *volatile savehandler; struct jmploc jmploc; int e; + int savefuncline; saveparam = shellparam; + savefuncline = funcline; if ((e = setjmp(jmploc.loc))) { goto funcdone; } @@ -947,18 +968,18 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags) handler = &jmploc; shellparam.malloc = 0; func->count++; - funcnest++; + funcline = func->n.ndefun.linno; INTON; shellparam.nparam = argc - 1; shellparam.p = argv + 1; shellparam.optind = 1; shellparam.optoff = -1; pushlocalvars(); - evaltree(func->n.narg.next, flags & EV_TESTED); + evaltree(func->n.ndefun.body, flags & EV_TESTED); poplocalvars(0); funcdone: INTOFF; - funcnest--; + funcline = savefuncline; freefunc(func); freeparam(&shellparam); shellparam = saveparam; @@ -1048,7 +1069,7 @@ returncmd(int argc, char **argv) * If called outside a function, do what ksh does; * skip the rest of the file. */ - evalskip = funcnest ? SKIPFUNC : SKIPFILE; + evalskip = funcline ? SKIPFUNC : SKIPFILE; return argv[1] ? number(argv[1]) : exitstatus; } diff --git a/src/exec.c b/src/exec.c index a13ad67..79e2007 100644 --- a/src/exec.c +++ b/src/exec.c @@ -697,7 +697,7 @@ defun(union node *func) INTOFF; entry.cmdtype = CMDFUNCTION; entry.u.func = copyfunc(func); - addcmdentry(func->narg.text, &entry); + addcmdentry(func->ndefun.text, &entry); INTON; } diff --git a/src/input.c b/src/input.c index bd3a9a2..d31c45b 100644 --- a/src/input.c +++ b/src/input.c @@ -54,7 +54,6 @@ #include "alias.h" #include "parser.h" #include "main.h" -#include "var.h" #ifndef SMALL #include "myhistedit.h" #endif @@ -531,12 +530,3 @@ closescript(void) parsefile->fd = 0; } } - - -int lineno_inc(void) -{ - int lineno = plinno++; - - setvarint("LINENO", lineno, 0); - return lineno; -} diff --git a/src/input.h b/src/input.h index bdf8857..50a7797 100644 --- a/src/input.h +++ b/src/input.h @@ -61,7 +61,6 @@ void setinputstring(char *); void popfile(void); void popallfiles(void); void closescript(void); -int lineno_inc(void); #define pgetc_macro() \ (--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer()) diff --git a/src/jobs.c b/src/jobs.c index 4b1b938..bf40204 100644 --- a/src/jobs.c +++ b/src/jobs.c @@ -1288,7 +1288,7 @@ dotail: p = "; done"; goto dodo; case NDEFUN: - cmdputs(n->narg.text); + cmdputs(n->ndefun.text); p = "() { ... }"; goto dotail2; case NCMD: diff --git a/src/nodetypes b/src/nodetypes index 17a7b3c..ceaf478 100644 --- a/src/nodetypes +++ b/src/nodetypes @@ -51,6 +51,7 @@ NCMD ncmd # a simple command type int + linno int assign nodeptr # variable assignments args nodeptr # the arguments redirect nodeptr # list of file redirections @@ -62,6 +63,7 @@ NPIPE npipe # a pipeline NREDIR nredir # redirection (of a complex command) type int + linno int n nodeptr # the command redirect nodeptr # list of file redirections @@ -87,12 +89,14 @@ NUNTIL nbinary # the until statement NFOR nfor # the for statement type int + linno int args nodeptr # for var in args body nodeptr # do body; done var string # the for variable NCASE ncase # a case statement type int + linno int expr nodeptr # the word to switch on cases nodeptr # the list of cases (NCLIST nodes) @@ -103,8 +107,11 @@ NCLIST nclist # a case body nodeptr # code to execute for this case -NDEFUN narg # define a function. The "next" field contains - # the body of the function. +NDEFUN ndefun # a function + type int + linno int + text string + body nodeptr NARG narg # represents a word type int diff --git a/src/parser.c b/src/parser.c index be20ff7..0bfd620 100644 --- a/src/parser.c +++ b/src/parser.c @@ -93,7 +93,6 @@ struct nodelist *backquotelist; union node *redirnode; struct heredoc *heredoc; int quoteflag; /* set if (part of) last token was quoted */ -int startlinno; /* line # where last token started */ STATIC union node *list(int); @@ -304,10 +303,13 @@ command(void) union node *redir, **rpp; union node **rpp2; int t; + int savelinno; redir = NULL; rpp2 = &redir; + savelinno = plinno; + switch (readtoken()) { default: synexpect(-1); @@ -356,6 +358,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); synerror("Bad for loop variable"); n1 = (union node *)stalloc(sizeof (struct nfor)); n1->type = NFOR; + n1->nfor.linno = savelinno; n1->nfor.var = wordtext; checkkwd = CHKNL | CHKKWD | CHKALIAS; if (readtoken() == TIN) { @@ -395,6 +398,7 @@ TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : "")); case TCASE: n1 = (union node *)stalloc(sizeof (struct ncase)); n1->type = NCASE; + n1->ncase.linno = savelinno; if (readtoken() != TWORD) synexpect(TWORD); n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg)); @@ -445,6 +449,7 @@ next_case: case TLP: n1 = (union node *)stalloc(sizeof (struct nredir)); n1->type = NSUBSHELL; + n1->nredir.linno = savelinno; n1->nredir.n = list(0); n1->nredir.redirect = NULL; t = TRP; @@ -477,6 +482,7 @@ redir: if (n1->type != NSUBSHELL) { n2 = (union node *)stalloc(sizeof (struct nredir)); n2->type = NREDIR; + n2->nredir.linno = savelinno; n2->nredir.n = n1; n1 = n2; } @@ -494,6 +500,7 @@ simplecmd(void) { union node *vars, **vpp; union node **rpp, *redir; int savecheckkwd; + int savelinno; args = NULL; app = &args; @@ -503,6 +510,7 @@ simplecmd(void) { rpp = &redir; savecheckkwd = CHKALIAS; + savelinno = plinno; for (;;) { checkkwd = savecheckkwd; switch (readtoken()) { @@ -546,7 +554,9 @@ simplecmd(void) { synerror("Bad function name"); n->type = NDEFUN; checkkwd = CHKNL | CHKKWD | CHKALIAS; - n->narg.next = command(); + n->ndefun.text = n->narg.text; + n->ndefun.linno = plinno; + n->ndefun.body = command(); return n; } /* fall through */ @@ -561,6 +571,7 @@ out: *rpp = NULL; n = (union node *)stalloc(sizeof (struct ncmd)); n->type = NCMD; + n->ncmd.linno = savelinno; n->ncmd.args = args; n->ncmd.assign = vars; n->ncmd.redirect = redir; @@ -738,8 +749,6 @@ out: * quoted. * If the token is TREDIR, then we set redirnode to a structure containing * the redirection. - * In all cases, the variable startlinno is set to the number of the line - * on which the token starts. * * [Change comment: here documents and internal procedures] * [Readtoken shouldn't have any arguments. Perhaps we should make the @@ -763,7 +772,6 @@ xxreadtoken(void) if (needprompt) { setprompt(2); } - startlinno = plinno; for (;;) { /* until token or start of word found */ c = pgetc_macro(); switch (c) { @@ -776,7 +784,7 @@ xxreadtoken(void) continue; case '\\': if (pgetc() == '\n') { - startlinno = lineno_inc(); + plinno++; if (doprompt) setprompt(2); continue; @@ -784,7 +792,7 @@ xxreadtoken(void) pungetc(); goto breakloop; case '\n': - lineno_inc(); + plinno++; needprompt = doprompt; RETURN(TNL); case PEOF: @@ -855,7 +863,6 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) /* syntax before arithmetic */ char const *uninitialized_var(prevsyntax); - startlinno = plinno; dblquote = 0; if (syntax == DQSYNTAX) dblquote = 1; @@ -886,7 +893,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) if (syntax == BASESYNTAX) goto endword; /* exit outer loop */ USTPUTC(c, out); - lineno_inc(); + plinno++; if (doprompt) setprompt(2); c = pgetc(); @@ -907,6 +914,7 @@ readtoken1(int firstc, char const *syntax, char *eofmark, int striptabs) USTPUTC('\\', out); pungetc(); } else if (c == '\n') { + plinno++; if (doprompt) setprompt(2); } else { @@ -1008,7 +1016,6 @@ endword: if (syntax != BASESYNTAX && eofmark == NULL) synerror("Unterminated quoted string"); if (varnest != 0) { - startlinno = plinno; /* { */ synerror("Missing '}'"); } @@ -1065,7 +1072,7 @@ checkend: { if (c == '\n' || c == PEOF) { c = PEOF; - lineno_inc(); + plinno++; needprompt = doprompt; } else { int len; @@ -1315,7 +1322,7 @@ parsebackq: { case '\\': if ((pc = pgetc()) == '\n') { - lineno_inc(); + plinno++; if (doprompt) setprompt(2); /* @@ -1336,11 +1343,10 @@ parsebackq: { case PEOF: case PEOA: - startlinno = plinno; synerror("EOF in backquote substitution"); case '\n': - lineno_inc(); + plinno++; needprompt = doprompt; break; @@ -1472,6 +1478,7 @@ synexpect(int token) STATIC void synerror(const char *msg) { + errlinno = plinno; sh_error("Syntax error: %s", msg); /* NOTREACHED */ } diff --git a/src/parser.h b/src/parser.h index 6bdf1c9..e6caed6 100644 --- a/src/parser.h +++ b/src/parser.h @@ -77,7 +77,6 @@ extern int tokpushback; #define NEOF ((union node *)&tokpushback) extern int whichprompt; /* 1 == PS1, 2 == PS2 */ extern int checkkwd; -extern int startlinno; /* line # where last token started */ union node *parsecmd(int); diff --git a/src/var.c b/src/var.c index aec1076..ecc8c90 100644 --- a/src/var.c +++ b/src/var.c @@ -33,6 +33,7 @@ */ #include <unistd.h> +#include <stdio.h> #include <stdlib.h> #ifdef HAVE_PATHS_H #include <paths.h> @@ -80,6 +81,9 @@ const char defifsvar[] = "IFS= \t\n"; const char defifs[] = " \t\n"; #endif +int lineno; +char linenovar[sizeof("LINENO=")+sizeof(int)*CHAR_BIT/3+1] = "LINENO="; + /* Some macros in var.h depend on the order, add new variables to the end. */ struct var varinit[] = { #if ATTY @@ -97,11 +101,11 @@ struct var varinit[] = { { 0, VSTRFIXED|VTEXTFIXED, "PS2=> ", 0 }, { 0, VSTRFIXED|VTEXTFIXED, "PS4=+ ", 0 }, { 0, VSTRFIXED|VTEXTFIXED, "OPTIND=1", getoptsreset }, + { 0, VSTRFIXED|VTEXTFIXED, linenovar, 0 }, #ifndef SMALL { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "TERM\0", 0 }, { 0, VSTRFIXED|VTEXTFIXED|VUNSET, "HISTSIZE\0", sethistsize }, #endif - { 0, VSTRFIXED|VTEXTFIXED, "LINENO=1", 0 }, }; STATIC struct var *vartab[VTABSIZE]; @@ -331,6 +335,9 @@ lookupvar(const char *name) struct var *v; if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) { + if (v == &vlineno && v->text == linenovar) { + fmtstr(linenovar+7, sizeof(linenovar)-7, "%d", lineno); + } return strchrnul(v->text, '=') + 1; } return NULL; diff --git a/src/var.h b/src/var.h index 35dd099..54f7b2d 100644 --- a/src/var.h +++ b/src/var.h @@ -88,8 +88,9 @@ extern struct var varinit[]; #define vps2 (&vps1)[1] #define vps4 (&vps2)[1] #define voptind (&vps4)[1] +#define vlineno (&voptind)[1] #ifndef SMALL -#define vterm (&voptind)[1] +#define vterm (&vlineno)[1] #define vhistsize (&vterm)[1] #endif @@ -102,6 +103,9 @@ extern const char defifs[]; extern const char defpathvar[]; #define defpath (defpathvar + 5) +extern int lineno; +extern char linenovar[]; + /* * The following macros access the values of the above variables. * They have to skip over the name. They return the null string @@ -117,6 +121,7 @@ extern const char defpathvar[]; #define ps2val() (vps2.text + 4) #define ps4val() (vps4.text + 4) #define optindval() (voptind.text + 7) +#define linenoval() (vlineno.text + 7) #ifndef SMALL #define histsizeval() (vhistsize.text + 9) #define termval() (vterm.text + 5) |