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