1 /*-
2 * Copyright (c) 1993
3 * The Regents of the University of California. All rights reserved.
4 *
5 * This code is derived from software contributed to Berkeley by
6 * Peter McIlroy.
7 *
8 * %sccs.include.redist.c%
9 */
10
11 #ifndef lint
12 static char sccsid[] = "@(#)init.c 8.1 (Berkeley) 06/06/93";
13 #endif /* not lint */
14
15 #include "sort.h"
16
17 #include <ctype.h>
18 #include <string.h>
19
20 extern struct coldesc clist[(ND+1)*2];
21 extern int ncols;
22 u_char gweights[NBINS];
23
24 /*
25 * clist (list of columns which correspond to one or more icol or tcol)
26 * is in increasing order of columns.
27 * Fields are kept in increasing order of fields.
28 */
29
30 /*
31 * keep clist in order--inserts a column in a sorted array
32 */
33 static void
insertcol(field)34 insertcol(field)
35 struct field *field;
36 {
37 int i;
38 for (i = 0; i < ncols; i++)
39 if (field->icol.num <= clist[i].num)
40 break;
41 if (field->icol.num != clist[i].num) {
42 memmove(clist+i+1, clist+i, sizeof(COLDESC)*(ncols-i));
43 clist[i].num = field->icol.num;
44 ncols++;
45 }
46 if (field->tcol.num && field->tcol.num != field->icol.num) {
47 for (i = 0; i < ncols; i++)
48 if (field->tcol.num <= clist[i].num)
49 break;
50 if (field->tcol.num != clist[i].num) {
51 memmove(clist+i+1, clist+i,sizeof(COLDESC)*(ncols-i));
52 clist[i].num = field->tcol.num;
53 ncols++;
54 }
55 }
56 }
57
58 /*
59 * matches fields with the appropriate columns--n^2 but who cares?
60 */
61 void
fldreset(fldtab)62 fldreset(fldtab)
63 struct field *fldtab;
64 {
65 int i;
66 fldtab[0].tcol.p = clist+ncols-1;
67 for (++fldtab; fldtab->icol.num; ++fldtab) {
68 for (i = 0; fldtab->icol.num != clist[i].num; i++);
69 fldtab->icol.p = clist + i;
70 if (!fldtab->tcol.num)
71 continue;
72 for (i = 0; fldtab->tcol.num != clist[i].num; i++);
73 fldtab->tcol.p = clist + i;
74 }
75 }
76
77 /*
78 * interprets a column in a -k field
79 */
80 char *
setcolumn(pos,cur_fld,gflag)81 setcolumn(pos, cur_fld, gflag)
82 char *pos;
83 struct field *cur_fld;
84 int gflag;
85 {
86 struct column *col;
87 int tmp;
88 col = cur_fld->icol.num ? (&(*cur_fld).tcol) : (&(*cur_fld).icol);
89 pos += sscanf(pos, "%d", &(col->num));
90 while (isdigit(*pos))
91 pos++;
92 if (col->num <= 0 && !(col->num == 0 && col == &(cur_fld->tcol)))
93 errx(2, "field numbers must be positive");
94 if (*pos == '.') {
95 if (!col->num)
96 errx(2, "cannot indent end of line");
97 pos += sscanf(++pos, "%d", &(col->indent));
98 while (isdigit(*pos))
99 pos++;
100 if (&cur_fld->icol == col)
101 col->indent--;
102 if (col->indent < 0)
103 errx(2, "illegal offset");
104 }
105 if (optval(*pos, cur_fld->tcol.num))
106 while (tmp = optval(*pos, cur_fld->tcol.num)) {
107 cur_fld->flags |= tmp;
108 pos++;
109 }
110 if (cur_fld->icol.num == 0)
111 cur_fld->icol.num = 1;
112 return (pos);
113 }
114
115 int
setfield(pos,cur_fld,gflag)116 setfield(pos, cur_fld, gflag)
117 char *pos;
118 struct field *cur_fld;
119 int gflag;
120 {
121 static int nfields = 0;
122 int tmp;
123 char *setcolumn();
124 if (++nfields == ND)
125 errx(2, "too many sort keys. (Limit is %d)", ND-1);
126 cur_fld->weights = ascii;
127 cur_fld->mask = alltable;
128 pos = setcolumn(pos, cur_fld, gflag);
129 if (*pos == '\0') /* key extends to EOL. */
130 cur_fld->tcol.num = 0;
131 else {
132 if (*pos != ',')
133 errx(2, "illegal field descriptor");
134 setcolumn((++pos), cur_fld, gflag);
135 }
136 if (!cur_fld->flags)
137 cur_fld->flags = gflag;
138 tmp = cur_fld->flags;
139
140 /*
141 * Assign appropriate mask table and weight table.
142 * If the global weights are reversed, the local field
143 * must be "re-reversed".
144 */
145 if (((tmp & R) ^ (gflag & R)) && tmp & F)
146 cur_fld->weights = RFtable;
147 else if (tmp & F)
148 cur_fld->weights = Ftable;
149 else if ((tmp & R) ^ (gflag & R))
150 cur_fld->weights = Rascii;
151 if (tmp & I)
152 cur_fld->mask = itable;
153 else if (tmp & D)
154 cur_fld->mask = dtable;
155 cur_fld->flags |= (gflag & (BI | BT));
156 if (!cur_fld->tcol.indent) /* BT has no meaning at end of field */
157 cur_fld->flags &= (D|F|I|N|R|BI);
158 if (cur_fld->tcol.num && !(!(cur_fld->flags & BI)
159 && cur_fld->flags & BT) && (cur_fld->tcol.num <= cur_fld->icol.num
160 && cur_fld->tcol.indent < cur_fld->icol.indent))
161 errx(2, "fields out of order");
162 insertcol(cur_fld);
163 return (cur_fld->tcol.num);
164 }
165
166 int
optval(desc,tcolflag)167 optval(desc, tcolflag)
168 int desc, tcolflag;
169 {
170 switch(desc) {
171 case 'b':
172 if (!tcolflag)
173 return(BI);
174 else
175 return(BT);
176 case 'd': return(D);
177 case 'f': return(F);
178 case 'i': return(I);
179 case 'n': return(N);
180 case 'r': return(R);
181 default: return(0);
182 }
183 }
184
185 void
fixit(argc,argv)186 fixit(argc, argv)
187 int *argc;
188 char **argv;
189 {
190 int i, j, v, w, x;
191 static char vbuf[ND*20], *vpos, *tpos;
192 vpos = vbuf;
193
194 for (i = 1; i < *argc; i++) {
195 if (argv[i][0] == '+') {
196 tpos = argv[i]+1;
197 argv[i] = vpos;
198 vpos += sprintf(vpos, "-k");
199 tpos += sscanf(tpos, "%d", &v);
200 while (isdigit(*tpos))
201 tpos++;
202 vpos += sprintf(vpos, "%d", v+1);
203 if (*tpos == '.') {
204 tpos += sscanf(++tpos, "%d", &x);
205 vpos += sprintf(vpos, ".%d", x+1);
206 }
207 while (*tpos)
208 *vpos++ = *tpos++;
209 vpos += sprintf(vpos, ",");
210 if (argv[i+1] &&
211 argv[i+1][0] == '-' && isdigit(argv[i+1][1])) {
212 tpos = argv[i+1] + 1;
213 tpos += sscanf(tpos, "%d", &w);
214 while (isdigit(*tpos))
215 tpos++;
216 x = 0;
217 if (*tpos == '.') {
218 tpos += sscanf(++tpos, "%d", &x);
219 while (isdigit(*tpos))
220 *tpos++;
221 }
222 if (x) {
223 vpos += sprintf(vpos, "%d", w+1);
224 vpos += sprintf(vpos, ".%d", x);
225 } else
226 vpos += sprintf(vpos, "%d", w);
227 while (*tpos)
228 *vpos++ = *tpos++;
229 for (j= i+1; j < *argc; j++)
230 argv[j] = argv[j+1];
231 *argc -= 1;
232 }
233 }
234 }
235 }
236
237 /*
238 * ascii, Rascii, Ftable, and RFtable map
239 * REC_D -> REC_D; {not REC_D} -> {not REC_D}.
240 * gweights maps REC_D -> (0 or 255); {not REC_D} -> {not gweights[REC_D]}.
241 * Note: when sorting in forward order, to encode character zero in a key,
242 * use \001\001; character 1 becomes \001\002. In this case, character 0
243 * is reserved for the field delimiter. Analagously for -r (fld_d = 255).
244 * Note: this is only good for ASCII sorting. For different LC 's,
245 * all bets are off. See also num_init in number.c
246 */
247 void
settables(gflags)248 settables(gflags)
249 int gflags;
250 {
251 u_char *wts;
252 int i, incr;
253 for (i=0; i < 256; i++) {
254 ascii[i] = i;
255 if (i > REC_D && i < 255 - REC_D+1)
256 Rascii[i] = 255 - i + 1;
257 else
258 Rascii[i] = 255 - i;
259 if (islower(i)) {
260 Ftable[i] = Ftable[i- ('a' -'A')];
261 RFtable[i] = RFtable[i - ('a' - 'A')];
262 } else if (REC_D>= 'A' && REC_D < 'Z' && i < 'a' && i > REC_D) {
263 Ftable[i] = i + 1;
264 RFtable[i] = Rascii[i] - 1;
265 } else {
266 Ftable[i] = i;
267 RFtable[i] = Rascii[i];
268 }
269 alltable[i] = 1;
270 if (i == '\n' || isprint(i))
271 itable[i] = 1;
272 else itable[i] = 0;
273 if (i == '\n' || i == '\t' || i == ' ' || isalnum(i))
274 dtable[i] = 1;
275 else dtable[i] = 0;
276 }
277 Rascii[REC_D] = RFtable[REC_D] = REC_D;
278 if (REC_D >= 'A' && REC_D < 'Z')
279 ++Ftable[REC_D + ('a' - 'A')];
280 if (gflags & R && (!(gflags & F) || !SINGL_FLD))
281 wts = Rascii;
282 else if (!(gflags & F) || !SINGL_FLD)
283 wts = ascii;
284 else if (gflags & R)
285 wts = RFtable;
286 else
287 wts = Ftable;
288 memmove(gweights, wts, sizeof(gweights));
289 incr = (gflags & R) ? -1 : 1;
290 for (i = 0; i < REC_D; i++)
291 gweights[i] += incr;
292 gweights[REC_D] = ((gflags & R) ? 255 : 0);
293 if (SINGL_FLD && gflags & F) {
294 for (i = 0; i < REC_D; i++) {
295 ascii[i] += incr;
296 Rascii[i] += incr;
297 }
298 ascii[REC_D] = Rascii[REC_D] = gweights[REC_D];
299 }
300 }
301