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