xref: /original-bsd/old/vfilters/vsort/vsort.c (revision 3b6250d9)
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.4 (Berkeley) 03/02/91";
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 error(s)
319 	char *s;
320 {
321 
322 	fflush(out);
323 	fprintf(stderr, "vsort: %s\n", s);
324 }
325 
326 crail(nrail)
327 	register int nrail;
328 {
329 	register int psize;
330 
331 	psize = cpsize;
332 	loadfont(nrail, psize);
333 }
334 
335 loadfont(fnum, size)
336 	register int fnum;
337 	register int size;
338 {
339 
340 	cpsize = size;
341 	return(0);
342 }
343 
344 startline()
345 {
346 
347 	if(pstart != 0) {
348 		cline.row = row;
349 		return;
350 	}
351 	cline.len = 0;
352 	cline.row = row;
353 	cline.start.col = col;
354 	cline.start.psize = cpsize;
355 	cline.start.mcase = mcase;
356 	cline.start.back = back;
357 	cline.start.verd = verd;
358 	cline.start.railmag = railmag;
359 	codep = tbuf;
360 }
361 
362 termline()
363 {
364 	register struct line *linep;
365 	register char *allp;
366 	register char *cp;
367 	int i;
368 
369 	if(pstart != 0)
370 		return;
371 	if((allp = calloc(sizeof *linep,1)) == ((char *)-1))
372 		error("alloc");
373 	linep = (struct line *)allp;
374 	linep->end.col = col;
375 	linep->end.psize = cpsize;
376 	linep->end.mcase = mcase;
377 	linep->end.back = back;
378 	linep->end.verd = verd;
379 	linep->end.railmag = railmag;
380 	linep->start.col = cline.start.col;
381 	linep->start.psize = cline.start.psize;
382 	linep->start.mcase = cline.start.mcase;
383 	linep->start.back = cline.start.back;
384 	linep->start.verd = cline.start.verd;
385 	linep->start.railmag = cline.start.railmag;
386 	linep->len = cline.len;
387 	linep->row = row;
388 	if((allp = calloc(cline.len,1)) == ((char *)-1))
389 		error("alloc");
390 	linep->codep = allp;
391 	cp = tbuf;
392 	for(i = 0; i < cline.len; i++)
393 		*allp++ = *cp++;
394 	sortin(linep);
395 	}
396 
397 sortin(linep)
398 	register struct line *linep;
399 {
400 	register struct line *clp;
401 
402 	if((clp = tail) == NULL) {
403 		head = tail = linep;
404 		linep->lastp = linep->nextp = NULL;
405 		return;
406 	}
407 	while(clp != NULL && clp->row > linep->row)
408 		clp = clp->lastp;
409 	if(clp == tail) {
410 		linep->lastp = tail;
411 		linep->nextp = NULL;
412 		tail->nextp = linep;
413 		tail = linep;
414 	} else
415 		if(clp == NULL)	/*  goes at head of list  */ {
416 			linep->lastp = NULL;
417 			linep->nextp = head;
418 			head->lastp = linep;
419 			head = linep;
420 		} else {
421 			linep->lastp = clp;
422 			linep->nextp = clp->nextp;
423 			clp->nextp->lastp = linep;
424 			clp->nextp = linep;
425 		}
426 }
427 
428 stuffc(code)
429 	register int code;
430 {
431 
432 	if(pstart != 0) {
433 		pstart = 0;
434 		startline();
435 	}
436 	if(cline.len > TBUFLEN) {
437 		termline();
438 		startline();
439 	}
440 	*codep++ = code;
441 	cline.len++;
442 }
443 
444 
445 allflush()	/* Flush all lines, then put out trailing leading. */
446 {
447 
448 	linesflush();
449 	if (row > orow) {
450 		ptlead(row - orow);
451 	}
452 	row -= pagelength;
453 	orow = row;
454 }
455 
456 linesflush()
457 {
458 	while(head != NULL)
459 		sendline();
460 }
461 
462 sendline()
463 {
464 	register char *cp;
465 	register struct line *linep;
466 	register int i;
467 	register int remcutmark;
468 
469 	if ((linep = head) == NULL)
470 		return;
471 
472 	/* Heuristic: if cut marks are present, they are on lines whose
473 	 * row numbers are <= 24 or >= pagelength-4.
474 	 * Cut marks are formed from 023's, 040's, or 061's.
475 	 * There are 2 or 4 of them on a line, and no other characters
476 	 * are present.  cutmark(...) checks this.
477 	 * Cutmark lines are removed if nocutmarks is true.
478 	 * Three leading units are removed, too, to compensate for
479 	 * varian output not being exactly 1584 leading units long.
480 	 */
481 #ifdef DUMPLINE
482 	dumpline(linep);
483 #endif
484 	remcutmark = 0;
485 	if (nocutmarks
486  	    && (linep->row <= 24 || linep->row >= pagelength-4)
487 	    && cutmark(linep)) {
488 		remcutmark++;
489 		orow = orow + 3;
490 	}
491 	if(linep->start.railmag != orailmag)
492 		ptrail(linep->start.railmag);
493 	if(linep->start.psize != opsize)
494 		ptsize(linep->start.psize);
495 	if(linep->start.mcase != omcase)
496 		ptmcase();
497 	if(linep->row > orow)	/*  lead forward  */
498 		ptlead(linep->row - orow);
499 	if(linep->start.col != ocol)
500 		ptesc(linep->start.col-ocol);
501 	if(linep->start.back != oback)
502 		ptback();
503 	cp = linep->codep;
504 	if (remcutmark) {
505 		for(i = 0; i < linep->len; i++) {
506 			if (!iscutmark(*cp))	/* iscutmark is a macro. */
507 				putc(*cp++, out);
508 			else
509 				cp++;
510 		}
511 	} else {
512 		for(i = 0; i < linep->len; i++)
513 			putc(*cp++, out);
514 	}
515 
516 	orow = linep->row;
517 	orailmag = linep->end.railmag;
518 	opsize = linep->end.psize;
519 	omcase = linep->end.mcase;
520 	ocol = linep->end.col;
521 	oback = linep->end.back;
522 	head = linep->nextp;
523 
524 	cfree(linep->codep);
525 	cfree(linep);
526 	if(head == NULL)
527 		tail = NULL;
528 	else
529 		head->lastp = NULL;
530 }
531 
532 int
533 cutmark(linep)
534 register struct line *linep;
535 {
536 	register int i;
537 	register int ch;
538 	register int dashcount = 0;
539 	register int firstdash = 0;
540 
541 	for (i = 0; i < linep->len; i++) {
542 		ch = linep->codep[i] & 0377;
543 		if (ch < 0100) {
544 			if (iscutmark(ch)) {
545 					if (firstdash == 0)
546 						firstdash = ch;
547 					if (ch != firstdash)
548 						return (0);
549 					dashcount++;
550 			} else
551 				return(0);
552 		}
553 	}
554 	/* Must have 2 or 4 dashes on a line. */
555 	return (dashcount == 4 || dashcount == 2);
556 }
557 
558 ptrail(rlmg)
559 	register int rlmg;
560 {
561 
562 	if((rlmg & 01) != (orailmag & 01))
563 		putc((rlmg & 01) ? 0102:0101, out);	/*  rail  */
564 	if((rlmg & 02) != (orailmag & 02))
565 		putc((rlmg & 02) ? 0103:0104, out);	/*  mag  */
566 }
567 
568 ptback()
569 {
570 
571 	putc(oback ? 0107:0110, out);
572 	oback = !oback;
573 }
574 
575 ptsize(size)
576 	register int size;
577 {
578 
579 	putc(0120 | (size & 017), out);
580 	ptesc(-stupidadj(size, opsize));
581 }
582 
583 stupidadj(code, lcode)
584 	register int code;
585 	int lcode;
586 {
587 	register struct point_sizes *psp;
588 	register struct point_sizes *lpsp;
589 
590 	psp = point_sizes;
591 	while(psp->real_code != 0) {
592 		if((psp->stupid_code & 017) == code)
593 			break;
594 		psp++;
595 	}
596 	lpsp = point_sizes;
597 	while(lpsp->real_code != 0) {
598 		if((lpsp->stupid_code & 017) == lcode)
599 			break;
600 		lpsp++;
601 	}
602 	code = 0;
603 	if(!(lpsp->stupid_code & 0200) && (psp->stupid_code & 0200))
604 		code = -55;
605 	else
606 		if((lpsp->stupid_code & 0200) && !(psp->stupid_code & 0200))
607 			code = 55;
608 	return(code);
609 }
610 
611 ptmcase()
612 {
613 
614 	putc(omcase ? 0105:0106, out);
615 }
616 
617 ptesc(escc)
618 	register int escc;
619 {
620 
621 	if((escc < 0 && !oback ) || (escc >= 0 && oback))
622 		ptback();
623 	escc = abs(escc);
624 	while(escc > 0177) {
625 		putc(0200, out);
626 		escc -= 0177;
627 	}
628 	if(escc)
629 		putc(0200 | ((~escc) & 0177), out);
630 }
631 
632 ptlead(leadd)
633 	register int leadd;
634 {
635 
636 	while(leadd > 037) {
637 		putc(0140, out);
638 		leadd -= 037;
639 	}
640 	if(leadd)
641 		putc(0140 | ((~leadd) & 037), out);
642 }
643 
644 #ifdef DUMPLINE
645 dumpline(linep)
646 register struct line *linep;
647 {
648 	int i;
649 
650 	fprintf(stderr, "row: %d\n", linep->row);
651 	fprintf(stderr, "start.col: %o  ", linep->start.col & 0377);
652 	fprintf(stderr, ".psize: %o  ", linep->start.psize);
653 	fprintf(stderr, ".railmag: %o  ", linep->start.railmag);
654 	fprintf(stderr, ".verd: %o  ", linep->start.verd);
655 	fprintf(stderr, ".back: %o  ", linep->start.back);
656 	fprintf(stderr, ".mcase: %o\n", linep->start.mcase);
657 	fprintf(stderr, "  end.col: %o  ", linep->end.col);
658 	fprintf(stderr, ".psize: %o  ", linep->end.psize);
659 	fprintf(stderr, ".railmag: %o  ", linep->end.railmag);
660 	fprintf(stderr, ".verd: %o  ", linep->end.verd);
661 	fprintf(stderr, ".back: %o  ", linep->end.back);
662 	fprintf(stderr, ".mcase: %o\n", linep->end.mcase);
663 	fprintf(stderr, "len: %d\t", linep->len);
664 	fprintf(stderr, "codep: ");
665 	for (i = 0; i < linep->len; i++)
666 		fprintf(stderr, "%o ", linep->codep[i] & 0377);
667 	fprintf(stderr, "\n\n");
668 }
669 #endif
670