xref: /original-bsd/usr.bin/sort/sort.c (revision ad93c43e)
1 static	char *sccsid = "@(#)sort.c	4.13 (Berkeley) 11/12/87";
2 #include <sys/param.h>
3 #include <stdio.h>
4 #include <ctype.h>
5 #include <signal.h>
6 #include <sys/stat.h>
7 
8 #define	L	2048
9 #define	N	7
10 #define	C	20
11 #ifndef pdp11
12 #define	MEM	(128*2048)
13 #else
14 #define	MEM	(16*2048)
15 #endif
16 #define NF	10
17 
18 #define rline(mp)	(fgets((mp)->l, L, (mp)->b) == NULL)
19 
20 FILE	*is, *os;
21 char	*dirtry[] = {"/usr/tmp", "/tmp", NULL};
22 char	**dirs;
23 char	file1[MAXPATHLEN];
24 char	*file = file1;
25 char	*filep;
26 int	nfiles;
27 unsigned	nlines;
28 unsigned	ntext;
29 int	*lspace;
30 char	*tspace;
31 int	cmp(), cmpa();
32 int	(*compare)() = cmpa;
33 char	*eol();
34 int	term();
35 int 	mflg;
36 int	cflg;
37 int	uflg;
38 char	*outfil;
39 int unsafeout;	/*kludge to assure -m -o works*/
40 char	tabchar;
41 int 	eargc;
42 char	**eargv;
43 
44 char zero[256];
45 
46 char	fold[256] = {
47 	0200,0201,0202,0203,0204,0205,0206,0207,
48 	0210,0211,0212,0213,0214,0215,0216,0217,
49 	0220,0221,0222,0223,0224,0225,0226,0227,
50 	0230,0231,0232,0233,0234,0235,0236,0237,
51 	0240,0241,0242,0243,0244,0245,0246,0247,
52 	0250,0251,0252,0253,0254,0255,0256,0257,
53 	0260,0261,0262,0263,0264,0265,0266,0267,
54 	0270,0271,0272,0273,0274,0275,0276,0277,
55 	0300,0301,0302,0303,0304,0305,0306,0307,
56 	0310,0311,0312,0313,0314,0315,0316,0317,
57 	0320,0321,0322,0323,0324,0325,0326,0327,
58 	0330,0331,0332,0333,0334,0335,0336,0337,
59 	0340,0341,0342,0343,0344,0345,0346,0347,
60 	0350,0351,0352,0353,0354,0355,0356,0357,
61 	0360,0361,0362,0363,0364,0365,0366,0367,
62 	0370,0371,0372,0373,0374,0375,0376,0377,
63 	0000,0001,0002,0003,0004,0005,0006,0007,
64 	0010,0011,0012,0013,0014,0015,0016,0017,
65 	0020,0021,0022,0023,0024,0025,0026,0027,
66 	0030,0031,0032,0033,0034,0035,0036,0037,
67 	0040,0041,0042,0043,0044,0045,0046,0047,
68 	0050,0051,0052,0053,0054,0055,0056,0057,
69 	0060,0061,0062,0063,0064,0065,0066,0067,
70 	0070,0071,0072,0073,0074,0075,0076,0077,
71 	0100,0101,0102,0103,0104,0105,0106,0107,
72 	0110,0111,0112,0113,0114,0115,0116,0117,
73 	0120,0121,0122,0123,0124,0125,0126,0127,
74 	0130,0131,0132,0133,0134,0135,0136,0137,
75 	0140,0101,0102,0103,0104,0105,0106,0107,
76 	0110,0111,0112,0113,0114,0115,0116,0117,
77 	0120,0121,0122,0123,0124,0125,0126,0127,
78 	0130,0131,0132,0173,0174,0175,0176,0177
79 };
80 char nofold[256] = {
81 	0200,0201,0202,0203,0204,0205,0206,0207,
82 	0210,0211,0212,0213,0214,0215,0216,0217,
83 	0220,0221,0222,0223,0224,0225,0226,0227,
84 	0230,0231,0232,0233,0234,0235,0236,0237,
85 	0240,0241,0242,0243,0244,0245,0246,0247,
86 	0250,0251,0252,0253,0254,0255,0256,0257,
87 	0260,0261,0262,0263,0264,0265,0266,0267,
88 	0270,0271,0272,0273,0274,0275,0276,0277,
89 	0300,0301,0302,0303,0304,0305,0306,0307,
90 	0310,0311,0312,0313,0314,0315,0316,0317,
91 	0320,0321,0322,0323,0324,0325,0326,0327,
92 	0330,0331,0332,0333,0334,0335,0336,0337,
93 	0340,0341,0342,0343,0344,0345,0346,0347,
94 	0350,0351,0352,0353,0354,0355,0356,0357,
95 	0360,0361,0362,0363,0364,0365,0366,0367,
96 	0370,0371,0372,0373,0374,0375,0376,0377,
97 	0000,0001,0002,0003,0004,0005,0006,0007,
98 	0010,0011,0012,0013,0014,0015,0016,0017,
99 	0020,0021,0022,0023,0024,0025,0026,0027,
100 	0030,0031,0032,0033,0034,0035,0036,0037,
101 	0040,0041,0042,0043,0044,0045,0046,0047,
102 	0050,0051,0052,0053,0054,0055,0056,0057,
103 	0060,0061,0062,0063,0064,0065,0066,0067,
104 	0070,0071,0072,0073,0074,0075,0076,0077,
105 	0100,0101,0102,0103,0104,0105,0106,0107,
106 	0110,0111,0112,0113,0114,0115,0116,0117,
107 	0120,0121,0122,0123,0124,0125,0126,0127,
108 	0130,0131,0132,0133,0134,0135,0136,0137,
109 	0140,0141,0142,0143,0144,0145,0146,0147,
110 	0150,0151,0152,0153,0154,0155,0156,0157,
111 	0160,0161,0162,0163,0164,0165,0166,0167,
112 	0170,0171,0172,0173,0174,0175,0176,0177
113 };
114 
115 char	nonprint[256] = {
116 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
117 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
118 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
119 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
120 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
121 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
122 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
123 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
124 	1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,
125 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
126 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
127 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
128 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
129 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
130 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
131 	0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,1
132 };
133 
134 char	dict[256] = {
135 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
136 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
137 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
138 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
139 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
140 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
141 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
142 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
143 	1,1,1,1,1,1,1,1,1,0,0,1,1,1,1,1,
144 	1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
145 	0,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,
146 	0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,1,
147 	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
148 	0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1,
149 	1,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
150 	0,0,0,0,0,0,0,0,0,0,0,1,1,1,1,1
151 };
152 
153 struct	field {
154 	char *code;
155 	char *ignore;
156 	int nflg;
157 	int rflg;
158 	int bflg[2];
159 	int m[2];
160 	int n[2];
161 }	fields[NF];
162 struct field proto = {
163 	nofold+128,
164 	zero+128,
165 	0,
166 	1,
167 	0,0,
168 	0,-1,
169 	0,0
170 };
171 int	nfields;
172 int 	error = 1;
173 char	*setfil();
174 char	*sbrk();
175 char	*brk();
176 
177 #define	blank(c)	((c) == ' ' || (c) == '\t')
178 
179 main(argc, argv)
180 char **argv;
181 {
182 	register a;
183 	extern char end[1];
184 	char *ep;
185 	char *arg;
186 	struct field *p, *q;
187 	int i;
188 
189 	copyproto();
190 	eargv = argv;
191 	while (--argc > 0) {
192 		if(**++argv == '-') for(arg = *argv;;) {
193 			switch(*++arg) {
194 			case '\0':
195 				if(arg[-1] == '-')
196 					eargv[eargc++] = "-";
197 				break;
198 
199 			case 'o':
200 				if(--argc > 0)
201 					outfil = *++argv;
202 				continue;
203 
204 			case 'T':
205 				if (--argc > 0)
206 					dirtry[0] = *++argv;
207 				continue;
208 
209 			default:
210 				field(++*argv,nfields>0);
211 				break;
212 			}
213 			break;
214 		} else if (**argv == '+') {
215 			if(++nfields>=NF) {
216 				diag("too many keys","");
217 				exit(1);
218 			}
219 			copyproto();
220 			field(++*argv,0);
221 		} else
222 			eargv[eargc++] = *argv;
223 	}
224 	q = &fields[0];
225 	for(a=1; a<=nfields; a++) {
226 		p = &fields[a];
227 		if(p->code != proto.code) continue;
228 		if(p->ignore != proto.ignore) continue;
229 		if(p->nflg != proto.nflg) continue;
230 		if(p->rflg != proto.rflg) continue;
231 		if(p->bflg[0] != proto.bflg[0]) continue;
232 		if(p->bflg[1] != proto.bflg[1]) continue;
233 		p->code = q->code;
234 		p->ignore = q->ignore;
235 		p->nflg = q->nflg;
236 		p->rflg = q->rflg;
237 		p->bflg[0] = p->bflg[1] = q->bflg[0];
238 	}
239 	if(eargc == 0)
240 		eargv[eargc++] = "-";
241 	if(cflg && eargc>1) {
242 		diag("can check only 1 file","");
243 		exit(1);
244 	}
245 	safeoutfil();
246 
247 	ep = end + MEM;
248 	lspace = (int *)sbrk(0);
249 	while((int)brk(ep) == -1)
250 		ep -= 512;
251 #ifndef	vax
252 	brk(ep -= 512);	/* for recursion */
253 #endif
254 	a = ep - (char*)lspace;
255 	nlines = (a-L);
256 	nlines /= (5*(sizeof(char *)/sizeof(char)));
257 	ntext = nlines * 4 * (sizeof(char *)/sizeof(char));
258 	tspace = (char *)(lspace + nlines);
259 	a = -1;
260 	for(dirs=dirtry; *dirs; dirs++) {
261 		sprintf(filep=file1, "%s/stm%05uaa", *dirs, getpid());
262 		while (*filep)
263 			filep++;
264 		filep -= 2;
265 		if ( (a=creat(file, 0600)) >=0)
266 			break;
267 	}
268 	if(a < 0) {
269 		diag("can't locate temp","");
270 		exit(1);
271 	}
272 	close(a);
273 	unlink(file);
274 	if (signal(SIGHUP, SIG_IGN) != SIG_IGN)
275 		signal(SIGHUP, term);
276 	if (signal(SIGINT, SIG_IGN) != SIG_IGN)
277 		signal(SIGINT, term);
278 	signal(SIGPIPE,term);
279 	if (signal(SIGTERM, SIG_IGN) != SIG_IGN)
280 		signal(SIGTERM,term);
281 	nfiles = eargc;
282 	if(!mflg && !cflg) {
283 		sort();
284 		fclose(stdin);
285 	}
286 	for(a = mflg|cflg?0:eargc; a+N<nfiles || unsafeout&&a<eargc; a=i) {
287 		i = a+N;
288 		if(i>=nfiles)
289 			i = nfiles;
290 		newfile();
291 		merge(a, i);
292 	}
293 	if(a != nfiles) {
294 		oldfile();
295 		merge(a, nfiles);
296 	}
297 	error = 0;
298 	term();
299 }
300 
301 sort()
302 {
303 	register char *cp;
304 	register char **lp;
305 	register lines, text, len;
306 	int done = 0;
307 	int i = 0;
308 	char *f;
309 	char c;
310 
311 	if((f = setfil(i++)) == NULL)
312 		is = stdin;
313 	else if((is = fopen(f, "r")) == NULL)
314 		cant(f);
315 
316 	do {
317 		cp = tspace;
318 		lp = (char **)lspace;
319 		lines = nlines;
320 		text = ntext;
321 		while(lines > 0 && text > 0) {
322 			if(fgets(cp, L, is) == NULL) {
323 				if(i >= eargc) {
324 					++done;
325 					break;
326 				}
327 				fclose(is);
328 				if((f = setfil(i++)) == NULL)
329 					is = stdin;
330 				else if((is = fopen(f, "r")) == NULL)
331 					cant(f);
332 				continue;
333 			}
334 			*lp++ = cp;
335 			len = strlen(cp) + 1; /* null terminate */
336 			if(cp[len - 2] != '\n')
337 				if (len == L) {
338 					diag("line too long (skipped): ", cp);
339 					while((c=getc(is)) != EOF && c != '\n')
340 						/* throw it away */;
341 					--lp;
342 					continue;
343 				} else {
344 					diag("missing newline before EOF in ",
345 						f ? f : "standard input");
346 					/* be friendly, append a newline */
347 					++len;
348 					cp[len - 2] = '\n';
349 					cp[len - 1] = '\0';
350 				}
351 			cp += len;
352 			--lines;
353 			text -= len;
354 		}
355 		qsort((char **)lspace, lp);
356 		if(done == 0 || nfiles != eargc)
357 			newfile();
358 		else
359 			oldfile();
360 		clearerr(os);
361 		while(lp > (char **)lspace) {
362 			cp = *--lp;
363 			if(*cp)
364 				fputs(cp, os);
365 			if (ferror(os)) {
366 				error = 1;
367 				term();
368 			}
369 		}
370 		fclose(os);
371 	} while(done == 0);
372 }
373 
374 struct merg
375 {
376 	char	l[L];
377 	FILE	*b;
378 } *ibuf[256];
379 
380 merge(a,b)
381 {
382 	struct	merg	*p;
383 	register char	*cp, *dp;
384 	register	i;
385 	struct merg **ip, *jp;
386 	char	*f;
387 	int	j;
388 	int	k, l;
389 	int	muflg;
390 
391 	p = (struct merg *)lspace;
392 	j = 0;
393 	for(i=a; i < b; i++) {
394 		f = setfil(i);
395 		if(f == 0)
396 			p->b = stdin;
397 		else if((p->b = fopen(f, "r")) == NULL)
398 			cant(f);
399 		ibuf[j] = p;
400 		if(!rline(p))	j++;
401 		p++;
402 	}
403 
404 	do {
405 		i = j;
406 		qsort((char **)ibuf, (char **)(ibuf+i));
407 		l = 0;
408 		while(i--) {
409 			cp = ibuf[i]->l;
410 			if(*cp == '\0') {
411 				l = 1;
412 				if(rline(ibuf[i])) {
413 					k = i;
414 					while(++k < j)
415 						ibuf[k-1] = ibuf[k];
416 					j--;
417 				}
418 			}
419 		}
420 	} while(l);
421 
422 	clearerr(os);
423 	muflg = mflg & uflg | cflg;
424 	i = j;
425 	while(i > 0) {
426 		cp = ibuf[i-1]->l;
427 		if (!cflg && (uflg == 0 || muflg || i == 1 ||
428 			(*compare)(ibuf[i-1]->l,ibuf[i-2]->l))) {
429 			fputs(cp, os);
430 			if (ferror(os)) {
431 				error = 1;
432 				term();
433 			}
434 		}
435 		if(muflg){
436 			cp = ibuf[i-1]->l;
437 			dp = p->l;
438 			do {
439 			} while((*dp++ = *cp++) != '\n');
440 		}
441 		for(;;) {
442 			if(rline(ibuf[i-1])) {
443 				i--;
444 				if(i == 0)
445 					break;
446 				if(i == 1)
447 					muflg = uflg;
448 			}
449 			ip = &ibuf[i];
450 			while(--ip>ibuf&&(*compare)(ip[0]->l,ip[-1]->l)<0){
451 				jp = *ip;
452 				*ip = *(ip-1);
453 				*(ip-1) = jp;
454 			}
455 			if(!muflg)
456 				break;
457 			j = (*compare)(ibuf[i-1]->l,p->l);
458 			if(cflg) {
459 				if(j > 0)
460 					disorder("disorder:",ibuf[i-1]->l);
461 				else if(uflg && j==0)
462 					disorder("nonunique:",ibuf[i-1]->l);
463 			} else if(j == 0)
464 				continue;
465 			break;
466 		}
467 	}
468 	p = (struct merg *)lspace;
469 	for(i=a; i<b; i++) {
470 		fclose(p->b);
471 		p++;
472 		if(i >= eargc)
473 			unlink(setfil(i));
474 	}
475 	fclose(os);
476 }
477 
478 disorder(s,t)
479 char *s, *t;
480 {
481 	register char *u;
482 	for(u=t; *u!='\n';u++) ;
483 	*u = 0;
484 	diag(s,t);
485 	term();
486 }
487 
488 newfile()
489 {
490 	register char *f;
491 
492 	f = setfil(nfiles);
493 	if((os=fopen(f, "w")) == NULL) {
494 		diag("can't create ",f);
495 		term();
496 	}
497 	nfiles++;
498 }
499 
500 char *
501 setfil(i)
502 {
503 
504 	if(i < eargc)
505 		if(eargv[i][0] == '-' && eargv[i][1] == '\0')
506 			return(0);
507 		else
508 			return(eargv[i]);
509 	i -= eargc;
510 	filep[0] = i/26 + 'a';
511 	filep[1] = i%26 + 'a';
512 	return(file);
513 }
514 
515 oldfile()
516 {
517 
518 	if(outfil) {
519 		if((os=fopen(outfil, "w")) == NULL) {
520 			diag("can't create ",outfil);
521 			term();
522 		}
523 	} else
524 		os = stdout;
525 }
526 
527 safeoutfil()
528 {
529 	register int i;
530 	struct stat obuf,ibuf;
531 
532 	if(!mflg||outfil==0)
533 		return;
534 	if(stat(outfil,&obuf)==-1)
535 		return;
536 	for(i=eargc-N;i<eargc;i++) {	/*-N is suff., not nec.*/
537 		if(stat(eargv[i],&ibuf)==-1)
538 			continue;
539 		if(obuf.st_dev==ibuf.st_dev&&
540 		   obuf.st_ino==ibuf.st_ino)
541 			unsafeout++;
542 	}
543 }
544 
545 cant(f)
546 char *f;
547 {
548 
549 	perror(f);
550 	term();
551 }
552 
553 diag(s,t)
554 char *s, *t;
555 {
556 	fputs("sort: ",stderr);
557 	fputs(s,stderr);
558 	fputs(t,stderr);
559 	fputs("\n",stderr);
560 }
561 
562 term()
563 {
564 	register i;
565 
566 	signal(SIGINT, SIG_IGN);
567 	signal(SIGHUP, SIG_IGN);
568 	signal(SIGTERM, SIG_IGN);
569 	if(nfiles == eargc)
570 		nfiles++;
571 	for(i=eargc; i<=nfiles; i++) {	/*<= in case of interrupt*/
572 		unlink(setfil(i));	/*with nfiles not updated*/
573 	}
574 	_exit(error);
575 }
576 
577 cmp(i, j)
578 char *i, *j;
579 {
580 	register char *pa, *pb;
581 	char *skip();
582 	char *code, *ignore;
583 	int a, b;
584 	int k;
585 	char *la, *lb;
586 	register int sa;
587 	int sb;
588 	char *ipa, *ipb, *jpa, *jpb;
589 	struct field *fp;
590 
591 	for(k = nfields>0; k<=nfields; k++) {
592 		fp = &fields[k];
593 		pa = i;
594 		pb = j;
595 		if(k) {
596 			la = skip(pa, fp, 1);
597 			pa = skip(pa, fp, 0);
598 			lb = skip(pb, fp, 1);
599 			pb = skip(pb, fp, 0);
600 		} else {
601 			la = eol(pa);
602 			lb = eol(pb);
603 		}
604 		if(fp->nflg) {
605 			if(tabchar) {
606 				if(pa<la&&*pa==tabchar)
607 					pa++;
608 				if(pb<lb&&*pb==tabchar)
609 					pb++;
610 			}
611 			while(blank(*pa))
612 				pa++;
613 			while(blank(*pb))
614 				pb++;
615 			sa = sb = fp->rflg;
616 			if(*pa == '-') {
617 				pa++;
618 				sa = -sa;
619 			}
620 			if(*pb == '-') {
621 				pb++;
622 				sb = -sb;
623 			}
624 			for(ipa = pa; ipa<la&&isdigit(*ipa); ipa++) ;
625 			for(ipb = pb; ipb<lb&&isdigit(*ipb); ipb++) ;
626 			jpa = ipa;
627 			jpb = ipb;
628 			a = 0;
629 			if(sa==sb)
630 				while(ipa > pa && ipb > pb)
631 					if(b = *--ipb - *--ipa)
632 						a = b;
633 			while(ipa > pa)
634 				if(*--ipa != '0')
635 					return(-sa);
636 			while(ipb > pb)
637 				if(*--ipb != '0')
638 					return(sb);
639 			if(a) return(a*sa);
640 			if(*(pa=jpa) == '.')
641 				pa++;
642 			if(*(pb=jpb) == '.')
643 				pb++;
644 			if(sa==sb)
645 				while(pa<la && isdigit(*pa)
646 				   && pb<lb && isdigit(*pb))
647 					if(a = *pb++ - *pa++)
648 						return(a*sa);
649 			while(pa<la && isdigit(*pa))
650 				if(*pa++ != '0')
651 					return(-sa);
652 			while(pb<lb && isdigit(*pb))
653 				if(*pb++ != '0')
654 					return(sb);
655 			continue;
656 		}
657 		code = fp->code;
658 		ignore = fp->ignore;
659 loop:
660 		while(ignore[*pa])
661 			pa++;
662 		while(ignore[*pb])
663 			pb++;
664 		if(pa>=la || *pa=='\n')
665 			if(pb<lb && *pb!='\n')
666 				return(fp->rflg);
667 			else continue;
668 		if(pb>=lb || *pb=='\n')
669 			return(-fp->rflg);
670 		if((sa = code[*pb++]-code[*pa++]) == 0)
671 			goto loop;
672 		return(sa*fp->rflg);
673 	}
674 	if(uflg)
675 		return(0);
676 	return(cmpa(i, j));
677 }
678 
679 cmpa(pa, pb)
680 register char *pa, *pb;
681 {
682 	while(*pa == *pb) {
683 		if(*pa++ == '\n')
684 			return(0);
685 		pb++;
686 	}
687 	return(
688 		*pa == '\n' ? fields[0].rflg:
689 		*pb == '\n' ?-fields[0].rflg:
690 		*pb > *pa   ? fields[0].rflg:
691 		-fields[0].rflg
692 	);
693 }
694 
695 char *
696 skip(pp, fp, j)
697 struct field *fp;
698 char *pp;
699 {
700 	register i;
701 	register char *p;
702 
703 	p = pp;
704 	if( (i=fp->m[j]) < 0)
705 		return(eol(p));
706 	while(i-- > 0) {
707 		if(tabchar != 0) {
708 			while(*p != tabchar)
709 				if(*p != '\n')
710 					p++;
711 				else goto ret;
712 			if(i>0||j==0)
713 				p++;
714 		} else {
715 			while(blank(*p))
716 				p++;
717 			while(!blank(*p))
718 				if(*p != '\n')
719 					p++;
720 				else goto ret;
721 		}
722 	}
723 	if(tabchar==0||fp->bflg[j])
724 		while(blank(*p))
725 			p++;
726 	i = fp->n[j];
727 	while(i-- > 0) {
728 		if(*p != '\n')
729 			p++;
730 		else goto ret;
731 	}
732 ret:
733 	return(p);
734 }
735 
736 char *
737 eol(p)
738 register char *p;
739 {
740 	while(*p != '\n') p++;
741 	return(p);
742 }
743 
744 copyproto()
745 {
746 	register i;
747 	register int *p, *q;
748 
749 	p = (int *)&proto;
750 	q = (int *)&fields[nfields];
751 	for(i=0; i<sizeof(proto)/sizeof(*p); i++)
752 		*q++ = *p++;
753 }
754 
755 field(s,k)
756 char *s;
757 {
758 	register struct field *p;
759 	register d;
760 	p = &fields[nfields];
761 	d = 0;
762 	for(; *s!=0; s++) {
763 		switch(*s) {
764 		case '\0':
765 			return;
766 
767 		case 'b':
768 			p->bflg[k]++;
769 			break;
770 
771 		case 'd':
772 			p->ignore = dict+128;
773 			break;
774 
775 		case 'f':
776 			p->code = fold+128;
777 			break;
778 		case 'i':
779 			p->ignore = nonprint+128;
780 			break;
781 
782 		case 'c':
783 			cflg = 1;
784 			continue;
785 
786 		case 'm':
787 			mflg = 1;
788 			continue;
789 
790 		case 'n':
791 			p->nflg++;
792 			break;
793 		case 't':
794 			tabchar = *++s;
795 			if(tabchar == 0) s--;
796 			continue;
797 
798 		case 'r':
799 			p->rflg = -1;
800 			continue;
801 		case 'u':
802 			uflg = 1;
803 			break;
804 
805 		case '.':
806 			if(p->m[k] == -1)	/* -m.n with m missing */
807 				p->m[k] = 0;
808 			d = &fields[0].n[0]-&fields[0].m[0];
809 
810 		default:
811 			p->m[k+d] = number(&s);
812 		}
813 		compare = cmp;
814 	}
815 }
816 
817 number(ppa)
818 char **ppa;
819 {
820 	int n;
821 	register char *pa;
822 	pa = *ppa;
823 	n = 0;
824 	while(isdigit(*pa)) {
825 		n = n*10 + *pa - '0';
826 		*ppa = pa++;
827 	}
828 	return(n);
829 }
830 
831 #define qsexc(p,q) t= *p;*p= *q;*q=t
832 #define qstexc(p,q,r) t= *p;*p= *r;*r= *q;*q=t
833 
834 qsort(a,l)
835 char **a, **l;
836 {
837 	register char **i, **j;
838 	char **k;
839 	char **lp, **hp;
840 	int c;
841 	char *t;
842 	unsigned n;
843 
844 
845 
846 start:
847 	if((n=l-a) <= 1)
848 		return;
849 
850 
851 	n /= 2;
852 	hp = lp = a+n;
853 	i = a;
854 	j = l-1;
855 
856 
857 	for(;;) {
858 		if(i < lp) {
859 			if((c = (*compare)(*i, *lp)) == 0) {
860 				--lp;
861 				qsexc(i, lp);
862 				continue;
863 			}
864 			if(c < 0) {
865 				++i;
866 				continue;
867 			}
868 		}
869 
870 loop:
871 		if(j > hp) {
872 			if((c = (*compare)(*hp, *j)) == 0) {
873 				++hp;
874 				qsexc(hp, j);
875 				goto loop;
876 			}
877 			if(c > 0) {
878 				if(i == lp) {
879 					++hp;
880 					qstexc(i, hp, j);
881 					i = ++lp;
882 					goto loop;
883 				}
884 				qsexc(i, j);
885 				--j;
886 				++i;
887 				continue;
888 			}
889 			--j;
890 			goto loop;
891 		}
892 
893 
894 		if(i == lp) {
895 			if(uflg)
896 				for(k=lp+1; k<=hp;) **k++ = '\0';
897 			if(lp-a >= l-hp) {
898 				qsort(hp+1, l);
899 				l = lp;
900 			} else {
901 				qsort(a, lp);
902 				a = hp+1;
903 			}
904 			goto start;
905 		}
906 
907 
908 		--lp;
909 		qstexc(j, lp, i);
910 		j = --hp;
911 	}
912 }
913 
914