diff options
Diffstat (limited to 'contrib/awk/field.c')
-rw-r--r-- | contrib/awk/field.c | 998 |
1 files changed, 0 insertions, 998 deletions
diff --git a/contrib/awk/field.c b/contrib/awk/field.c deleted file mode 100644 index 1d0f22e..0000000 --- a/contrib/awk/field.c +++ /dev/null @@ -1,998 +0,0 @@ -/* - * field.c - routines for dealing with fields and record parsing - */ - -/* - * Copyright (C) 1986, 1988, 1989, 1991-2001 the Free Software Foundation, Inc. - * - * This file is part of GAWK, the GNU implementation of the - * AWK Programming Language. - * - * GAWK is free software; you can redistribute it and/or modify - * it under the terms of the GNU General Public License as published by - * the Free Software Foundation; either version 2 of the License, or - * (at your option) any later version. - * - * GAWK is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA - * - * $FreeBSD$ - */ - -#include "awk.h" - -typedef void (* Setfunc) P((long, char *, long, NODE *)); - -static long (*parse_field) P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static void rebuild_record P((void)); -static long re_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static long def_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static long posix_def_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static long null_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static long sc_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static long fw_parse_field P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); -static void set_element P((long num, char * str, long len, NODE *arr)); -static void grow_fields_arr P((long num)); -static void set_field P((long num, char *str, long len, NODE *dummy)); -static void update_PROCINFO P((char *subscript, char *str)); - - -static char *parse_extent; /* marks where to restart parse of record */ -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 - */ -static int *FIELDWIDTHS = NULL; - -NODE **fields_arr; /* array of pointers to the field nodes */ -int field0_valid; /* $(>0) has not been changed yet */ -int default_FS; /* TRUE when FS == " " */ -Regexp *FS_regexp = NULL; -static NODE *Null_field = NULL; - -/* using_FIELDWIDTHS --- static function, macro to avoid overhead */ -#define using_FIELDWIDTHS() (parse_field == fw_parse_field) - -/* init_fields --- set up the fields array to start with */ - -void -init_fields() -{ - NODE *n; - - emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields"); - getnode(n); - *n = *Nnull_string; - n->flags |= (SCALAR|FIELD); - n->flags &= ~PERM; - fields_arr[0] = n; - parse_extent = fields_arr[0]->stptr; - save_FS = dupnode(FS_node->var_value); - getnode(Null_field); - *Null_field = *Nnull_string; - Null_field->flags |= (SCALAR|FIELD); - Null_field->flags &= ~(NUM|NUMBER|MAYBE_NUM|PERM); - field0_valid = TRUE; -} - -/* grow_fields --- acquire new fields as needed */ - -static void -grow_fields_arr(long num) -{ - register int t; - register NODE *n; - - erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "grow_fields_arr"); - for (t = nf_high_water + 1; t <= num; t++) { - getnode(n); - *n = *Null_field; - fields_arr[t] = n; - } - nf_high_water = num; -} - -/* set_field --- set the value of a particular field */ - -/*ARGSUSED*/ -static void -set_field(long num, - char *str, - long len, - NODE *dummy) /* not used -- just to make interface same as set_element */ -{ - register NODE *n; - - if (num > nf_high_water) - grow_fields_arr(num); - n = fields_arr[num]; - n->stptr = str; - n->stlen = len; - n->flags = (STR|STRING|MAYBE_NUM|SCALAR|FIELD); -} - -/* rebuild_record --- Someone assigned a value to $(something). - Fix up $0 to be right */ - -static void -rebuild_record() -{ - /* - * use explicit unsigned longs for lengths, in case - * a size_t isn't big enough. - */ - register unsigned long tlen; - register unsigned long ofslen; - register NODE *tmp; - NODE *ofs; - char *ops; - register char *cops; - long i; - - assert(NF != -1); - - tlen = 0; - ofs = force_string(OFS_node->var_value); - ofslen = ofs->stlen; - for (i = NF; i > 0; i--) { - tmp = fields_arr[i]; - tmp = force_string(tmp); - tlen += tmp->stlen; - } - tlen += (NF - 1) * ofslen; - if ((long) tlen < 0) - tlen = 0; - emalloc(ops, char *, tlen + 2, "rebuild_record"); - cops = ops; - ops[0] = '\0'; - for (i = 1; i <= NF; i++) { - tmp = fields_arr[i]; - /* copy field */ - if (tmp->stlen == 1) - *cops++ = tmp->stptr[0]; - else if (tmp->stlen != 0) { - memcpy(cops, tmp->stptr, tmp->stlen); - cops += tmp->stlen; - } - /* copy OFS */ - if (i != NF) { - if (ofslen == 1) - *cops++ = ofs->stptr[0]; - else if (ofslen != 0) { - memcpy(cops, ofs->stptr, ofslen); - cops += ofslen; - } - } - } - tmp = make_str_node(ops, tlen, ALREADY_MALLOCED); - - /* - * Since we are about to unref fields_arr[0], we want to find - * any fields that still point into it, and have them point - * into the new field zero. This has to be done intelligently, - * so that unrefing a field doesn't try to unref into the old $0. - */ - for (cops = ops, i = 1; i <= NF; i++) { - if (fields_arr[i]->stlen > 0) { - NODE *n; - getnode(n); - - if ((fields_arr[i]->flags & FIELD) == 0) { - *n = *Null_field; - n->stlen = fields_arr[i]->stlen; - if ((fields_arr[i]->flags & (NUM|NUMBER)) != 0) { - n->flags |= (fields_arr[i]->flags & (NUM|NUMBER)); - n->numbr = fields_arr[i]->numbr; - } - } else { - *n = *(fields_arr[i]); - n->flags &= ~(MALLOC|TEMP|PERM|STRING); - } - - n->stptr = cops; - unref(fields_arr[i]); - fields_arr[i] = n; - } - cops += fields_arr[i]->stlen + ofslen; - } - - unref(fields_arr[0]); - - fields_arr[0] = tmp; - field0_valid = TRUE; -} - -/* - * set_record: - * setup $0, but defer parsing rest of line until reference is made to $(>0) - * or to NF. At that point, parse only as much as necessary. - * - * Manage a private buffer for the contents of $0. Doing so keeps us safe - * if `getline var' decides to rearrange the contents of the IOBUF that - * $0 might have been pointing into. The cost is the copying of the buffer; - * but better correct than fast. - */ -void -set_record(char *buf, /* ignored if ! freeold */ - int cnt, /* ignored if ! freeold */ - int freeold) -{ - register int i; - NODE *n; - static char *databuf; - static unsigned long databuf_size; -#define INITIAL_SIZE 512 -#define MAX_SIZE ((unsigned long) ~0) /* maximally portable ... */ - - NF = -1; - for (i = 1; i <= parse_high_water; i++) { - unref(fields_arr[i]); - getnode(n); - *n = *Null_field; - fields_arr[i] = n; - } - - parse_high_water = 0; - /* - * $0 = $0 should resplit using the current value of FS, thus, - * this is executed orthogonally to the value of freeold. - */ - if (resave_fs) { - resave_fs = FALSE; - unref(save_FS); - save_FS = dupnode(FS_node->var_value); - } - if (freeold) { - /* buffer management: */ - if (databuf_size == 0) { /* first time */ - emalloc(databuf, char *, INITIAL_SIZE, "set_record"); - databuf_size = INITIAL_SIZE; - memset(databuf, '\0', INITIAL_SIZE); - - } - /* - * Make sure there's enough room. Since we sometimes need - * to place a sentinel at the end, we make sure - * databuf_size is > cnt after allocation. - */ - if (cnt >= databuf_size) { - while (cnt >= databuf_size && databuf_size <= MAX_SIZE) - databuf_size *= 2; - erealloc(databuf, char *, databuf_size, "set_record"); - memset(databuf, '\0', databuf_size); - } - /* copy the data */ - memcpy(databuf, buf, cnt); - - /* manage field 0: */ - unref(fields_arr[0]); - getnode(n); - n->stptr = databuf; - n->stlen = cnt; - n->stref = 1; - n->type = Node_val; - n->stfmt = -1; - n->flags = (STRING|STR|MAYBE_NUM|SCALAR|FIELD); - fields_arr[0] = n; - } - fields_arr[0]->flags |= MAYBE_NUM; - field0_valid = TRUE; - -#undef INITIAL_SIZE -#undef MAX_SIZE -} - -/* reset_record --- start over again with current $0 */ - -void -reset_record() -{ - (void) force_string(fields_arr[0]); - set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, FALSE); -} - -/* set_NF --- handle what happens to $0 and fields when NF is changed */ - -void -set_NF() -{ - register int i; - NODE *n; - - assert(NF != -1); - - NF = (long) force_number(NF_node->var_value); - if (NF > nf_high_water) - grow_fields_arr(NF); - if (parse_high_water < NF) { - for (i = parse_high_water + 1; i <= NF; i++) { - unref(fields_arr[i]); - getnode(n); - *n = *Null_field; - fields_arr[i] = n; - } - } else if (parse_high_water > 0) { - for (i = NF + 1; i <= parse_high_water; i++) { - unref(fields_arr[i]); - getnode(n); - *n = *Null_field; - fields_arr[i] = n; - } - parse_high_water = NF; - } - field0_valid = FALSE; -} - -/* - * re_parse_field --- parse fields using a regexp. - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for when FS is a regular - * expression -- either user-defined or because RS=="" and FS==" " - */ -static long -re_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register long nf = parse_high_water; - register char *field; - register char *end = scan + len; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - - if (RS_is_null && default_FS) - while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n')) - scan++; - field = scan; - while (scan < end - && research(rp, scan, 0, (end - scan), TRUE) != -1 - && nf < up_to) { - if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */ - scan++; - if (scan == end) { - (*set)(++nf, field, (long)(scan - field), n); - up_to = nf; - break; - } - continue; - } - (*set)(++nf, field, - (long)(scan + RESTART(rp, scan) - field), n); - scan += REEND(rp, scan); - field = scan; - if (scan == end) /* FS at end of record */ - (*set)(++nf, field, 0L, n); - } - if (nf != up_to && scan < end) { - (*set)(++nf, scan, (long)(end - scan), n); - scan = end; - } - *buf = scan; - return (nf); -} - -/* - * def_parse_field --- default field parsing. - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for when FS is a single space - * character. - */ - -static long -def_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register long nf = parse_high_water; - register char *field; - register char *end = scan + len; - char sav; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - - /* - * Nasty special case. If FS set to "", return whole record - * as first field. This is not worth a separate function. - */ - if (fs->stlen == 0) { - (*set)(++nf, *buf, len, n); - *buf += len; - return nf; - } - - /* before doing anything save the char at *end */ - sav = *end; - /* because it will be destroyed now: */ - - *end = ' '; /* sentinel character */ - for (; nf < up_to; scan++) { - /* - * special case: fs is single space, strip leading whitespace - */ - while (scan < end && (*scan == ' ' || *scan == '\t' || *scan == '\n')) - scan++; - if (scan >= end) - break; - field = scan; - while (*scan != ' ' && *scan != '\t' && *scan != '\n') - scan++; - (*set)(++nf, field, (long)(scan - field), n); - if (scan == end) - break; - } - - /* everything done, restore original char at *end */ - *end = sav; - - *buf = scan; - return nf; -} - -/* - * posix_def_parse_field --- default field parsing. - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for when FS is a single space - * character. The only difference between this and def_parse_field() - * is that this one does not allow newlines to separate fields. - */ - -static long -posix_def_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register long nf = parse_high_water; - register char *field; - register char *end = scan + len; - char sav; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - - /* - * Nasty special case. If FS set to "", return whole record - * as first field. This is not worth a separate function. - */ - if (fs->stlen == 0) { - (*set)(++nf, *buf, len, n); - *buf += len; - return nf; - } - - /* before doing anything save the char at *end */ - sav = *end; - /* because it will be destroyed now: */ - - *end = ' '; /* sentinel character */ - for (; nf < up_to; scan++) { - /* - * special case: fs is single space, strip leading whitespace - */ - while (scan < end && (*scan == ' ' || *scan == '\t')) - scan++; - if (scan >= end) - break; - field = scan; - while (*scan != ' ' && *scan != '\t') - scan++; - (*set)(++nf, field, (long)(scan - field), n); - if (scan == end) - break; - } - - /* everything done, restore original char at *end */ - *end = sav; - - *buf = scan; - return nf; -} - -/* - * null_parse_field --- each character is a separate field - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for when FS is the null string. - */ -static long -null_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register long nf = parse_high_water; - register char *end = scan + len; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - - for (; nf < up_to && scan < end; scan++) - (*set)(++nf, scan, 1L, n); - - *buf = scan; - return nf; -} - -/* - * sc_parse_field --- single character field separator - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for when FS is a single character - * other than space. - */ -static long -sc_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register char fschar; - register long nf = parse_high_water; - register char *field; - register char *end = scan + len; - int onecase; - char sav; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - - if (RS_is_null && fs->stlen == 0) - fschar = '\n'; - else - fschar = fs->stptr[0]; - - onecase = (IGNORECASE && ISALPHA(fschar)); - if (onecase) - fschar = casetable[(unsigned char) fschar]; - - /* before doing anything save the char at *end */ - sav = *end; - /* because it will be destroyed now: */ - *end = fschar; /* sentinel character */ - - for (; nf < up_to;) { - field = scan; - if (onecase) { - while (casetable[(unsigned char) *scan] != fschar) - scan++; - } else { - while (*scan != fschar) - scan++; - } - (*set)(++nf, field, (long)(scan - field), n); - if (scan == end) - break; - scan++; - if (scan == end) { /* FS at end of record */ - (*set)(++nf, field, 0L, n); - break; - } - } - - /* everything done, restore original char at *end */ - *end = sav; - - *buf = scan; - return nf; -} - -/* - * fw_parse_field --- field parsing using FIELDWIDTHS spec - * - * This is called both from get_field() and from do_split() - * via (*parse_field)(). This variation is for fields are fixed widths. - */ -static long -fw_parse_field(long up_to, /* parse only up to this field number */ - char **buf, /* on input: string to parse; on output: point to start next */ - int len, - NODE *fs, - Regexp *rp, - Setfunc set, /* routine to set the value of the parsed field */ - NODE *n) -{ - register char *scan = *buf; - register long nf = parse_high_water; - register char *end = scan + len; - - if (up_to == HUGE) - nf = 0; - if (len == 0) - return nf; - for (; nf < up_to && (len = FIELDWIDTHS[nf+1]) != -1; ) { - if (len > end - scan) - len = end - scan; - (*set)(++nf, scan, (long) len, n); - scan += len; - } - if (len == -1) - *buf = end; - else - *buf = scan; - return nf; -} - -/* get_field --- return a particular $n */ - -/* assign is not NULL if this field is on the LHS of an assign */ - -NODE ** -get_field(register long requested, Func_ptr *assign) -{ - /* - * if requesting whole line but some other field has been altered, - * then the whole line must be rebuilt - */ - if (requested == 0) { - if (! field0_valid) { - /* first, parse remainder of input record */ - if (NF == -1) { - NF = (*parse_field)(HUGE-1, &parse_extent, - fields_arr[0]->stlen - - (parse_extent - fields_arr[0]->stptr), - save_FS, FS_regexp, set_field, - (NODE *) NULL); - parse_high_water = NF; - } - rebuild_record(); - } - if (assign != NULL) - *assign = reset_record; - return &fields_arr[0]; - } - - /* assert(requested > 0); */ - - if (assign != NULL) - field0_valid = FALSE; /* $0 needs reconstruction */ - - if (requested <= parse_high_water) /* already parsed this field */ - return &fields_arr[requested]; - - if (NF == -1) { /* have not yet parsed to end of record */ - /* - * parse up to requested fields, calling set_field() for each, - * saving in parse_extent the point where the parse left off - */ - if (parse_high_water == 0) /* starting at the beginning */ - parse_extent = fields_arr[0]->stptr; - parse_high_water = (*parse_field)(requested, &parse_extent, - fields_arr[0]->stlen - (parse_extent - fields_arr[0]->stptr), - save_FS, FS_regexp, set_field, (NODE *) NULL); - - /* - * if we reached the end of the record, set NF to the number of - * fields so far. Note that requested might actually refer to - * a field that is beyond the end of the record, but we won't - * set NF to that value at this point, since this is only a - * reference to the field and NF only gets set if the field - * is assigned to -- this case is handled below - */ - if (parse_extent == fields_arr[0]->stptr + fields_arr[0]->stlen) - NF = parse_high_water; - if (requested == HUGE-1) /* HUGE-1 means set NF */ - requested = parse_high_water; - } - if (parse_high_water < requested) { /* requested beyond end of record */ - if (assign != NULL) { /* expand record */ - if (requested > nf_high_water) - grow_fields_arr(requested); - - NF = requested; - parse_high_water = requested; - } else - return &Null_field; - } - - return &fields_arr[requested]; -} - -/* set_element --- set an array element, used by do_split() */ - -static void -set_element(long num, char *s, long len, NODE *n) -{ - register NODE *it; - - it = make_string(s, len); - it->flags |= MAYBE_NUM; - *assoc_lookup(n, tmp_number((AWKNUM) (num)), FALSE) = it; -} - -/* do_split --- implement split(), semantics are same as for field splitting */ - -NODE * -do_split(NODE *tree) -{ - NODE *src, *arr, *sep, *tmp; - NODE *fs; - char *s; - long (*parseit) P((long, char **, int, NODE *, - Regexp *, Setfunc, NODE *)); - Regexp *rp = NULL; - - /* - * do dupnode(), to avoid problems like - * x = split(a[1], a, "blah") - * since we assoc_clear the array. gack. - * this also gives us complete call by value semantics. - */ - tmp = tree_eval(tree->lnode); - src = dupnode(tmp); - free_temp(tmp); - - arr = tree->rnode->lnode; - if (tree->rnode->rnode != NULL) - sep = tree->rnode->rnode->lnode; /* 3rd arg */ - else - sep = NULL; - - (void) force_string(src); - - if (arr->type == Node_param_list) - arr = stack_ptr[arr->param_cnt]; - if (arr->type == Node_array_ref) - arr = arr->orig_array; - if (arr->type != Node_var && arr->type != Node_var_array) - fatal(_("split: second argument is not an array")); - arr->type = Node_var_array; - assoc_clear(arr); - - if (src->stlen == 0) { - /* - * Skip the work if first arg is the null string. - * Check after clearing the array, to preserve - * correct semantics. - */ - tmp = tmp_number((AWKNUM) 0); - goto out; - } - - if ((sep->re_flags & FS_DFLT) != 0 && ! using_FIELDWIDTHS()) { - parseit = parse_field; - fs = force_string(FS_node->var_value); - rp = FS_regexp; - } else { - tmp = force_string(tree_eval(sep->re_exp)); - if (tmp->stlen == 0) { - static short warned = FALSE; - - parseit = null_parse_field; - - if (do_lint && ! warned) { - warned = TRUE; - lintwarn(_("split: null string for third arg is a gawk extension")); - } - } else if (tmp->stlen == 1 && (sep->re_flags & CONST) == 0) { - if (tmp->stptr[0] == ' ') { - if (do_posix) - parseit = posix_def_parse_field; - else - parseit = def_parse_field; - } else - parseit = sc_parse_field; - } else { - parseit = re_parse_field; - rp = re_update(sep); - } - fs = tmp; - } - - s = src->stptr; - tmp = tmp_number((AWKNUM) (*parseit)(HUGE, &s, (int) src->stlen, - fs, rp, set_element, arr)); -out: - unref(src); - free_temp(sep); - return tmp; -} - -/* set_FIELDWIDTHS --- handle an assignment to FIELDWIDTHS */ - -void -set_FIELDWIDTHS() -{ - register char *scan; - char *end; - register int i; - static int fw_alloc = 1; - static int warned = FALSE; - extern double strtod(); - - if (do_lint && ! warned) { - warned = TRUE; - lintwarn(_("`FIELDWIDTHS' is a gawk extension")); - } - if (do_traditional) /* 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; - if (FIELDWIDTHS == NULL) - emalloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS"); - FIELDWIDTHS[0] = 0; - for (i = 1; ; i++) { - if (i >= fw_alloc) { - fw_alloc *= 2; - erealloc(FIELDWIDTHS, int *, fw_alloc * sizeof(int), "set_FIELDWIDTHS"); - } - FIELDWIDTHS[i] = (int) strtod(scan, &end); - if (end == scan) - break; - if (FIELDWIDTHS[i] <= 0) - fatal(_("field %d in FIELDWIDTHS, must be > 0"), i); - scan = end; - } - FIELDWIDTHS[i] = -1; - - update_PROCINFO("FS", "FIELDWIDTHS"); -} - -void -set_FS_if_not_FIELDWIDTHS() -{ - if (parse_field != fw_parse_field) - set_FS(); -} - -/* set_FS --- handle things when FS is assigned to */ - -void -set_FS() -{ - char buf[10]; - NODE *fs; - static NODE *save_fs = NULL; - static NODE *save_rs = NULL; - - /* - * 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); - - if (! (save_fs && cmp_nodes(FS_node->var_value, save_fs) == 0 - && save_rs && cmp_nodes(RS_node->var_value, save_rs) == 0)) { - unref(save_fs); - save_fs = dupnode(FS_node->var_value); - unref(save_rs); - save_rs = dupnode(RS_node->var_value); - resave_fs = TRUE; - if (FS_regexp) { - refree(FS_regexp); - FS_regexp = NULL; - } - } - buf[0] = '\0'; - default_FS = FALSE; - fs = force_string(FS_node->var_value); - if (! do_traditional && fs->stlen == 0) { - static short warned = FALSE; - - parse_field = null_parse_field; - - if (do_lint && ! warned) { - warned = TRUE; - lintwarn(_("null string for `FS' is a gawk extension")); - } - } else if (fs->stlen > 1) - parse_field = re_parse_field; - else if (RS_is_null) { - parse_field = sc_parse_field; - if (fs->stlen == 1) { - if (fs->stptr[0] == ' ') { - default_FS = TRUE; - strcpy(buf, "[ \t\n]+"); - } else if (fs->stptr[0] != '\n') - sprintf(buf, "[%c\n]", fs->stptr[0]); - } - } else { - if (do_posix) - parse_field = posix_def_parse_field; - else - parse_field = def_parse_field; - if (fs->stptr[0] == ' ' && fs->stlen == 1) - default_FS = TRUE; - else if (fs->stptr[0] != ' ' && fs->stlen == 1) { - if (! ISALPHA(fs->stptr[0]) || ! IGNORECASE) - parse_field = sc_parse_field; - else if (fs->stptr[0] == '\\') - /* yet another special case */ - strcpy(buf, "[\\\\]"); - else - sprintf(buf, "[%c]", fs->stptr[0]); - } - } - if (buf[0] != '\0') { - FS_regexp = make_regexp(buf, strlen(buf), IGNORECASE, TRUE); - parse_field = re_parse_field; - } else if (parse_field == re_parse_field) { - FS_regexp = make_regexp(fs->stptr, fs->stlen, IGNORECASE, TRUE); - } else - FS_regexp = NULL; - - update_PROCINFO("FS", "FS"); -} - -/* using_fieldwidths --- is FS or FIELDWIDTHS in use? */ - -int -using_fieldwidths() -{ - return using_FIELDWIDTHS(); -} - -/* update_PROCINFO --- update PROCINFO[sub] when FS or FIELDWIDTHS set */ - -static void -update_PROCINFO(char *subscript, char *str) -{ - NODE **aptr; - - if (PROCINFO_node == NULL) - return; - - aptr = assoc_lookup(PROCINFO_node, tmp_string(subscript, strlen(subscript)), FALSE); - assign_val(aptr, tmp_string(str, strlen(str))); -} |