From 7498ade3b6f7198c2f3cfe6e9522a5b14510a07a Mon Sep 17 00:00:00 2001 From: Stathis Kamperis Date: Tue, 21 Jul 2009 14:00:56 +0300 Subject: [PATCH] sh(1): Expand $LINENO to the current line number. This is required by SUSv3's "User Portability Utilities" option. Obtained-from: FreeBSD (SVN Revision 179022 by stefanf@) --- bin/sh/expand.c | 9 ++++++++- bin/sh/parser.c | 25 ++++++++++++++++++++++--- bin/sh/parser.h | 8 +++++--- 3 files changed, 35 insertions(+), 7 deletions(-) diff --git a/bin/sh/expand.c b/bin/sh/expand.c index a397528..1163314 100644 --- a/bin/sh/expand.c +++ b/bin/sh/expand.c @@ -636,7 +636,13 @@ evalvar(char *p, int flag) special = 1; p = strchr(p, '=') + 1; again: /* jump here after setting a variable with ${var=text} */ - if (special) { + if (varflags & VSLINENO) { + set = 1; + special = 0; + val = var; + p[-1] = '\0'; /* temporarily overwrite '=' to have \0 + terminated string */ + } else if (special) { set = varisset(var, varflags & VSNUL); val = NULL; } else { @@ -766,6 +772,7 @@ record: default: abort(); } + p[-1] = '='; /* recover overwritten '=' */ if (subtype != VSNORMAL) { /* skip to end of alternative */ int nesting = 1; diff --git a/bin/sh/parser.c b/bin/sh/parser.c index 6648bf2..bbe18ce 100644 --- a/bin/sh/parser.c +++ b/bin/sh/parser.c @@ -99,6 +99,7 @@ STATIC union node *redirnode; STATIC struct heredoc *heredoc; STATIC int quoteflag; /* set if (part of) last token was quoted */ STATIC int startlinno; /* line # where last token started */ +STATIC int funclinno; /* line # where the current function started */ /* XXX When 'noaliases' is set to one, no alias expansion takes place. */ static int noaliases = 0; @@ -566,12 +567,14 @@ simplecmd(union node **rpp, union node *redir) /* We have a function */ if (readtoken() != TRP) synexpect(TRP); + funclinno = plinno; #ifdef notdef if (! goodname(n->narg.text)) synerror("Bad function name"); #endif n->type = NDEFUN; n->narg.next = command(); + funclinno = 0; return n; } else { tokpushback++; @@ -1159,12 +1162,15 @@ parseredir: { */ parsesub: { + char buf[10]; int subtype; int typeloc; int flags; char *p; static const char types[] = "}-+?="; - int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ + int bracketed_name = 0; /* used to handle ${[0-9]*} variables */ + int i; + int linno; c = pgetc(); if (c != '(' && c != '{' && (is_eof(c) || !is_name(c)) && @@ -1183,6 +1189,7 @@ parsesub: { typeloc = out - stackblock(); USTPUTC(VSNORMAL, out); subtype = VSNORMAL; + flags = 0; if (c == '{') { bracketed_name = 1; c = pgetc(); @@ -1196,10 +1203,23 @@ parsesub: { subtype = 0; } if (!is_eof(c) && is_name(c)) { + p = out; do { STPUTC(c, out); c = pgetc(); } while (!is_eof(c) && is_in_name(c)); + if (out - p == 6 && strncmp(p, "LINENO", 6) == 0) { + /* Replace the variable name with the + * current line number. */ + linno = plinno; + if (funclinno != 0) + linno -= funclinno - 1; + snprintf(buf, sizeof(buf), "%d", linno); + STADJUST(-6, out); + for (i = 0; buf[i] != '\0'; i++) + STPUTC(buf[i], out); + flags |= VSLINENO; + } } else if (is_digit(c)) { if (bracketed_name) { do { @@ -1222,11 +1242,10 @@ parsesub: { c = pgetc(); } } - flags = 0; if (subtype == 0) { switch (c) { case ':': - flags = VSNUL; + flags |= VSNUL; c = pgetc(); /*FALLTHROUGH*/ default: diff --git a/bin/sh/parser.h b/bin/sh/parser.h index 877bf1d..712715b 100644 --- a/bin/sh/parser.h +++ b/bin/sh/parser.h @@ -50,9 +50,11 @@ #define CTLQUOTEMARK '\210' /* variable substitution byte (follows CTLVAR) */ -#define VSTYPE 0x0f /* type of variable substitution */ -#define VSNUL 0x10 /* colon--treat the empty string as unset */ -#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ +#define VSTYPE 0x0f /* type of variable substitution */ +#define VSNUL 0x10 /* colon--treat the empty string as unset */ +#define VSLINENO 0x20 /* expansion of $LINENO, the line number \ + follows immediately */ +#define VSQUOTE 0x80 /* inside double quotes--suppress splitting */ /* values of VSTYPE field */ #define VSNORMAL 0x1 /* normal variable: $var or ${var} */ -- 1.6.2.5