📄 field.c
字号:
/* * field.c - routines for dealing with fields and record parsing *//* * Copyright (C) 1986, 1988, 1989, 1991, 1992 the Free Software Foundation, Inc. * * This file is part of GAWK, the GNU implementation of the * AWK Progamming 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 GAWK; see the file COPYING. If not, write to * the Free Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */#include "awk.h"static int (*parse_field) P((int, char **, int, NODE *, Regexp *, void (*)(), NODE *));static void rebuild_record P((void));static int re_parse_field P((int, char **, int, NODE *, Regexp *, void (*)(), NODE *));static int def_parse_field P((int, char **, int, NODE *, Regexp *, void (*)(), NODE *));static int sc_parse_field P((int, char **, int, NODE *, Regexp *, void (*)(), NODE *));static int fw_parse_field P((int, char **, int, NODE *, Regexp *, void (*)(), NODE *));static void set_element P((int, char *, int, NODE *));static void grow_fields_arr P((int 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 int resave_fs;static NODE *save_FS; /* save current value of FS when line is read, * to be used in deferred parsing */NODE **fields_arr; /* array of pointers to the field nodes */int field0_valid; /* $(>0) has not been changed yet */int default_FS;static NODE **nodes; /* permanent repository of field nodes */static int *FIELDWIDTHS = NULL;voidinit_fields(){ NODE *n; emalloc(fields_arr, NODE **, sizeof(NODE *), "init_fields"); emalloc(nodes, NODE **, sizeof(NODE *), "init_fields"); getnode(n); *n = *Nnull_string; fields_arr[0] = nodes[0] = n; parse_extent = fields_arr[0]->stptr; save_FS = dupnode(FS_node->var_value); field0_valid = 1;}static voidgrow_fields_arr(num)int num;{ register int t; register NODE *n; erealloc(fields_arr, NODE **, (num + 1) * sizeof(NODE *), "set_field"); erealloc(nodes, NODE **, (num+1) * sizeof(NODE *), "set_field"); for (t = nf_high_water+1; t <= num; t++) { getnode(n); *n = *Nnull_string; fields_arr[t] = nodes[t] = n; } nf_high_water = num;}/*ARGSUSED*/static voidset_field(num, str, len, dummy)int num;char *str;int 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 = nodes[num]; n->stptr = str; n->stlen = len; n->flags = (PERM|STR|STRING|MAYBE_NUM); fields_arr[num] = n;}/* Someone assigned a value to $(something). Fix up $0 to be right */static voidrebuild_record(){ register int tlen; register NODE *tmp; NODE *ofs; char *ops; register char *cops; register NODE **ptr; register int ofslen; tlen = 0; ofs = force_string(OFS_node->var_value); ofslen = ofs->stlen; ptr = &fields_arr[NF]; while (ptr > &fields_arr[0]) { tmp = force_string(*ptr); tlen += tmp->stlen; ptr--; } tlen += (NF - 1) * ofslen; if (tlen < 0) tlen = 0; emalloc(ops, char *, tlen + 2, "fix_fields"); cops = ops; ops[0] = '\0'; for (ptr = &fields_arr[1]; ptr <= &fields_arr[NF]; ptr++) { tmp = *ptr; if (tmp->stlen == 1) *cops++ = tmp->stptr[0]; else if (tmp->stlen != 0) { memcpy(cops, tmp->stptr, tmp->stlen); cops += tmp->stlen; } if (ptr != &fields_arr[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); unref(fields_arr[0]); fields_arr[0] = tmp; field0_valid = 1;}/* * 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. */voidset_record(buf, cnt, freeold)char *buf;int cnt;int freeold;{ register int i; NF = -1; for (i = 1; i <= parse_high_water; i++) { unref(fields_arr[i]); } parse_high_water = 0; if (freeold) { unref(fields_arr[0]); if (resave_fs) { resave_fs = 0; unref(save_FS); save_FS = dupnode(FS_node->var_value); } nodes[0]->stptr = buf; nodes[0]->stlen = cnt; nodes[0]->stref = 1; nodes[0]->flags = (STRING|STR|PERM|MAYBE_NUM); fields_arr[0] = nodes[0]; } fields_arr[0]->flags |= MAYBE_NUM; field0_valid = 1;}voidreset_record(){ (void) force_string(fields_arr[0]); set_record(fields_arr[0]->stptr, fields_arr[0]->stlen, 0);}voidset_NF(){ register int i; NF = (int) force_number(NF_node->var_value); if (NF > nf_high_water) grow_fields_arr(NF); for (i = parse_high_water + 1; i <= NF; i++) { unref(fields_arr[i]); fields_arr[i] = Nnull_string; } field0_valid = 0;}/* * 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 intre_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 */int len;NODE *fs;Regexp *rp;void (*set) (); /* routine to set the value of the parsed field */NODE *n;{ register char *scan = *buf; register int 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 == 0 && default_FS) while (scan < end && isspace(*scan)) scan++; field = scan; while (scan < end && research(rp, scan, 0, (int)(end - scan), 1) != -1 && nf < up_to) { if (REEND(rp, scan) == RESTART(rp, scan)) { /* null match */ scan++; if (scan == end) { (*set)(++nf, field, scan - field, n); up_to = nf; break; } continue; } (*set)(++nf, field, scan + RESTART(rp, scan) - field, n); scan += REEND(rp, scan); field = scan; if (scan == end) /* FS at end of record */ (*set)(++nf, field, 0, n); } if (nf != up_to && scan < end) { (*set)(++nf, scan, (int)(end - scan), n); scan = end; } *buf = scan; return (nf);}/* * 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 intdef_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 */int len;NODE *fs;Regexp *rp;void (*set) (); /* routine to set the value of the parsed field */NODE *n;{ register char *scan = *buf; register int 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; /* 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, (int)(scan - field), n); if (scan == end) break; } /* everything done, restore original char at *end */ *end = sav; *buf = scan; return nf;
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -