1 /* $NetBSD: init.c,v 1.27 2010/06/06 00:00:33 wiz Exp $ */
4 * Copyright (c) 2000-2003 The NetBSD Foundation, Inc.
7 * This code is derived from software contributed to The NetBSD Foundation
8 * by Ben Harris and Jaromir Dolecek.
10 * Redistribution and use in source and binary forms, with or without
11 * modification, are permitted provided that the following conditions
13 * 1. Redistributions of source code must retain the above copyright
14 * notice, this list of conditions and the following disclaimer.
15 * 2. Redistributions in binary form must reproduce the above copyright
16 * notice, this list of conditions and the following disclaimer in the
17 * documentation and/or other materials provided with the distribution.
19 * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20 * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21 * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22 * PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23 * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24 * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25 * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26 * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27 * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28 * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29 * POSSIBILITY OF SUCH DAMAGE.
34 * The Regents of the University of California. All rights reserved.
36 * This code is derived from software contributed to Berkeley by
39 * Redistribution and use in source and binary forms, with or without
40 * modification, are permitted provided that the following conditions
42 * 1. Redistributions of source code must retain the above copyright
43 * notice, this list of conditions and the following disclaimer.
44 * 2. Redistributions in binary form must reproduce the above copyright
45 * notice, this list of conditions and the following disclaimer in the
46 * documentation and/or other materials provided with the distribution.
47 * 3. Neither the name of the University nor the names of its contributors
48 * may be used to endorse or promote products derived from this software
49 * without specific prior written permission.
51 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
52 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
53 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
54 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
55 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
56 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
57 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
58 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
59 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
60 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
69 static void insertcol(struct field *);
70 static const char *setcolumn(const char *, struct field *);
73 * masks of ignored characters.
75 static u_char dtable[NBINS], itable[NBINS];
80 struct coldesc *clist = NULL;
84 * clist (list of columns which correspond to one or more icol or tcol)
85 * is in increasing order of columns.
86 * Fields are kept in increasing order of fields.
90 * keep clist in order--inserts a column in a sorted array
93 insertcol(struct field *field)
98 /* Make space for new item */
99 p = realloc(clist, (ncols + 2) * sizeof(*clist));
103 memset(&clist[ncols], 0, sizeof(clist[ncols]));
105 for (i = 0; i < ncols; i++)
106 if (field->icol.num <= clist[i].num)
108 if (field->icol.num != clist[i].num) {
109 memmove(clist+i+1, clist+i, sizeof(COLDESC)*(ncols-i));
110 clist[i].num = field->icol.num;
113 if (field->tcol.num && field->tcol.num != field->icol.num) {
114 for (i = 0; i < ncols; i++)
115 if (field->tcol.num <= clist[i].num)
117 if (field->tcol.num != clist[i].num) {
118 memmove(clist+i+1, clist+i,sizeof(COLDESC)*(ncols-i));
119 clist[i].num = field->tcol.num;
126 * matches fields with the appropriate columns--n^2 but who cares?
129 fldreset(struct field *fldtab)
133 fldtab[0].tcol.p = clist + ncols - 1;
134 for (++fldtab; fldtab->icol.num; ++fldtab) {
135 for (i = 0; fldtab->icol.num != clist[i].num; i++)
137 fldtab->icol.p = clist + i;
138 if (!fldtab->tcol.num)
140 for (i = 0; fldtab->tcol.num != clist[i].num; i++)
142 fldtab->tcol.p = clist + i;
147 * interprets a column in a -k field
150 setcolumn(const char *pos, struct field *cur_fld)
155 col = cur_fld->icol.num ? (&cur_fld->tcol) : (&cur_fld->icol);
156 col->num = (int) strtol(pos, &npos, 10);
158 if (col->num <= 0 && !(col->num == 0 && col == &(cur_fld->tcol)))
159 errx(2, "field numbers must be positive");
162 errx(2, "cannot indent end of line");
164 col->indent = (int) strtol(pos, &npos, 10);
166 if (&cur_fld->icol == col)
169 errx(2, "illegal offset");
171 for(; (tmp = optval(*pos, cur_fld->tcol.num)); pos++)
172 cur_fld->flags |= tmp;
173 if (cur_fld->icol.num == 0)
174 cur_fld->icol.num = 1;
179 setfield(const char *pos, struct field *cur_fld, int gflag)
181 cur_fld->mask = NULL;
183 pos = setcolumn(pos, cur_fld);
184 if (*pos == '\0') /* key extends to EOL. */
185 cur_fld->tcol.num = 0;
188 errx(2, "illegal field descriptor");
189 setcolumn((++pos), cur_fld);
192 cur_fld->flags = gflag;
194 /* A local 'r' doesn't invert the global one */
195 cur_fld->flags &= ~R;
197 /* Assign appropriate mask table and weight table. */
198 cur_fld->weights = weight_tables[cur_fld->flags & (R | F)];
199 if (cur_fld->flags & I)
200 cur_fld->mask = itable;
201 else if (cur_fld->flags & D)
202 cur_fld->mask = dtable;
204 cur_fld->flags |= (gflag & (BI | BT));
205 if (!cur_fld->tcol.indent) /* BT has no meaning at end of field */
206 cur_fld->flags &= ~BT;
208 if (cur_fld->tcol.num
209 && !(!(cur_fld->flags & BI) && cur_fld->flags & BT)
210 && (cur_fld->tcol.num <= cur_fld->icol.num
211 /* indent if 0 -> end of field, i.e. okay */
212 && cur_fld->tcol.indent != 0
213 && cur_fld->tcol.indent < cur_fld->icol.indent))
214 errx(2, "fields out of order");
217 return (cur_fld->tcol.num);
221 optval(int desc, int tcolflag)
240 * Return true if the options found in ARG, according to the getopt
241 * spec in OPTS, require an additional argv word as an option
245 options_need_argument(const char *arg, const char *opts)
250 /*assert(arg[0] == '-');*/
254 s = strchr(opts, arg[pos]);
260 /* option requires argument */
261 if (arg[pos+1] == '\0') {
262 /* no argument in this arg */
266 /* argument is in this arg; no more options */
276 * Replace historic +SPEC arguments with appropriate -kSPEC.
278 * The form can be either a single +SPEC or a pair +SPEC -SPEC.
279 * The following -SPEC is not recognized unless it follows
283 fixit(int *argc, char **argv, const char *opts)
286 char *vpos, *tpos, spec[20];
291 for (i = 1; i < *argc; i++) {
293 * This loop must stop exactly where getopt will stop.
294 * Otherwise it turns e.g. "sort x +3" into "sort x
295 * -k4.1", which will croak if +3 was in fact really a
296 * file name. In order to do this reliably we need to
297 * be able to identify argv words that are option
301 if (!strcmp(argv[i], "--")) {
302 /* End of options; stop. */
306 if (argv[i][0] == '+') {
309 } else if (argv[i][0] == '-' && sawplus &&
310 isdigit((unsigned char)argv[i][1])) {
313 } else if (argv[i][0] == '-') {
316 if (options_need_argument(argv[i], opts)) {
317 /* skip over the argument */
322 /* not an option at all; stop */
328 * At this point argv[i] is an old-style spec. The
329 * sawplus flag used by the above loop logic also
330 * tells us if it's a +SPEC or -SPEC.
335 col = (int)strtol(tpos, &tpos, 10);
338 indent = (int) strtol(tpos, &tpos, 10);
341 /* tpos now points to the optional flags */
344 * In the traditional form, x.0 means beginning of line;
345 * in the new form, x.0 means end of line. Adjust the
346 * value of INDENT accordingly.
358 /* make the new style spec */
359 sz = snprintf(spec, sizeof(spec), "%d.%d%s", col, indent,
363 /* Replace the +POS argument with new-style -kSPEC */
364 asprintf(&vpos, "-k%s", spec);
368 * Append the spec to the one from the
369 * preceding +POS argument, and remove the
370 * current argv element entirely.
372 asprintf(&vpos, "%s,%s", argv[i-1], spec);
375 for (j=i; j < *argc; j++)
384 * ascii, Rascii, Ftable, and RFtable map
386 * Sorting 'weight' tables.
387 * Convert 'ascii' characters into their sort order.
388 * The 'F' variants fold lower case to upper equivalent
389 * The 'R' variants are for reverse sorting.
391 * The record separator (REC_D) never needs a weight, this frees one
392 * byte value as an 'end of key' marker. This must be 0 for normal
393 * weight tables, and 0xff for reverse weight tables - and is used
394 * to terminate keys so that short keys sort before (after if reverse)
397 * The field separator has a normal weight - although it cannot occur
398 * within a key unless it is the default (space+tab).
400 * All other bytes map to the appropriate value for the sort order.
401 * Numeric sorts don't need any tables, they are reversed by negation.
403 * Global reverse sorts are done by writing the sorted keys in reverse
404 * order - the sort itself is stil forwards.
405 * This means that weights are only ever used when generating keys, any
406 * sort of the original data bytes is always forwards and unweighted.
408 * Note: this is only good for ASCII sorting. For different LC 's,
411 * itable[] and dtable[] are the masks for -i (ignore non-printables)
412 * and -d (only sort blank and alphanumerics).
419 int rev_weight = 254;
424 RFtable[REC_D] = 255;
426 for (i = 0; i < 256; i++) {
429 ascii[i] = next_weight;
430 Rascii[i] = rev_weight;
431 if (Ftable[i] == 0) {
432 Ftable[i] = next_weight;
433 RFtable[i] = rev_weight;
434 Ftable[tolower(i)] = next_weight;
435 RFtable[tolower(i)] = rev_weight;
440 if (i == '\n' || isprint(i))
443 if (i == '\n' || i == '\t' || i == ' ' || isalnum(i))