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