bc: print error line numbers
authorDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 16:48:01 +0000 (17:48 +0100)
committerDenys Vlasenko <vda.linux@googlemail.com>
Wed, 5 Dec 2018 16:48:01 +0000 (17:48 +0100)
FILE:
print 1
print "

$ busybox bc -q FILE
bc: FILE:2: string end could not be found
ready for more input
>>> _

function                                             old     new   delta
bc_verror_msg                                          -      99     +99
bc_lex_file                                           12      28     +16
bc_lex_next                                           77      92     +15
dc_lex_token                                         687     701     +14
bc_lex_token                                        1237    1251     +14
bc_posix_error_fmt                                    90      58     -32
bc_error_fmt                                          70      36     -34
------------------------------------------------------------------------------
(add/remove: 1/0 grow/shrink: 4/2 up/down: 158/-66)            Total: 92 bytes
   text    data     bss     dec     hex filename
 987108     485    7296  994889   f2e49 busybox_old
 987210     485    7296  994991   f2eaf busybox_unstripped

Signed-off-by: Denys Vlasenko <vda.linux@googlemail.com>
miscutils/bc.c

index 97adeaa532e75e8ee6e3863fc77f71b40e319638..1c1672c0012d03a6fcd8ab6bc8b8c6fa1cbf389b 100644 (file)
@@ -786,6 +786,10 @@ struct globals {
        BcParse prs;
        BcProgram prog;
 
+       // For error messages. Can be set to current parsed line,
+       // or [TODO] to current executing line (can be before last parsed one)
+       unsigned err_line;
+
        BcVec files;
 
        char *env_args;
@@ -928,19 +932,27 @@ static void quit(void)
        exit(0);
 }
 
+static void bc_verror_msg(const char *fmt, va_list p)
+{
+       const char *sv = sv; /* for compiler */
+       if (G.prog.file) {
+               sv = applet_name;
+               applet_name = xasprintf("%s: %s:%u", applet_name, G.prog.file, G.err_line);
+       }
+       bb_verror_msg(fmt, p, NULL);
+       if (G.prog.file) {
+               free((char*)applet_name);
+               applet_name = sv;
+       }
+}
+
 static NOINLINE int bc_error_fmt(const char *fmt, ...)
 {
-       const char *sv;
        va_list p;
 
-       sv = applet_name;
-       if (G.prog.file)
-               applet_name = G.prog.file;
-
        va_start(p, fmt);
-       bb_verror_msg(fmt, p, NULL);
+       bc_verror_msg(fmt, p);
        va_end(p);
-       applet_name = sv;
 
        if (!G.ttyin)
                exit(1);
@@ -949,21 +961,15 @@ static NOINLINE int bc_error_fmt(const char *fmt, ...)
 
 static NOINLINE int bc_posix_error_fmt(const char *fmt, ...)
 {
-       const char *sv;
        va_list p;
 
        // Are non-POSIX constructs totally ok?
        if (!(option_mask32 & (BC_FLAG_S|BC_FLAG_W)))
                return BC_STATUS_SUCCESS; // yes
 
-       sv = applet_name;
-       if (G.prog.file)
-               applet_name = G.prog.file;
-
        va_start(p, fmt);
-       bb_verror_msg(fmt, p, NULL);
+       bc_verror_msg(fmt, p);
        va_end(p);
-       applet_name = sv;
 
        // Do we treat non-POSIX constructs as errors?
        if (!(option_mask32 & BC_FLAG_S))
@@ -2877,7 +2883,7 @@ static void bc_lex_free(BcLex *l)
 
 static void bc_lex_file(BcLex *l)
 {
-       l->line = 1;
+       G.err_line = l->line = 1;
        l->newline = false;
 }
 
@@ -2889,6 +2895,7 @@ static BcStatus bc_lex_next(BcLex *l)
        if (l->t.last == BC_LEX_EOF) return bc_error("end of file");
 
        l->line += l->newline;
+       G.err_line = l->line;
        l->t.t = BC_LEX_EOF;
 
        l->newline = (l->i == l->len);
@@ -2971,6 +2978,7 @@ static BcStatus bc_lex_string(BcLex *l)
 
        l->i = i + 1;
        l->line += nls;
+       G.err_line = l->line;
 
        return BC_STATUS_SUCCESS;
 }
@@ -3011,6 +3019,7 @@ static BcStatus bc_lex_comment(BcLex *l)
 
        l->i = i + 1;
        l->line += nls;
+       G.err_line = l->line;
 
        return BC_STATUS_SUCCESS;
 }
@@ -3347,6 +3356,7 @@ static BcStatus dc_lex_string(BcLex *l)
 
        l->i = i;
        l->line += nls;
+       G.err_line = l->line;
 
        return BC_STATUS_SUCCESS;
 }