xref: /original-bsd/usr.bin/sort/sort.c (revision 440fde76)
1 static	char *sccsid = "@(#)sort.c	4.15 (Berkeley) 05/11/89";
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	2048
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 int	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 term()
568 {
569 	register i;
570 
571 	signal(SIGINT, SIG_IGN);
572 	signal(SIGHUP, SIG_IGN);
573 	signal(SIGTERM, SIG_IGN);
574 	if(nfiles == eargc)
575 		nfiles++;
576 	for(i=eargc; i<=nfiles; i++) {	/*<= in case of interrupt*/
577 		unlink(setfil(i));	/*with nfiles not updated*/
578 	}
579 	_exit(error);
580 }
581 
582 cmp(i, j)
583 char *i, *j;
584 {
585 	register char *pa, *pb;
586 	char *skip();
587 	char *code, *ignore;
588 	int a, b;
589 	int k;
590 	char *la, *lb;
591 	register int sa;
592 	int sb;
593 	char *ipa, *ipb, *jpa, *jpb;
594 	struct field *fp;
595 
596 	for(k = nfields>0; k<=nfields; k++) {
597 		fp = &fields[k];
598 		pa = i;
599 		pb = j;
600 		if(k) {
601 			la = skip(pa, fp, 1);
602 			pa = skip(pa, fp, 0);
603 			lb = skip(pb, fp, 1);
604 			pb = skip(pb, fp, 0);
605 		} else {
606 			la = eol(pa);
607 			lb = eol(pb);
608 		}
609 		if(fp->nflg) {
610 			if(tabchar) {
611 				if(pa<la&&*pa==tabchar)
612 					pa++;
613 				if(pb<lb&&*pb==tabchar)
614 					pb++;
615 			}
616 			while(blank(*pa))
617 				pa++;
618 			while(blank(*pb))
619 				pb++;
620 			sa = sb = fp->rflg;
621 			if(*pa == '-') {
622 				pa++;
623 				sa = -sa;
624 			}
625 			if(*pb == '-') {
626 				pb++;
627 				sb = -sb;
628 			}
629 			for(ipa = pa; ipa<la&&isdigit(*ipa); ipa++) ;
630 			for(ipb = pb; ipb<lb&&isdigit(*ipb); ipb++) ;
631 			jpa = ipa;
632 			jpb = ipb;
633 			a = 0;
634 			if(sa==sb)
635 				while(ipa > pa && ipb > pb)
636 					if(b = *--ipb - *--ipa)
637 						a = b;
638 			while(ipa > pa)
639 				if(*--ipa != '0')
640 					return(-sa);
641 			while(ipb > pb)
642 				if(*--ipb != '0')
643 					return(sb);
644 			if(a) return(a*sa);
645 			if(*(pa=jpa) == '.')
646 				pa++;
647 			if(*(pb=jpb) == '.')
648 				pb++;
649 			if(sa==sb)
650 				while(pa<la && isdigit(*pa)
651 				   && pb<lb && isdigit(*pb))
652 					if(a = *pb++ - *pa++)
653 						return(a*sa);
654 			while(pa<la && isdigit(*pa))
655 				if(*pa++ != '0')
656 					return(-sa);
657 			while(pb<lb && isdigit(*pb))
658 				if(*pb++ != '0')
659 					return(sb);
660 			continue;
661 		}
662 		code = fp->code;
663 		ignore = fp->ignore;
664 loop:
665 		while(ignore[*pa])
666 			pa++;
667 		while(ignore[*pb])
668 			pb++;
669 		if(pa>=la || *pa=='\n')
670 			if(pb<lb && *pb!='\n')
671 				return(fp->rflg);
672 			else continue;
673 		if(pb>=lb || *pb=='\n')
674 			return(-fp->rflg);
675 		if((sa = code[*pb++]-code[*pa++]) == 0)
676 			goto loop;
677 		return(sa*fp->rflg);
678 	}
679 	if(uflg)
680 		return(0);
681 	return(cmpa(i, j));
682 }
683 
684 cmpa(pa, pb)
685 register char *pa, *pb;
686 {
687 	while(*pa == *pb) {
688 		if(*pa++ == '\n')
689 			return(0);
690 		pb++;
691 	}
692 	return(
693 		*pa == '\n' ? fields[0].rflg:
694 		*pb == '\n' ?-fields[0].rflg:
695 		*pb > *pa   ? fields[0].rflg:
696 		-fields[0].rflg
697 	);
698 }
699 
700 char *
701 skip(pp, fp, j)
702 struct field *fp;
703 char *pp;
704 {
705 	register i;
706 	register char *p;
707 
708 	p = pp;
709 	if( (i=fp->m[j]) < 0)
710 		return(eol(p));
711 	while(i-- > 0) {
712 		if(tabchar != 0) {
713 			while(*p != tabchar)
714 				if(*p != '\n')
715 					p++;
716 				else goto ret;
717 			if(i>0||j==0)
718 				p++;
719 		} else {
720 			while(blank(*p))
721 				p++;
722 			while(!blank(*p))
723 				if(*p != '\n')
724 					p++;
725 				else goto ret;
726 		}
727 	}
728 	if(tabchar==0||fp->bflg[j])
729 		while(blank(*p))
730 			p++;
731 	i = fp->n[j];
732 	while(i-- > 0) {
733 		if(*p != '\n')
734 			p++;
735 		else goto ret;
736 	}
737 ret:
738 	return(p);
739 }
740 
741 char *
742 eol(p)
743 register char *p;
744 {
745 	while(*p != '\n') p++;
746 	return(p);
747 }
748 
749 copyproto()
750 {
751 	register i;
752 	register int *p, *q;
753 
754 	p = (int *)&proto;
755 	q = (int *)&fields[nfields];
756 	for(i=0; i<sizeof(proto)/sizeof(*p); i++)
757 		*q++ = *p++;
758 }
759 
760 field(s,k)
761 char *s;
762 {
763 	register struct field *p;
764 	register d;
765 	p = &fields[nfields];
766 	d = 0;
767 	for(; *s!=0; s++) {
768 		switch(*s) {
769 		case '\0':
770 			return;
771 
772 		case 'b':
773 			p->bflg[k]++;
774 			break;
775 
776 		case 'd':
777 			p->ignore = dict+128;
778 			break;
779 
780 		case 'f':
781 			p->code = fold+128;
782 			break;
783 		case 'i':
784 			p->ignore = nonprint+128;
785 			break;
786 
787 		case 'c':
788 			cflg = 1;
789 			continue;
790 
791 		case 'm':
792 			mflg = 1;
793 			continue;
794 
795 		case 'n':
796 			p->nflg++;
797 			break;
798 		case 't':
799 			tabchar = *++s;
800 			if(tabchar == 0) s--;
801 			continue;
802 
803 		case 'r':
804 			p->rflg = -1;
805 			continue;
806 		case 'u':
807 			uflg = 1;
808 			break;
809 
810 		case '.':
811 			if(p->m[k] == -1)	/* -m.n with m missing */
812 				p->m[k] = 0;
813 			d = &fields[0].n[0]-&fields[0].m[0];
814 
815 		default:
816 			p->m[k+d] = number(&s);
817 		}
818 		compare = cmp;
819 	}
820 }
821 
822 number(ppa)
823 char **ppa;
824 {
825 	int n;
826 	register char *pa;
827 	pa = *ppa;
828 	n = 0;
829 	while(isdigit(*pa)) {
830 		n = n*10 + *pa - '0';
831 		*ppa = pa++;
832 	}
833 	return(n);
834 }
835 
836 #define qsexc(p,q) t= *p;*p= *q;*q=t
837 #define qstexc(p,q,r) t= *p;*p= *r;*r= *q;*q=t
838 
839 qsort(a,l)
840 char **a, **l;
841 {
842 	register char **i, **j;
843 	char **k;
844 	char **lp, **hp;
845 	int c;
846 	char *t;
847 	unsigned n;
848 
849 
850 
851 start:
852 	if((n=l-a) <= 1)
853 		return;
854 
855 
856 	n /= 2;
857 	hp = lp = a+n;
858 	i = a;
859 	j = l-1;
860 
861 
862 	for(;;) {
863 		if(i < lp) {
864 			if((c = (*compare)(*i, *lp)) == 0) {
865 				--lp;
866 				qsexc(i, lp);
867 				continue;
868 			}
869 			if(c < 0) {
870 				++i;
871 				continue;
872 			}
873 		}
874 
875 loop:
876 		if(j > hp) {
877 			if((c = (*compare)(*hp, *j)) == 0) {
878 				++hp;
879 				qsexc(hp, j);
880 				goto loop;
881 			}
882 			if(c > 0) {
883 				if(i == lp) {
884 					++hp;
885 					qstexc(i, hp, j);
886 					i = ++lp;
887 					goto loop;
888 				}
889 				qsexc(i, j);
890 				--j;
891 				++i;
892 				continue;
893 			}
894 			--j;
895 			goto loop;
896 		}
897 
898 
899 		if(i == lp) {
900 			if(uflg)
901 				for(k=lp+1; k<=hp;) **k++ = '\0';
902 			if(lp-a >= l-hp) {
903 				qsort(hp+1, l);
904 				l = lp;
905 			} else {
906 				qsort(a, lp);
907 				a = hp+1;
908 			}
909 			goto start;
910 		}
911 
912 
913 		--lp;
914 		qstexc(j, lp, i);
915 		j = --hp;
916 	}
917 }
918 
919