diff options
Diffstat (limited to 'field.c')
-rw-r--r-- | field.c | 79 |
1 files changed, 55 insertions, 24 deletions
@@ -27,26 +27,26 @@ typedef void (* Setfunc) P((int, char*, int, NODE *)); -static int (*parse_field) P((int, char **, int, NODE *, +static long (*parse_field) P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); static void rebuild_record P((void)); -static int re_parse_field P((int, char **, int, NODE *, +static long re_parse_field P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); -static int def_parse_field P((int, char **, int, NODE *, +static long def_parse_field P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); -static int sc_parse_field P((int, char **, int, NODE *, +static long sc_parse_field P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); -static int fw_parse_field P((int, char **, int, NODE *, +static long fw_parse_field P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); static void set_element P((int, char *, int, NODE *)); -static void grow_fields_arr P((int num)); +static void grow_fields_arr P((long num)); static void set_field P((int num, char *str, int len, NODE *dummy)); static Regexp *FS_regexp = NULL; static char *parse_extent; /* marks where to restart parse of record */ -static int parse_high_water=0; /* field number that we have parsed so far */ -static int nf_high_water = 0; /* size of fields_arr */ +static long parse_high_water=0; /* field number that we have parsed so far */ +static long nf_high_water = 0; /* size of fields_arr */ static int resave_fs; static NODE *save_FS; /* save current value of FS when line is read, * to be used in deferred parsing @@ -76,7 +76,7 @@ init_fields() static void grow_fields_arr(num) -int num; +long num; { register int t; register NODE *n; @@ -134,7 +134,7 @@ rebuild_record() tlen += (NF - 1) * ofslen; if ((long)tlen < 0) tlen = 0; - emalloc(ops, char *, tlen + 2, "fix_fields"); + emalloc(ops, char *, tlen + 2, "rebuild_record"); cops = ops; ops[0] = '\0'; for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) { @@ -206,7 +206,7 @@ set_NF() { register int i; - NF = (int) force_number(NF_node->var_value); + NF = (long) force_number(NF_node->var_value); if (NF > nf_high_water) grow_fields_arr(NF); for (i = parse_high_water + 1; i <= NF; i++) { @@ -221,7 +221,7 @@ set_NF() * via (*parse_field)(). This variation is for when FS is a regular * expression -- either user-defined or because RS=="" and FS==" " */ -static int +static long re_parse_field(up_to, buf, len, fs, rp, set, n) int up_to; /* parse only up to this field number */ char **buf; /* on input: string to parse; on output: point to start next */ @@ -242,7 +242,7 @@ NODE *n; return nf; if (*RS == 0 && default_FS) - while (scan < end && isspace(*scan)) + while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n')) scan++; field = scan; while (scan < end @@ -277,7 +277,7 @@ NODE *n; * via (*parse_field)(). This variation is for when FS is a single space * character. */ -static int +static long def_parse_field(up_to, buf, len, fs, rp, set, n) int up_to; /* parse only up to this field number */ char **buf; /* on input: string to parse; on output: point to start next */ @@ -331,7 +331,7 @@ NODE *n; * via (*parse_field)(). This variation is for when FS is a single character * other than space. */ -static int +static long sc_parse_field(up_to, buf, len, fs, rp, set, n) int up_to; /* parse only up to this field number */ char **buf; /* on input: string to parse; on output: point to start next */ @@ -363,14 +363,18 @@ NODE *n; /* because it will be destroyed now: */ *end = fschar; /* sentinel character */ - for (; nf < up_to; scan++) { + for (; nf < up_to;) { field = scan; - while (*scan++ != fschar) - ; - scan--; + while (*scan != fschar) + scan++; (*set)(++nf, field, (int)(scan - field), n); if (scan == end) break; + scan++; + if (scan == end) { /* FS at end of record */ + (*set)(++nf, field, 0, n); + break; + } } /* everything done, restore original char at *end */ @@ -384,7 +388,7 @@ NODE *n; * this is called both from get_field() and from do_split() * via (*parse_field)(). This variation is for fields are fixed widths. */ -static int +static long fw_parse_field(up_to, buf, len, fs, rp, set, n) int up_to; /* parse only up to this field number */ char **buf; /* on input: string to parse; on output: point to start next */ @@ -395,7 +399,7 @@ Setfunc set; /* routine to set the value of the parsed field */ NODE *n; { register char *scan = *buf; - register int nf = parse_high_water; + register long nf = parse_high_water; register char *end = scan + len; if (up_to == HUGE) @@ -515,11 +519,21 @@ NODE *tree; NODE *t1, *t2, *t3, *tmp; NODE *fs; char *s; - int (*parseit)P((int, char **, int, NODE *, + long (*parseit)P((int, char **, int, NODE *, Regexp *, Setfunc, NODE *)); Regexp *rp = NULL; - t1 = tree_eval(tree->lnode); + + /* + * do dupnode(), to avoid problems like + * x = split(a[1], a, "blah") + * since we assoc_clear the array. gack. + * this also gives up complete call by value semantics. + */ + tmp = tree_eval(tree->lnode); + t1 = dupnode(tmp); + free_temp(tmp); + t2 = tree->rnode->lnode; t3 = tree->rnode->rnode->lnode; @@ -552,7 +566,7 @@ NODE *tree; s = t1->stptr; tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int)t1->stlen, fs, rp, set_element, t2)); - free_temp(t1); + unref(t1); free_temp(t3); return tmp; } @@ -563,6 +577,13 @@ set_FS() char buf[10]; NODE *fs; + /* + * If changing the way fields are split, obey least-suprise + * semantics, and force $0 to be split totally. + */ + if (fields_arr != NULL) + (void) get_field(HUGE - 1, 0); + buf[0] = '\0'; default_FS = 0; if (FS_regexp) { @@ -588,6 +609,9 @@ set_FS() else if (fs->stptr[0] != ' ' && fs->stlen == 1) { if (IGNORECASE == 0) parse_field = sc_parse_field; + else if (fs->stptr[0] == '\\') + /* yet another special case */ + strcpy(buf, "[\\\\]"); else sprintf(buf, "[%c]", fs->stptr[0]); } @@ -627,6 +651,13 @@ set_FIELDWIDTHS() if (do_unix) /* quick and dirty, does the trick */ return; + /* + * If changing the way fields are split, obey least-suprise + * semantics, and force $0 to be split totally. + */ + if (fields_arr != NULL) + (void) get_field(HUGE - 1, 0); + parse_field = fw_parse_field; scan = force_string(FIELDWIDTHS_node->var_value)->stptr; end = scan + 1; |