diff options
-rw-r--r-- | usr.bin/awk/FIXES | 39 | ||||
-rw-r--r-- | usr.bin/awk/awk.1 | 41 | ||||
-rw-r--r-- | usr.bin/awk/awk.h | 7 | ||||
-rw-r--r-- | usr.bin/awk/awkgram.y | 6 | ||||
-rw-r--r-- | usr.bin/awk/b.c | 4 | ||||
-rw-r--r-- | usr.bin/awk/lib.c | 16 | ||||
-rw-r--r-- | usr.bin/awk/main.c | 4 | ||||
-rw-r--r-- | usr.bin/awk/maketab.c | 3 | ||||
-rw-r--r-- | usr.bin/awk/proto.h | 5 | ||||
-rw-r--r-- | usr.bin/awk/run.c | 53 | ||||
-rw-r--r-- | usr.bin/awk/tran.c | 159 |
11 files changed, 293 insertions, 44 deletions
diff --git a/usr.bin/awk/FIXES b/usr.bin/awk/FIXES index 3aad2c78334..f355591ac2b 100644 --- a/usr.bin/awk/FIXES +++ b/usr.bin/awk/FIXES @@ -1,4 +1,4 @@ -/* $OpenBSD: FIXES,v 1.18 2020/06/10 20:59:06 millert Exp $ */ +/* $OpenBSD: FIXES,v 1.19 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -26,6 +26,41 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the AWK book was sent to the printers in August, 1987. +Aug 23, 2018: + A long list of fixes courtesy of Arnold Robbins, + to whom profound thanks. + + 1. ofs-rebuild: OFS value used to rebuild the record was incorrect. + Fixed August 19, 2014. Revised fix August 2018. + + 2. system-status: Instead of a floating-point division by 256, use + the wait(2) macros to create a reasonable exit status. + Fixed March 12, 2016. + + 3. space: Use provided xisblank() function instead of ispace() for + matching [[:blank:]]. + + 4. a-format: Add POSIX standard %a and %A to supported formats. Check + at runtime that this format is available. + + 5. decr-NF: Decrementing NF did not change $0. This is a decades-old + bug. There are interactions with the old and new value of OFS as well. + Most of the fix came from the NetBSD awk. + + 6. string-conv: String conversions of scalars were sticky. Once a + conversion to string happened, even with OFMT, that value was used until + a new numeric value was assigned, even if OFMT differed from CONVFMT, + and also if CONVFMT changed. + + 7. unary-plus: Unary plus on a string constant returned the string. + Instead, it should convert the value to numeric and give that value. + + Also added Arnold's tests for these to awktest.tar as T.arnold. + +Aug 15, 2018: + fixed mangled awktest.tar (thanks, Arnold), posted all + current (very minor) fixes to github / onetrueawk + Jun 7, 2018: (yes, a long layoff) Updated some broken tests (beebe.tar, T.lilly) @@ -511,6 +546,8 @@ May 12, 1998: Mar 12, 1998: added -V to print version number and die. +[notify dave kerns, dkerns@dacsoup.ih.lucent.com] + Feb 11, 1998: subtle silent bug in lex.c: if the program ended with a number longer than 1 digit, part of the input would be pushed back and diff --git a/usr.bin/awk/awk.1 b/usr.bin/awk/awk.1 index 8e473f86149..7c0fda130be 100644 --- a/usr.bin/awk/awk.1 +++ b/usr.bin/awk/awk.1 @@ -1,4 +1,4 @@ -.\" $OpenBSD: awk.1,v 1.46 2020/01/22 03:47:38 deraadt Exp $ +.\" $OpenBSD: awk.1,v 1.47 2020/06/10 21:00:01 millert Exp $ .\" .\" Copyright (C) Lucent Technologies 1997 .\" All Rights Reserved @@ -22,7 +22,7 @@ .\" ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF .\" THIS SOFTWARE. .\" -.Dd $Mdocdate: January 22 2020 $ +.Dd $Mdocdate: June 10 2020 $ .Dt AWK 1 .Os .Sh NAME @@ -162,7 +162,7 @@ as the field separator, use the option with a value of .Sq [t] . .Pp -A pattern-action statement has the form +A pattern-action statement has the form: .Pp .D1 Ar pattern Ic \&{ Ar action Ic \&} .Pp @@ -288,9 +288,9 @@ The .Ic print statement prints its arguments on the standard output (or on a file if -.Pf > Ar file +.Pf >\ \& Ar file or -.Pf >> Ar file +.Pf >>\ \& Ar file is present or on a pipe if .Pf |\ \& Ar cmd is present), separated by the current output field separator, @@ -303,7 +303,8 @@ identical string values in different statements denote the same open file. The .Ic printf -statement formats its expression list according to the format +statement formats its expression list according to the +.Ar format (see .Xr printf 1 ) . .Pp @@ -373,6 +374,9 @@ may be used to capture control after processing is finished. and .Ic END do not combine with other patterns. +They may appear multiple times in a program and execute +in the order they are read by +.Nm . .Pp Variable names with special meanings: .Pp @@ -502,7 +506,8 @@ occurs, or 0 if it does not. The length of .Fa s taken as a string, -or of +number of elements in an array for an array argument, +or length of .Va $0 if no argument is given. .It Fn match s r @@ -658,7 +663,7 @@ and returns 1 for a successful input, 0 for end of file, and \-1 for an error. .It Xo .Ic getline Op Va var -.Pf \ \&< Ar file +.Pf <\ \& Ar file .Xc Sets .Va $0 @@ -687,6 +692,19 @@ remains open until explicitly closed with a call to Executes .Fa cmd and returns its exit status. +This will be \-1 upon error, +.Ar cmd Ns 's +exit status upon a normal exit, +256 + +.Em sig +if +.Fa cmd +was terminated by a signal, where +.Em sig +is the number of the signal, +or 512 + +.Em sig +if there was a core dump. .El .Ss Bit-Operation Functions .Bl -tag -width "lshift(a, b)" @@ -718,7 +736,7 @@ Print first two fields in opposite order: .Pp .Dl { print $2, $1 } .Pp -Same, with input fields separated by comma and/or blanks and tabs: +Same, with input fields separated by comma and/or spaces and tabs: .Bd -literal -offset indent BEGIN { FS = ",[ \et]*|[ \et]+" } { print $2, $1 } @@ -749,6 +767,7 @@ Print an error message to standard error: .Ed .Sh SEE ALSO .Xr cut 1 , +.Xr grep 1 , .Xr lex 1 , .Xr printf 1 , .Xr sed 1 , @@ -795,3 +814,7 @@ to it. .Pp The scope rules for variables in functions are a botch; the syntax is worse. +.Pp +POSIX-standard interval expressions in regular expressions are not supported. +.Pp +Only eight-bit character sets are handled correctly. diff --git a/usr.bin/awk/awk.h b/usr.bin/awk/awk.h index 4f535f64017..2eda23b4fa4 100644 --- a/usr.bin/awk/awk.h +++ b/usr.bin/awk/awk.h @@ -1,4 +1,4 @@ -/* $OpenBSD: awk.h,v 1.14 2017/10/09 14:51:31 deraadt Exp $ */ +/* $OpenBSD: awk.h,v 1.15 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -82,7 +82,8 @@ typedef struct Cell { char *nval; /* name, for variables only */ char *sval; /* string value */ Awkfloat fval; /* value as number */ - int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE */ + int tval; /* type info: STR|NUM|ARR|FCN|FLD|CON|DONTFREE|CONVC|CONVO */ + char *fmt; /* CONVFMT/OFMT value used to convert from number */ struct Cell *cnext; /* ptr to next if chained */ } Cell; @@ -110,6 +111,8 @@ extern Cell *rlengthloc; /* RLENGTH */ #define FCN 040 /* this is a function name */ #define FLD 0100 /* this is a field $1, $2, ... */ #define REC 0200 /* this is $0 */ +#define CONVC 0400 /* string was converted from number via CONVFMT */ +#define CONVO 01000 /* string was converted from number via OFMT */ /* function types */ diff --git a/usr.bin/awk/awkgram.y b/usr.bin/awk/awkgram.y index 4eb03106dce..24e110bc9ae 100644 --- a/usr.bin/awk/awkgram.y +++ b/usr.bin/awk/awkgram.y @@ -1,4 +1,4 @@ -/* $OpenBSD: awkgram.y,v 1.9 2011/09/28 19:27:18 millert Exp $ */ +/* $OpenBSD: awkgram.y,v 1.10 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -87,7 +87,7 @@ Node *arglist = 0; /* list of args for current function */ %left CAT %left '+' '-' %left '*' '/' '%' -%left NOT UMINUS +%left NOT UMINUS UPLUS %right POWER %right DECR INCR %left INDIRECT @@ -358,7 +358,7 @@ term: | term '%' term { $$ = op2(MOD, $1, $3); } | term POWER term { $$ = op2(POWER, $1, $3); } | '-' term %prec UMINUS { $$ = op1(UMINUS, $2); } - | '+' term %prec UMINUS { $$ = $2; } + | '+' term %prec UMINUS { $$ = op1(UPLUS, $2); } | NOT term %prec UMINUS { $$ = op1(NOT, notnull($2)); } | BLTIN '(' ')' { $$ = op2(BLTIN, itonp($1), rectonode()); } | BLTIN '(' patlist ')' { $$ = op2(BLTIN, itonp($1), $3); } diff --git a/usr.bin/awk/b.c b/usr.bin/awk/b.c index 5091823bb01..8f9bc16b12b 100644 --- a/usr.bin/awk/b.c +++ b/usr.bin/awk/b.c @@ -1,4 +1,4 @@ -/* $OpenBSD: b.c,v 1.20 2018/01/24 16:28:25 millert Exp $ */ +/* $OpenBSD: b.c,v 1.21 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -757,7 +757,7 @@ struct charclass { { "alnum", 5, isalnum }, { "alpha", 5, isalpha }, #ifndef HAS_ISBLANK - { "blank", 5, isspace }, /* was isblank */ + { "blank", 5, xisblank }, #else { "blank", 5, isblank }, #endif diff --git a/usr.bin/awk/lib.c b/usr.bin/awk/lib.c index f1ff64731ca..bd51ca41b62 100644 --- a/usr.bin/awk/lib.c +++ b/usr.bin/awk/lib.c @@ -1,4 +1,4 @@ -/* $OpenBSD: lib.c,v 1.25 2017/12/08 17:04:15 deraadt Exp $ */ +/* $OpenBSD: lib.c,v 1.26 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -359,6 +359,7 @@ void fldbld(void) /* create fields from current record */ } } setfval(nfloc, (Awkfloat) lastfld); + donerec = 1; /* restore */ if (dbg) { for (j = 0; j <= lastfld; j++) { p = fldtab[j]; @@ -390,6 +391,19 @@ void newfld(int n) /* add field n after end of existing lastfld */ setfval(nfloc, (Awkfloat) n); } +void setlastfld(int n) /* set lastfld cleaning fldtab cells if necessary */ +{ + if (n > nfields) + growfldtab(n); + + if (lastfld < n) + cleanfld(lastfld+1, n); + else + cleanfld(n+1, lastfld); + + lastfld = n; +} + Cell *fieldadr(int n) /* get nth field */ { if (n < 0) diff --git a/usr.bin/awk/main.c b/usr.bin/awk/main.c index 8d2db5c309a..4f61c3960f9 100644 --- a/usr.bin/awk/main.c +++ b/usr.bin/awk/main.c @@ -1,4 +1,4 @@ -/* $OpenBSD: main.c,v 1.23 2020/06/10 20:59:06 millert Exp $ */ +/* $OpenBSD: main.c,v 1.24 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -23,7 +23,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ -const char *version = "version 20130105"; +const char *version = "version 20180823"; #define DEBUG #include <stdio.h> diff --git a/usr.bin/awk/maketab.c b/usr.bin/awk/maketab.c index 84aef727031..071458bfd95 100644 --- a/usr.bin/awk/maketab.c +++ b/usr.bin/awk/maketab.c @@ -1,4 +1,4 @@ -/* $OpenBSD: maketab.c,v 1.11 2010/06/13 17:58:19 millert Exp $ */ +/* $OpenBSD: maketab.c,v 1.12 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -63,6 +63,7 @@ struct xx { DIVIDE, "arith", " / " }, { MOD, "arith", " % " }, { UMINUS, "arith", " -" }, + { UPLUS, "arith", " +" }, { POWER, "arith", " **" }, { PREINCR, "incrdecr", "++" }, { POSTINCR, "incrdecr", "++" }, diff --git a/usr.bin/awk/proto.h b/usr.bin/awk/proto.h index 7c084922e77..326fddf0c87 100644 --- a/usr.bin/awk/proto.h +++ b/usr.bin/awk/proto.h @@ -1,4 +1,4 @@ -/* $OpenBSD: proto.h,v 1.11 2020/02/27 21:43:46 millert Exp $ */ +/* $OpenBSD: proto.h,v 1.12 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -125,6 +125,7 @@ extern void setclvar(char *); extern void fldbld(void); extern void cleanfld(int, int); extern void newfld(int); +extern void setlastfld(int); extern int refldbld(const char *, const char *); extern void recbld(void); extern Cell *fieldadr(int); @@ -194,3 +195,5 @@ extern Cell *gsub(Node **, int); extern FILE *popen(const char *, const char *); extern int pclose(FILE *); + +extern const char *flags2str(int flags); diff --git a/usr.bin/awk/run.c b/usr.bin/awk/run.c index 416ca609289..a71dba3e0fd 100644 --- a/usr.bin/awk/run.c +++ b/usr.bin/awk/run.c @@ -1,4 +1,4 @@ -/* $OpenBSD: run.c,v 1.46 2020/06/10 20:59:06 millert Exp $ */ +/* $OpenBSD: run.c,v 1.47 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -33,6 +33,8 @@ THIS SOFTWARE. #include <string.h> #include <stdlib.h> #include <time.h> +#include <sys/types.h> +#include <sys/wait.h> #include "awk.h" #include "ytab.h" @@ -326,14 +328,18 @@ Cell *copycell(Cell *x) /* make a copy of a cell in a temp */ { Cell *y; + /* copy is not constant or field */ + y = gettemp(); + y->tval = x->tval & ~(CON|FLD|REC); y->csub = CCOPY; /* prevents freeing until call is over */ y->nval = x->nval; /* BUG? */ - if (isstr(x)) + if (isstr(x) /* || x->ctype == OCELL */) { y->sval = tostring(x->sval); + y->tval &= ~DONTFREE; + } else + y->tval |= DONTFREE; y->fval = x->fval; - y->tval = x->tval & ~(CON|FLD|REC|DONTFREE); /* copy is not constant or field */ - /* is DONTFREE right? */ return y; } @@ -820,6 +826,17 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co char *buf = *pbuf; int bufsize = *pbufsize; + static int first = 1; + static int have_a_format = 0; + + if (first) { + char buf[100]; + + snprintf(buf, sizeof(buf), "%a", 42.0); + have_a_format = (strcmp(buf, "0x1.5p+5") == 0); + first = 0; + } + os = s; p = buf; if ((fmt = (char *) malloc(fmtsz)) == NULL) @@ -864,6 +881,12 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co adjbuf(&buf, &bufsize, fmtwd+1+p-buf, recsize, &p, "format4"); switch (*s) { + case 'a': case 'A': + if (have_a_format) + flag = *s; + else + flag = 'f'; + break; case 'f': case 'e': case 'g': case 'E': case 'G': flag = 'f'; break; @@ -907,6 +930,8 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co p += strlen(p); snprintf(p, buf + bufsize - p, "%s", t); break; + case 'a': + case 'A': case 'f': snprintf(p, buf + bufsize - p, fmt, getfval(x)); break; case 'd': snprintf(p, buf + bufsize - p, fmt, (long) getfval(x)); break; case 'u': snprintf(p, buf + bufsize - p, fmt, (int) getfval(x)); break; @@ -1009,7 +1034,7 @@ Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ x = execute(a[0]); i = getfval(x); tempfree(x); - if (n != UMINUS) { + if (n != UMINUS && n != UPLUS) { y = execute(a[1]); j = getfval(y); tempfree(y); @@ -1039,6 +1064,8 @@ Cell *arith(Node **a, int n) /* a[0] + a[1], etc. also -a[0] */ case UMINUS: i = -i; break; + case UPLUS: /* handled by getfval(), above */ + break; case POWER: if (j >= 0 && modf(j, &v) == 0.0) /* pos integer exponent */ i = ipow(i, (int) j); @@ -1492,6 +1519,7 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis char *p, *buf; Node *nextarg; FILE *fp; + int status = 0; t = ptoi(a[0]); x = execute(a[1]); @@ -1589,7 +1617,20 @@ Cell *bltin(Node **a, int n) /* builtin functions. a[0] is type, a[1] is arg lis break; case FSYSTEM: fflush(stdout); /* in case something is buffered already */ - u = (Awkfloat) system(getsval(x)) / 256; /* 256 is unix-dep */ + status = system(getsval(x)); + u = status; + if (status != -1) { + if (WIFEXITED(status)) { + u = WEXITSTATUS(status); + } else if (WIFSIGNALED(status)) { + u = WTERMSIG(status) + 256; +#ifdef WCOREDUMP + if (WCOREDUMP(status)) + u += 256; +#endif + } else /* something else?!? */ + u = 0; + } break; case FRAND: u = (Awkfloat) (random() & RAND_MAX) / ((u_int)RAND_MAX + 1); diff --git a/usr.bin/awk/tran.c b/usr.bin/awk/tran.c index b56c9435d9d..c47e3403dae 100644 --- a/usr.bin/awk/tran.c +++ b/usr.bin/awk/tran.c @@ -1,4 +1,4 @@ -/* $OpenBSD: tran.c,v 1.18 2020/02/27 21:43:46 millert Exp $ */ +/* $OpenBSD: tran.c,v 1.19 2020/06/10 21:00:01 millert Exp $ */ /**************************************************************** Copyright (C) Lucent Technologies 1997 All Rights Reserved @@ -68,6 +68,18 @@ Cell *literal0; extern Cell **fldtab; +static void +setfree(Cell *vp) +{ + if (&vp->sval == FS || &vp->sval == RS || + &vp->sval == OFS || &vp->sval == ORS || + &vp->sval == OFMT || &vp->sval == CONVFMT || + &vp->sval == FILENAME || &vp->sval == SUBSEP) + vp->tval |= DONTFREE; + else + vp->tval &= ~DONTFREE; +} + void syminit(void) /* initialize symbol table with builtin vars */ { literal0 = setsymtab("0", "0", 0.0, NUM|STR|CON|DONTFREE, symtab); @@ -283,6 +295,7 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ { int fldno; + f += 0.0; /* normalise negative zero to positive zero */ if ((vp->tval & (NUM | STR)) == 0) funnyvar(vp, "assign to"); if (isfld(vp)) { @@ -291,13 +304,18 @@ Awkfloat setfval(Cell *vp, Awkfloat f) /* set float val of a Cell */ if (fldno > *NF) newfld(fldno); DPRINTF( ("setting field %d to %g\n", fldno, f) ); + } else if (&vp->fval == NF) { + donerec = 0; /* mark $0 invalid */ + setlastfld(f); + DPRINTF( ("setting NF to %g\n", f) ); } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; } if (freeable(vp)) xfree(vp->sval); /* free any previous string */ - vp->tval &= ~STR; /* mark string invalid */ + vp->tval &= ~(STR|CONVC|CONVO); /* mark string invalid */ + vp->fmt = NULL; vp->tval |= NUM; /* mark number ok */ if (f == -0) /* who would have thought this possible? */ f = 0; @@ -319,6 +337,7 @@ char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ { char *t; int fldno; + Awkfloat f; DPRINTF( ("starting setsval %p: %s = \"%s\", t=%o, r,f=%d,%d\n", (void*)vp, NN(vp->nval), s, vp->tval, donerec, donefld) ); @@ -333,16 +352,28 @@ char *setsval(Cell *vp, const char *s) /* set string val of a Cell */ } else if (isrec(vp)) { donefld = 0; /* mark $1... invalid */ donerec = 1; + } else if (&vp->sval == OFS) { + if (donerec == 0) + recbld(); } - t = tostring(s); /* in case it's self-assign */ + t = s ? tostring(s) : tostring(""); /* in case it's self-assign */ if (freeable(vp)) xfree(vp->sval); - vp->tval &= ~NUM; + vp->tval &= ~(NUM|CONVC|CONVO); vp->tval |= STR; - vp->tval &= ~DONTFREE; + vp->fmt = NULL; + setfree(vp); DPRINTF( ("setsval %p: %s = \"%s (%p) \", t=%o r,f=%d,%d\n", (void*)vp, NN(vp->nval), t,t, vp->tval, donerec, donefld) ); - return(vp->sval = t); + vp->sval = t; + if (&vp->fval == NF) { + donerec = 0; /* mark $0 invalid */ + f = getfval(vp); + setlastfld(f); + DPRINTF( ("setting NF to %g\n", f) ); + } + + return(vp->sval); } Awkfloat getfval(Cell *vp) /* get float val of a Cell */ @@ -374,18 +405,79 @@ static char *get_str_val(Cell *vp, char **fmt) /* get string val of a Cel fldbld(); else if (isrec(vp) && donerec == 0) recbld(); + + /* + * ADR: This is complicated and more fragile than is desirable. + * Retrieving a string value for a number associates the string + * value with the scalar. Previously, the string value was + * sticky, meaning if converted via OFMT that became the value + * (even though POSIX wants it to be via CONVFMT). Or if CONVFMT + * changed after a string value was retrieved, the original value + * was maintained and used. Also not per POSIX. + * + * We work around this design by adding two additional flags, + * CONVC and CONVO, indicating how the string value was + * obtained (via CONVFMT or OFMT) and _also_ maintaining a copy + * of the pointer to the xFMT format string used for the + * conversion. This pointer is only read, **never** dereferenced. + * The next time we do a conversion, if it's coming from the same + * xFMT as last time, and the pointer value is different, we + * know that the xFMT format string changed, and we need to + * redo the conversion. If it's the same, we don't have to. + * + * There are also several cases where we don't do a conversion, + * such as for a field (see the checks below). + */ + + /* Don't duplicate the code for actually updating the value */ +#define update_str_val(vp) \ + { \ + if (freeable(vp)) \ + xfree(vp->sval); \ + if (modf(vp->fval, &dtemp) == 0) /* it's integral */ \ + n = asprintf(&vp->sval, "%.30g", vp->fval); \ + else \ + n = asprintf(&vp->sval, *fmt, vp->fval); \ + if (n == -1) \ + FATAL("out of space in get_str_val"); \ + vp->tval &= ~DONTFREE; \ + vp->tval |= STR; \ + } + if (isstr(vp) == 0) { - if (freeable(vp)) - xfree(vp->sval); - if (modf(vp->fval, &dtemp) == 0) /* it's integral */ - n = asprintf(&vp->sval, "%.30g", vp->fval); - else - n = asprintf(&vp->sval, *fmt, vp->fval); - if (n == -1) - FATAL("out of space in get_str_val"); - vp->tval &= ~DONTFREE; - vp->tval |= STR; + update_str_val(vp); + if (fmt == OFMT) { + vp->tval &= ~CONVC; + vp->tval |= CONVO; + } else { + /* CONVFMT */ + vp->tval &= ~CONVO; + vp->tval |= CONVC; + } + vp->fmt = *fmt; + } else if ((vp->tval & DONTFREE) != 0 || ! isnum(vp) || isfld(vp)) { + goto done; + } else if (isstr(vp)) { + if (fmt == OFMT) { + if ((vp->tval & CONVC) != 0 + || ((vp->tval & CONVO) != 0 && vp->fmt != *fmt)) { + update_str_val(vp); + vp->tval &= ~CONVC; + vp->tval |= CONVO; + vp->fmt = *fmt; + } + } else { + /* CONVFMT */ + if ((vp->tval & CONVO) != 0 + || ((vp->tval & CONVC) != 0 && vp->fmt != *fmt)) { + update_str_val(vp); + vp->tval &= ~CONVO; + vp->tval |= CONVC; + vp->fmt = *fmt; + } + } } +done: DPRINTF( ("getsval %p: %s = \"%s (%p)\", t=%o\n", (void*)vp, NN(vp->nval), vp->sval, vp->sval, vp->tval) ); return(vp->sval); @@ -460,3 +552,38 @@ char *qstring(const char *is, int delim) /* collect string up to next delim */ *bp++ = 0; return (char *) buf; } + +const char *flags2str(int flags) +{ + static const struct ftab { + const char *name; + int value; + } flagtab[] = { + { "NUM", NUM }, + { "STR", STR }, + { "DONTFREE", DONTFREE }, + { "CON", CON }, + { "ARR", ARR }, + { "FCN", FCN }, + { "FLD", FLD }, + { "REC", REC }, + { "CONVC", CONVC }, + { "CONVO", CONVO }, + { NULL, 0 } + }; + static char buf[100]; + int i, len; + char *cp = buf; + + for (i = 0; flagtab[i].name != NULL; i++) { + if ((flags & flagtab[i].value) != 0) { + len = snprintf(cp, sizeof(buf) - (cp - buf), + "%s%s", cp > buf ? "|" : "", flagtab[i].name); + if (len < 0 || len >= sizeof(buf) - (cp - buf)) + FATAL("out of space in flags2str"); + cp += len; + } + } + + return buf; +} |