diff options
author | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-01-09 17:31:45 +0000 |
---|---|---|
committer | Automerger Merge Worker <android-build-automerger-merge-worker@system.gserviceaccount.com> | 2020-01-09 17:31:45 +0000 |
commit | c55d3b6808ee724814e54ec00ab2faba04519855 (patch) | |
tree | d9f8db750df527ca8061b6196d5ae1eac77f5edd | |
parent | bc266eabe3d1b136ef93d5366210db9560d7f317 (diff) | |
parent | 7be0794073f08277c25000415f5d66ac1a645c61 (diff) | |
download | one-true-awk-c55d3b6808ee724814e54ec00ab2faba04519855.tar.gz |
Upgrade one-true-awk to 944989bf683d30f306d8f29a3eb8c68c7c603fb4 am: 2b2ca9f3fb am: 78cb1093df am: 7be0794073
Change-Id: I31b2a71bd29660973c47448599812f37d575c9a6
-rw-r--r-- | ChangeLog | 26 | ||||
-rw-r--r-- | FIXES | 15 | ||||
-rw-r--r-- | METADATA | 8 | ||||
-rw-r--r-- | README | 90 | ||||
-rw-r--r-- | README.md | 96 | ||||
-rw-r--r-- | b.c | 33 | ||||
-rw-r--r-- | lex.c | 9 | ||||
-rw-r--r-- | main.c | 2 | ||||
-rw-r--r-- | run.c | 20 | ||||
-rwxr-xr-x | testdir/T.concat | 29 | ||||
-rwxr-xr-x | testdir/T.expr | 18 | ||||
-rwxr-xr-x | testdir/T.int-expr | 82 | ||||
-rw-r--r-- | tran.c | 14 |
13 files changed, 308 insertions, 134 deletions
@@ -1,3 +1,29 @@ +2020-01-06 Arnold D. Robbins <arnold@skeeve.com> + + Minor fixes. + * b.c (replace_repeat): Turn init_q back into an int. + * lex.c (string): Use \a instead of \007. + * tran.c (catstr): Use snprintf instead of sprintf. + +2020-01-01 Arnold D. Robbins <arnold@skeeve.com> + + * tran.c (syminit, arginit, envinit): Free sval member before + setting it. Thanks to valgrind. + * b.c: Small formatting cleanups in several routines. + +2019-12-27 Arnold D. Robbins <arnold@skeeve.com> + + * b.c (replace_repeat): Fix a bug whereby a{0,3} could match + four a's. Thanks to Anonymous AWK fan <awkfan77@mailfence.com> + for the report. Also, minor code formatting cleanups. + * testdir/T.int-expr: New file. + +2019-12-11 Arnold D. Robbins <arnold@skeeve.com> + + * README: Renamed to ... + * README.md: ... this. Cleaned up some as well, + including moving to Markdown. + 2019-11-08 Arnold D. Robbins <arnold@skeeve.com> * test/T.chem: Use $oldawk instead of hardwiring 'awk'. @@ -25,6 +25,21 @@ THIS SOFTWARE. This file lists all bug fixes, changes, etc., made since the AWK book was sent to the printers in August, 1987. +January 5, 2020: + Fix a bug in the concatentation of two string constants into + one done in the grammar. Fixes GitHub issue #61. Thanks + to GitHub user awkfan77 for pointing out the direction for + the fix. New test T.concat added to the test suite. + Fix a few memory leaks reported by valgrind, as well. + +December 27, 2019: + Fix a bug whereby a{0,3} could match four a's. Thanks to + "Anonymous AWK fan" for the report. + +December 11, 2019: + Further printf-related fixes for 32 bit systems. + Thanks again to Christos Zoulas. + December 8, 2019: Fix the return value of sprintf("%d") on 32 bit systems. Thanks to Jim Lowe for the report and to Christos Zoulas @@ -5,11 +5,11 @@ third_party { type: GIT value: "https://github.com/onetrueawk/awk.git" } - version: "af86dacfad85857b2ea9fa95150ddd8c671695ed" + version: "944989bf683d30f306d8f29a3eb8c68c7c603fb4" license_type: NOTICE last_upgrade_date { - year: 2019 - month: 12 - day: 9 + year: 2020 + month: 1 + day: 8 } } @@ -1,90 +0,0 @@ -/**************************************************************** -Copyright (C) Lucent Technologies 1997 -All Rights Reserved - -Permission to use, copy, modify, and distribute this software and -its documentation for any purpose and without fee is hereby -granted, provided that the above copyright notice appear in all -copies and that both that the copyright notice and this -permission notice and warranty disclaimer appear in supporting -documentation, and that the name Lucent Technologies or any of -its entities not be used in advertising or publicity pertaining -to distribution of the software without specific, written prior -permission. - -LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, -INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. -IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY -SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER -IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, -ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF -THIS SOFTWARE. -****************************************************************/ - -This is the version of awk described in "The AWK Programming Language", -by Al Aho, Brian Kernighan, and Peter Weinberger -(Addison-Wesley, 1988, ISBN 0-201-07981-X). - -Changes, mostly bug fixes and occasional enhancements, are listed -in FIXES. If you distribute this code further, please please please -distribute FIXES with it. If you find errors, please report them -to bwk@cs.princeton.edu. Thanks. - -The program itself is created by - make -which should produce a sequence of messages roughly like this: - - yacc -d awkgram.y - -conflicts: 43 shift/reduce, 85 reduce/reduce - mv y.tab.c ytab.c - mv y.tab.h ytab.h - cc -c ytab.c - cc -c b.c - cc -c main.c - cc -c parse.c - cc maketab.c -o maketab - ./maketab >proctab.c - cc -c proctab.c - cc -c tran.c - cc -c lib.c - cc -c run.c - cc -c lex.c - cc ytab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm - -This produces an executable a.out; you will eventually want to -move this to some place like /usr/bin/awk. - -If your system does not have yacc or bison (the GNU -equivalent), you must compile the pieces manually. We have -included yacc output in ytab.c and ytab.h, and backup copies in -case you overwrite them. We have also included a copy of -proctab.c so you do not need to run maketab. - -NOTE: This version uses ANSI C, as you should also. We have -compiled this without any changes using gcc -Wall and/or local C -compilers on a variety of systems, but new systems or compilers -may raise some new complaint; reports of difficulties are -welcome. - -This also compiles with Visual C++ on all flavors of Windows, -*if* you provide versions of popen and pclose. The file -missing95.c contains versions that can be used to get started -with, though the underlying support has mysterious properties, -the symptom of which can be truncated pipe output. Beware. The -file makefile.win gives hints on how to proceed; if you run -vcvars32.bat, it will set up necessary paths and parameters so -you can subsequently run nmake -f makefile.win. Beware also that -when running on Windows under command.com, various quoting -conventions are different from Unix systems: single quotes won't -work around arguments, and various characters like % are -interpreted within double quotes. - -This compiles without change on Macintosh OS X using gcc and -the standard developer tools. - -The version of malloc that comes with some systems is sometimes -astonishly slow. If awk seems slow, you might try fixing that. -More generally, turning on optimization can significantly improve -awk's speed, perhaps by 1/3 for highest levels. diff --git a/README.md b/README.md new file mode 100644 index 0000000..77701d7 --- /dev/null +++ b/README.md @@ -0,0 +1,96 @@ +# The One True Awk + +This is the version of `awk` described in _The AWK Programming Language_, +by Al Aho, Brian Kernighan, and Peter Weinberger +(Addison-Wesley, 1988, ISBN 0-201-07981-X). + +## Copyright + +Copyright (C) Lucent Technologies 1997<br/> +All Rights Reserved + +Permission to use, copy, modify, and distribute this software and +its documentation for any purpose and without fee is hereby +granted, provided that the above copyright notice appear in all +copies and that both that the copyright notice and this +permission notice and warranty disclaimer appear in supporting +documentation, and that the name Lucent Technologies or any of +its entities not be used in advertising or publicity pertaining +to distribution of the software without specific, written prior +permission. + +LUCENT DISCLAIMS ALL WARRANTIES WITH REGARD TO THIS SOFTWARE, +INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS. +IN NO EVENT SHALL LUCENT OR ANY OF ITS ENTITIES BE LIABLE FOR ANY +SPECIAL, INDIRECT OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES +WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER +IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, +ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF +THIS SOFTWARE. + +## Distribution and Reporting Problems + +Changes, mostly bug fixes and occasional enhancements, are listed +in `FIXES`. If you distribute this code further, please please please +distribute `FIXES` with it. + +If you find errors, please report them +to bwk@cs.princeton.edu. +Please _also_ open an issue in the GitHub issue tracker, to make +it easy to track issues. +Thanks. + +## Submitting Pull Requests + +Pull requests are welcome. However, please create them with a request +to merge into the `staging` branch instead of into the `master` branch. +This allows us to do testing, and to make any additional edits or changes +after the merge but before merging to `master`. + +## Building + +The program itself is created by + + make + +which should produce a sequence of messages roughly like this: + + yacc -d awkgram.y + conflicts: 43 shift/reduce, 85 reduce/reduce + mv y.tab.c ytab.c + mv y.tab.h ytab.h + cc -c ytab.c + cc -c b.c + cc -c main.c + cc -c parse.c + cc maketab.c -o maketab + ./maketab >proctab.c + cc -c proctab.c + cc -c tran.c + cc -c lib.c + cc -c run.c + cc -c lex.c + cc ytab.o b.o main.o parse.o proctab.o tran.o lib.o run.o lex.o -lm + +This produces an executable `a.out`; you will eventually want to +move this to some place like `/usr/bin/awk`. + +If your system does not have `yacc` or `bison` (the GNU +equivalent), you need to install one of them first. + +NOTE: This version uses ANSI C (C 99), as you should also. We have +compiled this without any changes using `gcc -Wall` and/or local C +compilers on a variety of systems, but new systems or compilers +may raise some new complaint; reports of difficulties are +welcome. + +This compiles without change on Macintosh OS X using `gcc` and +the standard developer tools. + +The version of `malloc` that comes with some systems is sometimes +astonishly slow. If `awk` seems slow, you might try fixing that. +More generally, turning on optimization can significantly improve +`awk`'s speed, perhaps by 1/3 for highest levels. + +#### Last Updated +Wed Jan 1 22:44:38 IST 2020 @@ -180,7 +180,7 @@ fa *makedfa(const char *s, bool anchor) /* returns dfa for reg expr s */ } fa *mkdfa(const char *s, bool anchor) /* does the real work of making a dfa */ - /* anchor = 1 for anchored matches, else 0 */ + /* anchor = true for anchored matches, else false */ { Node *p, *p1; fa *f; @@ -223,17 +223,17 @@ int makeinit(fa *f, bool anchor) k = *(f->re[0].lfollow); xfree(f->posns[2]); f->posns[2] = intalloc(k + 1, __func__); - for (i=0; i <= k; i++) { + for (i = 0; i <= k; i++) { (f->posns[2])[i] = (f->re[0].lfollow)[i]; } if ((f->posns[2])[1] == f->accept) f->out[2] = 1; - for (i=0; i < NCHARS; i++) + for (i = 0; i < NCHARS; i++) f->gototab[2][i] = 0; f->curstat = cgoto(f, 2, HAT); if (anchor) { *f->posns[2] = k-1; /* leave out position 0 */ - for (i=0; i < k; i++) { + for (i = 0; i < k; i++) { (f->posns[0])[i] = (f->posns[2])[i]; } @@ -463,9 +463,10 @@ int first(Node *p) /* collects initially active leaves of p into setvec */ } if (type(p) == CCL && (*(char *) right(p)) == '\0') return(0); /* empty CCL */ - else return(1); + return(1); case PLUS: - if (first(left(p)) == 0) return(0); + if (first(left(p)) == 0) + return(0); return(1); case STAR: case QUEST: @@ -714,7 +715,7 @@ bool fnematch(fa *pfa, FILE *f, char **pbuf, int *pbufsize, int quantum) if (buf[--k] && ungetc(buf[k], f) == EOF) FATAL("unable to ungetc '%c'", buf[k]); while (k > i + patlen); - buf[k] = 0; + buf[k] = '\0'; return true; } else @@ -935,7 +936,7 @@ replace_repeat(const uschar *reptok, int reptoklen, const uschar *atom, buf[j++] = '('; buf[j++] = ')'; } - for (i=1; i < firstnum; i++) { /* copy x reps */ + for (i = 1; i < firstnum; i++) { /* copy x reps */ memcpy(&buf[j], atom, atomlen); j += atomlen; } @@ -944,7 +945,7 @@ replace_repeat(const uschar *reptok, int reptoklen, const uschar *atom, } else if (special_case == REPEAT_WITH_Q) { if (init_q) buf[j++] = '?'; - for (i = 0; i < n_q_reps; i++) { /* copy x? reps */ + for (i = init_q; i < n_q_reps; i++) { /* copy x? reps */ memcpy(&buf[j], atom, atomlen); j += atomlen; buf[j++] = '?'; @@ -1166,15 +1167,17 @@ rescan: if (commafound) { if (digitfound) { /* {n,m} */ m = num; - if (m<n) + if (m < n) FATAL("illegal repetition expression: class %.20s", lastre); - if ((n==0) && (m==1)) { + if (n == 0 && m == 1) { return QUEST; } } else { /* {n,} */ - if (n==0) return STAR; - if (n==1) return PLUS; + if (n == 0) + return STAR; + else if (n == 1) + return PLUS; } } else { if (digitfound) { /* {n} same as {n,n} */ @@ -1187,7 +1190,7 @@ rescan: } if (repeat(starttok, prestr-starttok, lastatom, startreptok - lastatom, n, m) > 0) { - if ((n==0) && (m==0)) { + if (n == 0 && m == 0) { return EMPTYRE; } /* must rescan input for next token */ @@ -1313,7 +1316,7 @@ void freefa(fa *f) /* free a finite automaton */ for (i = 0; i <= f->accept; i++) { xfree(f->re[i].lfollow); if (f->re[i].ltype == CCL || f->re[i].ltype == NCCL) - xfree((f->re[i].lval.np)); + xfree(f->re[i].lval.np); } xfree(f->restr); xfree(f->out); @@ -190,7 +190,9 @@ int yylex(void) if (isalpha(c) || c == '_') return word(buf); if (isdigit(c)) { - yylval.cp = setsymtab(buf, tostring(buf), atof(buf), CON|NUM, symtab); + char *cp = tostring(buf); + yylval.cp = setsymtab(buf, cp, atof(buf), CON|NUM, symtab); + free(cp); /* should this also have STR set? */ RET(NUMBER); } @@ -388,7 +390,7 @@ int string(void) case 'r': *bp++ = '\r'; break; case 'b': *bp++ = '\b'; break; case 'v': *bp++ = '\v'; break; - case 'a': *bp++ = '\007'; break; + case 'a': *bp++ = '\a'; break; case '\\': *bp++ = '\\'; break; case '0': case '1': case '2': /* octal: \d \dd \ddd */ @@ -431,8 +433,9 @@ int string(void) } *bp = 0; s = tostring(buf); - *bp++ = ' '; *bp++ = 0; + *bp++ = ' '; *bp++ = '\0'; yylval.cp = setsymtab(buf, s, 0.0, CON|STR|DONTFREE, symtab); + free(s); RET(STRING); } @@ -22,7 +22,7 @@ ARISING OUT OF OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. ****************************************************************/ -const char *version = "version 20191208"; +const char *version = "version 20200105"; #define DEBUG #include <stdio.h> @@ -855,8 +855,13 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co for (t = fmt; (*t++ = *s) != '\0'; s++) { if (!adjbuf(&fmt, &fmtsz, MAXNUMSIZE+1+t-fmt, recsize, &t, "format3")) FATAL("format item %.30s... ran format() out of memory", os); - if (isalpha((uschar)*s) && *s != 'l' && *s != 'h' && *s != 'L') - break; /* the ansi panoply */ + /* Ignore size specifiers */ + if (strchr("hjLlqtz", *s) != NULL) { /* the ansi panoply */ + t--; + continue; + } + if (isalpha((uschar)*s)) + break; if (*s == '$') { FATAL("'$' not permitted in awk formats"); } @@ -889,15 +894,8 @@ int format(char **pbuf, int *pbufsize, const char *s, Node *a) /* printf-like co case 'f': case 'e': case 'g': case 'E': case 'G': flag = 'f'; break; - case 'd': case 'i': - flag = 'd'; - if(*(s-1) == 'l') break; - *(t-1) = 'j'; - *t = 'd'; - *++t = '\0'; - break; - case 'o': case 'x': case 'X': case 'u': - flag = *(s-1) == 'l' ? 'd' : 'u'; + case 'd': case 'i': case 'o': case 'x': case 'X': case 'u': + flag = (*s == 'd' || *s == 'i') ? 'd' : 'u'; *(t-1) = 'j'; *t = *s; *++t = '\0'; diff --git a/testdir/T.concat b/testdir/T.concat new file mode 100755 index 0000000..c6bd016 --- /dev/null +++ b/testdir/T.concat @@ -0,0 +1,29 @@ +echo T.concat: test constant string concatentation + +awk=${awk-../a.out} + +$awk ' +BEGIN { + $0 = "aaa" + print "abcdef" " " $0 +} +BEGIN { print "hello" "world"; print helloworld } +BEGIN { + print " " "hello" + print "hello" " " + print "hello" " " "world" + print "hello" (" " "world") +} +' > foo1 + +cat << \EOF > foo2 +abcdef aaa +helloworld + + hello +hello +hello world +hello world +EOF + +diff foo1 foo2 || echo 'BAD: T.concat (1)' diff --git a/testdir/T.expr b/testdir/T.expr index 7390e8b..304b3d0 100755 --- a/testdir/T.expr +++ b/testdir/T.expr @@ -167,15 +167,15 @@ try { printf("a%-*.*sb\n", $1, $2, "hello") } 2 1 ah b 3 1 ah b -try { printf("%d %ld\n", $1, $1) } -1 1 1 -10 10 10 -10000 10000 10000 - -try { printf("%x %lx\n", $1, $1) } -1 1 1 -10 a a -10000 2710 2710 +try { printf("%d %ld %lld %zd %jd %hd %hhd\n", $1, $1, $1, $1, $1, $1, $1) } +1 1 1 1 1 1 1 1 +10 10 10 10 10 10 10 10 +10000 10000 10000 10000 10000 10000 10000 10000 + +try { printf("%x %lx %llx %zx %jx %hx %hhx\n", $1, $1, $1, $1, $1, $1, $1) } +1 1 1 1 1 1 1 1 +10 a a a a a a a +10000 2710 2710 2710 2710 2710 2710 2710 try { if ($1 ~ $2) print 1; else print 0 } a \141 1 diff --git a/testdir/T.int-expr b/testdir/T.int-expr new file mode 100755 index 0000000..e71a075 --- /dev/null +++ b/testdir/T.int-expr @@ -0,0 +1,82 @@ +echo T.int-expr: test interval expressions + +awk=${awk-../a.out} + +rm -f foo + +cat << \EOF > prog +NF == 0 { next } +$1 == "pat" { pattern = $2; next } +{ + check = ($1 ~ pattern) + printf("%s ~ /%s/ -> should be %d, is %d\n", $1, pattern, $2, check) +} +EOF + +cat << \EOF > foo.in +pat ab{0}c +ac 1 +abc 0 + +pat ab{1}c +ac 0 +abc 1 +abbc 0 + +pat ab{1,}c +ac 0 +abc 1 +abbc 1 +abbbc 1 +abbbbc 1 + +pat ab{0,1}c +ac 1 +abc 1 +abbc 0 + +pat ab{0,3}c +ac 1 +abc 1 +abbc 1 +abbbc 1 +abbbbc 0 + +pat ab{1,3}c +ac 0 +abc 1 +abbc 1 +abbbc 1 +abbbbc 0 +EOF + +cat << \EOF > foo1 +ac ~ /ab{0}c/ -> should be 1, is 1 +abc ~ /ab{0}c/ -> should be 0, is 0 +ac ~ /ab{1}c/ -> should be 0, is 0 +abc ~ /ab{1}c/ -> should be 1, is 1 +abbc ~ /ab{1}c/ -> should be 0, is 0 +ac ~ /ab{1,}c/ -> should be 0, is 0 +abc ~ /ab{1,}c/ -> should be 1, is 1 +abbc ~ /ab{1,}c/ -> should be 1, is 1 +abbbc ~ /ab{1,}c/ -> should be 1, is 1 +abbbbc ~ /ab{1,}c/ -> should be 1, is 1 +ac ~ /ab{0,1}c/ -> should be 1, is 1 +abc ~ /ab{0,1}c/ -> should be 1, is 1 +abbc ~ /ab{0,1}c/ -> should be 0, is 0 +ac ~ /ab{0,3}c/ -> should be 1, is 1 +abc ~ /ab{0,3}c/ -> should be 1, is 1 +abbc ~ /ab{0,3}c/ -> should be 1, is 1 +abbbc ~ /ab{0,3}c/ -> should be 1, is 1 +abbbbc ~ /ab{0,3}c/ -> should be 0, is 0 +ac ~ /ab{1,3}c/ -> should be 0, is 0 +abc ~ /ab{1,3}c/ -> should be 1, is 1 +abbc ~ /ab{1,3}c/ -> should be 1, is 1 +abbbc ~ /ab{1,3}c/ -> should be 1, is 1 +abbbbc ~ /ab{1,3}c/ -> should be 0, is 0 +EOF + + +$awk -f prog foo.in > foo2 +diff foo1 foo2 || echo 'BAD: T.int-expr (1)' +rm -f prog @@ -114,6 +114,7 @@ void syminit(void) /* initialize symbol table with builtin vars */ rlengthloc = setsymtab("RLENGTH", "", 0.0, NUM, symtab); RLENGTH = &rlengthloc->fval; symtabloc = setsymtab("SYMTAB", "", 0.0, ARR, symtab); + free(symtabloc->sval); symtabloc->sval = (char *) symtab; } @@ -126,6 +127,7 @@ void arginit(int ac, char **av) /* set up ARGV and ARGC */ ARGC = &setsymtab("ARGC", "", (Awkfloat) ac, NUM, symtab)->fval; cp = setsymtab("ARGV", "", 0.0, ARR, symtab); ARGVtab = makesymtab(NSYMTAB); /* could be (int) ARGC as well */ + free(cp->sval); cp->sval = (char *) ARGVtab; for (i = 0; i < ac; i++) { sprintf(temp, "%d", i); @@ -144,6 +146,7 @@ void envinit(char **envp) /* set up ENVIRON variable */ cp = setsymtab("ENVIRON", "", 0.0, ARR, symtab); ENVtab = makesymtab(NSYMTAB); + free(cp->sval); cp->sval = (char *) ENVtab; for ( ; *envp; envp++) { if ((p = strchr(*envp, '=')) == NULL) @@ -524,8 +527,17 @@ Cell *catstr(Cell *a, Cell *b) /* concatenate a and b */ if (p == NULL) FATAL("out of space concatenating %s and %s", sa, sb); snprintf(p, l, "%s%s", sa, sb); - c = setsymtab(p, p, 0.0, CON|STR|DONTFREE, symtab); + + l++; // add room for ' ' + char *newbuf = malloc(l); + if (newbuf == NULL) + FATAL("out of space concatenating %s and %s", sa, sb); + // See string() in lex.c; a string "xx" is stored in the symbol + // table as "xx ". + snprintf(newbuf, l, "%s ", p); + c = setsymtab(newbuf, p, 0.0, CON|STR|DONTFREE, symtab); free(p); + free(newbuf); return c; } |