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