xref: /netbsd-src/usr.bin/sort/init.c (revision c1d86c14663dbd9e4adc65740b011d226b6c7f9c)
1*c1d86c14Sandvar /*	$NetBSD: init.c,v 1.30 2021/09/19 11:37:01 andvar Exp $	*/
2f84513a7Sjdolecek 
3f84513a7Sjdolecek /*-
4f84513a7Sjdolecek  * Copyright (c) 2000-2003 The NetBSD Foundation, Inc.
5f84513a7Sjdolecek  * All rights reserved.
6f84513a7Sjdolecek  *
7f84513a7Sjdolecek  * This code is derived from software contributed to The NetBSD Foundation
8f84513a7Sjdolecek  * by Ben Harris and Jaromir Dolecek.
9f84513a7Sjdolecek  *
10f84513a7Sjdolecek  * Redistribution and use in source and binary forms, with or without
11f84513a7Sjdolecek  * modification, are permitted provided that the following conditions
12f84513a7Sjdolecek  * are met:
13f84513a7Sjdolecek  * 1. Redistributions of source code must retain the above copyright
14f84513a7Sjdolecek  *    notice, this list of conditions and the following disclaimer.
15f84513a7Sjdolecek  * 2. Redistributions in binary form must reproduce the above copyright
16f84513a7Sjdolecek  *    notice, this list of conditions and the following disclaimer in the
17f84513a7Sjdolecek  *    documentation and/or other materials provided with the distribution.
18f84513a7Sjdolecek  *
19f84513a7Sjdolecek  * THIS SOFTWARE IS PROVIDED BY THE NETBSD FOUNDATION, INC. AND CONTRIBUTORS
20f84513a7Sjdolecek  * ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
21f84513a7Sjdolecek  * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
22f84513a7Sjdolecek  * PURPOSE ARE DISCLAIMED.  IN NO EVENT SHALL THE FOUNDATION OR CONTRIBUTORS
23f84513a7Sjdolecek  * BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR
24f84513a7Sjdolecek  * CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
25f84513a7Sjdolecek  * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS
26f84513a7Sjdolecek  * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN
27f84513a7Sjdolecek  * CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE)
28f84513a7Sjdolecek  * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE
29f84513a7Sjdolecek  * POSSIBILITY OF SUCH DAMAGE.
30f84513a7Sjdolecek  */
316029888aSbjh21 
321d5d9b5bSbjh21 /*-
331d5d9b5bSbjh21  * Copyright (c) 1993
341d5d9b5bSbjh21  *	The Regents of the University of California.  All rights reserved.
351d5d9b5bSbjh21  *
361d5d9b5bSbjh21  * This code is derived from software contributed to Berkeley by
371d5d9b5bSbjh21  * Peter McIlroy.
381d5d9b5bSbjh21  *
391d5d9b5bSbjh21  * Redistribution and use in source and binary forms, with or without
401d5d9b5bSbjh21  * modification, are permitted provided that the following conditions
411d5d9b5bSbjh21  * are met:
421d5d9b5bSbjh21  * 1. Redistributions of source code must retain the above copyright
431d5d9b5bSbjh21  *    notice, this list of conditions and the following disclaimer.
441d5d9b5bSbjh21  * 2. Redistributions in binary form must reproduce the above copyright
451d5d9b5bSbjh21  *    notice, this list of conditions and the following disclaimer in the
461d5d9b5bSbjh21  *    documentation and/or other materials provided with the distribution.
4789aaa1bbSagc  * 3. Neither the name of the University nor the names of its contributors
481d5d9b5bSbjh21  *    may be used to endorse or promote products derived from this software
491d5d9b5bSbjh21  *    without specific prior written permission.
501d5d9b5bSbjh21  *
511d5d9b5bSbjh21  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
521d5d9b5bSbjh21  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
531d5d9b5bSbjh21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
541d5d9b5bSbjh21  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
551d5d9b5bSbjh21  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
561d5d9b5bSbjh21  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
571d5d9b5bSbjh21  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
581d5d9b5bSbjh21  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
591d5d9b5bSbjh21  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
601d5d9b5bSbjh21  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
611d5d9b5bSbjh21  * SUCH DAMAGE.
621d5d9b5bSbjh21  */
631d5d9b5bSbjh21 
641d5d9b5bSbjh21 #include "sort.h"
651d5d9b5bSbjh21 
66*c1d86c14Sandvar __RCSID("$NetBSD: init.c,v 1.30 2021/09/19 11:37:01 andvar Exp $");
676029888aSbjh21 
681d5d9b5bSbjh21 #include <ctype.h>
691d5d9b5bSbjh21 #include <string.h>
701d5d9b5bSbjh21 
712a0ab276Sdsl static void insertcol(struct field *);
721310aa04Sdsl static const char *setcolumn(const char *, struct field *);
736029888aSbjh21 
741d5d9b5bSbjh21 /*
757b4a02beSdsl  * masks of ignored characters.
76adefa598Sjdolecek  */
777b4a02beSdsl static u_char dtable[NBINS], itable[NBINS];
78adefa598Sjdolecek 
79adefa598Sjdolecek /*
809f774323Sjdolecek  * parsed key options
819f774323Sjdolecek  */
829f774323Sjdolecek struct coldesc *clist = NULL;
839f774323Sjdolecek int ncols = 0;
849f774323Sjdolecek 
859f774323Sjdolecek /*
861d5d9b5bSbjh21  * clist (list of columns which correspond to one or more icol or tcol)
871d5d9b5bSbjh21  * is in increasing order of columns.
881d5d9b5bSbjh21  * Fields are kept in increasing order of fields.
891d5d9b5bSbjh21  */
901d5d9b5bSbjh21 
911d5d9b5bSbjh21 /*
921d5d9b5bSbjh21  * keep clist in order--inserts a column in a sorted array
931d5d9b5bSbjh21  */
941d5d9b5bSbjh21 static void
insertcol(struct field * field)952a0ab276Sdsl insertcol(struct field *field)
961d5d9b5bSbjh21 {
971d5d9b5bSbjh21 	int i;
98909cd63cSitojun 	struct coldesc *p;
999f774323Sjdolecek 
1009f774323Sjdolecek 	/* Make space for new item */
101de243242Sjdolecek 	p = realloc(clist, (ncols + 2) * sizeof(*clist));
102909cd63cSitojun 	if (!p)
103909cd63cSitojun 		err(1, "realloc");
104909cd63cSitojun 	clist = p;
105909cd63cSitojun 	memset(&clist[ncols], 0, sizeof(clist[ncols]));
1069f774323Sjdolecek 
1071d5d9b5bSbjh21 	for (i = 0; i < ncols; i++)
1081d5d9b5bSbjh21 		if (field->icol.num <= clist[i].num)
1091d5d9b5bSbjh21 			break;
1101d5d9b5bSbjh21 	if (field->icol.num != clist[i].num) {
1111d5d9b5bSbjh21 		memmove(clist+i+1, clist+i, sizeof(COLDESC)*(ncols-i));
1121d5d9b5bSbjh21 		clist[i].num = field->icol.num;
1131d5d9b5bSbjh21 		ncols++;
1141d5d9b5bSbjh21 	}
1151d5d9b5bSbjh21 	if (field->tcol.num && field->tcol.num != field->icol.num) {
1161d5d9b5bSbjh21 		for (i = 0; i < ncols; i++)
1171d5d9b5bSbjh21 			if (field->tcol.num <= clist[i].num)
1181d5d9b5bSbjh21 				break;
1191d5d9b5bSbjh21 		if (field->tcol.num != clist[i].num) {
1201d5d9b5bSbjh21 			memmove(clist+i+1, clist+i,sizeof(COLDESC)*(ncols-i));
1211d5d9b5bSbjh21 			clist[i].num = field->tcol.num;
1221d5d9b5bSbjh21 			ncols++;
1231d5d9b5bSbjh21 		}
1241d5d9b5bSbjh21 	}
1251d5d9b5bSbjh21 }
1261d5d9b5bSbjh21 
1271d5d9b5bSbjh21 /*
1281d5d9b5bSbjh21  * matches fields with the appropriate columns--n^2 but who cares?
1291d5d9b5bSbjh21  */
1301d5d9b5bSbjh21 void
fldreset(struct field * fldtab)1312a0ab276Sdsl fldreset(struct field *fldtab)
1321d5d9b5bSbjh21 {
1331d5d9b5bSbjh21 	int i;
134909cd63cSitojun 
1351d5d9b5bSbjh21 	fldtab[0].tcol.p = clist + ncols - 1;
1361d5d9b5bSbjh21 	for (++fldtab; fldtab->icol.num; ++fldtab) {
137affba8f2Sjdolecek 		for (i = 0; fldtab->icol.num != clist[i].num; i++)
138affba8f2Sjdolecek 			;
1391d5d9b5bSbjh21 		fldtab->icol.p = clist + i;
1401d5d9b5bSbjh21 		if (!fldtab->tcol.num)
1411d5d9b5bSbjh21 			continue;
142affba8f2Sjdolecek 		for (i = 0; fldtab->tcol.num != clist[i].num; i++)
143affba8f2Sjdolecek 			;
1441d5d9b5bSbjh21 		fldtab->tcol.p = clist + i;
1451d5d9b5bSbjh21 	}
1461d5d9b5bSbjh21 }
1471d5d9b5bSbjh21 
1481d5d9b5bSbjh21 /*
1491d5d9b5bSbjh21  * interprets a column in a -k field
1501d5d9b5bSbjh21  */
151a65a3ad7Sjdolecek static const char *
setcolumn(const char * pos,struct field * cur_fld)1521310aa04Sdsl setcolumn(const char *pos, struct field *cur_fld)
1531d5d9b5bSbjh21 {
1541d5d9b5bSbjh21 	struct column *col;
155afac62bcSjdolecek 	char *npos;
1561d5d9b5bSbjh21 	int tmp;
157afac62bcSjdolecek 	col = cur_fld->icol.num ? (&cur_fld->tcol) : (&cur_fld->icol);
158afac62bcSjdolecek 	col->num = (int) strtol(pos, &npos, 10);
159afac62bcSjdolecek 	pos = npos;
1601d5d9b5bSbjh21 	if (col->num <= 0 && !(col->num == 0 && col == &(cur_fld->tcol)))
1611d5d9b5bSbjh21 		errx(2, "field numbers must be positive");
1621d5d9b5bSbjh21 	if (*pos == '.') {
1631d5d9b5bSbjh21 		if (!col->num)
1641d5d9b5bSbjh21 			errx(2, "cannot indent end of line");
1652aa37f4aSthorpej 		++pos;
166afac62bcSjdolecek 		col->indent = (int) strtol(pos, &npos, 10);
167afac62bcSjdolecek 		pos = npos;
1681d5d9b5bSbjh21 		if (&cur_fld->icol == col)
1691d5d9b5bSbjh21 			col->indent--;
1701d5d9b5bSbjh21 		if (col->indent < 0)
1711d5d9b5bSbjh21 			errx(2, "illegal offset");
1721d5d9b5bSbjh21 	}
173afac62bcSjdolecek 	for(; (tmp = optval(*pos, cur_fld->tcol.num)); pos++)
1741d5d9b5bSbjh21 		cur_fld->flags |= tmp;
1751d5d9b5bSbjh21 	if (cur_fld->icol.num == 0)
1761d5d9b5bSbjh21 		cur_fld->icol.num = 1;
1771d5d9b5bSbjh21 	return (pos);
1781d5d9b5bSbjh21 }
1791d5d9b5bSbjh21 
1801d5d9b5bSbjh21 int
setfield(const char * pos,struct field * cur_fld,int gflag)1812a0ab276Sdsl setfield(const char *pos, struct field *cur_fld, int gflag)
1821d5d9b5bSbjh21 {
1837b4a02beSdsl 	cur_fld->mask = NULL;
184adefa598Sjdolecek 
1851310aa04Sdsl 	pos = setcolumn(pos, cur_fld);
1861d5d9b5bSbjh21 	if (*pos == '\0')			/* key extends to EOL. */
1871d5d9b5bSbjh21 		cur_fld->tcol.num = 0;
1881d5d9b5bSbjh21 	else {
1891d5d9b5bSbjh21 		if (*pos != ',')
1901d5d9b5bSbjh21 			errx(2, "illegal field descriptor");
1911310aa04Sdsl 		setcolumn((++pos), cur_fld);
1921d5d9b5bSbjh21 	}
1931d5d9b5bSbjh21 	if (!cur_fld->flags)
1941d5d9b5bSbjh21 		cur_fld->flags = gflag;
1951310aa04Sdsl 	if (REVERSE)
1961310aa04Sdsl 		/* A local 'r' doesn't invert the global one */
1971310aa04Sdsl 		cur_fld->flags &= ~R;
1981d5d9b5bSbjh21 
1997b4a02beSdsl 	/* Assign appropriate mask table and weight table. */
2001310aa04Sdsl 	cur_fld->weights = weight_tables[cur_fld->flags & (R | F)];
2011310aa04Sdsl 	if (cur_fld->flags & I)
2021d5d9b5bSbjh21 		cur_fld->mask = itable;
2031310aa04Sdsl 	else if (cur_fld->flags & D)
2041d5d9b5bSbjh21 		cur_fld->mask = dtable;
205adefa598Sjdolecek 
2061d5d9b5bSbjh21 	cur_fld->flags |= (gflag & (BI | BT));
2071d5d9b5bSbjh21 	if (!cur_fld->tcol.indent)	/* BT has no meaning at end of field */
208adefa598Sjdolecek 		cur_fld->flags &= ~BT;
209adefa598Sjdolecek 
2104611f32cSdsl 	if (cur_fld->tcol.num
2114611f32cSdsl 	    && !(!(cur_fld->flags & BI) && cur_fld->flags & BT)
2124611f32cSdsl 	    && (cur_fld->tcol.num <= cur_fld->icol.num
2134611f32cSdsl 		    /* indent if 0 -> end of field, i.e. okay */
2144611f32cSdsl 		    && cur_fld->tcol.indent != 0
2151d5d9b5bSbjh21 		    && cur_fld->tcol.indent < cur_fld->icol.indent))
2161d5d9b5bSbjh21 		errx(2, "fields out of order");
2171310aa04Sdsl 
2181d5d9b5bSbjh21 	insertcol(cur_fld);
2191d5d9b5bSbjh21 	return (cur_fld->tcol.num);
2201d5d9b5bSbjh21 }
2211d5d9b5bSbjh21 
2221d5d9b5bSbjh21 int
optval(int desc,int tcolflag)2232a0ab276Sdsl optval(int desc, int tcolflag)
2241d5d9b5bSbjh21 {
2251d5d9b5bSbjh21 	switch(desc) {
2261d5d9b5bSbjh21 	case 'b':
2271d5d9b5bSbjh21 		if (!tcolflag)
2287e6e5c1fSchristos 			return BI;
2291d5d9b5bSbjh21 		else
2307e6e5c1fSchristos 			return BT;
2317e6e5c1fSchristos 	case 'd': return D;
2327e6e5c1fSchristos 	case 'f': return F;
2337e6e5c1fSchristos 	case 'i': return I;
2347e6e5c1fSchristos 	case 'l': return L;
2357e6e5c1fSchristos 	case 'n': return N;
2367e6e5c1fSchristos 	case 'r': return R;
2377e6e5c1fSchristos 	default:  return 0;
2381d5d9b5bSbjh21 	}
2391d5d9b5bSbjh21 }
2401d5d9b5bSbjh21 
24187c48f11Sjdolecek /*
242fcf4d3f7Sdholland  * Return true if the options found in ARG, according to the getopt
243fcf4d3f7Sdholland  * spec in OPTS, require an additional argv word as an option
244fcf4d3f7Sdholland  * argument.
245fcf4d3f7Sdholland  */
246fcf4d3f7Sdholland static int
options_need_argument(const char * arg,const char * opts)247fcf4d3f7Sdholland options_need_argument(const char *arg, const char *opts)
248fcf4d3f7Sdholland {
249fcf4d3f7Sdholland 	size_t pos;
250fcf4d3f7Sdholland 	const char *s;
251fcf4d3f7Sdholland 
252fcf4d3f7Sdholland 	/*assert(arg[0] == '-');*/
253fcf4d3f7Sdholland 
254fcf4d3f7Sdholland 	pos = 1;
255fcf4d3f7Sdholland 	while (arg[pos]) {
256fcf4d3f7Sdholland 		s = strchr(opts, arg[pos]);
257fcf4d3f7Sdholland 		if (s == NULL) {
258fcf4d3f7Sdholland 			/* invalid option */
259fcf4d3f7Sdholland 			return 0;
260fcf4d3f7Sdholland 		}
261fcf4d3f7Sdholland 		if (s[1] == ':') {
262fcf4d3f7Sdholland 			/* option requires argument */
263fcf4d3f7Sdholland 			if (arg[pos+1] == '\0') {
264fcf4d3f7Sdholland 				/* no argument in this arg */
265fcf4d3f7Sdholland 				return 1;
266fcf4d3f7Sdholland 			}
267fcf4d3f7Sdholland 			else {
268fcf4d3f7Sdholland 				/* argument is in this arg; no more options */
269fcf4d3f7Sdholland 				return 0;
270fcf4d3f7Sdholland 			}
271fcf4d3f7Sdholland 		}
272fcf4d3f7Sdholland 		pos++;
273fcf4d3f7Sdholland 	}
274fcf4d3f7Sdholland 	return 0;
275fcf4d3f7Sdholland }
276fcf4d3f7Sdholland 
277fcf4d3f7Sdholland /*
27887c48f11Sjdolecek  * Replace historic +SPEC arguments with appropriate -kSPEC.
279fcf4d3f7Sdholland  *
280fcf4d3f7Sdholland  * The form can be either a single +SPEC or a pair +SPEC -SPEC.
28190abead5Swiz  * The following -SPEC is not recognized unless it follows
282fcf4d3f7Sdholland  * immediately.
28387c48f11Sjdolecek  */
2841d5d9b5bSbjh21 void
fixit(int * argc,char ** argv,const char * opts)285fcf4d3f7Sdholland fixit(int *argc, char **argv, const char *opts)
2861d5d9b5bSbjh21 {
287fcf4d3f7Sdholland 	int i, j, sawplus;
28887c48f11Sjdolecek 	char *vpos, *tpos, spec[20];
28987c48f11Sjdolecek 	int col, indent;
2901d5d9b5bSbjh21 
291fcf4d3f7Sdholland 	sawplus = 0;
2921d5d9b5bSbjh21 	for (i = 1; i < *argc; i++) {
293b6360c7fSdholland 		/*
294fcf4d3f7Sdholland 		 * This loop must stop exactly where getopt will stop.
295fcf4d3f7Sdholland 		 * Otherwise it turns e.g. "sort x +3" into "sort x
296fcf4d3f7Sdholland 		 * -k4.1", which will croak if +3 was in fact really a
297fcf4d3f7Sdholland 		 * file name. In order to do this reliably we need to
298fcf4d3f7Sdholland 		 * be able to identify argv words that are option
299fcf4d3f7Sdholland 		 * arguments.
300b6360c7fSdholland 		 */
301b6360c7fSdholland 
302fcf4d3f7Sdholland 		if (!strcmp(argv[i], "--")) {
303fcf4d3f7Sdholland 			/* End of options; stop. */
304fcf4d3f7Sdholland 			break;
305fcf4d3f7Sdholland 		}
30687c48f11Sjdolecek 
307fcf4d3f7Sdholland 		if (argv[i][0] == '+') {
308fcf4d3f7Sdholland 			/* +POS argument */
309fcf4d3f7Sdholland 			sawplus = 1;
310fcf4d3f7Sdholland 		} else if (argv[i][0] == '-' && sawplus &&
311fcf4d3f7Sdholland 			   isdigit((unsigned char)argv[i][1])) {
312fcf4d3f7Sdholland 			/* -POS argument */
313fcf4d3f7Sdholland 			sawplus = 0;
314fcf4d3f7Sdholland 		} else if (argv[i][0] == '-') {
315fcf4d3f7Sdholland 			/* other option */
316fcf4d3f7Sdholland 			sawplus = 0;
317fcf4d3f7Sdholland 			if (options_need_argument(argv[i], opts)) {
318fcf4d3f7Sdholland 				/* skip over the argument */
319fcf4d3f7Sdholland 				i++;
320fcf4d3f7Sdholland 			}
32187c48f11Sjdolecek 			continue;
322fcf4d3f7Sdholland 		} else {
323fcf4d3f7Sdholland 			/* not an option at all; stop */
324fcf4d3f7Sdholland 			sawplus = 0;
325fcf4d3f7Sdholland 			break;
32687c48f11Sjdolecek 		}
327fcf4d3f7Sdholland 
328fcf4d3f7Sdholland 		/*
329fcf4d3f7Sdholland 		 * At this point argv[i] is an old-style spec. The
330fcf4d3f7Sdholland 		 * sawplus flag used by the above loop logic also
331fcf4d3f7Sdholland 		 * tells us if it's a +SPEC or -SPEC.
332fcf4d3f7Sdholland 		 */
33387c48f11Sjdolecek 
33487c48f11Sjdolecek 		/* parse spec */
3351d5d9b5bSbjh21 		tpos = argv[i]+1;
33687c48f11Sjdolecek 		col = (int)strtol(tpos, &tpos, 10);
3371d5d9b5bSbjh21 		if (*tpos == '.') {
3382aa37f4aSthorpej 			++tpos;
33987c48f11Sjdolecek 			indent = (int) strtol(tpos, &tpos, 10);
3401d5d9b5bSbjh21 		} else
34187c48f11Sjdolecek 			indent = 0;
342fcf4d3f7Sdholland 		/* tpos now points to the optional flags */
34387c48f11Sjdolecek 
34487c48f11Sjdolecek 		/*
345fcf4d3f7Sdholland 		 * In the traditional form, x.0 means beginning of line;
346fcf4d3f7Sdholland 		 * in the new form, x.0 means end of line. Adjust the
347fcf4d3f7Sdholland 		 * value of INDENT accordingly.
34887c48f11Sjdolecek 		 */
349fcf4d3f7Sdholland 		if (sawplus) {
35087c48f11Sjdolecek 			/* +POS */
35187c48f11Sjdolecek 			col += 1;
35287c48f11Sjdolecek 			indent += 1;
35387c48f11Sjdolecek 		} else {
35487c48f11Sjdolecek 			/* -POS */
35587c48f11Sjdolecek 			if (indent > 0)
35687c48f11Sjdolecek 				col += 1;
35787c48f11Sjdolecek 		}
35887c48f11Sjdolecek 
359fcf4d3f7Sdholland 		/* make the new style spec */
3606e28978dSchristos 		(void)snprintf(spec, sizeof(spec), "%d.%d%s", col, indent,
36187c48f11Sjdolecek 		    tpos);
36287c48f11Sjdolecek 
363fcf4d3f7Sdholland 		if (sawplus) {
36487c48f11Sjdolecek 			/* Replace the +POS argument with new-style -kSPEC */
36587c48f11Sjdolecek 			asprintf(&vpos, "-k%s", spec);
36687c48f11Sjdolecek 			argv[i] = vpos;
36787c48f11Sjdolecek 		} else {
36887c48f11Sjdolecek 			/*
369fcf4d3f7Sdholland 			 * Append the spec to the one from the
370fcf4d3f7Sdholland 			 * preceding +POS argument, and remove the
371fcf4d3f7Sdholland 			 * current argv element entirely.
37287c48f11Sjdolecek 			 */
37387c48f11Sjdolecek 			asprintf(&vpos, "%s,%s", argv[i-1], spec);
37487c48f11Sjdolecek 			free(argv[i-1]);
37587c48f11Sjdolecek 			argv[i-1] = vpos;
37687c48f11Sjdolecek 			for (j=i; j < *argc; j++)
3771d5d9b5bSbjh21 				argv[j] = argv[j+1];
3781d5d9b5bSbjh21 			*argc -= 1;
379c8e0ab67Sjdolecek 			i--;
3801d5d9b5bSbjh21 		}
3811d5d9b5bSbjh21 	}
3821d5d9b5bSbjh21 }
3831d5d9b5bSbjh21 
3841d5d9b5bSbjh21 /*
3851d5d9b5bSbjh21  * ascii, Rascii, Ftable, and RFtable map
3867b4a02beSdsl  *
3877b4a02beSdsl  * Sorting 'weight' tables.
3887b4a02beSdsl  * Convert 'ascii' characters into their sort order.
3897b4a02beSdsl  * The 'F' variants fold lower case to upper equivalent
3907b4a02beSdsl  * The 'R' variants are for reverse sorting.
3911310aa04Sdsl  *
3921310aa04Sdsl  * The record separator (REC_D) never needs a weight, this frees one
3931310aa04Sdsl  * byte value as an 'end of key' marker. This must be 0 for normal
3941310aa04Sdsl  * weight tables, and 0xff for reverse weight tables - and is used
3951310aa04Sdsl  * to terminate keys so that short keys sort before (after if reverse)
3961310aa04Sdsl  * longer keys.
3971310aa04Sdsl  *
3981310aa04Sdsl  * The field separator has a normal weight - although it cannot occur
3991310aa04Sdsl  * within a key unless it is the default (space+tab).
4001310aa04Sdsl  *
4017b4a02beSdsl  * All other bytes map to the appropriate value for the sort order.
4027b4a02beSdsl  * Numeric sorts don't need any tables, they are reversed by negation.
4037b4a02beSdsl  *
4041310aa04Sdsl  * Global reverse sorts are done by writing the sorted keys in reverse
405*c1d86c14Sandvar  * order - the sort itself is still forwards.
4061310aa04Sdsl  * This means that weights are only ever used when generating keys, any
4071310aa04Sdsl  * sort of the original data bytes is always forwards and unweighted.
4081310aa04Sdsl  *
4091d5d9b5bSbjh21  * Note: this is only good for ASCII sorting.  For different LC 's,
4107b4a02beSdsl  * all bets are off.
4117b4a02beSdsl  *
4127b4a02beSdsl  * itable[] and dtable[] are the masks for -i (ignore non-printables)
4137b4a02beSdsl  * and -d (only sort blank and alphanumerics).
4141d5d9b5bSbjh21  */
4151d5d9b5bSbjh21 void
settables(void)4164611f32cSdsl settables(void)
4171d5d9b5bSbjh21 {
4187b4a02beSdsl 	int i;
4191310aa04Sdsl 	int next_weight = 1;
4201310aa04Sdsl 	int rev_weight = 254;
4211310aa04Sdsl 
4221310aa04Sdsl 	ascii[REC_D] = 0;
4231310aa04Sdsl 	Rascii[REC_D] = 255;
4241310aa04Sdsl 	Ftable[REC_D] = 0;
4251310aa04Sdsl 	RFtable[REC_D] = 255;
4267b4a02beSdsl 
4271d5d9b5bSbjh21 	for (i = 0; i < 256; i++) {
4281310aa04Sdsl 		if (i == REC_D)
4297b4a02beSdsl 			continue;
4307b4a02beSdsl 		ascii[i] = next_weight;
4317b4a02beSdsl 		Rascii[i] = rev_weight;
4327b4a02beSdsl 		if (Ftable[i] == 0) {
4337b4a02beSdsl 			Ftable[i] = next_weight;
4347b4a02beSdsl 			RFtable[i] = rev_weight;
4357b4a02beSdsl 			Ftable[tolower(i)] = next_weight;
4367b4a02beSdsl 			RFtable[tolower(i)] = rev_weight;
4377b4a02beSdsl 		}
4387b4a02beSdsl 		next_weight++;
4397b4a02beSdsl 		rev_weight--;
440adefa598Sjdolecek 
4411d5d9b5bSbjh21 		if (i == '\n' || isprint(i))
4421d5d9b5bSbjh21 			itable[i] = 1;
443adefa598Sjdolecek 
4441d5d9b5bSbjh21 		if (i == '\n' || i == '\t' || i == ' ' || isalnum(i))
4451d5d9b5bSbjh21 			dtable[i] = 1;
4461d5d9b5bSbjh21 	}
4471d5d9b5bSbjh21 }
448