xref: /original-bsd/old/vfilters/vsort/vsort.c (revision 26d59569)
1 /*
2  * Copyright (c) 1983 Regents of the University of California.
3  * All rights reserved.
4  *
5  * %sccs.include.redist.c%
6  */
7 
8 #ifndef lint
9 char copyright[] =
10 "@(#) Copyright (c) 1983 Regents of the University of California.\n\
11  All rights reserved.\n";
12 #endif /* not lint */
13 
14 #ifndef lint
15 static char sccsid[] = "@(#)vsort.c	5.3 (Berkeley) 06/01/90";
16 #endif /* not lint */
17 
18 # include <stdio.h>
19 /*
20  * vsort - Sort troff output for versatec to reduce amount of reverse leading
21  */
22 
23 #define NULL 0
24 
25 double atof();
26 char *calloc();
27 
28 FILE *in,*out;
29 
30 int skipfirst = 1;	/* skip the first leading so start at top of page */
31 int cpsize = 02;	/*  Funny sizes  */
32 struct point_sizes
33 	{
34 	int stupid_code;
35 	int real_code;
36 	} point_sizes[] =
37 		{
38 		010, 6,
39 		0, 7,
40 		01, 8,
41 		07, 9,
42 		02, 10,
43 		03, 11,
44 		04, 12,
45 		05, 14,
46 		0211, 16,
47 		06, 18,
48 		0212, 20,
49 		0213, 22,
50 		0214, 24,
51 		0215, 28,
52 		0216, 36,
53 		0, 0
54 		};
55 
56 int	pagelength = 144 * 11;	/* in Leading units */
57 int	pagemod;		/* horizontal page number (for versatec) */
58 #define	MODOFF 3672		/* 432 * 8.5 */
59 
60 int esc, lead, back, verd, mcase, railmag;
61 int col, row;
62 int pstart = 0;	/*  Means a startline is pending  */
63 
64 int oback, omcase, orailmag, ocol, orow;
65 int opsize = 02;
66 
67 struct lstate
68 	{
69 	int col;
70 	int psize;
71 	char railmag;
72 	char verd;
73 	char back;
74 	char mcase;
75 	};
76 
77 struct line
78 	{
79 	struct line *nextp;
80 	struct line *lastp;
81 	int len;
82 	int row;
83 	struct lstate start;
84 	struct lstate end;
85 	char *codep;
86 	};
87 
88 struct line *head;
89 struct line *tail;
90 struct line cline;
91 
92 #define TBUFLEN 1024
93 char *codep;
94 char tbuf[TBUFLEN];
95 
96 char	wide = 0;
97 char	nocutmarks = 0;	/* Remove lines that seem to be cut marks. */
98 
99 #define	iscutmark(ch)	(ch == 023 || ch == 040 || ch == 061)
100 main(argc, argv)
101 	int argc;
102 	char *argv[];
103 	{
104 	register i;
105 
106 	for(i = 3; i < 15; i++)
107 		close(i);
108 	while (argc > 1 && argv[1][0] == '-') {
109 		switch (argv[1][1]) {
110 			case 'l': {
111 					float f = 144 * atof(argv[1] + 2);
112 					if (f < 144) {
113 						error("bad length");
114 						exit(1);
115 					}
116 					pagelength = f;
117 					break;
118 			}
119 
120 			case 'W':
121 				wide++;
122 				break;
123 
124 			case 'c':
125 				nocutmarks++;
126 				break;
127 		}
128 		argc--; argv++;
129 	}
130 	out = stdout;
131 	if(argc > 1)
132 		{
133 		while(--argc)
134 			{
135 			argv++;
136 			if((in=fopen(argv[0], "r")) == NULL)
137 				perror("vsort");
138 			else {
139 			     ofile();
140 			     fclose(in);
141 			     }
142 			}
143 		}
144 	   else
145 		{
146 		in = stdin;
147 		ofile();
148 		}
149 	exit(0);
150 }
151 
152 ofile()
153 	{
154 	register int c;
155 	static int initialized;
156 
157 	while((c = getch()) != -1) {
158 		if(!c)
159 			continue;
160 		if(c & 0200)		/* escape (left/right) */
161 			{
162 			if(!pstart)
163 				stuffc(c);
164 			esc += (~c) & 0177;
165 			continue;
166 			}
167 		if(esc)
168 			{
169 			if(back)
170 				esc = -esc;
171 			col += esc;
172 			esc = 0;
173 			}
174 		if((c & 0377) < 0100)	/*  Purely for efficiency  */
175 			goto normal_char;
176 		switch(c) {
177 			case 0100:
178 				if(initialized++) {
179 					termline();
180 					linesflush();	/* Omit trailing leading. */
181 					return;
182 				}
183 				row = 0;
184 				col = 0;	esc = 0;
185 				lead = 0;
186 				verd = 0;	back = 0;	mcase = 0;
187 				railmag = 0;
188 				ocol = 0;
189 				orow = 0;
190 				oback = 0;	omcase = 0;
191 				orailmag = 0;
192 				if(loadfont(railmag, cpsize) < 0)
193 					error("init");
194 				startline();
195 				putc(0100, out);	/*  Dont stuff it guys  */
196 				break;
197 			case 0101:	/* lower rail */
198 				crail(railmag &= ~01);
199 				if(!pstart)
200 					stuffc(c);
201 				break;
202 			case 0102:	/* upper rail */
203 				crail(railmag |= 01);
204 				if(!pstart)
205 					stuffc(c);
206 				break;
207 			case 0103:	/* upper mag */
208 				crail(railmag |= 02);
209 				if(!pstart)
210 					stuffc(c);
211 				break;
212 			case 0104:	/* lower mag */
213 				crail(railmag &= ~02);
214 				if(!pstart)
215 					stuffc(c);
216 				break;
217 			case 0105:	/* lower case */
218 				mcase = 0;
219 				if(!pstart)
220 					stuffc(c);
221 				break;
222 			case 0106:	/* upper case */
223 				mcase = 1;
224 				if(!pstart)
225 					stuffc(c);
226 				break;
227 			case 0107:	/* escape forward */
228 				back = 0;
229 				if(!pstart)
230 					stuffc(c);
231 				break;
232 			case 0110:	/* escape backwards */
233 				back = 1;
234 				if(!pstart)
235 					stuffc(c);
236 				break;
237 			case 0111:	/* stop */
238 				stuffc(c);
239 				break;
240 			case 0112:	/* lead forward */
241 				verd = 0;
242 				break;
243 			case 0113:	/* undefined */
244 				break;
245 			case 0114:	/* lead backward */
246 				verd = 1;
247 				break;
248 			case 0115:	/* undefined */
249 			case 0116:
250 			case 0117:
251 				break;
252 			default:
253 				if((c & 0340) == 0140)	/* leading */
254 					{
255 					termline();
256 					lead = (~c) & 037;
257 					if(verd)
258 						lead = -lead;
259 					if (skipfirst > 0) {
260 						skipfirst--;
261 						continue;
262 					}
263 					row += lead;
264 					if (row >= pagelength) {
265 						if (wide) {
266 							if (pagemod == 3) {
267 								allflush();
268 								col %= MODOFF;
269 								pagemod = 0;
270 							} else {
271 								pagemod++;
272 								col += MODOFF;
273 								row -= pagelength;
274 							}
275 						} else {
276 							allflush();
277 						}
278 					}
279 					if (wide && row < 0 && pagemod) {
280 						pagemod--;
281 						col -= MODOFF;
282 						row += pagelength;
283 					}
284 					pstart++;
285 					continue;
286 				}
287 				if((c & 0360) == 0120)	/* size change */
288 				{
289 					if(!pstart)
290 						stuffc(c);
291 					col += stupidadj(c & 017, cpsize);
292 					loadfont(railmag, c & 017);
293 					continue;
294 				}
295 				if(c & 0300)
296 					continue;
297 			normal_char:
298 				c = (c & 077);
299 				stuffc(c);
300 		}
301 	}	/* End of while loop reading chars. */
302 	termline();
303 	linesflush();	/*  don't put out trailing leading. */
304 }
305 
306 
307 int peekc;
308 getch() {
309 	register c;
310 	if(peekc) {
311 		c = peekc;
312 		peekc = 0;
313 		return(c);
314 	}
315 	return(getc(in));
316 }
317 
318 ungetc(c) {
319 	peekc = c;
320 }
321 
322 
323 error(s)
324 	char *s;
325 {
326 
327 	fflush(out);
328 	fprintf(stderr, stderr, "vsort: %s\n", s);
329 }
330 
331 crail(nrail)
332 	register int nrail;
333 {
334 	register int psize;
335 
336 	psize = cpsize;
337 	loadfont(nrail, psize);
338 }
339 
340 loadfont(fnum, size)
341 	register int fnum;
342 	register int size;
343 {
344 
345 	cpsize = size;
346 	return(0);
347 }
348 
349 startline()
350 {
351 
352 	if(pstart != 0) {
353 		cline.row = row;
354 		return;
355 	}
356 	cline.len = 0;
357 	cline.row = row;
358 	cline.start.col = col;
359 	cline.start.psize = cpsize;
360 	cline.start.mcase = mcase;
361 	cline.start.back = back;
362 	cline.start.verd = verd;
363 	cline.start.railmag = railmag;
364 	codep = tbuf;
365 }
366 
367 termline()
368 {
369 	register struct line *linep;
370 	register char *allp;
371 	register char *cp;
372 	int i;
373 
374 	if(pstart != 0)
375 		return;
376 	if((allp = calloc(sizeof *linep,1)) == ((char *)-1))
377 		error("alloc");
378 	linep = (struct line *)allp;
379 	linep->end.col = col;
380 	linep->end.psize = cpsize;
381 	linep->end.mcase = mcase;
382 	linep->end.back = back;
383 	linep->end.verd = verd;
384 	linep->end.railmag = railmag;
385 	linep->start.col = cline.start.col;
386 	linep->start.psize = cline.start.psize;
387 	linep->start.mcase = cline.start.mcase;
388 	linep->start.back = cline.start.back;
389 	linep->start.verd = cline.start.verd;
390 	linep->start.railmag = cline.start.railmag;
391 	linep->len = cline.len;
392 	linep->row = row;
393 	if((allp = calloc(cline.len,1)) == ((char *)-1))
394 		error("alloc");
395 	linep->codep = allp;
396 	cp = tbuf;
397 	for(i = 0; i < cline.len; i++)
398 		*allp++ = *cp++;
399 	sortin(linep);
400 	}
401 
402 sortin(linep)
403 	register struct line *linep;
404 {
405 	register struct line *clp;
406 
407 	if((clp = tail) == NULL) {
408 		head = tail = linep;
409 		linep->lastp = linep->nextp = NULL;
410 		return;
411 	}
412 	while(clp != NULL && clp->row > linep->row)
413 		clp = clp->lastp;
414 	if(clp == tail) {
415 		linep->lastp = tail;
416 		linep->nextp = NULL;
417 		tail->nextp = linep;
418 		tail = linep;
419 	} else
420 		if(clp == NULL)	/*  goes at head of list  */ {
421 			linep->lastp = NULL;
422 			linep->nextp = head;
423 			head->lastp = linep;
424 			head = linep;
425 		} else {
426 			linep->lastp = clp;
427 			linep->nextp = clp->nextp;
428 			clp->nextp->lastp = linep;
429 			clp->nextp = linep;
430 		}
431 }
432 
433 stuffc(code)
434 	register int code;
435 {
436 
437 	if(pstart != 0) {
438 		pstart = 0;
439 		startline();
440 	}
441 	if(cline.len > TBUFLEN) {
442 		termline();
443 		startline();
444 	}
445 	*codep++ = code;
446 	cline.len++;
447 }
448 
449 
450 allflush()	/* Flush all lines, then put out trailing leading. */
451 {
452 
453 	linesflush();
454 	if (row > orow) {
455 		ptlead(row - orow);
456 	}
457 	row -= pagelength;
458 	orow = row;
459 }
460 
461 linesflush()
462 {
463 	while(head != NULL)
464 		sendline();
465 }
466 
467 sendline()
468 {
469 	register char *cp;
470 	register struct line *linep;
471 	register int i;
472 	register int remcutmark;
473 
474 	if ((linep = head) == NULL)
475 		return;
476 
477 	/* Heuristic: if cut marks are present, they are on lines whose
478 	 * row numbers are <= 24 or >= pagelength-4.
479 	 * Cut marks are formed from 023's, 040's, or 061's.
480 	 * There are 2 or 4 of them on a line, and no other characters
481 	 * are present.  cutmark(...) checks this.
482 	 * Cutmark lines are removed if nocutmarks is true.
483 	 * Three leading units are removed, too, to compensate for
484 	 * varian output not being exactly 1584 leading units long.
485 	 */
486 #ifdef DUMPLINE
487 	dumpline(linep);
488 #endif
489 	remcutmark = 0;
490 	if (nocutmarks
491  	    && (linep->row <= 24 || linep->row >= pagelength-4)
492 	    && cutmark(linep)) {
493 		remcutmark++;
494 		orow = orow + 3;
495 	}
496 	if(linep->start.railmag != orailmag)
497 		ptrail(linep->start.railmag);
498 	if(linep->start.psize != opsize)
499 		ptsize(linep->start.psize);
500 	if(linep->start.mcase != omcase)
501 		ptmcase();
502 	if(linep->row > orow)	/*  lead forward  */
503 		ptlead(linep->row - orow);
504 	if(linep->start.col != ocol)
505 		ptesc(linep->start.col-ocol);
506 	if(linep->start.back != oback)
507 		ptback();
508 	cp = linep->codep;
509 	if (remcutmark) {
510 		for(i = 0; i < linep->len; i++) {
511 			if (!iscutmark(*cp))	/* iscutmark is a macro. */
512 				putc(*cp++, out);
513 			else
514 				cp++;
515 		}
516 	} else {
517 		for(i = 0; i < linep->len; i++)
518 			putc(*cp++, out);
519 	}
520 
521 	orow = linep->row;
522 	orailmag = linep->end.railmag;
523 	opsize = linep->end.psize;
524 	omcase = linep->end.mcase;
525 	ocol = linep->end.col;
526 	oback = linep->end.back;
527 	head = linep->nextp;
528 
529 	cfree(linep->codep);
530 	cfree(linep);
531 	if(head == NULL)
532 		tail = NULL;
533 	else
534 		head->lastp = NULL;
535 }
536 
537 int
538 cutmark(linep)
539 register struct line *linep;
540 {
541 	register int i;
542 	register int ch;
543 	register int dashcount = 0;
544 	register int firstdash = 0;
545 
546 	for (i = 0; i < linep->len; i++) {
547 		ch = linep->codep[i] & 0377;
548 		if (ch < 0100) {
549 			if (iscutmark(ch)) {
550 					if (firstdash == 0)
551 						firstdash = ch;
552 					if (ch != firstdash)
553 						return (0);
554 					dashcount++;
555 			} else
556 				return(0);
557 		}
558 	}
559 	/* Must have 2 or 4 dashes on a line. */
560 	return (dashcount == 4 || dashcount == 2);
561 }
562 
563 ptrail(rlmg)
564 	register int rlmg;
565 {
566 
567 	if((rlmg & 01) != (orailmag & 01))
568 		putc((rlmg & 01) ? 0102:0101, out);	/*  rail  */
569 	if((rlmg & 02) != (orailmag & 02))
570 		putc((rlmg & 02) ? 0103:0104, out);	/*  mag  */
571 }
572 
573 ptback()
574 {
575 
576 	putc(oback ? 0107:0110, out);
577 	oback = !oback;
578 }
579 
580 ptsize(size)
581 	register int size;
582 {
583 
584 	putc(0120 | (size & 017), out);
585 	ptesc(-stupidadj(size, opsize));
586 }
587 
588 stupidadj(code, lcode)
589 	register int code;
590 	int lcode;
591 {
592 	register struct point_sizes *psp;
593 	register struct point_sizes *lpsp;
594 
595 	psp = point_sizes;
596 	while(psp->real_code != 0) {
597 		if((psp->stupid_code & 017) == code)
598 			break;
599 		psp++;
600 	}
601 	lpsp = point_sizes;
602 	while(lpsp->real_code != 0) {
603 		if((lpsp->stupid_code & 017) == lcode)
604 			break;
605 		lpsp++;
606 	}
607 	code = 0;
608 	if(!(lpsp->stupid_code & 0200) && (psp->stupid_code & 0200))
609 		code = -55;
610 	else
611 		if((lpsp->stupid_code & 0200) && !(psp->stupid_code & 0200))
612 			code = 55;
613 	return(code);
614 }
615 
616 ptmcase()
617 {
618 
619 	putc(omcase ? 0105:0106, out);
620 }
621 
622 ptesc(escc)
623 	register int escc;
624 {
625 
626 	if((escc < 0 && !oback ) || (escc >= 0 && oback))
627 		ptback();
628 	escc = abs(escc);
629 	while(escc > 0177) {
630 		putc(0200, out);
631 		escc -= 0177;
632 	}
633 	if(escc)
634 		putc(0200 | ((~escc) & 0177), out);
635 }
636 
637 ptlead(leadd)
638 	register int leadd;
639 {
640 
641 	while(leadd > 037) {
642 		putc(0140, out);
643 		leadd -= 037;
644 	}
645 	if(leadd)
646 		putc(0140 | ((~leadd) & 037), out);
647 }
648 
649 #ifdef DUMPLINE
650 dumpline(linep)
651 register struct line *linep;
652 {
653 	int i;
654 
655 	fprintf(stderr, "row: %d\n", linep->row);
656 	fprintf(stderr, "start.col: %o  ", linep->start.col & 0377);
657 	fprintf(stderr, ".psize: %o  ", linep->start.psize);
658 	fprintf(stderr, ".railmag: %o  ", linep->start.railmag);
659 	fprintf(stderr, ".verd: %o  ", linep->start.verd);
660 	fprintf(stderr, ".back: %o  ", linep->start.back);
661 	fprintf(stderr, ".mcase: %o\n", linep->start.mcase);
662 	fprintf(stderr, "  end.col: %o  ", linep->end.col);
663 	fprintf(stderr, ".psize: %o  ", linep->end.psize);
664 	fprintf(stderr, ".railmag: %o  ", linep->end.railmag);
665 	fprintf(stderr, ".verd: %o  ", linep->end.verd);
666 	fprintf(stderr, ".back: %o  ", linep->end.back);
667 	fprintf(stderr, ".mcase: %o\n", linep->end.mcase);
668 	fprintf(stderr, "len: %d\t", linep->len);
669 	fprintf(stderr, "codep: ");
670 	for (i = 0; i < linep->len; i++)
671 		fprintf(stderr, "%o ", linep->codep[i] & 0377);
672 	fprintf(stderr, "\n\n");
673 }
674 #endif
675