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