* [PATCH] Improved LINENO support
@ 2010-11-08 20:33 Harald van Dijk
2010-11-10 22:00 ` Jilles Tjoelker
0 siblings, 1 reply; 12+ messages in thread
From: Harald van Dijk @ 2010-11-08 20:33 UTC (permalink / raw)
To: dash
[-- Attachment #1: Type: text/plain, Size: 756 bytes --]
Hi,
This patch improves LINENO support by storing line numbers in the parse
tree, for commands as well as for function definitions. It makes LINENO
behaves properly when calling functions, and has the added benefit of
improved line numbers in error messages when the last-parsed command is
not the last-executed one. It removes the earlier LINENO support, and
instead sets LINENO from evaltree when a command is executed. I have
used it for a while, and have seen correct line numbers in basic testing
and in error messages in fairly large and complicated autoconf-generated
shell scripts. Does this look good enough to add to dash? If there are
any problems with it, please let me know, I will be happy to look at
this further.
Cheers,
Harald
[-- Attachment #2: dash-improved-lineno.diff --]
[-- Type: text/plain, Size: 14452 bytes --]
diff --git a/src/error.c b/src/error.c
index e304d3d..e60e430 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 3162e15..08f96e9 100644
--- a/src/error.h
+++ b/src/error.h
@@ -122,6 +122,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 b966749..8c5f82c 100644
--- a/src/eval.c
+++ b/src/eval.c
@@ -32,6 +32,7 @@
* SUCH DAMAGE.
*/
+#include <stdio.h>
#include <stdlib.h>
#include <signal.h>
#include <unistd.h>
@@ -73,7 +74,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;
@@ -191,6 +192,9 @@ evalstring(char *s, int flags)
void
evaltree(union node *n, int flags)
{
+ static char linenoeq[7+(sizeof(int)*CHAR_BIT/3)+2] = "LINENO=";
+ char *lineno = linenoeq+7;
+
int checkexit = 0;
void (*evalfn)(union node *, int);
unsigned isor;
@@ -204,6 +208,12 @@ evaltree(union node *n, int flags)
#endif
TRACE(("pid %d, evaltree(%p: %d, %d) called\n",
getpid(), n, n->type, flags));
+ /* In a function, LINENO must refer to the line number from the start
+ * of the function. However, errlinno contains the source line number,
+ * used in error messages. */
+ errlinno = n->ncmd.linno;
+ sprintf(lineno, "%d", n->ncmd.linno - (funcline ? funcline-1 : 0));
+ setvareq(linenoeq, VTEXTFIXED);
switch (n->type) {
default:
#ifdef DEBUG
@@ -296,7 +306,7 @@ calleval:
}
goto success;
case NDEFUN:
- defun(n->narg.text, n->narg.next);
+ defun(n->ndefun.text, n->ndefun.body);
success:
status = 0;
setstatus:
@@ -730,7 +740,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;
@@ -928,8 +938,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;
}
@@ -938,7 +950,7 @@ 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;
@@ -949,7 +961,7 @@ evalfun(struct funcnode *func, int argc, char **argv, int flags)
poplocalvars(0);
funcdone:
INTOFF;
- funcnest--;
+ funcline = savefuncline;
freefunc(func);
freeparam(&shellparam);
shellparam = saveparam;
@@ -1039,7 +1051,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/input.c b/src/input.c
index e57ad76..1e198e9 100644
--- a/src/input.c
+++ b/src/input.c
@@ -53,7 +53,6 @@
#include "alias.h"
#include "parser.h"
#include "main.h"
-#include "var.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
@@ -529,12 +528,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 826a9af..3d7ce93 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1284,7 +1284,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..ae467cb 100644
--- a/src/nodetypes
+++ b/src/nodetypes
@@ -51,17 +51,20 @@
NCMD ncmd # a simple command
type int
+ linno int
assign nodeptr # variable assignments
args nodeptr # the arguments
redirect nodeptr # list of file redirections
NPIPE npipe # a pipeline
type int
+ linno int
backgnd int # set to run pipeline in background
cmdlist nodelist # the commands in the pipeline
NREDIR nredir # redirection (of a complex command)
type int
+ linno int
n nodeptr # the command
redirect nodeptr # list of file redirections
@@ -73,11 +76,13 @@ NOR nbinary # the || operator
NSEMI nbinary # two commands separated by a semicolon
type int
+ linno int
ch1 nodeptr # the first child
ch2 nodeptr # the second child
NIF nif # the if statement. Elif clauses are handled
type int # using multiple if nodes.
+ linno int
test nodeptr # if test
ifpart nodeptr # then ifpart
elsepart nodeptr # else elsepart
@@ -87,12 +92,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)
@@ -102,9 +109,11 @@ NCLIST nclist # a case
pattern nodeptr # list of patterns for this 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
@@ -140,5 +149,6 @@ NXHERE nhere # fd<<!
doc nodeptr # input to command (NARG node)
NNOT nnot # ! command (actually pipeline)
- type int
- com nodeptr
+ type int
+ linno int
+ com nodeptr
diff --git a/src/parser.c b/src/parser.c
index be20ff7..1881114 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);
@@ -185,6 +184,7 @@ list(int nlflag)
else {
n3 = (union node *)stalloc(sizeof (struct nbinary));
n3->type = NSEMI;
+ n3->nbinary.linno = n1->ncmd.linno;
n3->nbinary.ch1 = n1;
n3->nbinary.ch2 = n2;
n1 = n3;
@@ -243,6 +243,7 @@ andor(void)
n2 = pipeline();
n3 = (union node *)stalloc(sizeof (struct nbinary));
n3->type = t;
+ n3->nbinary.linno = n1->ncmd.linno;
n3->nbinary.ch1 = n1;
n3->nbinary.ch2 = n2;
n1 = n3;
@@ -269,6 +270,7 @@ pipeline(void)
if (readtoken() == TPIPE) {
pipenode = (union node *)stalloc(sizeof (struct npipe));
pipenode->type = NPIPE;
+ pipenode->npipe.linno = n1->ncmd.linno;
pipenode->npipe.backgnd = 0;
lp = (struct nodelist *)stalloc(sizeof (struct nodelist));
pipenode->npipe.cmdlist = lp;
@@ -315,6 +317,7 @@ command(void)
case TIF:
n1 = (union node *)stalloc(sizeof (struct nif));
n1->type = NIF;
+ n1->nif.linno = plinno;
n1->nif.test = list(0);
if (readtoken() != TTHEN)
synexpect(TTHEN);
@@ -324,6 +327,7 @@ command(void)
n2->nif.elsepart = (union node *)stalloc(sizeof (struct nif));
n2 = n2->nif.elsepart;
n2->type = NIF;
+ n2->nif.linno = plinno;
n2->nif.test = list(0);
if (readtoken() != TTHEN)
synexpect(TTHEN);
@@ -342,6 +346,7 @@ command(void)
int got;
n1 = (union node *)stalloc(sizeof (struct nbinary));
n1->type = (lasttoken == TWHILE)? NWHILE : NUNTIL;
+ n1->nbinary.linno = plinno;
n1->nbinary.ch1 = list(0);
if ((got=readtoken()) != TDO) {
TRACE(("expecting DO got %s %s\n", tokname[got], got == TWORD ? wordtext : ""));
@@ -356,6 +361,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 = plinno;
n1->nfor.var = wordtext;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
if (readtoken() == TIN) {
@@ -395,6 +401,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 = plinno;
if (readtoken() != TWORD)
synexpect(TWORD);
n1->ncase.expr = n2 = (union node *)stalloc(sizeof (struct narg));
@@ -445,6 +452,7 @@ next_case:
case TLP:
n1 = (union node *)stalloc(sizeof (struct nredir));
n1->type = NSUBSHELL;
+ n1->nredir.linno = plinno;
n1->nredir.n = list(0);
n1->nredir.redirect = NULL;
t = TRP;
@@ -477,6 +485,7 @@ redir:
if (n1->type != NSUBSHELL) {
n2 = (union node *)stalloc(sizeof (struct nredir));
n2->type = NREDIR;
+ n2->nredir.linno = plinno;
n2->nredir.n = n1;
n1 = n2;
}
@@ -494,6 +503,7 @@ simplecmd(void) {
union node *vars, **vpp;
union node **rpp, *redir;
int savecheckkwd;
+ int savelinno = plinno;
args = NULL;
app = &args;
@@ -531,7 +541,7 @@ simplecmd(void) {
!vars && !redir
) {
struct builtincmd *bcmd;
- const char *name;
+ char *name;
/* We have a function */
if (readtoken() != TRP)
@@ -546,7 +556,9 @@ simplecmd(void) {
synerror("Bad function name");
n->type = NDEFUN;
checkkwd = CHKNL | CHKKWD | CHKALIAS;
- n->narg.next = command();
+ n->ndefun.linno = plinno;
+ n->ndefun.text = name;
+ n->ndefun.body = command();
return n;
}
/* fall through */
@@ -561,6 +573,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 +751,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 +774,6 @@ xxreadtoken(void)
if (needprompt) {
setprompt(2);
}
- startlinno = plinno;
for (;;) { /* until token or start of word found */
c = pgetc_macro();
switch (c) {
@@ -776,7 +786,7 @@ xxreadtoken(void)
continue;
case '\\':
if (pgetc() == '\n') {
- startlinno = lineno_inc();
+ plinno++;
if (doprompt)
setprompt(2);
continue;
@@ -784,7 +794,7 @@ xxreadtoken(void)
pungetc();
goto breakloop;
case '\n':
- lineno_inc();
+ plinno++;
needprompt = doprompt;
RETURN(TNL);
case PEOF:
@@ -855,7 +865,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 +895,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 +916,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 +1018,6 @@ endword:
if (syntax != BASESYNTAX && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
- startlinno = plinno;
/* { */
synerror("Missing '}'");
}
@@ -1065,7 +1074,7 @@ checkend: {
if (c == '\n' || c == PEOF) {
c = PEOF;
- lineno_inc();
+ plinno++;
needprompt = doprompt;
} else {
int len;
@@ -1315,7 +1324,7 @@ parsebackq: {
case '\\':
if ((pc = pgetc()) == '\n') {
- lineno_inc();
+ plinno++;
if (doprompt)
setprompt(2);
/*
@@ -1336,11 +1345,10 @@ parsebackq: {
case PEOF:
case PEOA:
- startlinno = plinno;
synerror("EOF in backquote substitution");
case '\n':
- lineno_inc();
+ plinno++;
needprompt = doprompt;
break;
@@ -1472,6 +1480,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 25c2216..6be9ab4 100644
--- a/src/var.c
+++ b/src/var.c
@@ -99,7 +99,6 @@ struct var varinit[] = {
{ 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];
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-08 20:33 [PATCH] Improved LINENO support Harald van Dijk
@ 2010-11-10 22:00 ` Jilles Tjoelker
2010-11-11 20:33 ` Harald van Dijk
2010-11-12 18:17 ` Harald van Dijk
0 siblings, 2 replies; 12+ messages in thread
From: Jilles Tjoelker @ 2010-11-10 22:00 UTC (permalink / raw)
To: Harald van Dijk; +Cc: dash
On Mon, Nov 08, 2010 at 09:32:56PM +0059, Harald van Dijk wrote:
> This patch improves LINENO support by storing line numbers in the parse
> tree, for commands as well as for function definitions. It makes LINENO
> behaves properly when calling functions, and has the added benefit of
> improved line numbers in error messages when the last-parsed command is
> not the last-executed one. It removes the earlier LINENO support, and
> instead sets LINENO from evaltree when a command is executed. I have
> used it for a while, and have seen correct line numbers in basic testing
> and in error messages in fairly large and complicated autoconf-generated
> shell scripts. Does this look good enough to add to dash? If there are
> any problems with it, please let me know, I will be happy to look at
> this further.
What I was thinking of was adding a lineno field to narg instead of to
all command types. The lineno variable would then be set by expand.c. I
think that leads to a smaller patch and it should still give a sensible
value for almost all errors. Downside is a few more int-to-ascii
conversions. A few divisions is not that bad relative to other things
that are done but printf in modern libcs is bloated and slow and might
slow down things measurably.
FreeBSD's code subtracts the function's starting line number in the
parser rather than at run time. I wonder which is best. (FreeBSD
neglects to save and restore the value, so nested function definitions
may lead to incorrect line numbers, but that could be fixed.)
I think this patch will increase dash's code size at least a little,
which is always a consideration here. I can also look at getting this
into FreeBSD sh.
Thanks,
--
Jilles Tjoelker
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-10 22:00 ` Jilles Tjoelker
@ 2010-11-11 20:33 ` Harald van Dijk
2010-11-12 18:17 ` Harald van Dijk
1 sibling, 0 replies; 12+ messages in thread
From: Harald van Dijk @ 2010-11-11 20:33 UTC (permalink / raw)
To: dash; +Cc: Jilles Tjoelker
On 10/11/10 22:59, Jilles Tjoelker wrote:
> What I was thinking of was adding a lineno field to narg instead of to
> all command types. The lineno variable would then be set by expand.c. I
> think that leads to a smaller patch and it should still give a sensible
> value for almost all errors. Downside is a few more int-to-ascii
> conversions. A few divisions is not that bad relative to other things
> that are done but printf in modern libcs is bloated and slow and might
> slow down things measurably.
I made an attempt at this, but managed to keep the printing in one place
by making LINENO a special variable, which is stored in an int and set
in expandarg. When $LINENO is evaluated, the code checks to see if the
variable is LINENO, and if so, converts the value to a string. This is
one simple pointer comparison in the common case in lookupvar:
if (v == &vlineno && v->text == linenovar)
and avoids sprintf in scripts that don't use LINENO.
> FreeBSD's code subtracts the function's starting line number in the
> parser rather than at run time. I wonder which is best. (FreeBSD
> neglects to save and restore the value, so nested function definitions
> may lead to incorrect line numbers, but that could be fixed.)
I used this approach in my updated patch, by resetting plinno to 0 in
simplecmd, and restoring it after calling command().
> I think this patch will increase dash's code size at least a little,
> which is always a consideration here.
The code size varies little: the current limited LINENO support gives an
executable size of 67680 bytes (default configure settings, no libedit,
gcc 4.5.1, CFLAGS=-Os, strip after compilation), my previous patch gives
67688 bytes, my latest patch gives 67704 bytes. I do not think 24 bytes
should be a problem.
> I can also look at getting this
> into FreeBSD sh.
That would be great.
I will send the updated patch when I can properly test it. Basic testing
shows it works, but more extensive testing fails. As it turns out, this
is unrelated to my changes: current git, unmodified, has a problem:
$ cat test.sh
echo
cat <<_ACEOF
$0 $@
_ACEOF
echo
$ src/dash test.sh wtf
test.sh wtf
�����
$
I had not noticed it with my earlier patch, because I actually did my
testing with modified 0.5.6.1 sources.
Thanks for the comments.
Cheers,
Harald
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-10 22:00 ` Jilles Tjoelker
2010-11-11 20:33 ` Harald van Dijk
@ 2010-11-12 18:17 ` Harald van Dijk
2010-11-12 18:35 ` Eric Blake
1 sibling, 1 reply; 12+ messages in thread
From: Harald van Dijk @ 2010-11-12 18:17 UTC (permalink / raw)
To: dash; +Cc: Jilles Tjoelker
On 10/11/10 22:59, Jilles Tjoelker wrote:
> What I was thinking of was adding a lineno field to narg instead of to
> all command types. The lineno variable would then be set by expand.c. I
> think that leads to a smaller patch and it should still give a sensible
> value for almost all errors.
Unfortunately, I do not believe this will work. In
echo $LINENO \
$LINENO
two identical numbers must be printed, because LINENO is supposed to be
set when a command is executed. It is not supposed to change during the
execution of the command. Taking the first word of a command also will
not work:
(
:
:
:
:
:
) >test-$LINENO
should write to file test-1, not test-7, even though the only word is on
line 7. bash gets this wrong, pdksh gets this almost right.
If I am missing an obvious way to address these issues, or if I am
missing some part of the standard that clarifies why these issues do not
exist, please share, but otherwise I will take the rest of your
suggestions and rework my first patch, storing the line number for each
command.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-12 18:17 ` Harald van Dijk
@ 2010-11-12 18:35 ` Eric Blake
2010-11-12 19:08 ` Harald van Dijk
0 siblings, 1 reply; 12+ messages in thread
From: Eric Blake @ 2010-11-12 18:35 UTC (permalink / raw)
To: Harald van Dijk; +Cc: dash, Jilles Tjoelker
[-- Attachment #1: Type: text/plain, Size: 1202 bytes --]
On 11/12/2010 11:17 AM, Harald van Dijk wrote:
> (
> :
> :
> :
> :
> :
> ) >test-$LINENO
>
> should write to file test-1, not test-7, even though the only word is on
> line 7. bash gets this wrong, pdksh gets this almost right.
Umm - there was more than one word in that example (each : in the
subshell is a word). But I agree that the subshell command itself
started on line 1, but the word containing $LINENO is on line 7.
There are _so many_ variations on what this example would do that it's
hard to say that any one version is definitively correct. In general,
the standard tends to favor the ksh93 interpretation of things; but on
your example, it touches the file test-6 (not test-7 nor test-1).
All I can see in the standard is:
"Set by the shell to a decimal number representing the current
sequential line number (numbered starting with 1) within a script or
function before it executes each command."
with no hint as to whether LINENO auto-increments over the number of
newlines encountered while parsing that command.
--
Eric Blake eblake@redhat.com +1-801-349-2682
Libvirt virtualization library http://libvirt.org
[-- Attachment #2: OpenPGP digital signature --]
[-- Type: application/pgp-signature, Size: 619 bytes --]
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-12 18:35 ` Eric Blake
@ 2010-11-12 19:08 ` Harald van Dijk
2010-11-12 19:40 ` Harald van Dijk
2010-11-12 21:29 ` Jilles Tjoelker
0 siblings, 2 replies; 12+ messages in thread
From: Harald van Dijk @ 2010-11-12 19:08 UTC (permalink / raw)
To: dash; +Cc: Eric Blake, Jilles Tjoelker
On 12/11/10 19:35, Eric Blake wrote:
> On 11/12/2010 11:17 AM, Harald van Dijk wrote:
>> (
>> :
>> :
>> :
>> :
>> :
>> )>test-$LINENO
>>
>> should write to file test-1, not test-7, even though the only word is on
>> line 7. bash gets this wrong, pdksh gets this almost right.
>
> Umm - there was more than one word in that example (each : in the
> subshell is a word). But I agree that the subshell command itself
> started on line 1, but the word containing $LINENO is on line 7.
That was because it was a poor example. I meant to use comments, but
forgot to change this before posting. I haven't checked if they count as
words in SUS, but they don't in the dash source code.
> There are _so many_ variations on what this example would do that it's
> hard to say that any one version is definitively correct. In general,
> the standard tends to favor the ksh93 interpretation of things; but on
> your example, it touches the file test-6 (not test-7 nor test-1).
>
> All I can see in the standard is:
>
> "Set by the shell to a decimal number representing the current
> sequential line number (numbered starting with 1) within a script or
> function before it executes each command."
>
> with no hint as to whether LINENO auto-increments over the number of
> newlines encountered while parsing that command.
You may be right. SUS doesn't really specify whether "current" refers to
the first or the last line number of a command. test-1 and test-7 are
equally defensible, so I was too quick to say that bash gets this wrong.
I hope you agree, though, that test-6 is iffy, and for my other example:
echo $LINENO \
$LINENO
two identical numbers must be printed. SUS only requires and only allows
LINENO to be set before a command is executed, so once it is set, it is
set for both expansions. Given that,
(
#
#
#
#
#
)>test-$LINENO \
>>test2-$LINENO
must not write to test-7 and test2-8. It may write to test-1 and
test2-1, or it may write to test-8 and test2-8. Perhaps even to test-7
and test2-7. Again, though, LINENO must be the same in both expansions.
So for dash, the problem doesn't change: storing the line number of each
word, rather than each command, makes it very hard to get LINENO right.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-12 19:08 ` Harald van Dijk
@ 2010-11-12 19:40 ` Harald van Dijk
2010-11-12 21:29 ` Jilles Tjoelker
1 sibling, 0 replies; 12+ messages in thread
From: Harald van Dijk @ 2010-11-12 19:40 UTC (permalink / raw)
To: dash; +Cc: Eric Blake, Jilles Tjoelker
On 12/11/10 20:08, Harald van Dijk wrote:
> On 12/11/10 19:35, Eric Blake wrote:
>> On 11/12/2010 11:17 AM, Harald van Dijk wrote:
>>> (
>>> :
>>> :
>>> :
>>> :
>>> :
>>> )>test-$LINENO
>>>
>> Umm - there was more than one word in that example (each : in the
>> subshell is a word)
>
> That was because it was a poor example. I meant to use comments,
...which don't work, because a command is required between ( and ).
Never mind that part.
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-12 19:08 ` Harald van Dijk
2010-11-12 19:40 ` Harald van Dijk
@ 2010-11-12 21:29 ` Jilles Tjoelker
2010-11-27 16:56 ` Harald van Dijk
1 sibling, 1 reply; 12+ messages in thread
From: Jilles Tjoelker @ 2010-11-12 21:29 UTC (permalink / raw)
To: Harald van Dijk; +Cc: dash, Eric Blake
On Fri, Nov 12, 2010 at 08:07:41PM +0059, Harald van Dijk wrote:
> must not write to test-7 and test2-8. It may write to test-1 and
> test2-1, or it may write to test-8 and test2-8. Perhaps even to test-7
> and test2-7. Again, though, LINENO must be the same in both expansions.
> So for dash, the problem doesn't change: storing the line number of each
> word, rather than each command, makes it very hard to get LINENO right.
Hmm, I hadn't thought of that. I considered a LINENO that points to the
affected word most useful and easiest to implement (also because FreeBSD
sh's LINENO works this way).
So some more ideas:
A per-command LINENO does not require adding the number to all of the
node types. Only node types that are commands that perform expansions
need it: NCMD, NREDIR, NBACKGND, NSUBSHELL, NFOR, NCASE.
NFOR and NCASE may be wrapped in an NREDIR node to hold the line number.
This simplifies the code a bit at the cost of some extra memory usage.
A further simplification might be removing the redirect field from
NBACKGND and NSUBSHELL and putting any redirect in an additional NREDIR
node inside the NBACKGND/NSUBSHELL (so that the file is opened in the
child process and job control works correctly). However, NREDIR,
NBACKGND and NSUBSHELL are compatible types so it does not seem to gain
much.
What about making the lineno an element of the redirection list like
NTO? This minimizes changes to eval.c but perhaps it is too contrived.
Second idea: use a per-word LINENO but somehow ensure it is the same for
all words in a command. I think this is wrong, but perhaps I'm wrong.
--
Jilles Tjoelker
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-12 21:29 ` Jilles Tjoelker
@ 2010-11-27 16:56 ` Harald van Dijk
2011-03-10 8:10 ` Herbert Xu
0 siblings, 1 reply; 12+ messages in thread
From: Harald van Dijk @ 2010-11-27 16:56 UTC (permalink / raw)
To: dash; +Cc: Jilles Tjoelker
[-- Attachment #1: Type: text/plain, Size: 1090 bytes --]
On 12/11/10 22:29, Jilles Tjoelker wrote:
> So some more ideas:
>
> A per-command LINENO does not require adding the number to all of the
> node types. Only node types that are commands that perform expansions
> need it: NCMD, NREDIR, NBACKGND, NSUBSHELL, NFOR, NCASE.
This makes sense, and I've tried this with good results. I added NDEFUN
to the list, to get the source to function line number mapping correct.
I noticed when wrapping half-parsed commands in an NREDIR, I got the
line number wrong (not necessarily nonconforming, but different from
what I had intended). I changed it in this patch by saving the line
number in a variable before starting the parsing of the command.
> NFOR and NCASE may be wrapped in an NREDIR node to hold the line number.
> This simplifies the code a bit at the cost of some extra memory usage.
That's possible. I have not used that idea in this patch, but it should
be an easy change.
Your other suggestions would work, but I am not able to say whether they
form an improvement, so I did not use those for now.
Again, comments are welcome.
[-- Attachment #2: dash-improved-lineno-3.diff --]
[-- Type: text/plain, Size: 15873 bytes --]
diff --git a/src/error.c b/src/error.c
index e304d3d..e60e430 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 3162e15..08f96e9 100644
--- a/src/error.h
+++ b/src/error.h
@@ -122,6 +122,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 b966749..d85f66f 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);
@@ -296,7 +299,7 @@ calleval:
}
goto success;
case NDEFUN:
- defun(n->narg.text, n->narg.next);
+ defun(n);
success:
status = 0;
setstatus:
@@ -370,6 +373,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) {
@@ -411,6 +418,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);
@@ -442,6 +453,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;
@@ -697,6 +712,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);
@@ -730,7 +749,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;
@@ -928,8 +947,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;
}
@@ -938,18 +959,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, flags & EV_TESTED);
+ evaltree(func->n.ndefun.body, flags & EV_TESTED);
poplocalvars(0);
funcdone:
INTOFF;
- funcnest--;
+ funcline = savefuncline;
freefunc(func);
freeparam(&shellparam);
shellparam = saveparam;
@@ -1039,7 +1060,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 42299ea..959b9f4 100644
--- a/src/exec.c
+++ b/src/exec.c
@@ -688,14 +688,14 @@ addcmdentry(char *name, struct cmdentry *entry)
*/
void
-defun(char *name, union node *func)
+defun(union node *func)
{
struct cmdentry entry;
INTOFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
- addcmdentry(name, &entry);
+ addcmdentry(func->ndefun.text, &entry);
INTON;
}
diff --git a/src/exec.h b/src/exec.h
index daa6f10..9ccb305 100644
--- a/src/exec.h
+++ b/src/exec.h
@@ -71,7 +71,7 @@ void changepath(const char *);
#ifdef notdef
void getcmdentry(char *, struct cmdentry *);
#endif
-void defun(char *, union node *);
+void defun(union node *);
void unsetfunc(const char *);
int typecmd(int, char **);
int commandcmd(int, char **);
diff --git a/src/input.c b/src/input.c
index e57ad76..1e198e9 100644
--- a/src/input.c
+++ b/src/input.c
@@ -53,7 +53,6 @@
#include "alias.h"
#include "parser.h"
#include "main.h"
-#include "var.h"
#ifndef SMALL
#include "myhistedit.h"
#endif
@@ -529,12 +528,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 826a9af..3d7ce93 100644
--- a/src/jobs.c
+++ b/src/jobs.c
@@ -1284,7 +1284,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..f7a2873 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)
@@ -102,9 +106,11 @@ NCLIST nclist # a case
pattern nodeptr # list of patterns for this 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..2f839f5 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()) {
@@ -531,7 +539,7 @@ simplecmd(void) {
!vars && !redir
) {
struct builtincmd *bcmd;
- const char *name;
+ char *name;
/* We have a function */
if (readtoken() != TRP)
@@ -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 25c2216..7e05e3d 100644
--- a/src/var.c
+++ b/src/var.c
@@ -33,6 +33,7 @@
*/
#include <unistd.h>
+#include <stdio.h>
#include <stdlib.h>
#include <paths.h>
@@ -78,6 +79,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
@@ -95,11 +99,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];
@@ -329,6 +333,9 @@ lookupvar(const char *name)
struct var *v;
if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
+ if (v == &vlineno && v->text == linenovar) {
+ sprintf(linenoval(), "%d", lineno);
+ }
return strchrnul(v->text, '=') + 1;
}
return NULL;
diff --git a/src/var.h b/src/var.h
index 7aa051f..3d2c2cb 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)
^ permalink raw reply related [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2010-11-27 16:56 ` Harald van Dijk
@ 2011-03-10 8:10 ` Herbert Xu
2011-03-11 21:56 ` Harald van Dijk
0 siblings, 1 reply; 12+ messages in thread
From: Herbert Xu @ 2011-03-10 8:10 UTC (permalink / raw)
To: Harald van Dijk; +Cc: dash, Jilles Tjoelker
On Sat, Nov 27, 2010 at 04:56:17PM +0000, Harald van Dijk wrote:
>
> Again, comments are welcome.
Thanks for working on this! Just a few minor problems to correct.
Oh and please add a changelog + sign-off.
> diff --git a/src/eval.c b/src/eval.c
> index b966749..d85f66f 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 */
Please don't add any new uses of STATIC. I'm fine with leaving
existing ones in place though.
> @@ -730,7 +749,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];
I like this bit :)
> diff --git a/src/exec.c b/src/exec.c
> index 42299ea..959b9f4 100644
> --- a/src/exec.c
> +++ b/src/exec.c
> @@ -688,14 +688,14 @@ addcmdentry(char *name, struct cmdentry *entry)
> */
>
> void
> -defun(char *name, union node *func)
> +defun(union node *func)
> {
> struct cmdentry entry;
>
> INTOFF;
> entry.cmdtype = CMDFUNCTION;
> entry.u.func = copyfunc(func);
> - addcmdentry(name, &entry);
> + addcmdentry(func->ndefun.text, &entry);
> INTON;
> }
Please separate out unrelated changes like this into distinct
patches.
> @@ -329,6 +333,9 @@ lookupvar(const char *name)
> struct var *v;
>
> if ((v = *findvar(hashvar(name), name)) && !(v->flags & VUNSET)) {
> + if (v == &vlineno && v->text == linenovar) {
> + sprintf(linenoval(), "%d", lineno);
> + }
Please use fmtstr instead of sprintf for consistency.
Cheers,
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2011-03-10 8:10 ` Herbert Xu
@ 2011-03-11 21:56 ` Harald van Dijk
2011-03-15 7:52 ` Herbert Xu
0 siblings, 1 reply; 12+ messages in thread
From: Harald van Dijk @ 2011-03-11 21:56 UTC (permalink / raw)
To: dash; +Cc: Jilles Tjoelker
[-- Attachment #1: Type: text/plain, Size: 1003 bytes --]
On Thu, 2011-03-10 at 16:10 +0800, Herbert Xu wrote:
> On Sat, Nov 27, 2010 at 04:56:17PM +0000, Harald van Dijk wrote:
> >
> > Again, comments are welcome.
>
> Thanks for working on this! Just a few minor problems to correct.
> Oh and please add a changelog + sign-off.
Done.
> Please don't add any new uses of STATIC. I'm fine with leaving
> existing ones in place though.
Changed to static.
> I like this bit :)
Thanks :)
> Please separate out unrelated changes like this into distinct
> patches.
It is not unrelated: I changed the meaning of struct funcnode's field n
to refer to the function definition, rather than the list of the
function's commands, because I needed to refer to the function
definition node from evalfun, which only gets passed a funcnode. But it
is something that could be applied independently (without being useful
by itself), so I've attached it as a separate patch for easier review.
> Please use fmtstr instead of sprintf for consistency.
Done.
Cheers,
Harald
[-- Attachment #2: dash-funcnode.patch --]
[-- Type: text/x-patch, Size: 1592 bytes --]
Signed-off-by: Harald van Dijk <harald@gigawatt.nl>
diff --git a/ChangeLog b/ChangeLog
--- a/ChangeLog
+++ b/ChangeLog
@@ -1,3 +1,7 @@
+2011-03-11 Harald van Dijk <harald@gigawatt.nl>
+
+ * Let funcnode refer to a function definition, not its first command.
+
2011-03-10 Jonathan Nieder <jrnieder@gmail.com>
* Dotcmd should exit with zero when doing nothing.
diff --git a/src/eval.c b/src/eval.c
--- a/src/eval.c
+++ b/src/eval.c
@@ -296,7 +296,7 @@ calleval:
}
goto success;
case NDEFUN:
- defun(n->narg.text, n->narg.next);
+ defun(n);
success:
status = 0;
setstatus:
@@ -954,7 +954,7 @@ evalfun(struct funcnode *func, int argc,
shellparam.optind = 1;
shellparam.optoff = -1;
pushlocalvars();
- evaltree(&func->n, flags & EV_TESTED);
+ evaltree(func->n.narg.next, flags & EV_TESTED);
poplocalvars(0);
funcdone:
INTOFF;
diff --git a/src/exec.c b/src/exec.c
--- a/src/exec.c
+++ b/src/exec.c
@@ -688,14 +688,14 @@ addcmdentry(char *name, struct cmdentry
*/
void
-defun(char *name, union node *func)
+defun(union node *func)
{
struct cmdentry entry;
INTOFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
- addcmdentry(name, &entry);
+ addcmdentry(func->narg.text, &entry);
INTON;
}
diff --git a/src/exec.h b/src/exec.h
--- a/src/exec.h
+++ b/src/exec.h
@@ -71,7 +71,7 @@ void changepath(const char *);
#ifdef notdef
void getcmdentry(char *, struct cmdentry *);
#endif
-void defun(char *, union node *);
+void defun(union node *);
void unsetfunc(const char *);
int typecmd(int, char **);
int commandcmd(int, char **);
[-- Attachment #3: dash-lineno-4.patch --]
[-- Type: text/x-patch, Size: 14213 bytes --]
Signed-off-by: Harald van Dijk <harald@gigawatt.nl>
diff -r 772aea7ed8c5 ChangeLog
--- a/ChangeLog Fri Mar 11 22:39:28 2011 +0100
+++ b/ChangeLog Fri Mar 11 22:45:57 2011 +0100
@@ -1,3 +1,7 @@
+2011-03-11 Harald van Dijk <harald@gigawatt.nl>
+
+ * Improve LINENO support.
+
2011-03-11 Harald van Dijk <harald@gigawatt.nl>
* Let funcnode refer to a function definition, not its first command.
diff -r 772aea7ed8c5 src/error.c
--- a/src/error.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/error.c Fri Mar 11 22:45:57 2011 +0100
@@ -62,6 +62,7 @@
int exception;
int suppressint;
volatile sig_atomic_t intpending;
+int errlinno;
static void exverror(int, const char *, va_list)
@@ -116,13 +117,12 @@
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 -r 772aea7ed8c5 src/error.h
--- a/src/error.h Fri Mar 11 22:39:28 2011 +0100
+++ b/src/error.h Fri Mar 11 22:45:57 2011 +0100
@@ -120,6 +120,7 @@
#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 -r 772aea7ed8c5 src/eval.c
--- a/src/eval.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/eval.c Fri Mar 11 22:45:57 2011 +0100
@@ -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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
*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 @@
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 @@
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 @@
* 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 -r 772aea7ed8c5 src/exec.c
--- a/src/exec.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/exec.c Fri Mar 11 22:45:57 2011 +0100
@@ -695,7 +695,7 @@
INTOFF;
entry.cmdtype = CMDFUNCTION;
entry.u.func = copyfunc(func);
- addcmdentry(func->narg.text, &entry);
+ addcmdentry(func->ndefun.text, &entry);
INTON;
}
diff -r 772aea7ed8c5 src/input.c
--- a/src/input.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/input.c Fri Mar 11 22:45:57 2011 +0100
@@ -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 @@
parsefile->fd = 0;
}
}
-
-
-int lineno_inc(void)
-{
- int lineno = plinno++;
-
- setvarint("LINENO", lineno, 0);
- return lineno;
-}
diff -r 772aea7ed8c5 src/input.h
--- a/src/input.h Fri Mar 11 22:39:28 2011 +0100
+++ b/src/input.h Fri Mar 11 22:45:57 2011 +0100
@@ -61,7 +61,6 @@
void popfile(void);
void popallfiles(void);
void closescript(void);
-int lineno_inc(void);
#define pgetc_macro() \
(--parsenleft >= 0 ? (signed char)*parsenextc++ : preadbuffer())
diff -r 772aea7ed8c5 src/jobs.c
--- a/src/jobs.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/jobs.c Fri Mar 11 22:45:57 2011 +0100
@@ -1286,7 +1286,7 @@
p = "; done";
goto dodo;
case NDEFUN:
- cmdputs(n->narg.text);
+ cmdputs(n->ndefun.text);
p = "() { ... }";
goto dotail2;
case NCMD:
diff -r 772aea7ed8c5 src/nodetypes
--- a/src/nodetypes Fri Mar 11 22:39:28 2011 +0100
+++ b/src/nodetypes Fri Mar 11 22:45:57 2011 +0100
@@ -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 @@
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 @@
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 @@
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 -r 772aea7ed8c5 src/parser.c
--- a/src/parser.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/parser.c Fri Mar 11 22:45:57 2011 +0100
@@ -93,7 +93,6 @@
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 @@
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 @@
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 @@
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 @@
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 @@
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 @@
union node *vars, **vpp;
union node **rpp, *redir;
int savecheckkwd;
+ int savelinno;
args = NULL;
app = &args;
@@ -503,6 +510,7 @@
rpp = &redir;
savecheckkwd = CHKALIAS;
+ savelinno = plinno;
for (;;) {
checkkwd = savecheckkwd;
switch (readtoken()) {
@@ -546,7 +554,9 @@
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 @@
*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 @@
* 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 @@
if (needprompt) {
setprompt(2);
}
- startlinno = plinno;
for (;;) { /* until token or start of word found */
c = pgetc_macro();
switch (c) {
@@ -776,7 +784,7 @@
continue;
case '\\':
if (pgetc() == '\n') {
- startlinno = lineno_inc();
+ plinno++;
if (doprompt)
setprompt(2);
continue;
@@ -784,7 +792,7 @@
pungetc();
goto breakloop;
case '\n':
- lineno_inc();
+ plinno++;
needprompt = doprompt;
RETURN(TNL);
case PEOF:
@@ -855,7 +863,6 @@
/* syntax before arithmetic */
char const *uninitialized_var(prevsyntax);
- startlinno = plinno;
dblquote = 0;
if (syntax == DQSYNTAX)
dblquote = 1;
@@ -886,7 +893,7 @@
if (syntax == BASESYNTAX)
goto endword; /* exit outer loop */
USTPUTC(c, out);
- lineno_inc();
+ plinno++;
if (doprompt)
setprompt(2);
c = pgetc();
@@ -907,6 +914,7 @@
USTPUTC('\\', out);
pungetc();
} else if (c == '\n') {
+ plinno++;
if (doprompt)
setprompt(2);
} else {
@@ -1008,7 +1016,6 @@
if (syntax != BASESYNTAX && eofmark == NULL)
synerror("Unterminated quoted string");
if (varnest != 0) {
- startlinno = plinno;
/* { */
synerror("Missing '}'");
}
@@ -1065,7 +1072,7 @@
if (c == '\n' || c == PEOF) {
c = PEOF;
- lineno_inc();
+ plinno++;
needprompt = doprompt;
} else {
int len;
@@ -1315,7 +1322,7 @@
case '\\':
if ((pc = pgetc()) == '\n') {
- lineno_inc();
+ plinno++;
if (doprompt)
setprompt(2);
/*
@@ -1336,11 +1343,10 @@
case PEOF:
case PEOA:
- startlinno = plinno;
synerror("EOF in backquote substitution");
case '\n':
- lineno_inc();
+ plinno++;
needprompt = doprompt;
break;
@@ -1472,6 +1478,7 @@
STATIC void
synerror(const char *msg)
{
+ errlinno = plinno;
sh_error("Syntax error: %s", msg);
/* NOTREACHED */
}
diff -r 772aea7ed8c5 src/parser.h
--- a/src/parser.h Fri Mar 11 22:39:28 2011 +0100
+++ b/src/parser.h Fri Mar 11 22:45:57 2011 +0100
@@ -77,7 +77,6 @@
#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 -r 772aea7ed8c5 src/var.c
--- a/src/var.c Fri Mar 11 22:39:28 2011 +0100
+++ b/src/var.c Fri Mar 11 22:45:57 2011 +0100
@@ -33,6 +33,7 @@
*/
#include <unistd.h>
+#include <stdio.h>
#include <stdlib.h>
#include <paths.h>
@@ -78,6 +79,9 @@
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
@@ -95,11 +99,11 @@
{ 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];
@@ -329,6 +333,9 @@
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 -r 772aea7ed8c5 src/var.h
--- a/src/var.h Fri Mar 11 22:39:28 2011 +0100
+++ b/src/var.h Fri Mar 11 22:45:57 2011 +0100
@@ -88,8 +88,9 @@
#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 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 @@
#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)
^ permalink raw reply [flat|nested] 12+ messages in thread
* Re: [PATCH] Improved LINENO support
2011-03-11 21:56 ` Harald van Dijk
@ 2011-03-15 7:52 ` Herbert Xu
0 siblings, 0 replies; 12+ messages in thread
From: Herbert Xu @ 2011-03-15 7:52 UTC (permalink / raw)
To: Harald van Dijk; +Cc: dash, Jilles Tjoelker
On Fri, Mar 11, 2011 at 09:56:49PM +0000, Harald van Dijk wrote:
>
> Signed-off-by: Harald van Dijk <harald@gigawatt.nl>
Both patches applied. Thanks a lot!
--
Email: Herbert Xu <herbert@gondor.apana.org.au>
Home Page: http://gondor.apana.org.au/~herbert/
PGP Key: http://gondor.apana.org.au/~herbert/pubkey.txt
^ permalink raw reply [flat|nested] 12+ messages in thread
end of thread, other threads:[~2011-03-15 7:52 UTC | newest]
Thread overview: 12+ messages (download: mbox.gz follow: Atom feed
-- links below jump to the message on this page --
2010-11-08 20:33 [PATCH] Improved LINENO support Harald van Dijk
2010-11-10 22:00 ` Jilles Tjoelker
2010-11-11 20:33 ` Harald van Dijk
2010-11-12 18:17 ` Harald van Dijk
2010-11-12 18:35 ` Eric Blake
2010-11-12 19:08 ` Harald van Dijk
2010-11-12 19:40 ` Harald van Dijk
2010-11-12 21:29 ` Jilles Tjoelker
2010-11-27 16:56 ` Harald van Dijk
2011-03-10 8:10 ` Herbert Xu
2011-03-11 21:56 ` Harald van Dijk
2011-03-15 7:52 ` Herbert Xu
This is an external index of several public inboxes,
see mirroring instructions on how to clone and mirror
all data and code used by this external index.