diff --git a/NEWS b/NEWS index c86d3b8a6..e3d73ac7b 100644 --- a/NEWS +++ b/NEWS @@ -14,6 +14,10 @@ Any uppercase BUG_* names are modernish shell bug IDs. nonzero exit status. Similarly, if both the 'errexit' and 'pipefail' options are active, ksh now correctly exits if any pipeline element returns nonzero. +- Autoloading a function no longer causes the calling script's $LINENO to be + off by the number of lines in the function definition file that was loaded. + This also corrects line numbers in warnings and error messages. + 2020-09-28: - While executing a ksh-style function, ksh 93u+ ignored all signals for which diff --git a/src/cmd/ksh93/sh/path.c b/src/cmd/ksh93/sh/path.c index 13c1ec4ec..65b6330f7 100644 --- a/src/cmd/ksh93/sh/path.c +++ b/src/cmd/ksh93/sh/path.c @@ -582,7 +582,7 @@ static void funload(Shell_t *shp,int fno, const char *name) char *pname,*oldname=shp->st.filename, buff[IOBSIZE+1]; Namval_t *np; struct Ufunction *rp,*rpfirst; - int savestates = sh_getstate(), oldload=shp->funload; + int savestates = sh_getstate(), oldload=shp->funload, savelineno = shp->inlineno; pname = path_fullname(shp,stakptr(PATH_OFFSET)); if(shp->fpathdict && (rp = dtmatch(shp->fpathdict,(void*)pname))) { @@ -615,6 +615,7 @@ static void funload(Shell_t *shp,int fno, const char *name) shp->readscript = (char*)name; shp->st.filename = pname; shp->funload = 1; + shp->inlineno = 1; error_info.line = 0; sh_eval(sfnew(NIL(Sfio_t*),buff,IOBSIZE,fno,SF_READ),SH_FUNEVAL); sh_close(fno); @@ -631,6 +632,7 @@ static void funload(Shell_t *shp,int fno, const char *name) pname = 0; free((void*)shp->st.filename); shp->funload = oldload; + shp->inlineno = savelineno; shp->st.filename = oldname; sh_setstate(savestates); if(pname) diff --git a/src/cmd/ksh93/tests/variables.sh b/src/cmd/ksh93/tests/variables.sh index 34738f6bc..428738791 100755 --- a/src/cmd/ksh93/tests/variables.sh +++ b/src/cmd/ksh93/tests/variables.sh @@ -1130,5 +1130,52 @@ case $'\n'$(env 'BASH_FUNC_a%%=() { echo test; }' "$SHELL" -c set) in err_exit 'ksh imports environment variables with invalid names' ;; esac +# ====== +# Autoloading a function caused $LINENO to be off by the # of lines in the function definition file. +# https://github.com/ksh93/ksh/issues/116 + +cd "$tmp" || exit 128 + +cat >lineno_autoload <<'EOF' +echo "begin: main script \$LINENO == $LINENO" +function main_script_fn +{ + lineno_autoload_fn + (: ${bad\subst\in\main_script_fn\on\line\5}) +} +main_script_fn +(eval 'syntax error(') +(: ${bad\subst\in\main\script\on\line\9}) +echo "end: main script \$LINENO == $LINENO" +EOF + +cat >lineno_autoload_fn <<'EOF' +function lineno_autoload_fn +{ + echo "Hi, I'm a function! On line 3, my \$LINENO is $LINENO" + (: ${bad\subst\in\function\on\line\4}) + (eval 'syntax error(') + echo "Hi, I'm still a function! On line 6, my \$LINENO is $LINENO" +} +echo "In definition file, outside function: \$LINENO on line 8 is $LINENO" +: ${bad\subst\in\def\file\on\line\9} +EOF + +exp="begin: main script \$LINENO == 1 +In definition file, outside function: \$LINENO on line 8 is 8 +./lineno_autoload[7]: main_script_fn: line 9: \${bad\subst\in\def\file\on\line\9}: bad substitution +Hi, I'm a function! On line 3, my \$LINENO is 3 +./lineno_autoload[7]: main_script_fn[4]: lineno_autoload_fn: line 4: \${bad\subst\in\function\on\line\4}: bad substitution +./lineno_autoload[7]: main_script_fn[4]: lineno_autoload_fn[5]: eval: syntax error at line 1: \`(' unexpected +Hi, I'm still a function! On line 6, my \$LINENO is 6 +./lineno_autoload[7]: main_script_fn: line 5: \${bad\subst\in\main_script_fn\on\line\5}: bad substitution +./lineno_autoload[8]: eval: syntax error at line 1: \`(' unexpected +./lineno_autoload: line 9: \${bad\subst\in\main\script\on\line\9}: bad substitution +end: main script \$LINENO == 10" + +got=$(FPATH=$tmp "$SHELL" ./lineno_autoload 2>&1) +[[ $got == "$exp" ]] || err_exit 'Regression in \$LINENO and/or error messages.' \ + $'Diff follows:\n'"$(diff -u <(print -r -- "$exp") <(print -r -- "$got") | sed $'s/^/\t| /')" + # ====== exit $((Errors<125?Errors:125))