xref: /plan9/sys/src/cmd/sort.c (revision 4db25db672e11d72a878263ef7c92def5c56957b)
1bd389b36SDavid du Colombier #include	<u.h>
2bd389b36SDavid du Colombier #include	<libc.h>
3bd389b36SDavid du Colombier #include	<bio.h>
4bd389b36SDavid du Colombier 
5bd389b36SDavid du Colombier /*
6bd389b36SDavid du Colombier bugs:
7bd389b36SDavid du Colombier 	00/ff for end of file can conflict with 00/ff characters
8bd389b36SDavid du Colombier */
9bd389b36SDavid du Colombier 
10bd389b36SDavid du Colombier enum
11bd389b36SDavid du Colombier {
127dd7cddfSDavid du Colombier 	Nline	= 100000,		/* default max number of lines saved in memory */
13bd389b36SDavid du Colombier 	Nmerge	= 10,			/* max number of temporary files merged */
14bd389b36SDavid du Colombier 	Nfield	= 20,			/* max number of argument fields */
15bd389b36SDavid du Colombier 
16bd389b36SDavid du Colombier 	Bflag	= 1<<0,			/* flags per field */
17bd389b36SDavid du Colombier 	B1flag	= 1<<1,
18bd389b36SDavid du Colombier 
19bd389b36SDavid du Colombier 	Dflag	= 1<<2,
20bd389b36SDavid du Colombier 	Fflag	= 1<<3,
21bd389b36SDavid du Colombier 	Gflag	= 1<<4,
22bd389b36SDavid du Colombier 	Iflag	= 1<<5,
23bd389b36SDavid du Colombier 	Mflag	= 1<<6,
24bd389b36SDavid du Colombier 	Nflag	= 1<<7,
25bd389b36SDavid du Colombier 	Rflag	= 1<<8,
26bd389b36SDavid du Colombier 	Wflag	= 1<<9,
27bd389b36SDavid du Colombier 
28bd389b36SDavid du Colombier 	NSstart	= 0,			/* states for number to key decoding */
29bd389b36SDavid du Colombier 	NSsign,
30bd389b36SDavid du Colombier 	NSzero,
31bd389b36SDavid du Colombier 	NSdigit,
32bd389b36SDavid du Colombier 	NSpoint,
33bd389b36SDavid du Colombier 	NSfract,
34bd389b36SDavid du Colombier 	NSzerofract,
35bd389b36SDavid du Colombier 	NSexp,
36bd389b36SDavid du Colombier 	NSexpsign,
37bd389b36SDavid du Colombier 	NSexpdigit,
38bd389b36SDavid du Colombier };
39bd389b36SDavid du Colombier 
40bd389b36SDavid du Colombier typedef	struct	Line	Line;
41bd389b36SDavid du Colombier typedef	struct	Key	Key;
42bd389b36SDavid du Colombier typedef	struct	Merge	Merge;
43bd389b36SDavid du Colombier typedef	struct	Field	Field;
44bd389b36SDavid du Colombier 
45bd389b36SDavid du Colombier struct	Line
46bd389b36SDavid du Colombier {
47bd389b36SDavid du Colombier 	Key*	key;
48bd389b36SDavid du Colombier 	int	llen;		/* always >= 1 */
49bd389b36SDavid du Colombier 	uchar	line[1];	/* always ends in '\n' */
50bd389b36SDavid du Colombier };
51bd389b36SDavid du Colombier 
52bd389b36SDavid du Colombier struct	Merge
53bd389b36SDavid du Colombier {
54bd389b36SDavid du Colombier 	Key*	key;		/* copy of line->key so (Line*) looks like (Merge*) */
55bd389b36SDavid du Colombier 	Line*	line;		/* line at the head of a merged temp file */
56bd389b36SDavid du Colombier 	int	fd;		/* file descriptor */
57bd389b36SDavid du Colombier 	Biobuf	b;		/* iobuf for reading a temp file */
58bd389b36SDavid du Colombier };
59bd389b36SDavid du Colombier 
60bd389b36SDavid du Colombier struct	Key
61bd389b36SDavid du Colombier {
62bd389b36SDavid du Colombier 	int	klen;
63bd389b36SDavid du Colombier 	uchar	key[1];
64bd389b36SDavid du Colombier };
65bd389b36SDavid du Colombier 
66bd389b36SDavid du Colombier struct	Field
67bd389b36SDavid du Colombier {
68bd389b36SDavid du Colombier 	int	beg1;
69bd389b36SDavid du Colombier 	int	beg2;
70bd389b36SDavid du Colombier 	int	end1;
71bd389b36SDavid du Colombier 	int	end2;
72bd389b36SDavid du Colombier 
73bd389b36SDavid du Colombier 	long	flags;
74*4db25db6SDavid du Colombier 	uchar	mapto[1+255];
75bd389b36SDavid du Colombier 
76bd389b36SDavid du Colombier 	void	(*dokey)(Key*, uchar*, uchar*, Field*);
77bd389b36SDavid du Colombier };
78bd389b36SDavid du Colombier 
79219b2ee8SDavid du Colombier struct args
80bd389b36SDavid du Colombier {
81bd389b36SDavid du Colombier 	char*	ofile;
82bd389b36SDavid du Colombier 	char*	tname;
83bd389b36SDavid du Colombier 	Rune	tabchar;
84bd389b36SDavid du Colombier 	char	cflag;
85bd389b36SDavid du Colombier 	char	uflag;
86bd389b36SDavid du Colombier 	char	vflag;
87bd389b36SDavid du Colombier 	int	nfield;
88bd389b36SDavid du Colombier 	int	nfile;
89bd389b36SDavid du Colombier 	Field	field[Nfield];
90bd389b36SDavid du Colombier 
91bd389b36SDavid du Colombier 	Line**	linep;
92bd389b36SDavid du Colombier 	long	nline;			/* number of lines in this temp file */
93bd389b36SDavid du Colombier 	long	lineno;			/* overall ordinal for -s option */
94bd389b36SDavid du Colombier 	int	ntemp;
957dd7cddfSDavid du Colombier 	long	mline;			/* max lines per file */
96bd389b36SDavid du Colombier } args;
97bd389b36SDavid du Colombier 
98bd389b36SDavid du Colombier extern	Rune*	month[12];
99bd389b36SDavid du Colombier 
100bd389b36SDavid du Colombier void	buildkey(Line*);
101bd389b36SDavid du Colombier void	doargs(int, char*[]);
102bd389b36SDavid du Colombier void	dofield(char*, int*, int*, int, int);
103bd389b36SDavid du Colombier void	dofile(Biobuf*);
104bd389b36SDavid du Colombier void	dokey_(Key*, uchar*, uchar*, Field*);
105bd389b36SDavid du Colombier void	dokey_dfi(Key*, uchar*, uchar*, Field*);
106bd389b36SDavid du Colombier void	dokey_gn(Key*, uchar*, uchar*, Field*);
107bd389b36SDavid du Colombier void	dokey_m(Key*, uchar*, uchar*, Field*);
108bd389b36SDavid du Colombier void	dokey_r(Key*, uchar*, uchar*, Field*);
109bd389b36SDavid du Colombier void	done(char*);
110bd389b36SDavid du Colombier int	kcmp(Key*, Key*);
111bd389b36SDavid du Colombier void	makemapd(Field*);
112bd389b36SDavid du Colombier void	makemapm(Field*);
113bd389b36SDavid du Colombier void	mergefiles(int, int, Biobuf*);
114bd389b36SDavid du Colombier void	mergeout(Biobuf*);
115bd389b36SDavid du Colombier void	newfield(void);
116bd389b36SDavid du Colombier Line*	newline(Biobuf*);
117bd389b36SDavid du Colombier void	nomem(void);
118bd389b36SDavid du Colombier void	notifyf(void*, char*);
119bd389b36SDavid du Colombier void	printargs(void);
120bd389b36SDavid du Colombier void	printout(Biobuf*);
121bd389b36SDavid du Colombier void	setfield(int, int);
122bd389b36SDavid du Colombier uchar*	skip(uchar*, int, int, int, int);
123bd389b36SDavid du Colombier void	sort4(void*, ulong);
124bd389b36SDavid du Colombier char*	tempfile(int);
125bd389b36SDavid du Colombier void	tempout(void);
126219b2ee8SDavid du Colombier void	lineout(Biobuf*, Line*);
127bd389b36SDavid du Colombier 
128bd389b36SDavid du Colombier void
main(int argc,char * argv[])129bd389b36SDavid du Colombier main(int argc, char *argv[])
130bd389b36SDavid du Colombier {
131bd389b36SDavid du Colombier 	int i, f;
132bd389b36SDavid du Colombier 	char *s;
133bd389b36SDavid du Colombier 	Biobuf bbuf;
134bd389b36SDavid du Colombier 
135bd389b36SDavid du Colombier 	notify(notifyf);	/**/
136bd389b36SDavid du Colombier 	doargs(argc, argv);
137bd389b36SDavid du Colombier 	if(args.vflag)
138bd389b36SDavid du Colombier 		printargs();
139bd389b36SDavid du Colombier 
140bd389b36SDavid du Colombier 	for(i=1; i<argc; i++) {
141bd389b36SDavid du Colombier 		s = argv[i];
142bd389b36SDavid du Colombier 		if(s == 0)
143bd389b36SDavid du Colombier 			continue;
144bd389b36SDavid du Colombier 		if(strcmp(s, "-") == 0) {
145bd389b36SDavid du Colombier 			Binit(&bbuf, 0, OREAD);
146bd389b36SDavid du Colombier 			dofile(&bbuf);
147219b2ee8SDavid du Colombier 			Bterm(&bbuf);
148bd389b36SDavid du Colombier 			continue;
149bd389b36SDavid du Colombier 		}
150bd389b36SDavid du Colombier 		f = open(s, OREAD);
151bd389b36SDavid du Colombier 		if(f < 0) {
152bd389b36SDavid du Colombier 			fprint(2, "sort: open %s: %r\n", s);
153bd389b36SDavid du Colombier 			done("open");
154bd389b36SDavid du Colombier 		}
155bd389b36SDavid du Colombier 		Binit(&bbuf, f, OREAD);
156bd389b36SDavid du Colombier 		dofile(&bbuf);
157219b2ee8SDavid du Colombier 		Bterm(&bbuf);
158bd389b36SDavid du Colombier 		close(f);
159bd389b36SDavid du Colombier 	}
160bd389b36SDavid du Colombier 	if(args.nfile == 0) {
161bd389b36SDavid du Colombier 		Binit(&bbuf, 0, OREAD);
162bd389b36SDavid du Colombier 		dofile(&bbuf);
163219b2ee8SDavid du Colombier 		Bterm(&bbuf);
164bd389b36SDavid du Colombier 	}
165bd389b36SDavid du Colombier 	if(args.cflag)
166bd389b36SDavid du Colombier 		done(0);
167bd389b36SDavid du Colombier 	if(args.vflag)
168bd389b36SDavid du Colombier 		fprint(2, "=========\n");
169bd389b36SDavid du Colombier 
170bd389b36SDavid du Colombier 	f = 1;
171bd389b36SDavid du Colombier 	if(args.ofile) {
172bd389b36SDavid du Colombier 		f = create(args.ofile, OWRITE, 0666);
173bd389b36SDavid du Colombier 		if(f < 0) {
174bd389b36SDavid du Colombier 			fprint(2, "sort: create %s: %r\n", args.ofile);
175bd389b36SDavid du Colombier 			done("create");
176bd389b36SDavid du Colombier 		}
177bd389b36SDavid du Colombier 	}
178bd389b36SDavid du Colombier 
179bd389b36SDavid du Colombier 	Binit(&bbuf, f, OWRITE);
180bd389b36SDavid du Colombier 	if(args.ntemp) {
181bd389b36SDavid du Colombier 		tempout();
182bd389b36SDavid du Colombier 		mergeout(&bbuf);
183bd389b36SDavid du Colombier 	} else {
184bd389b36SDavid du Colombier 		printout(&bbuf);
185bd389b36SDavid du Colombier 	}
186219b2ee8SDavid du Colombier 	Bterm(&bbuf);
187bd389b36SDavid du Colombier 	done(0);
188bd389b36SDavid du Colombier }
189bd389b36SDavid du Colombier 
190bd389b36SDavid du Colombier void
dofile(Biobuf * b)191bd389b36SDavid du Colombier dofile(Biobuf *b)
192bd389b36SDavid du Colombier {
193bd389b36SDavid du Colombier 	Line *l, *ol;
194bd389b36SDavid du Colombier 	int n;
195bd389b36SDavid du Colombier 
196bd389b36SDavid du Colombier 	if(args.cflag) {
197bd389b36SDavid du Colombier 		ol = newline(b);
198bd389b36SDavid du Colombier 		if(ol == 0)
199bd389b36SDavid du Colombier 			return;
200bd389b36SDavid du Colombier 		for(;;) {
201bd389b36SDavid du Colombier 			l = newline(b);
202bd389b36SDavid du Colombier 			if(l == 0)
203bd389b36SDavid du Colombier 				break;
204bd389b36SDavid du Colombier 			n = kcmp(ol->key, l->key);
205bd389b36SDavid du Colombier 			if(n > 0 || (n == 0 && args.uflag)) {
206bd389b36SDavid du Colombier 				fprint(2, "sort: -c file not in sort\n"); /**/
207bd389b36SDavid du Colombier 				done("order");
208bd389b36SDavid du Colombier 			}
209bd389b36SDavid du Colombier 			free(ol->key);
210bd389b36SDavid du Colombier 			free(ol);
211bd389b36SDavid du Colombier 			ol = l;
212bd389b36SDavid du Colombier 		}
213bd389b36SDavid du Colombier 		return;
214bd389b36SDavid du Colombier 	}
215bd389b36SDavid du Colombier 
216bd389b36SDavid du Colombier 	if(args.linep == 0) {
2177dd7cddfSDavid du Colombier 		args.linep = malloc(args.mline * sizeof(args.linep));
218bd389b36SDavid du Colombier 		if(args.linep == 0)
219bd389b36SDavid du Colombier 			nomem();
220bd389b36SDavid du Colombier 	}
221bd389b36SDavid du Colombier 	for(;;) {
222bd389b36SDavid du Colombier 		l = newline(b);
223bd389b36SDavid du Colombier 		if(l == 0)
224bd389b36SDavid du Colombier 			break;
2257dd7cddfSDavid du Colombier 		if(args.nline >= args.mline)
226bd389b36SDavid du Colombier 			tempout();
227bd389b36SDavid du Colombier 		args.linep[args.nline] = l;
228bd389b36SDavid du Colombier 		args.nline++;
229bd389b36SDavid du Colombier 		args.lineno++;
230bd389b36SDavid du Colombier 	}
231bd389b36SDavid du Colombier }
232bd389b36SDavid du Colombier 
233bd389b36SDavid du Colombier void
notifyf(void *,char * s)2347dd7cddfSDavid du Colombier notifyf(void*, char *s)
235bd389b36SDavid du Colombier {
236bd389b36SDavid du Colombier 
237bd389b36SDavid du Colombier 	if(strcmp(s, "interrupt") == 0)
238bd389b36SDavid du Colombier 		done(0);
239bd389b36SDavid du Colombier 	if(strcmp(s, "hangup") == 0)
240bd389b36SDavid du Colombier 		done(0);
241219b2ee8SDavid du Colombier 	if(strcmp(s, "kill") == 0)
242219b2ee8SDavid du Colombier 		done(0);
2437dd7cddfSDavid du Colombier 	if(strncmp(s, "sys: write on closed pipe", 25) == 0)
244219b2ee8SDavid du Colombier 		done(0);
245bd389b36SDavid du Colombier 	fprint(2, "sort: note: %s\n", s);
246bd389b36SDavid du Colombier 	abort();
247bd389b36SDavid du Colombier }
248bd389b36SDavid du Colombier 
249bd389b36SDavid du Colombier Line*
newline(Biobuf * b)250bd389b36SDavid du Colombier newline(Biobuf *b)
251bd389b36SDavid du Colombier {
252bd389b36SDavid du Colombier 	Line *l;
253bd389b36SDavid du Colombier 	char *p;
254bd389b36SDavid du Colombier 	int n, c;
255bd389b36SDavid du Colombier 
256bd389b36SDavid du Colombier 	p = Brdline(b, '\n');
257bd389b36SDavid du Colombier 	n = Blinelen(b);
258bd389b36SDavid du Colombier 	if(p == 0) {
259bd389b36SDavid du Colombier 		if(n == 0)
260bd389b36SDavid du Colombier 			return 0;
261bd389b36SDavid du Colombier 		l = 0;
262bd389b36SDavid du Colombier 		for(n=0;;) {
263bd389b36SDavid du Colombier 			if((n & 31) == 0) {
264bd389b36SDavid du Colombier 				l = realloc(l, sizeof(Line) +
265bd389b36SDavid du Colombier 					(n+31)*sizeof(l->line[0]));
266bd389b36SDavid du Colombier 				if(l == 0)
267bd389b36SDavid du Colombier 					nomem();
268bd389b36SDavid du Colombier 			}
269bd389b36SDavid du Colombier 			c = Bgetc(b);
270bd389b36SDavid du Colombier 			if(c < 0) {
271bd389b36SDavid du Colombier 				fprint(2, "sort: newline added\n");
272bd389b36SDavid du Colombier 				c = '\n';
273bd389b36SDavid du Colombier 			}
274bd389b36SDavid du Colombier 			l->line[n++] = c;
275bd389b36SDavid du Colombier 			if(c == '\n')
276bd389b36SDavid du Colombier 				break;
277bd389b36SDavid du Colombier 		}
278bd389b36SDavid du Colombier 		l->llen = n;
279bd389b36SDavid du Colombier 		buildkey(l);
280bd389b36SDavid du Colombier 		return l;
281bd389b36SDavid du Colombier 	}
282bd389b36SDavid du Colombier 	l = malloc(sizeof(Line) +
283bd389b36SDavid du Colombier 		(n-1)*sizeof(l->line[0]));
284bd389b36SDavid du Colombier 	if(l == 0)
285bd389b36SDavid du Colombier 		nomem();
286bd389b36SDavid du Colombier 	l->llen = n;
287bd389b36SDavid du Colombier 	memmove(l->line, p, n);
288bd389b36SDavid du Colombier 	buildkey(l);
289bd389b36SDavid du Colombier 	return l;
290bd389b36SDavid du Colombier }
291bd389b36SDavid du Colombier 
292bd389b36SDavid du Colombier void
lineout(Biobuf * b,Line * l)293219b2ee8SDavid du Colombier lineout(Biobuf *b, Line *l)
294219b2ee8SDavid du Colombier {
295219b2ee8SDavid du Colombier 	int n, m;
296219b2ee8SDavid du Colombier 
297219b2ee8SDavid du Colombier 	n = l->llen;
298219b2ee8SDavid du Colombier 	m = Bwrite(b, l->line, n);
299219b2ee8SDavid du Colombier 	if(n != m)
300219b2ee8SDavid du Colombier 		exits("write");
301219b2ee8SDavid du Colombier }
302219b2ee8SDavid du Colombier 
303219b2ee8SDavid du Colombier void
tempout(void)304bd389b36SDavid du Colombier tempout(void)
305bd389b36SDavid du Colombier {
306bd389b36SDavid du Colombier 	long n;
307bd389b36SDavid du Colombier 	Line **lp, *l;
308bd389b36SDavid du Colombier 	char *tf;
309219b2ee8SDavid du Colombier 	int f;
310bd389b36SDavid du Colombier 	Biobuf tb;
311bd389b36SDavid du Colombier 
312bd389b36SDavid du Colombier 	sort4(args.linep, args.nline);
313bd389b36SDavid du Colombier 	tf = tempfile(args.ntemp);
314bd389b36SDavid du Colombier 	args.ntemp++;
315bd389b36SDavid du Colombier 	f = create(tf, OWRITE, 0666);
316bd389b36SDavid du Colombier 	if(f < 0) {
317bd389b36SDavid du Colombier 		fprint(2, "sort: create %s: %r\n", tf);
318bd389b36SDavid du Colombier 		done("create");
319bd389b36SDavid du Colombier 	}
320bd389b36SDavid du Colombier 
321bd389b36SDavid du Colombier 	Binit(&tb, f, OWRITE);
322bd389b36SDavid du Colombier 	lp = args.linep;
323bd389b36SDavid du Colombier 	for(n=args.nline; n>0; n--) {
324bd389b36SDavid du Colombier 		l = *lp++;
325219b2ee8SDavid du Colombier 		lineout(&tb, l);
326bd389b36SDavid du Colombier 		free(l->key);
327bd389b36SDavid du Colombier 		free(l);
328bd389b36SDavid du Colombier 	}
329bd389b36SDavid du Colombier 	args.nline = 0;
330219b2ee8SDavid du Colombier 	Bterm(&tb);
331bd389b36SDavid du Colombier 	close(f);
332bd389b36SDavid du Colombier }
333bd389b36SDavid du Colombier 
334bd389b36SDavid du Colombier void
done(char * xs)335bd389b36SDavid du Colombier done(char *xs)
336bd389b36SDavid du Colombier {
337bd389b36SDavid du Colombier 	int i;
338bd389b36SDavid du Colombier 
339bd389b36SDavid du Colombier 	for(i=0; i<args.ntemp; i++)
340bd389b36SDavid du Colombier 		remove(tempfile(i));
341bd389b36SDavid du Colombier 	exits(xs);
342bd389b36SDavid du Colombier }
343bd389b36SDavid du Colombier 
344bd389b36SDavid du Colombier void
nomem(void)345bd389b36SDavid du Colombier nomem(void)
346bd389b36SDavid du Colombier {
347bd389b36SDavid du Colombier 	fprint(2, "sort: out of memory\n");
348bd389b36SDavid du Colombier 	done("mem");
349bd389b36SDavid du Colombier }
350bd389b36SDavid du Colombier 
351bd389b36SDavid du Colombier char*
tempfile(int n)352bd389b36SDavid du Colombier tempfile(int n)
353bd389b36SDavid du Colombier {
3547dd7cddfSDavid du Colombier 	static char file[100];
3557dd7cddfSDavid du Colombier 	static uint pid;
356bd389b36SDavid du Colombier 	char *dir;
357bd389b36SDavid du Colombier 
358bd389b36SDavid du Colombier 	dir = "/tmp";
359bd389b36SDavid du Colombier 	if(args.tname)
360bd389b36SDavid du Colombier 		dir = args.tname;
3617dd7cddfSDavid du Colombier 	if(strlen(dir) >= nelem(file)-20) {
3627dd7cddfSDavid du Colombier 		fprint(2, "temp file directory name is too long: %s\n", dir);
3637dd7cddfSDavid du Colombier 		done("tdir");
3647dd7cddfSDavid du Colombier 	}
3657dd7cddfSDavid du Colombier 
3667dd7cddfSDavid du Colombier 	if(pid == 0) {
3677dd7cddfSDavid du Colombier 		pid = getpid();
3687dd7cddfSDavid du Colombier 		if(pid == 0) {
3697dd7cddfSDavid du Colombier 			pid = time(0);
370bd389b36SDavid du Colombier 			if(pid == 0)
371bd389b36SDavid du Colombier 				pid = 1;
3727dd7cddfSDavid du Colombier 		}
3737dd7cddfSDavid du Colombier 	}
3747dd7cddfSDavid du Colombier 
3757dd7cddfSDavid du Colombier 	sprint(file, "%s/sort.%.4d.%.4d", dir, pid%10000, n);
376bd389b36SDavid du Colombier 	return file;
377bd389b36SDavid du Colombier }
378bd389b36SDavid du Colombier 
379bd389b36SDavid du Colombier void
mergeout(Biobuf * b)380bd389b36SDavid du Colombier mergeout(Biobuf *b)
381bd389b36SDavid du Colombier {
382bd389b36SDavid du Colombier 	int n, i, f;
383bd389b36SDavid du Colombier 	char *tf;
384bd389b36SDavid du Colombier 	Biobuf tb;
385bd389b36SDavid du Colombier 
386bd389b36SDavid du Colombier 	for(i=0; i<args.ntemp; i+=n) {
387bd389b36SDavid du Colombier 		n = args.ntemp - i;
388bd389b36SDavid du Colombier 		if(n > Nmerge) {
389bd389b36SDavid du Colombier 			tf = tempfile(args.ntemp);
390bd389b36SDavid du Colombier 			args.ntemp++;
391bd389b36SDavid du Colombier 			f = create(tf, OWRITE, 0666);
392bd389b36SDavid du Colombier 			if(f < 0) {
393bd389b36SDavid du Colombier 				fprint(2, "sort: create %s: %r\n", tf);
394bd389b36SDavid du Colombier 				done("create");
395bd389b36SDavid du Colombier 			}
396bd389b36SDavid du Colombier 			Binit(&tb, f, OWRITE);
397bd389b36SDavid du Colombier 
398bd389b36SDavid du Colombier 			n = Nmerge;
399bd389b36SDavid du Colombier 			mergefiles(i, n, &tb);
400bd389b36SDavid du Colombier 
401219b2ee8SDavid du Colombier 			Bterm(&tb);
402bd389b36SDavid du Colombier 			close(f);
403bd389b36SDavid du Colombier 		} else
404bd389b36SDavid du Colombier 			mergefiles(i, n, b);
405bd389b36SDavid du Colombier 	}
406bd389b36SDavid du Colombier }
407bd389b36SDavid du Colombier 
408bd389b36SDavid du Colombier void
mergefiles(int t,int n,Biobuf * b)409bd389b36SDavid du Colombier mergefiles(int t, int n, Biobuf *b)
410bd389b36SDavid du Colombier {
411bd389b36SDavid du Colombier 	Merge *m, *mp, **mmp;
412bd389b36SDavid du Colombier 	Key *ok;
413bd389b36SDavid du Colombier 	Line *l;
414bd389b36SDavid du Colombier 	char *tf;
415bd389b36SDavid du Colombier 	int i, f, nn;
416bd389b36SDavid du Colombier 
417bd389b36SDavid du Colombier 	mmp = malloc(n*sizeof(*mmp));
418bd389b36SDavid du Colombier 	mp = malloc(n*sizeof(*mp));
419bd389b36SDavid du Colombier 	if(mmp == 0 || mp == 0)
420bd389b36SDavid du Colombier 		nomem();
421bd389b36SDavid du Colombier 
422bd389b36SDavid du Colombier 	nn = 0;
423bd389b36SDavid du Colombier 	m = mp;
424bd389b36SDavid du Colombier 	for(i=0; i<n; i++,m++) {
425bd389b36SDavid du Colombier 		tf = tempfile(t+i);
426bd389b36SDavid du Colombier 		f = open(tf, OREAD);
427bd389b36SDavid du Colombier 		if(f < 0) {
428bd389b36SDavid du Colombier 			fprint(2, "sort: reopen %s: %r\n", tf);
429bd389b36SDavid du Colombier 			done("open");
430bd389b36SDavid du Colombier 		}
431bd389b36SDavid du Colombier 		m->fd = f;
432bd389b36SDavid du Colombier 		Binit(&m->b, f, OREAD);
433bd389b36SDavid du Colombier 		mmp[nn] = m;
434bd389b36SDavid du Colombier 
435bd389b36SDavid du Colombier 		l = newline(&m->b);
436bd389b36SDavid du Colombier 		if(l == 0)
437bd389b36SDavid du Colombier 			continue;
438bd389b36SDavid du Colombier 		nn++;
439bd389b36SDavid du Colombier 		m->line = l;
440bd389b36SDavid du Colombier 		m->key = l->key;
441bd389b36SDavid du Colombier 	}
442bd389b36SDavid du Colombier 
443bd389b36SDavid du Colombier 	ok = 0;
444bd389b36SDavid du Colombier 	for(;;) {
445bd389b36SDavid du Colombier 		sort4(mmp, nn);
446bd389b36SDavid du Colombier 		m = *mmp;
447bd389b36SDavid du Colombier 		if(nn == 0)
448bd389b36SDavid du Colombier 			break;
449bd389b36SDavid du Colombier 		for(;;) {
450bd389b36SDavid du Colombier 			l = m->line;
451bd389b36SDavid du Colombier 			if(args.uflag && ok && kcmp(ok, l->key) == 0) {
452bd389b36SDavid du Colombier 				free(l->key);
4537dd7cddfSDavid du Colombier 				free(l);
454bd389b36SDavid du Colombier 			} else {
455219b2ee8SDavid du Colombier 				lineout(b, l);
456bd389b36SDavid du Colombier 				if(ok)
457bd389b36SDavid du Colombier 					free(ok);
458bd389b36SDavid du Colombier 				ok = l->key;
459bd389b36SDavid du Colombier 				free(l);
460bd389b36SDavid du Colombier 			}
461bd389b36SDavid du Colombier 
462bd389b36SDavid du Colombier 			l = newline(&m->b);
463bd389b36SDavid du Colombier 			if(l == 0) {
464bd389b36SDavid du Colombier 				nn--;
465bd389b36SDavid du Colombier 				mmp[0] = mmp[nn];
466bd389b36SDavid du Colombier 				break;
467bd389b36SDavid du Colombier 			}
468bd389b36SDavid du Colombier 			m->line = l;
469bd389b36SDavid du Colombier 			m->key = l->key;
470bd389b36SDavid du Colombier 			if(nn > 1 && kcmp(mmp[0]->key, mmp[1]->key) > 0)
471bd389b36SDavid du Colombier 				break;
472bd389b36SDavid du Colombier 		}
473bd389b36SDavid du Colombier 	}
474bd389b36SDavid du Colombier 	if(ok)
475bd389b36SDavid du Colombier 		free(ok);
476bd389b36SDavid du Colombier 
477bd389b36SDavid du Colombier 	m = mp;
478bd389b36SDavid du Colombier 	for(i=0; i<n; i++,m++) {
479219b2ee8SDavid du Colombier 		Bterm(&m->b);
480bd389b36SDavid du Colombier 		close(m->fd);
481bd389b36SDavid du Colombier 	}
482bd389b36SDavid du Colombier 
483bd389b36SDavid du Colombier 	free(mp);
484bd389b36SDavid du Colombier 	free(mmp);
485bd389b36SDavid du Colombier }
486bd389b36SDavid du Colombier 
487bd389b36SDavid du Colombier int
kcmp(Key * ka,Key * kb)488bd389b36SDavid du Colombier kcmp(Key *ka, Key *kb)
489bd389b36SDavid du Colombier {
490bd389b36SDavid du Colombier 	int n, m;
491bd389b36SDavid du Colombier 
492bd389b36SDavid du Colombier 	/*
493bd389b36SDavid du Colombier 	 * set n to length of smaller key
494bd389b36SDavid du Colombier 	 */
495bd389b36SDavid du Colombier 	n = ka->klen;
496bd389b36SDavid du Colombier 	m = kb->klen;
497bd389b36SDavid du Colombier 	if(n > m)
498bd389b36SDavid du Colombier 		n = m;
499bd389b36SDavid du Colombier 	return memcmp(ka->key, kb->key, n);
500bd389b36SDavid du Colombier }
501bd389b36SDavid du Colombier 
502bd389b36SDavid du Colombier void
printout(Biobuf * b)503bd389b36SDavid du Colombier printout(Biobuf *b)
504bd389b36SDavid du Colombier {
505bd389b36SDavid du Colombier 	long n;
506bd389b36SDavid du Colombier 	Line **lp, *l;
507bd389b36SDavid du Colombier 	Key *ok;
508bd389b36SDavid du Colombier 
509bd389b36SDavid du Colombier 	sort4(args.linep, args.nline);
510bd389b36SDavid du Colombier 	lp = args.linep;
511bd389b36SDavid du Colombier 	ok = 0;
512bd389b36SDavid du Colombier 	for(n=args.nline; n>0; n--) {
513bd389b36SDavid du Colombier 		l = *lp++;
514bd389b36SDavid du Colombier 		if(args.uflag && ok && kcmp(ok, l->key) == 0)
515bd389b36SDavid du Colombier 			continue;
516219b2ee8SDavid du Colombier 		lineout(b, l);
517bd389b36SDavid du Colombier 		ok = l->key;
518bd389b36SDavid du Colombier 	}
519bd389b36SDavid du Colombier }
520bd389b36SDavid du Colombier 
521bd389b36SDavid du Colombier void
setfield(int n,int c)522bd389b36SDavid du Colombier setfield(int n, int c)
523bd389b36SDavid du Colombier {
524bd389b36SDavid du Colombier 	Field *f;
525bd389b36SDavid du Colombier 
526bd389b36SDavid du Colombier 	f = &args.field[n];
527bd389b36SDavid du Colombier 	switch(c) {
528bd389b36SDavid du Colombier 	default:
529bd389b36SDavid du Colombier 		fprint(2, "sort: unknown option: field.%C\n", c);
530bd389b36SDavid du Colombier 		done("option");
531bd389b36SDavid du Colombier 	case 'b':	/* skip blanks */
532bd389b36SDavid du Colombier 		f->flags |= Bflag;
533bd389b36SDavid du Colombier 		break;
534bd389b36SDavid du Colombier 	case 'd':	/* directory order */
535bd389b36SDavid du Colombier 		f->flags |= Dflag;
536bd389b36SDavid du Colombier 		break;
537bd389b36SDavid du Colombier 	case 'f':	/* fold case */
538bd389b36SDavid du Colombier 		f->flags |= Fflag;
539bd389b36SDavid du Colombier 		break;
540bd389b36SDavid du Colombier 	case 'g':	/* floating point -n case */
541bd389b36SDavid du Colombier 		f->flags |= Gflag;
542bd389b36SDavid du Colombier 		break;
543bd389b36SDavid du Colombier 	case 'i':	/* ignore non-ascii */
544bd389b36SDavid du Colombier 		f->flags |= Iflag;
545bd389b36SDavid du Colombier 		break;
546bd389b36SDavid du Colombier 	case 'M':	/* month */
547bd389b36SDavid du Colombier 		f->flags |= Mflag;
548bd389b36SDavid du Colombier 		break;
549bd389b36SDavid du Colombier 	case 'n':	/* numbers */
550bd389b36SDavid du Colombier 		f->flags |= Nflag;
551bd389b36SDavid du Colombier 		break;
552bd389b36SDavid du Colombier 	case 'r':	/* reverse */
553bd389b36SDavid du Colombier 		f->flags |= Rflag;
554bd389b36SDavid du Colombier 		break;
555bd389b36SDavid du Colombier 	case 'w':	/* ignore white */
556bd389b36SDavid du Colombier 		f->flags |= Wflag;
557bd389b36SDavid du Colombier 		break;
558bd389b36SDavid du Colombier 	}
559bd389b36SDavid du Colombier }
560bd389b36SDavid du Colombier 
561bd389b36SDavid du Colombier void
dofield(char * s,int * n1,int * n2,int off1,int off2)562bd389b36SDavid du Colombier dofield(char *s, int *n1, int *n2, int off1, int off2)
563bd389b36SDavid du Colombier {
564bd389b36SDavid du Colombier 	int c, n;
565bd389b36SDavid du Colombier 
566bd389b36SDavid du Colombier 	c = *s++;
567bd389b36SDavid du Colombier 	if(c >= '0' && c <= '9') {
568bd389b36SDavid du Colombier 		n = 0;
569bd389b36SDavid du Colombier 		while(c >= '0' && c <= '9') {
570bd389b36SDavid du Colombier 			n = n*10 + (c-'0');
571bd389b36SDavid du Colombier 			c = *s++;
572bd389b36SDavid du Colombier 		}
573bd389b36SDavid du Colombier 		n -= off1;	/* posix committee: rot in hell */
574bd389b36SDavid du Colombier 		if(n < 0) {
575bd389b36SDavid du Colombier 			fprint(2, "sort: field offset must be positive\n");
576bd389b36SDavid du Colombier 			done("option");
577bd389b36SDavid du Colombier 		}
578bd389b36SDavid du Colombier 		*n1 = n;
579bd389b36SDavid du Colombier 	}
580bd389b36SDavid du Colombier 	if(c == '.') {
581bd389b36SDavid du Colombier 		c = *s++;
582bd389b36SDavid du Colombier 		if(c >= '0' && c <= '9') {
583bd389b36SDavid du Colombier 			n = 0;
584bd389b36SDavid du Colombier 			while(c >= '0' && c <= '9') {
585bd389b36SDavid du Colombier 				n = n*10 + (c-'0');
586bd389b36SDavid du Colombier 				c = *s++;
587bd389b36SDavid du Colombier 			}
588bd389b36SDavid du Colombier 			n -= off2;
589bd389b36SDavid du Colombier 			if(n < 0) {
590bd389b36SDavid du Colombier 				fprint(2, "sort: character offset must be positive\n");
591bd389b36SDavid du Colombier 				done("option");
592bd389b36SDavid du Colombier 			}
593bd389b36SDavid du Colombier 			*n2 = n;
594bd389b36SDavid du Colombier 		}
595bd389b36SDavid du Colombier 	}
596bd389b36SDavid du Colombier 	while(c != 0) {
597bd389b36SDavid du Colombier 		setfield(args.nfield, c);
598bd389b36SDavid du Colombier 		c = *s++;
599bd389b36SDavid du Colombier 	}
600bd389b36SDavid du Colombier }
601bd389b36SDavid du Colombier 
602bd389b36SDavid du Colombier void
printargs(void)603bd389b36SDavid du Colombier printargs(void)
604bd389b36SDavid du Colombier {
605bd389b36SDavid du Colombier 	int i, n;
606bd389b36SDavid du Colombier 	Field *f;
607bd389b36SDavid du Colombier 	char *prefix;
608bd389b36SDavid du Colombier 
609bd389b36SDavid du Colombier 	fprint(2, "sort");
610bd389b36SDavid du Colombier 	for(i=0; i<=args.nfield; i++) {
611bd389b36SDavid du Colombier 		f = &args.field[i];
612bd389b36SDavid du Colombier 		prefix = " -";
613bd389b36SDavid du Colombier 		if(i) {
614bd389b36SDavid du Colombier 			n = f->beg1;
615bd389b36SDavid du Colombier 			if(n >= 0)
616bd389b36SDavid du Colombier 				fprint(2, " +%d", n);
617bd389b36SDavid du Colombier 			else
618bd389b36SDavid du Colombier 				fprint(2, " +*");
619bd389b36SDavid du Colombier 			n = f->beg2;
620bd389b36SDavid du Colombier 			if(n >= 0)
621bd389b36SDavid du Colombier 				fprint(2, ".%d", n);
622bd389b36SDavid du Colombier 			else
623bd389b36SDavid du Colombier 				fprint(2, ".*");
624bd389b36SDavid du Colombier 
625bd389b36SDavid du Colombier 			if(f->flags & B1flag)
626bd389b36SDavid du Colombier 				fprint(2, "b");
627bd389b36SDavid du Colombier 
628bd389b36SDavid du Colombier 			n = f->end1;
629bd389b36SDavid du Colombier 			if(n >= 0)
630bd389b36SDavid du Colombier 				fprint(2, " -%d", n);
631bd389b36SDavid du Colombier 			else
632bd389b36SDavid du Colombier 				fprint(2, " -*");
633bd389b36SDavid du Colombier 			n = f->end2;
634bd389b36SDavid du Colombier 			if(n >= 0)
635bd389b36SDavid du Colombier 				fprint(2, ".%d", n);
636bd389b36SDavid du Colombier 			else
637bd389b36SDavid du Colombier 				fprint(2, ".*");
638bd389b36SDavid du Colombier 			prefix = "";
639bd389b36SDavid du Colombier 		}
640bd389b36SDavid du Colombier 		if(f->flags & Bflag)
641bd389b36SDavid du Colombier 			fprint(2, "%sb", prefix);
642bd389b36SDavid du Colombier 		if(f->flags & Dflag)
643bd389b36SDavid du Colombier 			fprint(2, "%sd", prefix);
644bd389b36SDavid du Colombier 		if(f->flags & Fflag)
645bd389b36SDavid du Colombier 			fprint(2, "%sf", prefix);
646bd389b36SDavid du Colombier 		if(f->flags & Gflag)
647bd389b36SDavid du Colombier 			fprint(2, "%sg", prefix);
648bd389b36SDavid du Colombier 		if(f->flags & Iflag)
649bd389b36SDavid du Colombier 			fprint(2, "%si", prefix);
650bd389b36SDavid du Colombier 		if(f->flags & Mflag)
651bd389b36SDavid du Colombier 			fprint(2, "%sM", prefix);
652bd389b36SDavid du Colombier 		if(f->flags & Nflag)
653bd389b36SDavid du Colombier 			fprint(2, "%sn", prefix);
654bd389b36SDavid du Colombier 		if(f->flags & Rflag)
655bd389b36SDavid du Colombier 			fprint(2, "%sr", prefix);
656bd389b36SDavid du Colombier 		if(f->flags & Wflag)
657bd389b36SDavid du Colombier 			fprint(2, "%sw", prefix);
658bd389b36SDavid du Colombier 	}
659bd389b36SDavid du Colombier 	if(args.cflag)
660bd389b36SDavid du Colombier 		fprint(2, " -c");
661bd389b36SDavid du Colombier 	if(args.uflag)
662bd389b36SDavid du Colombier 		fprint(2, " -u");
663bd389b36SDavid du Colombier 	if(args.ofile)
664bd389b36SDavid du Colombier 		fprint(2, " -o %s", args.ofile);
6657dd7cddfSDavid du Colombier 	if(args.mline != Nline)
6667dd7cddfSDavid du Colombier 		fprint(2, " -l %ld", args.mline);
667bd389b36SDavid du Colombier 	fprint(2, "\n");
668bd389b36SDavid du Colombier }
669bd389b36SDavid du Colombier 
670bd389b36SDavid du Colombier void
newfield(void)671bd389b36SDavid du Colombier newfield(void)
672bd389b36SDavid du Colombier {
673bd389b36SDavid du Colombier 	int n;
674bd389b36SDavid du Colombier 	Field *f;
675bd389b36SDavid du Colombier 
676bd389b36SDavid du Colombier 	n = args.nfield + 1;
677bd389b36SDavid du Colombier 	if(n >= Nfield) {
678bd389b36SDavid du Colombier 		fprint(2, "sort: too many fields specified\n");
679bd389b36SDavid du Colombier 		done("option");
680bd389b36SDavid du Colombier 	}
681bd389b36SDavid du Colombier 	args.nfield = n;
682bd389b36SDavid du Colombier 	f = &args.field[n];
683bd389b36SDavid du Colombier 	f->beg1 = -1;
684bd389b36SDavid du Colombier 	f->beg2 = -1;
685bd389b36SDavid du Colombier 	f->end1 = -1;
686bd389b36SDavid du Colombier 	f->end2 = -1;
687bd389b36SDavid du Colombier }
688bd389b36SDavid du Colombier 
689bd389b36SDavid du Colombier void
doargs(int argc,char * argv[])690bd389b36SDavid du Colombier doargs(int argc, char *argv[])
691bd389b36SDavid du Colombier {
692bd389b36SDavid du Colombier 	int i, c, hadplus;
693bd389b36SDavid du Colombier 	char *s, *p, *q;
694bd389b36SDavid du Colombier 	Field *f;
695bd389b36SDavid du Colombier 
696bd389b36SDavid du Colombier 	hadplus = 0;
6977dd7cddfSDavid du Colombier 	args.mline = Nline;
698bd389b36SDavid du Colombier 	for(i=1; i<argc; i++) {
699bd389b36SDavid du Colombier 		s = argv[i];
700bd389b36SDavid du Colombier 		c = *s++;
701bd389b36SDavid du Colombier 		if(c == '-') {
702bd389b36SDavid du Colombier 			c = *s;
703bd389b36SDavid du Colombier 			if(c == 0)		/* forced end of arg marker */
704bd389b36SDavid du Colombier 				break;
705bd389b36SDavid du Colombier 			argv[i] = 0;		/* clobber args processed */
706bd389b36SDavid du Colombier 			if(c == '.' || (c >= '0' && c <= '9')) {
707bd389b36SDavid du Colombier 				if(!hadplus)
708bd389b36SDavid du Colombier 					newfield();
709bd389b36SDavid du Colombier 				f = &args.field[args.nfield];
710bd389b36SDavid du Colombier 				dofield(s, &f->end1, &f->end2, 0, 0);
711bd389b36SDavid du Colombier 				hadplus = 0;
712bd389b36SDavid du Colombier 				continue;
713bd389b36SDavid du Colombier 			}
714bd389b36SDavid du Colombier 
715bd389b36SDavid du Colombier 			while(c = *s++)
716bd389b36SDavid du Colombier 			switch(c) {
717bd389b36SDavid du Colombier 			case '-':	/* end of options */
718bd389b36SDavid du Colombier 				i = argc;
719bd389b36SDavid du Colombier 				continue;
720bd389b36SDavid du Colombier 			case 'T':	/* temp directory */
721bd389b36SDavid du Colombier 				if(*s == 0) {
722bd389b36SDavid du Colombier 					i++;
723bd389b36SDavid du Colombier 					if(i < argc) {
724bd389b36SDavid du Colombier 						args.tname = argv[i];
725bd389b36SDavid du Colombier 						argv[i] = 0;
726bd389b36SDavid du Colombier 					}
727bd389b36SDavid du Colombier 				} else
728bd389b36SDavid du Colombier 					args.tname = s;
729bd389b36SDavid du Colombier 				s = strchr(s, 0);
730bd389b36SDavid du Colombier 				break;
731bd389b36SDavid du Colombier 			case 'o':	/* output file */
732bd389b36SDavid du Colombier 				if(*s == 0) {
733bd389b36SDavid du Colombier 					i++;
734bd389b36SDavid du Colombier 					if(i < argc) {
735bd389b36SDavid du Colombier 						args.ofile = argv[i];
736bd389b36SDavid du Colombier 						argv[i] = 0;
737bd389b36SDavid du Colombier 					}
738bd389b36SDavid du Colombier 				} else
739bd389b36SDavid du Colombier 					args.ofile = s;
740bd389b36SDavid du Colombier 				s = strchr(s, 0);
741bd389b36SDavid du Colombier 				break;
742bd389b36SDavid du Colombier 			case 'k':	/* posix key (what were they thinking?) */
743bd389b36SDavid du Colombier 				p = 0;
744bd389b36SDavid du Colombier 				if(*s == 0) {
745bd389b36SDavid du Colombier 					i++;
746bd389b36SDavid du Colombier 					if(i < argc) {
747bd389b36SDavid du Colombier 						p = argv[i];
748bd389b36SDavid du Colombier 						argv[i] = 0;
749bd389b36SDavid du Colombier 					}
750bd389b36SDavid du Colombier 				} else
751bd389b36SDavid du Colombier 					p = s;
752bd389b36SDavid du Colombier 				s = strchr(s, 0);
753bd389b36SDavid du Colombier 				if(p == 0)
754bd389b36SDavid du Colombier 					break;
755bd389b36SDavid du Colombier 
756bd389b36SDavid du Colombier 				newfield();
757bd389b36SDavid du Colombier 				q = strchr(p, ',');
758bd389b36SDavid du Colombier 				if(q)
759bd389b36SDavid du Colombier 					*q++ = 0;
760bd389b36SDavid du Colombier 				f = &args.field[args.nfield];
761bd389b36SDavid du Colombier 				dofield(p, &f->beg1, &f->beg2, 1, 1);
762bd389b36SDavid du Colombier 				if(f->flags & Bflag) {
763bd389b36SDavid du Colombier 					f->flags |= B1flag;
764bd389b36SDavid du Colombier 					f->flags &= ~Bflag;
765bd389b36SDavid du Colombier 				}
766bd389b36SDavid du Colombier 				if(q) {
767bd389b36SDavid du Colombier 					dofield(q, &f->end1, &f->end2, 1, 0);
768bd389b36SDavid du Colombier 					if(f->end2 <= 0)
769bd389b36SDavid du Colombier 						f->end1++;
770bd389b36SDavid du Colombier 				}
771bd389b36SDavid du Colombier 				hadplus = 0;
772bd389b36SDavid du Colombier 				break;
773bd389b36SDavid du Colombier 			case 't':	/* tab character */
774bd389b36SDavid du Colombier 				if(*s == 0) {
775bd389b36SDavid du Colombier 					i++;
776bd389b36SDavid du Colombier 					if(i < argc) {
777bd389b36SDavid du Colombier 						chartorune(&args.tabchar, argv[i]);
778bd389b36SDavid du Colombier 						argv[i] = 0;
779bd389b36SDavid du Colombier 					}
780bd389b36SDavid du Colombier 				} else
781bd389b36SDavid du Colombier 					s += chartorune(&args.tabchar, s);
782bd389b36SDavid du Colombier 				if(args.tabchar == '\n') {
783bd389b36SDavid du Colombier 					fprint(2, "aw come on, rob\n");
784bd389b36SDavid du Colombier 					done("rob");
785bd389b36SDavid du Colombier 				}
786bd389b36SDavid du Colombier 				break;
787bd389b36SDavid du Colombier 			case 'c':	/* check order */
788bd389b36SDavid du Colombier 				args.cflag = 1;
789bd389b36SDavid du Colombier 				break;
790bd389b36SDavid du Colombier 			case 'u':	/* unique */
791bd389b36SDavid du Colombier 				args.uflag = 1;
792bd389b36SDavid du Colombier 				break;
793bd389b36SDavid du Colombier 			case 'v':	/* debugging noise */
794bd389b36SDavid du Colombier 				args.vflag = 1;
795bd389b36SDavid du Colombier 				break;
7967dd7cddfSDavid du Colombier 			case 'l':
7977dd7cddfSDavid du Colombier 				if(*s == 0) {
7987dd7cddfSDavid du Colombier 					i++;
7997dd7cddfSDavid du Colombier 					if(i < argc) {
8007dd7cddfSDavid du Colombier 						args.mline = atol(argv[i]);
8017dd7cddfSDavid du Colombier 						argv[i] = 0;
8027dd7cddfSDavid du Colombier 					}
8037dd7cddfSDavid du Colombier 				} else
8047dd7cddfSDavid du Colombier 					args.mline = atol(s);
8057dd7cddfSDavid du Colombier 				s = strchr(s, 0);
8067dd7cddfSDavid du Colombier 				break;
807bd389b36SDavid du Colombier 
808bd389b36SDavid du Colombier 			case 'M':	/* month */
809bd389b36SDavid du Colombier 			case 'b':	/* skip blanks */
810bd389b36SDavid du Colombier 			case 'd':	/* directory order */
811bd389b36SDavid du Colombier 			case 'f':	/* fold case */
812bd389b36SDavid du Colombier 			case 'g':	/* floating numbers */
813bd389b36SDavid du Colombier 			case 'i':	/* ignore non-ascii */
814bd389b36SDavid du Colombier 			case 'n':	/* numbers */
815bd389b36SDavid du Colombier 			case 'r':	/* reverse */
816bd389b36SDavid du Colombier 			case 'w':	/* ignore white */
817bd389b36SDavid du Colombier 				if(args.nfield > 0)
818bd389b36SDavid du Colombier 					fprint(2, "sort: global field set after -k\n");
819bd389b36SDavid du Colombier 				setfield(0, c);
820bd389b36SDavid du Colombier 				break;
821bd389b36SDavid du Colombier 			case 'm':
822219b2ee8SDavid du Colombier 				/* option m silently ignored but required by posix */
823bd389b36SDavid du Colombier 				break;
824bd389b36SDavid du Colombier 			default:
825bd389b36SDavid du Colombier 				fprint(2, "sort: unknown option: -%C\n", c);
826bd389b36SDavid du Colombier 				done("option");
827bd389b36SDavid du Colombier 			}
828bd389b36SDavid du Colombier 			continue;
829bd389b36SDavid du Colombier 		}
830bd389b36SDavid du Colombier 		if(c == '+') {
831bd389b36SDavid du Colombier 			argv[i] = 0;		/* clobber args processed */
832bd389b36SDavid du Colombier 			c = *s;
833bd389b36SDavid du Colombier 			if(c == '.' || (c >= '0' && c <= '9')) {
834bd389b36SDavid du Colombier 				newfield();
835bd389b36SDavid du Colombier 				f = &args.field[args.nfield];
836bd389b36SDavid du Colombier 				dofield(s, &f->beg1, &f->beg2, 0, 0);
837bd389b36SDavid du Colombier 				if(f->flags & Bflag) {
838bd389b36SDavid du Colombier 					f->flags |= B1flag;
839bd389b36SDavid du Colombier 					f->flags &= ~Bflag;
840bd389b36SDavid du Colombier 				}
841bd389b36SDavid du Colombier 				hadplus = 1;
842bd389b36SDavid du Colombier 				continue;
843bd389b36SDavid du Colombier 			}
844bd389b36SDavid du Colombier 			fprint(2, "sort: unknown option: +%C\n", c);
845bd389b36SDavid du Colombier 			done("option");
846bd389b36SDavid du Colombier 		}
847bd389b36SDavid du Colombier 		args.nfile++;
848bd389b36SDavid du Colombier 	}
849bd389b36SDavid du Colombier 
850bd389b36SDavid du Colombier 	for(i=0; i<=args.nfield; i++) {
851bd389b36SDavid du Colombier 		f = &args.field[i];
852bd389b36SDavid du Colombier 
853bd389b36SDavid du Colombier 		/*
854bd389b36SDavid du Colombier 		 * global options apply to fields that
855bd389b36SDavid du Colombier 		 * specify no options
856bd389b36SDavid du Colombier 		 */
857bd389b36SDavid du Colombier 		if(f->flags == 0) {
858bd389b36SDavid du Colombier 			f->flags = args.field[0].flags;
859bd389b36SDavid du Colombier 			if(args.field[0].flags & Bflag)
860bd389b36SDavid du Colombier 				f->flags |= B1flag;
861bd389b36SDavid du Colombier 		}
862bd389b36SDavid du Colombier 
863bd389b36SDavid du Colombier 
864bd389b36SDavid du Colombier 		/*
865bd389b36SDavid du Colombier 		 * build buildkey specification
866bd389b36SDavid du Colombier 		 */
867bd389b36SDavid du Colombier 		switch(f->flags & ~(Bflag|B1flag)) {
868bd389b36SDavid du Colombier 		default:
869bd389b36SDavid du Colombier 			fprint(2, "sort: illegal combination of flags: %lx\n", f->flags);
870bd389b36SDavid du Colombier 			done("option");
871bd389b36SDavid du Colombier 		case 0:
872bd389b36SDavid du Colombier 			f->dokey = dokey_;
873bd389b36SDavid du Colombier 			break;
874bd389b36SDavid du Colombier 		case Rflag:
875bd389b36SDavid du Colombier 			f->dokey = dokey_r;
876bd389b36SDavid du Colombier 			break;
877bd389b36SDavid du Colombier 		case Gflag:
878bd389b36SDavid du Colombier 		case Nflag:
879bd389b36SDavid du Colombier 		case Gflag|Nflag:
880bd389b36SDavid du Colombier 		case Gflag|Rflag:
881bd389b36SDavid du Colombier 		case Nflag|Rflag:
882bd389b36SDavid du Colombier 		case Gflag|Nflag|Rflag:
883bd389b36SDavid du Colombier 			f->dokey = dokey_gn;
884bd389b36SDavid du Colombier 			break;
885bd389b36SDavid du Colombier 		case Mflag:
886bd389b36SDavid du Colombier 		case Mflag|Rflag:
887bd389b36SDavid du Colombier 			f->dokey = dokey_m;
888bd389b36SDavid du Colombier 			makemapm(f);
889bd389b36SDavid du Colombier 			break;
890bd389b36SDavid du Colombier 		case Dflag:
891bd389b36SDavid du Colombier 		case Dflag|Fflag:
892bd389b36SDavid du Colombier 		case Dflag|Fflag|Iflag:
893bd389b36SDavid du Colombier 		case Dflag|Fflag|Iflag|Rflag:
894bd389b36SDavid du Colombier 		case Dflag|Fflag|Iflag|Rflag|Wflag:
895bd389b36SDavid du Colombier 		case Dflag|Fflag|Iflag|Wflag:
896bd389b36SDavid du Colombier 		case Dflag|Fflag|Rflag:
897bd389b36SDavid du Colombier 		case Dflag|Fflag|Rflag|Wflag:
898bd389b36SDavid du Colombier 		case Dflag|Fflag|Wflag:
899bd389b36SDavid du Colombier 		case Dflag|Iflag:
900bd389b36SDavid du Colombier 		case Dflag|Iflag|Rflag:
901bd389b36SDavid du Colombier 		case Dflag|Iflag|Rflag|Wflag:
902bd389b36SDavid du Colombier 		case Dflag|Iflag|Wflag:
903bd389b36SDavid du Colombier 		case Dflag|Rflag:
904bd389b36SDavid du Colombier 		case Dflag|Rflag|Wflag:
905bd389b36SDavid du Colombier 		case Dflag|Wflag:
906bd389b36SDavid du Colombier 		case Fflag:
907bd389b36SDavid du Colombier 		case Fflag|Iflag:
908bd389b36SDavid du Colombier 		case Fflag|Iflag|Rflag:
909bd389b36SDavid du Colombier 		case Fflag|Iflag|Rflag|Wflag:
910bd389b36SDavid du Colombier 		case Fflag|Iflag|Wflag:
911bd389b36SDavid du Colombier 		case Fflag|Rflag:
912bd389b36SDavid du Colombier 		case Fflag|Rflag|Wflag:
913bd389b36SDavid du Colombier 		case Fflag|Wflag:
914bd389b36SDavid du Colombier 		case Iflag:
915bd389b36SDavid du Colombier 		case Iflag|Rflag:
916bd389b36SDavid du Colombier 		case Iflag|Rflag|Wflag:
917bd389b36SDavid du Colombier 		case Iflag|Wflag:
918bd389b36SDavid du Colombier 		case Wflag:
919bd389b36SDavid du Colombier 			f->dokey = dokey_dfi;
920bd389b36SDavid du Colombier 			makemapd(f);
921bd389b36SDavid du Colombier 			break;
922bd389b36SDavid du Colombier 		}
923bd389b36SDavid du Colombier 	}
924bd389b36SDavid du Colombier 
925bd389b36SDavid du Colombier 	/*
926bd389b36SDavid du Colombier 	 * random spot checks
927bd389b36SDavid du Colombier 	 */
928bd389b36SDavid du Colombier 	if(args.nfile > 1 && args.cflag) {
929bd389b36SDavid du Colombier 		fprint(2, "sort: -c can have at most one input file\n");
930bd389b36SDavid du Colombier 		done("option");
931bd389b36SDavid du Colombier 	}
932bd389b36SDavid du Colombier 	return;
933bd389b36SDavid du Colombier }
934bd389b36SDavid du Colombier 
935bd389b36SDavid du Colombier uchar*
skip(uchar * l,int n1,int n2,int bflag,int endfield)936bd389b36SDavid du Colombier skip(uchar *l, int n1, int n2, int bflag, int endfield)
937bd389b36SDavid du Colombier {
938bd389b36SDavid du Colombier 	int i, c, tc;
939bd389b36SDavid du Colombier 	Rune r;
940bd389b36SDavid du Colombier 
941bd389b36SDavid du Colombier 	if(endfield && n1 < 0)
942bd389b36SDavid du Colombier 		return 0;
943bd389b36SDavid du Colombier 
944bd389b36SDavid du Colombier 	c = *l++;
945bd389b36SDavid du Colombier 	tc = args.tabchar;
946bd389b36SDavid du Colombier 	if(tc) {
947bd389b36SDavid du Colombier 		if(tc < Runeself) {
948bd389b36SDavid du Colombier 			for(i=n1; i>0; i--) {
949bd389b36SDavid du Colombier 				while(c != tc) {
950bd389b36SDavid du Colombier 					if(c == '\n')
951bd389b36SDavid du Colombier 						return 0;
952bd389b36SDavid du Colombier 					c = *l++;
953bd389b36SDavid du Colombier 				}
954bd389b36SDavid du Colombier 				if(!(endfield && i == 1))
955bd389b36SDavid du Colombier 					c = *l++;
956bd389b36SDavid du Colombier 			}
957bd389b36SDavid du Colombier 		} else {
958bd389b36SDavid du Colombier 			l--;
959bd389b36SDavid du Colombier 			l += chartorune(&r, (char*)l);
960bd389b36SDavid du Colombier 			for(i=n1; i>0; i--) {
961bd389b36SDavid du Colombier 				while(r != tc) {
962bd389b36SDavid du Colombier 					if(r == '\n')
963bd389b36SDavid du Colombier 						return 0;
964bd389b36SDavid du Colombier 					l += chartorune(&r, (char*)l);
965bd389b36SDavid du Colombier 				}
966bd389b36SDavid du Colombier 				if(!(endfield && i == 1))
967bd389b36SDavid du Colombier 					l += chartorune(&r, (char*)l);
968bd389b36SDavid du Colombier 			}
969bd389b36SDavid du Colombier 			c = r;
970bd389b36SDavid du Colombier 		}
971bd389b36SDavid du Colombier 	} else {
972bd389b36SDavid du Colombier 		for(i=n1; i>0; i--) {
973bd389b36SDavid du Colombier 			while(c == ' ' || c == '\t')
974bd389b36SDavid du Colombier 				c = *l++;
975bd389b36SDavid du Colombier 			while(c != ' ' && c != '\t') {
976bd389b36SDavid du Colombier 				if(c == '\n')
977bd389b36SDavid du Colombier 					return 0;
978bd389b36SDavid du Colombier 				c = *l++;
979bd389b36SDavid du Colombier 			}
980bd389b36SDavid du Colombier 		}
981bd389b36SDavid du Colombier 	}
982bd389b36SDavid du Colombier 
983bd389b36SDavid du Colombier 	if(bflag)
984bd389b36SDavid du Colombier 		while(c == ' ' || c == '\t')
985bd389b36SDavid du Colombier 			c = *l++;
986bd389b36SDavid du Colombier 
987bd389b36SDavid du Colombier 	l--;
988bd389b36SDavid du Colombier 	for(i=n2; i>0; i--) {
989bd389b36SDavid du Colombier 		c = *l;
990bd389b36SDavid du Colombier 		if(c < Runeself) {
991bd389b36SDavid du Colombier 			if(c == '\n')
992bd389b36SDavid du Colombier 				return 0;
993bd389b36SDavid du Colombier 			l++;
994bd389b36SDavid du Colombier 			continue;
995bd389b36SDavid du Colombier 		}
996bd389b36SDavid du Colombier 		l += chartorune(&r, (char*)l);
997bd389b36SDavid du Colombier 	}
998bd389b36SDavid du Colombier 	return l;
999bd389b36SDavid du Colombier }
1000bd389b36SDavid du Colombier 
1001bd389b36SDavid du Colombier void
dokey_gn(Key * k,uchar * lp,uchar * lpe,Field * f)1002bd389b36SDavid du Colombier dokey_gn(Key *k, uchar *lp, uchar *lpe, Field *f)
1003bd389b36SDavid du Colombier {
1004bd389b36SDavid du Colombier 	uchar *kp;
1005bd389b36SDavid du Colombier 	int c, cl, dp;
1006bd389b36SDavid du Colombier 	int state, nzero, exp, expsign, rflag;
1007bd389b36SDavid du Colombier 
1008bd389b36SDavid du Colombier 	cl = k->klen + 3;
1009bd389b36SDavid du Colombier 	kp = k->key + cl;	/* skip place for sign, exponent[2] */
1010bd389b36SDavid du Colombier 
1011bd389b36SDavid du Colombier 	nzero = 0;		/* number of trailing zeros */
1012bd389b36SDavid du Colombier 	exp = 0;		/* value of the exponent */
1013bd389b36SDavid du Colombier 	expsign = 0;		/* sign of the exponent */
1014bd389b36SDavid du Colombier 	dp = 0x4040;		/* location of decimal point */
1015bd389b36SDavid du Colombier 	rflag = f->flags&Rflag;	/* xor of rflag and - sign */
1016bd389b36SDavid du Colombier 	state = NSstart;
1017bd389b36SDavid du Colombier 
1018bd389b36SDavid du Colombier 	for(;; lp++) {
1019bd389b36SDavid du Colombier 		if(lp >= lpe)
1020bd389b36SDavid du Colombier 			break;
1021bd389b36SDavid du Colombier 		c = *lp;
1022bd389b36SDavid du Colombier 
1023bd389b36SDavid du Colombier 		if(c == ' ' || c == '\t') {
1024bd389b36SDavid du Colombier 			switch(state) {
1025bd389b36SDavid du Colombier 			case NSstart:
1026bd389b36SDavid du Colombier 			case NSsign:
1027bd389b36SDavid du Colombier 				continue;
1028bd389b36SDavid du Colombier 			}
1029bd389b36SDavid du Colombier 			break;
1030bd389b36SDavid du Colombier 		}
1031bd389b36SDavid du Colombier 		if(c == '+' || c == '-') {
1032bd389b36SDavid du Colombier 			switch(state) {
1033bd389b36SDavid du Colombier 			case NSstart:
1034bd389b36SDavid du Colombier 				state = NSsign;
1035bd389b36SDavid du Colombier 				if(c == '-')
1036bd389b36SDavid du Colombier 					rflag = !rflag;
1037bd389b36SDavid du Colombier 				continue;
1038bd389b36SDavid du Colombier 			case NSexp:
1039bd389b36SDavid du Colombier 				state = NSexpsign;
1040bd389b36SDavid du Colombier 				if(c == '-')
1041bd389b36SDavid du Colombier 					expsign = 1;
1042bd389b36SDavid du Colombier 				continue;
1043bd389b36SDavid du Colombier 			}
1044bd389b36SDavid du Colombier 			break;
1045bd389b36SDavid du Colombier 		}
1046bd389b36SDavid du Colombier 		if(c == '0') {
1047bd389b36SDavid du Colombier 			switch(state) {
1048bd389b36SDavid du Colombier 			case NSdigit:
1049bd389b36SDavid du Colombier 				if(rflag)
1050bd389b36SDavid du Colombier 					c = ~c;
1051bd389b36SDavid du Colombier 				*kp++ = c;
1052bd389b36SDavid du Colombier 				cl++;
1053bd389b36SDavid du Colombier 				nzero++;
1054bd389b36SDavid du Colombier 				dp++;
1055bd389b36SDavid du Colombier 				state = NSdigit;
1056bd389b36SDavid du Colombier 				continue;
1057bd389b36SDavid du Colombier 			case NSfract:
1058bd389b36SDavid du Colombier 				if(rflag)
1059bd389b36SDavid du Colombier 					c = ~c;
1060bd389b36SDavid du Colombier 				*kp++ = c;
1061bd389b36SDavid du Colombier 				cl++;
1062bd389b36SDavid du Colombier 				nzero++;
1063bd389b36SDavid du Colombier 				state = NSfract;
1064bd389b36SDavid du Colombier 				continue;
1065bd389b36SDavid du Colombier 			case NSstart:
1066bd389b36SDavid du Colombier 			case NSsign:
1067bd389b36SDavid du Colombier 			case NSzero:
1068bd389b36SDavid du Colombier 				state = NSzero;
1069bd389b36SDavid du Colombier 				continue;
1070bd389b36SDavid du Colombier 			case NSzerofract:
1071bd389b36SDavid du Colombier 			case NSpoint:
1072bd389b36SDavid du Colombier 				dp--;
1073bd389b36SDavid du Colombier 				state = NSzerofract;
1074bd389b36SDavid du Colombier 				continue;
1075bd389b36SDavid du Colombier 			case NSexpsign:
1076bd389b36SDavid du Colombier 			case NSexp:
1077bd389b36SDavid du Colombier 			case NSexpdigit:
1078bd389b36SDavid du Colombier 				exp = exp*10 + (c - '0');
1079bd389b36SDavid du Colombier 				state = NSexpdigit;
1080bd389b36SDavid du Colombier 				continue;
1081bd389b36SDavid du Colombier 			}
1082bd389b36SDavid du Colombier 			break;
1083bd389b36SDavid du Colombier 		}
1084bd389b36SDavid du Colombier 		if(c >= '1' && c <= '9') {
1085bd389b36SDavid du Colombier 			switch(state) {
1086bd389b36SDavid du Colombier 			case NSzero:
1087bd389b36SDavid du Colombier 			case NSstart:
1088bd389b36SDavid du Colombier 			case NSsign:
1089bd389b36SDavid du Colombier 			case NSdigit:
1090bd389b36SDavid du Colombier 				if(rflag)
1091bd389b36SDavid du Colombier 					c = ~c;
1092bd389b36SDavid du Colombier 				*kp++ = c;
1093bd389b36SDavid du Colombier 				cl++;
1094bd389b36SDavid du Colombier 				nzero = 0;
1095bd389b36SDavid du Colombier 				dp++;
1096bd389b36SDavid du Colombier 				state = NSdigit;
1097bd389b36SDavid du Colombier 				continue;
1098bd389b36SDavid du Colombier 			case NSzerofract:
1099bd389b36SDavid du Colombier 			case NSpoint:
1100bd389b36SDavid du Colombier 			case NSfract:
1101bd389b36SDavid du Colombier 				if(rflag)
1102bd389b36SDavid du Colombier 					c = ~c;
1103bd389b36SDavid du Colombier 				*kp++ = c;
1104bd389b36SDavid du Colombier 				cl++;
1105bd389b36SDavid du Colombier 				nzero = 0;
1106bd389b36SDavid du Colombier 				state = NSfract;
1107bd389b36SDavid du Colombier 				continue;
1108bd389b36SDavid du Colombier 			case NSexpsign:
1109bd389b36SDavid du Colombier 			case NSexp:
1110bd389b36SDavid du Colombier 			case NSexpdigit:
1111bd389b36SDavid du Colombier 				exp = exp*10 + (c - '0');
1112bd389b36SDavid du Colombier 				state = NSexpdigit;
1113bd389b36SDavid du Colombier 				continue;
1114bd389b36SDavid du Colombier 			}
1115bd389b36SDavid du Colombier 			break;
1116bd389b36SDavid du Colombier 		}
1117bd389b36SDavid du Colombier 		if(c == '.') {
1118bd389b36SDavid du Colombier 			switch(state) {
1119bd389b36SDavid du Colombier 			case NSstart:
1120bd389b36SDavid du Colombier 			case NSsign:
1121bd389b36SDavid du Colombier 				state = NSpoint;
1122bd389b36SDavid du Colombier 				continue;
1123bd389b36SDavid du Colombier 			case NSzero:
1124bd389b36SDavid du Colombier 				state = NSzerofract;
1125bd389b36SDavid du Colombier 				continue;
1126bd389b36SDavid du Colombier 			case NSdigit:
1127bd389b36SDavid du Colombier 				state = NSfract;
1128bd389b36SDavid du Colombier 				continue;
1129bd389b36SDavid du Colombier 			}
1130bd389b36SDavid du Colombier 			break;
1131bd389b36SDavid du Colombier 		}
1132bd389b36SDavid du Colombier 		if((f->flags & Gflag) && (c == 'e' || c == 'E')) {
1133bd389b36SDavid du Colombier 			switch(state) {
1134bd389b36SDavid du Colombier 			case NSdigit:
1135bd389b36SDavid du Colombier 			case NSfract:
1136bd389b36SDavid du Colombier 				state = NSexp;
1137bd389b36SDavid du Colombier 				continue;
1138bd389b36SDavid du Colombier 			}
1139bd389b36SDavid du Colombier 			break;
1140bd389b36SDavid du Colombier 		}
1141bd389b36SDavid du Colombier 		break;
1142bd389b36SDavid du Colombier 	}
1143bd389b36SDavid du Colombier 
1144bd389b36SDavid du Colombier 	switch(state) {
1145bd389b36SDavid du Colombier 	/*
1146bd389b36SDavid du Colombier 	 * result is zero
1147bd389b36SDavid du Colombier 	 */
1148bd389b36SDavid du Colombier 	case NSstart:
1149bd389b36SDavid du Colombier 	case NSsign:
1150bd389b36SDavid du Colombier 	case NSzero:
1151bd389b36SDavid du Colombier 	case NSzerofract:
1152bd389b36SDavid du Colombier 	case NSpoint:
1153bd389b36SDavid du Colombier 		kp = k->key + k->klen;
1154bd389b36SDavid du Colombier 		k->klen += 2;
1155bd389b36SDavid du Colombier 		kp[0] = 0x20;	/* between + and - */
1156bd389b36SDavid du Colombier 		kp[1] = 0;
1157bd389b36SDavid du Colombier 		return;
1158bd389b36SDavid du Colombier 	/*
1159bd389b36SDavid du Colombier 	 * result has exponent
1160bd389b36SDavid du Colombier 	 */
1161bd389b36SDavid du Colombier 	case NSexpsign:
1162bd389b36SDavid du Colombier 	case NSexp:
1163bd389b36SDavid du Colombier 	case NSexpdigit:
1164bd389b36SDavid du Colombier 		if(expsign)
1165bd389b36SDavid du Colombier 			exp = -exp;
1166bd389b36SDavid du Colombier 		dp += exp;
1167bd389b36SDavid du Colombier 
1168bd389b36SDavid du Colombier 	/*
1169bd389b36SDavid du Colombier 	 * result is fixed point number
1170bd389b36SDavid du Colombier 	 */
1171bd389b36SDavid du Colombier 	case NSdigit:
1172bd389b36SDavid du Colombier 	case NSfract:
1173bd389b36SDavid du Colombier 		kp -= nzero;
1174bd389b36SDavid du Colombier 		cl -= nzero;
1175bd389b36SDavid du Colombier 		break;
1176bd389b36SDavid du Colombier 	}
1177bd389b36SDavid du Colombier 
1178bd389b36SDavid du Colombier 	/*
1179bd389b36SDavid du Colombier 	 * end of number
1180bd389b36SDavid du Colombier 	 */
1181bd389b36SDavid du Colombier 	c = 0;
1182bd389b36SDavid du Colombier 	if(rflag)
1183bd389b36SDavid du Colombier 		c = ~c;
1184bd389b36SDavid du Colombier 	*kp = c;
1185bd389b36SDavid du Colombier 
1186bd389b36SDavid du Colombier 	/*
1187bd389b36SDavid du Colombier 	 * sign and exponent
1188bd389b36SDavid du Colombier 	 */
1189bd389b36SDavid du Colombier 	c = 0x30;
1190bd389b36SDavid du Colombier 	if(rflag) {
1191bd389b36SDavid du Colombier 		c = 0x10;
1192bd389b36SDavid du Colombier 		dp = ~dp;
1193bd389b36SDavid du Colombier 	}
1194bd389b36SDavid du Colombier 	kp = k->key + k->klen;
1195bd389b36SDavid du Colombier 	kp[0] = c;
1196bd389b36SDavid du Colombier 	kp[1] = (dp >> 8);
1197bd389b36SDavid du Colombier 	kp[2] = dp;
1198bd389b36SDavid du Colombier 	k->klen = cl+1;
1199bd389b36SDavid du Colombier }
1200bd389b36SDavid du Colombier 
1201bd389b36SDavid du Colombier void
dokey_m(Key * k,uchar * lp,uchar * lpe,Field * f)1202bd389b36SDavid du Colombier dokey_m(Key *k, uchar *lp, uchar *lpe, Field *f)
1203bd389b36SDavid du Colombier {
1204bd389b36SDavid du Colombier 	uchar *kp;
1205bd389b36SDavid du Colombier 	Rune r, place[3];
1206bd389b36SDavid du Colombier 	int c, cl, pc;
1207bd389b36SDavid du Colombier 	int rflag;
1208bd389b36SDavid du Colombier 
1209bd389b36SDavid du Colombier 	rflag = f->flags&Rflag;
1210bd389b36SDavid du Colombier 	pc = 0;
1211bd389b36SDavid du Colombier 
1212bd389b36SDavid du Colombier 	cl = k->klen;
1213bd389b36SDavid du Colombier 	kp = k->key + cl;
1214bd389b36SDavid du Colombier 
1215bd389b36SDavid du Colombier 	for(;;) {
1216bd389b36SDavid du Colombier 		/*
1217bd389b36SDavid du Colombier 		 * get the character
1218bd389b36SDavid du Colombier 		 */
1219bd389b36SDavid du Colombier 		if(lp >= lpe)
1220bd389b36SDavid du Colombier 			break;
1221bd389b36SDavid du Colombier 		c = *lp;
1222bd389b36SDavid du Colombier 		if(c >= Runeself) {
1223bd389b36SDavid du Colombier 			lp += chartorune(&r, (char*)lp);
1224bd389b36SDavid du Colombier 			c = r;
1225bd389b36SDavid du Colombier 		} else
1226bd389b36SDavid du Colombier 			lp++;
1227bd389b36SDavid du Colombier 
1228bd389b36SDavid du Colombier 		if(c < nelem(f->mapto)) {
1229bd389b36SDavid du Colombier 			c = f->mapto[c];
1230bd389b36SDavid du Colombier 			if(c == 0)
1231bd389b36SDavid du Colombier 				continue;
1232bd389b36SDavid du Colombier 		}
1233bd389b36SDavid du Colombier 		place[pc++] = c;
1234bd389b36SDavid du Colombier 		if(pc < 3)
1235bd389b36SDavid du Colombier 			continue;
1236bd389b36SDavid du Colombier 		for(c=11; c>=0; c--)
1237bd389b36SDavid du Colombier 			if(memcmp(month[c], place, sizeof(place)) == 0)
1238bd389b36SDavid du Colombier 				break;
1239bd389b36SDavid du Colombier 		c += 10;
1240bd389b36SDavid du Colombier 		if(rflag)
1241bd389b36SDavid du Colombier 			c = ~c;
1242bd389b36SDavid du Colombier 		*kp++ = c;
1243bd389b36SDavid du Colombier 		cl++;
1244bd389b36SDavid du Colombier 		break;
1245bd389b36SDavid du Colombier 	}
1246bd389b36SDavid du Colombier 
1247bd389b36SDavid du Colombier 	c = 0;
1248bd389b36SDavid du Colombier 	if(rflag)
1249bd389b36SDavid du Colombier 		c = ~c;
1250bd389b36SDavid du Colombier 	*kp = c;
1251bd389b36SDavid du Colombier 	k->klen = cl+1;
1252bd389b36SDavid du Colombier }
1253bd389b36SDavid du Colombier 
1254bd389b36SDavid du Colombier void
dokey_dfi(Key * k,uchar * lp,uchar * lpe,Field * f)1255bd389b36SDavid du Colombier dokey_dfi(Key *k, uchar *lp, uchar *lpe, Field *f)
1256bd389b36SDavid du Colombier {
1257bd389b36SDavid du Colombier 	uchar *kp;
1258bd389b36SDavid du Colombier 	Rune r;
1259bd389b36SDavid du Colombier 	int c, cl, n, rflag;
1260bd389b36SDavid du Colombier 
1261bd389b36SDavid du Colombier 	cl = k->klen;
1262bd389b36SDavid du Colombier 	kp = k->key + cl;
1263bd389b36SDavid du Colombier 	rflag = f->flags & Rflag;
1264bd389b36SDavid du Colombier 
1265bd389b36SDavid du Colombier 	for(;;) {
1266bd389b36SDavid du Colombier 		/*
1267bd389b36SDavid du Colombier 		 * get the character
1268bd389b36SDavid du Colombier 		 */
1269bd389b36SDavid du Colombier 		if(lp >= lpe)
1270bd389b36SDavid du Colombier 			break;
1271bd389b36SDavid du Colombier 		c = *lp;
1272bd389b36SDavid du Colombier 		if(c >= Runeself) {
1273bd389b36SDavid du Colombier 			lp += chartorune(&r, (char*)lp);
1274bd389b36SDavid du Colombier 			c = r;
1275bd389b36SDavid du Colombier 		} else
1276bd389b36SDavid du Colombier 			lp++;
1277bd389b36SDavid du Colombier 
1278bd389b36SDavid du Colombier 		/*
1279bd389b36SDavid du Colombier 		 * do the various mappings.
1280bd389b36SDavid du Colombier 		 * the common case is handled
1281bd389b36SDavid du Colombier 		 * completely by the table.
1282bd389b36SDavid du Colombier 		 */
1283bd389b36SDavid du Colombier 		if(c != 0 && c < Runeself) {
1284bd389b36SDavid du Colombier 			c = f->mapto[c];
1285bd389b36SDavid du Colombier 			if(c) {
1286bd389b36SDavid du Colombier 				*kp++ = c;
1287bd389b36SDavid du Colombier 				cl++;
1288bd389b36SDavid du Colombier 			}
1289bd389b36SDavid du Colombier 			continue;
1290bd389b36SDavid du Colombier 		}
1291bd389b36SDavid du Colombier 
1292bd389b36SDavid du Colombier 		/*
1293bd389b36SDavid du Colombier 		 * for characters out of range,
1294bd389b36SDavid du Colombier 		 * the table does not do Rflag.
1295*4db25db6SDavid du Colombier 		 * ignore is based on mapto[nelem(f->mapto)-1]
1296bd389b36SDavid du Colombier 		 */
1297bd389b36SDavid du Colombier 		if(c != 0 && c < nelem(f->mapto)) {
1298bd389b36SDavid du Colombier 			c = f->mapto[c];
1299bd389b36SDavid du Colombier 			if(c == 0)
1300bd389b36SDavid du Colombier 				continue;
1301eaba85aaSDavid du Colombier 		} else {
1302bd389b36SDavid du Colombier 			if(f->mapto[nelem(f->mapto)-1] == 0)
1303bd389b36SDavid du Colombier 				continue;
1304eaba85aaSDavid du Colombier 			/*
1305eaba85aaSDavid du Colombier 			 * consider building maps as necessary
1306eaba85aaSDavid du Colombier 			 */
1307eaba85aaSDavid du Colombier 			if(f->flags & Fflag)
1308eaba85aaSDavid du Colombier 				c = tolowerrune(tobaserune(c));
1309eaba85aaSDavid du Colombier 			if(f->flags & Dflag && !isalpharune(c) &&
1310eaba85aaSDavid du Colombier 			    !isdigitrune(c) && !isspacerune(c))
1311eaba85aaSDavid du Colombier 				continue;
1312eaba85aaSDavid du Colombier 			if((f->flags & Wflag) && isspacerune(c))
1313eaba85aaSDavid du Colombier 				continue;
1314eaba85aaSDavid du Colombier 		}
1315bd389b36SDavid du Colombier 
1316bd389b36SDavid du Colombier 		/*
1317bd389b36SDavid du Colombier 		 * put it in the key
1318bd389b36SDavid du Colombier 		 */
1319bd389b36SDavid du Colombier 		r = c;
1320bd389b36SDavid du Colombier 		n = runetochar((char*)kp, &r);
1321bd389b36SDavid du Colombier 		kp += n;
1322bd389b36SDavid du Colombier 		cl += n;
1323bd389b36SDavid du Colombier 		if(rflag)
1324bd389b36SDavid du Colombier 			while(n > 0) {
1325bd389b36SDavid du Colombier 				kp[-n] = ~kp[-n];
1326bd389b36SDavid du Colombier 				n--;
1327bd389b36SDavid du Colombier 			}
1328bd389b36SDavid du Colombier 	}
1329bd389b36SDavid du Colombier 
1330bd389b36SDavid du Colombier 	/*
1331bd389b36SDavid du Colombier 	 * end of key
1332bd389b36SDavid du Colombier 	 */
1333bd389b36SDavid du Colombier 	k->klen = cl+1;
1334bd389b36SDavid du Colombier 	if(rflag) {
1335bd389b36SDavid du Colombier 		*kp = ~0;
1336bd389b36SDavid du Colombier 		return;
1337bd389b36SDavid du Colombier 	}
1338bd389b36SDavid du Colombier 	*kp = 0;
1339bd389b36SDavid du Colombier }
1340bd389b36SDavid du Colombier 
1341bd389b36SDavid du Colombier void
dokey_r(Key * k,uchar * lp,uchar * lpe,Field *)13427dd7cddfSDavid du Colombier dokey_r(Key *k, uchar *lp, uchar *lpe, Field*)
1343bd389b36SDavid du Colombier {
1344bd389b36SDavid du Colombier 	int cl, n;
1345bd389b36SDavid du Colombier 	uchar *kp;
1346bd389b36SDavid du Colombier 
1347bd389b36SDavid du Colombier 	n = lpe - lp;
1348bd389b36SDavid du Colombier 	if(n < 0)
1349bd389b36SDavid du Colombier 		n = 0;
1350bd389b36SDavid du Colombier 	cl = k->klen;
1351bd389b36SDavid du Colombier 	kp = k->key + cl;
1352bd389b36SDavid du Colombier 	k->klen = cl+n+1;
1353bd389b36SDavid du Colombier 
1354bd389b36SDavid du Colombier 	lpe -= 3;
1355bd389b36SDavid du Colombier 	while(lp < lpe) {
1356bd389b36SDavid du Colombier 		kp[0] = ~lp[0];
1357bd389b36SDavid du Colombier 		kp[1] = ~lp[1];
1358bd389b36SDavid du Colombier 		kp[2] = ~lp[2];
1359bd389b36SDavid du Colombier 		kp[3] = ~lp[3];
1360bd389b36SDavid du Colombier 		kp += 4;
1361bd389b36SDavid du Colombier 		lp += 4;
1362bd389b36SDavid du Colombier 	}
1363bd389b36SDavid du Colombier 
1364bd389b36SDavid du Colombier 	lpe += 3;
1365bd389b36SDavid du Colombier 	while(lp < lpe)
1366bd389b36SDavid du Colombier 		*kp++ = ~*lp++;
1367bd389b36SDavid du Colombier 	*kp = ~0;
1368bd389b36SDavid du Colombier }
1369bd389b36SDavid du Colombier 
1370bd389b36SDavid du Colombier void
dokey_(Key * k,uchar * lp,uchar * lpe,Field *)13717dd7cddfSDavid du Colombier dokey_(Key *k, uchar *lp, uchar *lpe, Field*)
1372bd389b36SDavid du Colombier {
1373bd389b36SDavid du Colombier 	int n, cl;
1374bd389b36SDavid du Colombier 	uchar *kp;
1375bd389b36SDavid du Colombier 
1376bd389b36SDavid du Colombier 	n = lpe - lp;
1377bd389b36SDavid du Colombier 	if(n < 0)
1378bd389b36SDavid du Colombier 		n = 0;
1379bd389b36SDavid du Colombier 	cl = k->klen;
1380bd389b36SDavid du Colombier 	kp = k->key + cl;
1381bd389b36SDavid du Colombier 	k->klen = cl+n+1;
1382bd389b36SDavid du Colombier 	memmove(kp, lp, n);
1383bd389b36SDavid du Colombier 	kp[n] = 0;
1384bd389b36SDavid du Colombier }
1385bd389b36SDavid du Colombier 
1386bd389b36SDavid du Colombier void
buildkey(Line * l)1387bd389b36SDavid du Colombier buildkey(Line *l)
1388bd389b36SDavid du Colombier {
1389bd389b36SDavid du Colombier 	Key *k;
1390bd389b36SDavid du Colombier 	uchar *lp, *lpe;
1391bd389b36SDavid du Colombier 	int ll, kl, cl, i, n;
1392bd389b36SDavid du Colombier 	Field *f;
1393bd389b36SDavid du Colombier 
1394bd389b36SDavid du Colombier 	ll = l->llen - 1;
1395bd389b36SDavid du Colombier 	kl = 0;			/* allocated length */
1396bd389b36SDavid du Colombier 	cl = 0;			/* current length */
1397bd389b36SDavid du Colombier 	k = 0;
1398bd389b36SDavid du Colombier 
1399bd389b36SDavid du Colombier 	for(i=1; i<=args.nfield; i++) {
1400bd389b36SDavid du Colombier 		f = &args.field[i];
1401bd389b36SDavid du Colombier 		lp = skip(l->line, f->beg1, f->beg2, f->flags&B1flag, 0);
1402bd389b36SDavid du Colombier 		if(lp == 0)
1403bd389b36SDavid du Colombier 			lp = l->line + ll;
1404bd389b36SDavid du Colombier 		lpe = skip(l->line, f->end1, f->end2, f->flags&Bflag, 1);
1405bd389b36SDavid du Colombier 		if(lpe == 0)
1406bd389b36SDavid du Colombier 			lpe = l->line + ll;
1407bd389b36SDavid du Colombier 		n = (lpe - lp) + 1;
1408bd389b36SDavid du Colombier 		if(n <= 0)
1409bd389b36SDavid du Colombier 			n = 1;
1410bd389b36SDavid du Colombier 		if(cl+(n+4) > kl) {
1411bd389b36SDavid du Colombier 			kl = cl+(n+4);
1412bd389b36SDavid du Colombier 			k = realloc(k, sizeof(Key) +
1413bd389b36SDavid du Colombier 				(kl-1)*sizeof(k->key[0]));
1414bd389b36SDavid du Colombier 			if(k == 0)
1415bd389b36SDavid du Colombier 				nomem();
1416bd389b36SDavid du Colombier 		}
1417bd389b36SDavid du Colombier 		k->klen = cl;
1418bd389b36SDavid du Colombier 		(*f->dokey)(k, lp, lpe, f);
1419bd389b36SDavid du Colombier 		cl = k->klen;
1420bd389b36SDavid du Colombier 	}
1421bd389b36SDavid du Colombier 
1422bd389b36SDavid du Colombier 	/*
1423bd389b36SDavid du Colombier 	 * global comparisons
1424bd389b36SDavid du Colombier 	 */
1425bd389b36SDavid du Colombier 	if(!(args.uflag && cl > 0)) {
1426bd389b36SDavid du Colombier 		f = &args.field[0];
1427bd389b36SDavid du Colombier 		if(cl+(ll+4) > kl) {
1428bd389b36SDavid du Colombier 			kl = cl+(ll+4);
1429bd389b36SDavid du Colombier 			k = realloc(k, sizeof(Key) +
1430bd389b36SDavid du Colombier 				(kl-1)*sizeof(k->key[0]));
1431bd389b36SDavid du Colombier 			if(k == 0)
1432bd389b36SDavid du Colombier 				nomem();
1433bd389b36SDavid du Colombier 		}
1434bd389b36SDavid du Colombier 		k->klen = cl;
1435bd389b36SDavid du Colombier 		(*f->dokey)(k, l->line, l->line+ll, f);
1436bd389b36SDavid du Colombier 		cl = k->klen;
1437bd389b36SDavid du Colombier 	}
1438bd389b36SDavid du Colombier 
1439bd389b36SDavid du Colombier 	l->key = k;
1440bd389b36SDavid du Colombier 	k->klen = cl;
1441bd389b36SDavid du Colombier 
1442bd389b36SDavid du Colombier 	if(args.vflag) {
1443eaba85aaSDavid du Colombier 		if(write(2, l->line, l->llen) != l->llen)
1444eaba85aaSDavid du Colombier 			exits("write");
1445bd389b36SDavid du Colombier 		for(i=0; i<k->klen; i++) {
1446bd389b36SDavid du Colombier 			fprint(2, " %.2x", k->key[i]);
1447bd389b36SDavid du Colombier 			if(k->key[i] == 0x00 || k->key[i] == 0xff)
1448bd389b36SDavid du Colombier 				fprint(2, "\n");
1449bd389b36SDavid du Colombier 		}
1450bd389b36SDavid du Colombier 	}
1451bd389b36SDavid du Colombier }
1452bd389b36SDavid du Colombier 
1453bd389b36SDavid du Colombier void
makemapm(Field * f)1454bd389b36SDavid du Colombier makemapm(Field *f)
1455bd389b36SDavid du Colombier {
1456bd389b36SDavid du Colombier 	int i, c;
1457bd389b36SDavid du Colombier 
1458bd389b36SDavid du Colombier 	for(i=0; i<nelem(f->mapto); i++) {
1459bd389b36SDavid du Colombier 		c = 1;
1460bd389b36SDavid du Colombier 		if(i == ' ' || i == '\t')
1461bd389b36SDavid du Colombier 			c = 0;
1462bd389b36SDavid du Colombier 		if(i >= 'a' && i <= 'z')
1463bd389b36SDavid du Colombier 			c = i + ('A' - 'a');
1464bd389b36SDavid du Colombier 		if(i >= 'A' && i <= 'Z')
1465bd389b36SDavid du Colombier 			c = i;
1466bd389b36SDavid du Colombier 		f->mapto[i] = c;
1467bd389b36SDavid du Colombier 		if(args.vflag) {
1468bd389b36SDavid du Colombier 			if((i & 15) == 0)
1469bd389b36SDavid du Colombier 				fprint(2, "	");
1470bd389b36SDavid du Colombier 			fprint(2, " %.2x", c);
1471bd389b36SDavid du Colombier 			if((i & 15) == 15)
1472bd389b36SDavid du Colombier 				fprint(2, "\n");
1473bd389b36SDavid du Colombier 		}
1474bd389b36SDavid du Colombier 	}
1475bd389b36SDavid du Colombier }
1476bd389b36SDavid du Colombier 
1477bd389b36SDavid du Colombier void
makemapd(Field * f)1478bd389b36SDavid du Colombier makemapd(Field *f)
1479bd389b36SDavid du Colombier {
1480eaba85aaSDavid du Colombier 	int i, c;
1481bd389b36SDavid du Colombier 
1482bd389b36SDavid du Colombier 	for(i=0; i<nelem(f->mapto); i++) {
1483bd389b36SDavid du Colombier 		c = i;
1484bd389b36SDavid du Colombier 		if(f->flags & Iflag)
1485bd389b36SDavid du Colombier 			if(c < 040 || c > 0176)
1486bd389b36SDavid du Colombier 				c = -1;
1487bd389b36SDavid du Colombier 		if((f->flags & Wflag) && c >= 0)
1488bd389b36SDavid du Colombier 			if(c == ' ' || c == '\t')
1489bd389b36SDavid du Colombier 				c = -1;
1490bd389b36SDavid du Colombier 		if((f->flags & Dflag) && c >= 0)
1491bd389b36SDavid du Colombier 			if(!(c == ' ' || c == '\t' ||
1492bd389b36SDavid du Colombier 			    (c >= 'a' && c <= 'z') ||
1493bd389b36SDavid du Colombier 			    (c >= 'A' && c <= 'Z') ||
1494bd389b36SDavid du Colombier 			    (c >= '0' && c <= '9'))){
1495eaba85aaSDavid du Colombier 				if(!isupperrune(c = toupperrune(c)))
1496bd389b36SDavid du Colombier 					c = -1;
1497bd389b36SDavid du Colombier 			}
1498eaba85aaSDavid du Colombier 		if((f->flags & Fflag) && c >= 0)
1499eaba85aaSDavid du Colombier 			c = toupperrune(tobaserune(c));
1500bd389b36SDavid du Colombier 		if((f->flags & Rflag) && c >= 0 && i > 0 && i < Runeself)
1501bd389b36SDavid du Colombier 			c = ~c & 0xff;
1502bd389b36SDavid du Colombier 		if(c < 0)
1503bd389b36SDavid du Colombier 			c = 0;
1504bd389b36SDavid du Colombier 		f->mapto[i] = c;
1505bd389b36SDavid du Colombier 		if(args.vflag) {
1506bd389b36SDavid du Colombier 			if((i & 15) == 0)
1507bd389b36SDavid du Colombier 				fprint(2, "	");
1508bd389b36SDavid du Colombier 			fprint(2, " %.2x", c);
1509bd389b36SDavid du Colombier 			if((i & 15) == 15)
1510bd389b36SDavid du Colombier 				fprint(2, "\n");
1511bd389b36SDavid du Colombier 		}
1512bd389b36SDavid du Colombier 	}
1513bd389b36SDavid du Colombier }
1514bd389b36SDavid du Colombier 
1515bd389b36SDavid du Colombier Rune*	month[12] =
1516bd389b36SDavid du Colombier {
1517bd389b36SDavid du Colombier 	L"JAN",
1518bd389b36SDavid du Colombier 	L"FEB",
1519bd389b36SDavid du Colombier 	L"MAR",
1520bd389b36SDavid du Colombier 	L"APR",
1521bd389b36SDavid du Colombier 	L"MAY",
1522bd389b36SDavid du Colombier 	L"JUN",
1523bd389b36SDavid du Colombier 	L"JUL",
1524bd389b36SDavid du Colombier 	L"AUG",
1525bd389b36SDavid du Colombier 	L"SEP",
1526bd389b36SDavid du Colombier 	L"OCT",
1527bd389b36SDavid du Colombier 	L"NOV",
1528bd389b36SDavid du Colombier 	L"DEC",
1529bd389b36SDavid du Colombier };
1530bd389b36SDavid du Colombier 
1531bd389b36SDavid du Colombier /************** radix sort ***********/
1532bd389b36SDavid du Colombier 
1533bd389b36SDavid du Colombier enum
1534bd389b36SDavid du Colombier {
1535bd389b36SDavid du Colombier 	Threshold	= 14,
1536bd389b36SDavid du Colombier };
1537bd389b36SDavid du Colombier 
1538bd389b36SDavid du Colombier void	rsort4(Key***, ulong, int);
1539bd389b36SDavid du Colombier void	bsort4(Key***, ulong, int);
1540bd389b36SDavid du Colombier 
1541bd389b36SDavid du Colombier void
sort4(void * a,ulong n)1542bd389b36SDavid du Colombier sort4(void *a, ulong n)
1543bd389b36SDavid du Colombier {
1544bd389b36SDavid du Colombier 	if(n > Threshold)
1545bd389b36SDavid du Colombier 		rsort4((Key***)a, n, 0);
1546bd389b36SDavid du Colombier 	else
1547bd389b36SDavid du Colombier 		bsort4((Key***)a, n, 0);
1548bd389b36SDavid du Colombier }
1549bd389b36SDavid du Colombier 
1550bd389b36SDavid du Colombier void
rsort4(Key *** a,ulong n,int b)1551bd389b36SDavid du Colombier rsort4(Key ***a, ulong n, int b)
1552bd389b36SDavid du Colombier {
1553bd389b36SDavid du Colombier 	Key ***ea, ***t, ***u, **t1, **u1, *k;
1554bd389b36SDavid du Colombier 	Key ***part[257];
1555bd389b36SDavid du Colombier 	static long count[257];
1556bd389b36SDavid du Colombier 	long clist[257+257], *cp, *cp1;
1557bd389b36SDavid du Colombier 	int c, lowc, higc;
1558bd389b36SDavid du Colombier 
1559bd389b36SDavid du Colombier 	/*
1560bd389b36SDavid du Colombier 	 * pass 1 over all keys,
1561bd389b36SDavid du Colombier 	 * count the number of each key[b].
1562bd389b36SDavid du Colombier 	 * find low count and high count.
1563bd389b36SDavid du Colombier 	 */
1564bd389b36SDavid du Colombier 	lowc = 256;
1565bd389b36SDavid du Colombier 	higc = 0;
1566bd389b36SDavid du Colombier 	ea = a+n;
1567bd389b36SDavid du Colombier 	for(t=a; t<ea; t++) {
1568bd389b36SDavid du Colombier 		k = **t;
1569bd389b36SDavid du Colombier 		n = k->klen;
1570bd389b36SDavid du Colombier 		if(b >= n) {
1571bd389b36SDavid du Colombier 			count[256]++;
1572bd389b36SDavid du Colombier 			continue;
1573bd389b36SDavid du Colombier 		}
1574bd389b36SDavid du Colombier 		c = k->key[b];
1575bd389b36SDavid du Colombier 		n = count[c]++;
1576bd389b36SDavid du Colombier 		if(n == 0) {
1577bd389b36SDavid du Colombier 			if(c < lowc)
1578bd389b36SDavid du Colombier 				lowc = c;
1579bd389b36SDavid du Colombier 			if(c > higc)
1580bd389b36SDavid du Colombier 				higc = c;
1581bd389b36SDavid du Colombier 		}
1582bd389b36SDavid du Colombier 	}
1583bd389b36SDavid du Colombier 
1584bd389b36SDavid du Colombier 	/*
1585bd389b36SDavid du Colombier 	 * pass 2 over all counts,
1586bd389b36SDavid du Colombier 	 * put partition pointers in part[c].
1587bd389b36SDavid du Colombier 	 * save compacted indexes and counts
1588bd389b36SDavid du Colombier 	 * in clist[].
1589bd389b36SDavid du Colombier 	 */
1590bd389b36SDavid du Colombier 	t = a;
1591bd389b36SDavid du Colombier 	n = count[256];
1592bd389b36SDavid du Colombier 	clist[0] = n;
1593bd389b36SDavid du Colombier 	part[256] = t;
1594bd389b36SDavid du Colombier 	t += n;
1595bd389b36SDavid du Colombier 
1596bd389b36SDavid du Colombier 	cp1 = clist+1;
1597bd389b36SDavid du Colombier 	cp = count+lowc;
1598bd389b36SDavid du Colombier 	for(c=lowc; c<=higc; c++,cp++) {
1599bd389b36SDavid du Colombier 		n = *cp;
1600bd389b36SDavid du Colombier 		if(n) {
1601bd389b36SDavid du Colombier 			cp1[0] = n;
1602bd389b36SDavid du Colombier 			cp1[1] = c;
1603bd389b36SDavid du Colombier 			cp1 += 2;
1604bd389b36SDavid du Colombier 			part[c] = t;
1605bd389b36SDavid du Colombier 			t += n;
1606bd389b36SDavid du Colombier 		}
1607bd389b36SDavid du Colombier 	}
1608bd389b36SDavid du Colombier 	*cp1 = 0;
1609bd389b36SDavid du Colombier 
1610bd389b36SDavid du Colombier 	/*
1611bd389b36SDavid du Colombier 	 * pass 3 over all counts.
1612bd389b36SDavid du Colombier 	 * chase lowest pointer in each partition
1613bd389b36SDavid du Colombier 	 * around a permutation until it comes
1614bd389b36SDavid du Colombier 	 * back and is stored where it started.
1615bd389b36SDavid du Colombier 	 * static array, count[], should be
1616bd389b36SDavid du Colombier 	 * reduced to zero entries except maybe
1617bd389b36SDavid du Colombier 	 * count[256].
1618bd389b36SDavid du Colombier 	 */
1619bd389b36SDavid du Colombier 	for(cp1=clist+1; cp1[0]; cp1+=2) {
1620bd389b36SDavid du Colombier 		c = cp1[1];
1621bd389b36SDavid du Colombier 		cp = count+c;
1622bd389b36SDavid du Colombier 		while(*cp) {
1623bd389b36SDavid du Colombier 			t1 = *part[c];
1624bd389b36SDavid du Colombier 			for(;;) {
1625bd389b36SDavid du Colombier 				k = *t1;
1626bd389b36SDavid du Colombier 				n = 256;
1627bd389b36SDavid du Colombier 				if(b < k->klen)
1628bd389b36SDavid du Colombier 					n = k->key[b];
1629bd389b36SDavid du Colombier 				u = part[n]++;
1630bd389b36SDavid du Colombier 				count[n]--;
1631bd389b36SDavid du Colombier 				u1 = *u;
1632bd389b36SDavid du Colombier 				*u = t1;
1633bd389b36SDavid du Colombier 				if(n == c)
1634bd389b36SDavid du Colombier 					break;
1635bd389b36SDavid du Colombier 				t1 = u1;
1636bd389b36SDavid du Colombier 			}
1637bd389b36SDavid du Colombier 		}
1638bd389b36SDavid du Colombier 	}
1639bd389b36SDavid du Colombier 
1640bd389b36SDavid du Colombier 	/*
1641bd389b36SDavid du Colombier 	 * pass 4 over all partitions.
1642bd389b36SDavid du Colombier 	 * call recursively.
1643bd389b36SDavid du Colombier 	 */
1644bd389b36SDavid du Colombier 	b++;
1645bd389b36SDavid du Colombier 	t = a + clist[0];
1646bd389b36SDavid du Colombier 	count[256] = 0;
1647bd389b36SDavid du Colombier 	for(cp1=clist+1; n=cp1[0]; cp1+=2) {
1648bd389b36SDavid du Colombier 		if(n > Threshold)
1649bd389b36SDavid du Colombier 			rsort4(t, n, b);
1650bd389b36SDavid du Colombier 		else
1651bd389b36SDavid du Colombier 		if(n > 1)
1652bd389b36SDavid du Colombier 			bsort4(t, n, b);
1653bd389b36SDavid du Colombier 		t += n;
1654bd389b36SDavid du Colombier 	}
1655bd389b36SDavid du Colombier }
1656bd389b36SDavid du Colombier 
1657bd389b36SDavid du Colombier /*
1658bd389b36SDavid du Colombier  * bubble sort to pick up
1659bd389b36SDavid du Colombier  * the pieces.
1660bd389b36SDavid du Colombier  */
1661bd389b36SDavid du Colombier void
bsort4(Key *** a,ulong n,int b)1662bd389b36SDavid du Colombier bsort4(Key ***a, ulong n, int b)
1663bd389b36SDavid du Colombier {
1664bd389b36SDavid du Colombier 	Key ***i, ***j, ***k, ***l, **t;
1665bd389b36SDavid du Colombier 	Key *ka, *kb;
1666bd389b36SDavid du Colombier 	int n1, n2;
1667bd389b36SDavid du Colombier 
1668bd389b36SDavid du Colombier 	l = a+n;
1669bd389b36SDavid du Colombier 	j = a;
1670bd389b36SDavid du Colombier 
1671bd389b36SDavid du Colombier loop:
1672bd389b36SDavid du Colombier 	i = j;
1673bd389b36SDavid du Colombier 	j++;
1674bd389b36SDavid du Colombier 	if(j >= l)
1675bd389b36SDavid du Colombier 		return;
1676bd389b36SDavid du Colombier 
1677bd389b36SDavid du Colombier 	ka = **i;
1678bd389b36SDavid du Colombier 	kb = **j;
1679bd389b36SDavid du Colombier 	n1 = ka->klen - b;
1680bd389b36SDavid du Colombier 	n2 = kb->klen - b;
1681bd389b36SDavid du Colombier 	if(n1 > n2)
1682bd389b36SDavid du Colombier 		n1 = n2;
1683bd389b36SDavid du Colombier 	if(n1 <= 0)
1684bd389b36SDavid du Colombier 		goto loop;
1685bd389b36SDavid du Colombier 	n2 = ka->key[b] - kb->key[b];
1686bd389b36SDavid du Colombier 	if(n2 == 0)
1687bd389b36SDavid du Colombier 		n2 = memcmp(ka->key+b, kb->key+b, n1);
1688bd389b36SDavid du Colombier 	if(n2 <= 0)
1689bd389b36SDavid du Colombier 		goto loop;
1690bd389b36SDavid du Colombier 
1691bd389b36SDavid du Colombier 	for(;;) {
1692bd389b36SDavid du Colombier 		k = i+1;
1693bd389b36SDavid du Colombier 
1694bd389b36SDavid du Colombier 		t = *k;
1695bd389b36SDavid du Colombier 		*k = *i;
1696bd389b36SDavid du Colombier 		*i = t;
1697bd389b36SDavid du Colombier 
1698bd389b36SDavid du Colombier 		if(i <= a)
1699bd389b36SDavid du Colombier 			goto loop;
1700bd389b36SDavid du Colombier 
1701bd389b36SDavid du Colombier 		i--;
1702bd389b36SDavid du Colombier 		ka = **i;
1703bd389b36SDavid du Colombier 		kb = *t;
1704bd389b36SDavid du Colombier 		n1 = ka->klen - b;
1705bd389b36SDavid du Colombier 		n2 = kb->klen - b;
1706bd389b36SDavid du Colombier 		if(n1 > n2)
1707bd389b36SDavid du Colombier 			n1 = n2;
1708bd389b36SDavid du Colombier 		if(n1 <= 0)
1709bd389b36SDavid du Colombier 			goto loop;
1710bd389b36SDavid du Colombier 		n2 = ka->key[b] - kb->key[b];
1711bd389b36SDavid du Colombier 		if(n2 == 0)
1712bd389b36SDavid du Colombier 			n2 = memcmp(ka->key+b, kb->key+b, n1);
1713bd389b36SDavid du Colombier 		if(n2 <= 0)
1714bd389b36SDavid du Colombier 			goto loop;
1715bd389b36SDavid du Colombier 	}
1716bd389b36SDavid du Colombier }
1717