#define OC_B OC_BUILTIN
-static const char tokenlist[] =
+static const char tokenlist[] ALIGN1 =
"\1(" NTC
"\1)" NTC
"\1/" NTC /* REGEXP */
ENVIRON, F0, NUM_INTERNAL_VARS
};
-static const char vNames[] =
+static const char vNames[] ALIGN1 =
"CONVFMT\0" "OFMT\0" "FS\0*" "OFS\0"
"ORS\0" "RS\0*" "RT\0" "FILENAME\0"
"SUBSEP\0" "ARGIND\0" "ARGC\0" "ARGV\0"
"NR\0" "NF\0*" "IGNORECASE\0*"
"ENVIRON\0" "$\0*" "\0";
-static const char vValues[] =
+static const char vValues[] ALIGN1 =
"%.6g\0" "%.6g\0" " \0" " \0"
"\n\0" "\n\0" "\0" "\0"
"\034\0"
"\377";
/* hash size may grow to these values */
-#define FIRST_PRIME 61;
-static const unsigned PRIMES[] = { 251, 1021, 4093, 16381, 65521 };
-enum { NPRIMES = sizeof(PRIMES) / sizeof(PRIMES[0]) };
+#define FIRST_PRIME 61
+static const uint16_t PRIMES[] ALIGN2 = { 251, 1021, 4093, 16381, 65521 };
-/* globals */
+/* Globals. Split in two parts so that first one is addressed
+ * with (mostly short) negative offsets */
struct globals {
- /* former 'struct t' */
- uint32_t t_info; /* often used */
- uint32_t t_tclass;
- char *t_string;
- double t_double;
- int t_lineno;
- int t_rollback;
-
- /* the rest */
- smallint icase;
- smallint exiting;
- smallint nextrec;
- smallint nextfile;
- smallint is_f0_split;
chain beginseq, mainseq, endseq, *seq;
node *break_ptr, *continue_ptr;
rstream *iF;
nvblock *g_cb;
char *g_pos;
char *g_buf;
+ smallint icase;
+ smallint exiting;
+ smallint nextrec;
+ smallint nextfile;
+ smallint is_f0_split;
+};
+struct globals2 {
+ uint32_t t_info; /* often used */
+ uint32_t t_tclass;
+ char *t_string;
+ int t_lineno;
+ int t_rollback;
+
+ var *intvar[NUM_INTERNAL_VARS]; /* often used */
/* former statics from various functions */
char *split_f0__fstrings;
- rstream next_input_file__rsm;
- smallint next_input_file__files_happen;
-
- smallint next_token__concat_inserted;
uint32_t next_token__save_tclass;
uint32_t next_token__save_info;
uint32_t next_token__ltclass;
+ smallint next_token__concat_inserted;
+
+ smallint next_input_file__files_happen;
+ rstream next_input_file__rsm;
var *evaluate__fnargs;
unsigned evaluate__seed;
tsplitter exec_builtin__tspl;
- /* biggest members go last */
- var *intvar[NUM_INTERNAL_VARS];
+ /* biggest and least used members go last */
+ double t_double;
tsplitter fsplitter, rsplitter;
};
-#define G (*ptr_to_globals)
-/* for debug */
-/* char Gsize[sizeof(G)]; ~0x240 */
+#define G1 (ptr_to_globals[-1])
+#define G (*(struct globals2 *const)ptr_to_globals)
+/* For debug. nm --size-sort awk.o | grep -vi ' [tr] ' */
+/* char G1size[sizeof(G1)]; - 0x6c */
+/* char Gsize[sizeof(G)]; - 0x1cc */
/* Trying to keep most of members accessible with short offsets: */
-/* char Gofs_seed[offsetof(struct globals, evaluate__seed)]; ~0xc0 */
+/* char Gofs_seed[offsetof(struct globals2, evaluate__seed)]; - 0x90 */
+#define beginseq (G1.beginseq )
+#define mainseq (G1.mainseq )
+#define endseq (G1.endseq )
+#define seq (G1.seq )
+#define break_ptr (G1.break_ptr )
+#define continue_ptr (G1.continue_ptr)
+#define iF (G1.iF )
+#define vhash (G1.vhash )
+#define ahash (G1.ahash )
+#define fdhash (G1.fdhash )
+#define fnhash (G1.fnhash )
+#define g_progname (G1.g_progname )
+#define g_lineno (G1.g_lineno )
+#define nfields (G1.nfields )
+#define maxfields (G1.maxfields )
+#define Fields (G1.Fields )
+#define g_cb (G1.g_cb )
+#define g_pos (G1.g_pos )
+#define g_buf (G1.g_buf )
+#define icase (G1.icase )
+#define exiting (G1.exiting )
+#define nextrec (G1.nextrec )
+#define nextfile (G1.nextfile )
+#define is_f0_split (G1.is_f0_split )
#define t_info (G.t_info )
#define t_tclass (G.t_tclass )
#define t_string (G.t_string )
#define t_double (G.t_double )
#define t_lineno (G.t_lineno )
#define t_rollback (G.t_rollback )
-#define icase (G.icase )
-#define exiting (G.exiting )
-#define nextrec (G.nextrec )
-#define nextfile (G.nextfile )
-#define is_f0_split (G.is_f0_split )
-#define beginseq (G.beginseq )
-#define mainseq (G.mainseq )
-#define endseq (G.endseq )
-#define seq (G.seq )
-#define break_ptr (G.break_ptr )
-#define continue_ptr (G.continue_ptr)
-#define iF (G.iF )
-#define vhash (G.vhash )
-#define ahash (G.ahash )
-#define fdhash (G.fdhash )
-#define fnhash (G.fnhash )
-#define g_progname (G.g_progname )
-#define g_lineno (G.g_lineno )
-#define nfields (G.nfields )
-#define maxfields (G.maxfields )
-#define Fields (G.Fields )
-#define g_cb (G.g_cb )
-#define g_pos (G.g_pos )
-#define g_buf (G.g_buf )
#define intvar (G.intvar )
#define fsplitter (G.fsplitter )
#define rsplitter (G.rsplitter )
#define INIT_G() do { \
- PTR_TO_GLOBALS = xzalloc(sizeof(G)); \
+ PTR_TO_GLOBALS = xzalloc(sizeof(G1) + sizeof(G)) + sizeof(G1); \
G.next_token__ltclass = TC_OPTERM; \
G.evaluate__seed = 1; \
} while (0)
/* ---- error handling ---- */
-static const char EMSG_INTERNAL_ERROR[] = "Internal error";
-static const char EMSG_UNEXP_EOS[] = "Unexpected end of string";
-static const char EMSG_UNEXP_TOKEN[] = "Unexpected token";
-static const char EMSG_DIV_BY_ZERO[] = "Division by zero";
-static const char EMSG_INV_FMT[] = "Invalid format specifier";
-static const char EMSG_TOO_FEW_ARGS[] = "Too few arguments for builtin";
-static const char EMSG_NOT_ARRAY[] = "Not an array";
-static const char EMSG_POSSIBLE_ERROR[] = "Possible syntax error";
-static const char EMSG_UNDEF_FUNC[] = "Call to undefined function";
+static const char EMSG_INTERNAL_ERROR[] ALIGN1 = "Internal error";
+static const char EMSG_UNEXP_EOS[] ALIGN1 = "Unexpected end of string";
+static const char EMSG_UNEXP_TOKEN[] ALIGN1 = "Unexpected token";
+static const char EMSG_DIV_BY_ZERO[] ALIGN1 = "Division by zero";
+static const char EMSG_INV_FMT[] ALIGN1 = "Invalid format specifier";
+static const char EMSG_TOO_FEW_ARGS[] ALIGN1 = "Too few arguments for builtin";
+static const char EMSG_NOT_ARRAY[] ALIGN1 = "Not an array";
+static const char EMSG_POSSIBLE_ERROR[] ALIGN1 = "Possible syntax error";
+static const char EMSG_UNDEF_FUNC[] ALIGN1 = "Call to undefined function";
#if !ENABLE_FEATURE_AWK_MATH
-static const char EMSG_NO_MATH[] = "Math support is not compiled in";
+static const char EMSG_NO_MATH[] ALIGN1 = "Math support is not compiled in";
#endif
static void zero_out_var(var * vp)
memset(vp, 0, sizeof(*vp));
}
-static void syntax_error(const char * const message) ATTRIBUTE_NORETURN;
-static void syntax_error(const char * const message)
+static void syntax_error(const char *const message) ATTRIBUTE_NORETURN;
+static void syntax_error(const char *const message)
{
bb_error_msg_and_die("%s:%i: %s", g_progname, g_lineno, message);
}
unsigned newsize, i, idx;
hash_item **newitems, *hi, *thi;
- if (hash->nprime == NPRIMES)
+ if (hash->nprime == ARRAY_SIZE(PRIMES))
return;
newsize = PRIMES[hash->nprime++];
int l;
hi = hash_search(hash, name);
- if (! hi) {
+ if (!hi) {
if (++hash->nel / hash->csize > 10)
hash_rebuild(hash);
return c;
}
-static int ATTRIBUTE_ALWAYS_INLINE isalnum_(int c)
+static int ALWAYS_INLINE isalnum_(int c)
{
return (isalnum(c) || c == '_');
}
static var *incvar(var *v)
{
- return setvar_i(v, getvar_i(v)+1.);
+ return setvar_i(v, getvar_i(v) + 1.);
}
/* return true if v is number or numeric string */
n3 = parse_expr(TC_SEQTERM);
n = chain_loop(n3);
n->l.n = n2;
- if (! n2)
+ if (!n2)
n->info = OC_EXEC;
}
break;
n = &spl->n;
if ((n->info & OPCLSMASK) == OC_REGEXP) {
regfree(re);
- regfree(ire);
+ regfree(ire); // TODO: nuke ire, use re+1?
}
if (strlen(s) > 1) {
mk_re_node(s, n, re);
int l, n = 0;
char c[4];
char *s1;
- regmatch_t pmatch[2];
+ regmatch_t pmatch[2]; // TODO: why [2]? [1] is enough...
/* in worst case, each char would be a separate field */
*slist = s1 = xzalloc(strlen(s) * 2 + 3);
if (*getvar_s(intvar[RS]) == '\0')
c[2] = '\n';
- if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
- while (*s) {
- l = strcspn(s, c+2);
+ if ((spl->info & OPCLSMASK) == OC_REGEXP) { /* regex split */
+ if (!*s)
+ return n; /* "": zero fields */
+ n++; /* at least one field will be there */
+ do {
+ l = strcspn(s, c+2); /* len till next NUL or \n */
if (regexec(icase ? spl->r.ire : spl->l.re, s, 1, pmatch, 0) == 0
&& pmatch[0].rm_so <= l
) {
l++;
pmatch[0].rm_eo++;
}
+ n++; /* we saw yet another delimiter */
} else {
pmatch[0].rm_eo = l;
if (s[l]) pmatch[0].rm_eo++;
}
-
memcpy(s1, s, l);
s1[l] = '\0';
nextword(&s1);
s += pmatch[0].rm_eo;
- n++;
- }
- } else if (c[0] == '\0') { /* null split */
+ } while (*s);
+ return n;
+ }
+ if (c[0] == '\0') { /* null split */
while (*s) {
*s1++ = *s++;
*s1++ = '\0';
n++;
}
- } else if (c[0] != ' ') { /* single-character split */
+ return n;
+ }
+ if (c[0] != ' ') { /* single-character split */
if (icase) {
c[0] = toupper(c[0]);
c[1] = tolower(c[1]);
*s1++ = '\0';
n++;
}
- } else { /* space split */
- while (*s) {
- s = skip_whitespace(s);
- if (!*s) break;
- n++;
- while (*s && !isspace(*s))
- *s1++ = *s++;
- *s1++ = '\0';
- }
+ return n;
+ }
+ /* space split */
+ while (*s) {
+ s = skip_whitespace(s);
+ if (!*s) break;
+ n++;
+ while (*s && !isspace(*s))
+ *s1++ = *s++;
+ *s1++ = '\0';
}
return n;
}
static void split_f0(void)
{
+/* static char *fstrings; */
#define fstrings (G.split_f0__fstrings)
int i, n;
c = (char) rsplitter.n.info;
rp = 0;
- if (! m) qrealloc(&m, 256, &size);
+ if (!m) qrealloc(&m, 256, &size);
do {
b = m + a;
so = eo = p;
}
} else if (c != '\0') {
s = strchr(b+pp, c);
- if (! s) s = memchr(b+pp, '\0', p - pp);
+ if (!s) s = memchr(b+pp, '\0', p - pp);
if (s) {
so = eo = s-b;
eo++;
regex_t sreg, *re;
re = as_regex(rn, &sreg);
- if (! src) src = intvar[F0];
- if (! dest) dest = intvar[F0];
+ if (!src) src = intvar[F0];
+ if (!dest) dest = intvar[F0];
i = di = 0;
sp = getvar_s(src);
sp += eo;
if (i == nm) break;
if (eo == so) {
- if (! (ds[di++] = *sp++)) break;
+ ds[di] = *sp++;
+ if (!ds[di++]) break;
}
}
/* Huh, people report that sometimes environ is NULL. Oh well. */
if (environ) for (envp = environ; *envp; envp++) {
- char *s = xstrdup(*envp);
+ /* environ is writable, thus we don't strdup it needlessly */
+ char *s = *envp;
char *s1 = strchr(s, '=');
if (s1) {
- *s1++ = '\0';
- setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1);
+ *s1 = '\0';
+ /* Both findvar and setvar_u take const char*
+ * as 2nd arg -> environment is not trashed */
+ setvar_u(findvar(iamarray(intvar[ENVIRON]), s), s1 + 1);
+ *s1 = '=';
}
- free(s);
}
opt_complementary = "v::";
- opt = getopt32(argc, argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
+ opt = getopt32(argv, "F:v:f:W:", &opt_F, &opt_v, &g_progname, &opt_W);
argv += optind;
argc -= optind;
if (opt & 0x1)