|
|
1.1 root 1: /* D.L.Buck and Associates, Inc. - 10/16/84
2: *
3: * COPYRIGHT NOTICE:
4: * Copyright c 10/16/84 - An unpublished work by
5: * D.L.Buck and Associates, Inc.
6: *
7: * PROPRIETARY RIGHTS NOTICE:
8: * All rights reserved. This document and program contains
9: * proprietary information of D.L.Buck and Associates,Inc.
10: * of San Jose, California, U.S.A., embodying confidential
11: * information, ideas, and expressions, no part of which
12: * may be reproduced, or transmitted in any form or by any
13: * means, electronic, mechanical, or otherwise, without
14: * the written permission of D.L.Buck and Associates, Inc.
15: *
16: * NAME
17: * bscpr -- BISYNC batch file print utility
18: *
19: * SYNOPSIS
20: * bscpr [-ascii] [-page=pp] [chan=lineno ...] [file]
21: *
22: * DESCRIPTION
23: * bscpr paginates a file which contains IBM 2780 or 3780 terminal
24: * control characters and escape sequences which control paper motion
25: * on a line printer.
26: *
27: * ALGORITHM
28: * I. initialize, get options from command line
29: * A. special instructions coded in ASCII or EBCDIC
30: * B. page length
31: * C. channel assignments
32: * D. get and open file, if specified
33: *
34: * II. while not at end of file:
35: * A. read a line
36: * B. set character pointer (s1) to beginning of line
37: * C. if s1 points to an ESC character, this is the
38: * beginning of a special instruction (Escape) sequence.
39: * D. if the next character is an HT (horizontal tab) character:
40: * 1. set up tabs in the tab rack according to
41: * instructions on this line
42: * E. output the line a character at a time, expanding the tabs
43: * along the way
44: * F. do line feeds
45: *
46: * III. close the file
47: */
48:
49: #include <stdio.h>
50: #include "local.h"
51:
52: #ifndef lint
53: static char sccsid[] = "@(#)bscpr.c 1.8 REL";
54: #endif
55:
56: #define RCDLN 512 /* max allowed record length */
57: #define DEFLINES 66 /* default max lines allowed per page */
58:
59: #define ESC 0x1b /* ASCII escape */
60: #define HT 0x09 /* ASCII Horizontal Tab format effector */
61: #define VT 0x0b /* ASCII Vertical Tab format effector */
62: #define FF 0x0c /* ASCII Form Feed format effector */
63: #define DC1 0x11 /* select printer code */
64:
65: #define YES 1
66: #define NO 0
67: char tabrack[RCDLN]; /* contains horizontal tab positions */
68: char line[RCDLN]; /* simple data record */
69: char *index();
70: int channel[13]; /* contains "vertical tabbing" instructions -- line
71: numbers on the page corresponding to printer channels */
72:
73: /* the arrays asctab and ebctab are used to decode vertical tab instructions and
74: line skip instructions embedded in input lines in ASCII or EBCDIC, respectively.
75: negative numbers correspond to vertical tab instructions (ESC<alpha> sequences);
76: e.g. ESC B corresponds to asctab or ebctab -2, meaning "skip to channel 2".
77: the positive numbers correspond to line skip instructions; 1=skip 1 line, 2=skip
78: 2 lines, 3=skip 3 lines (all after printing the current one).
79:
80: A B C D E F G H I J K L M N O P Q R S T U V W X Y*/
81: int asctab[]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,0,1,1,1,1,2,3,1,1,1,1,1,1,
82: 1}; /* <-Z */
83:
84: /* A B C D E F G H I J K L M N O P Q R S T U V W X Y*/
85: int ebctab[]={-1,-2,-3,-4,-5,-6,-7,-8,-9,-10,-11,-12,0,1,1,1,1,1,2,3,1,1,1,1,1,
86: 1}; /* <-Z */
87:
88: int linect = 1; /* current position on page */
89: int maxlines; /* maximum # of lines per page */
90: void exit();
91:
92: main (argc,argv)
93: int argc;
94: char *argv[];
95: {
96: int i;
97: int chan; /* pulled-out channel goes here */
98: int lineno; /* pulled-out line# channel corresponds to goes here */
99: int maxused; /* max line # referred to in chan=line */
100: int usedin; /* chan having max line# above */
101: char *pos;
102: register char *s1,*s2;
103: int ascii; /* flags ASCII or EBCDIC esc sequence (YES or NO) */
104: FILE *bscfile; /* input file to be paginated */
105: FILE *fopen(); /* file open function */
106:
107: bscfile = stdin; /* default input file is the terminal */
108: ascii = NO; /* default transmission code is EBCDIC */
109: channel[1] = 1; /* channel 1 is always top-of-form */
110: maxlines = channel[12] =DEFLINES; /* default page length */
111: maxused = 1;
112: usedin = 1;
113:
114: for (i=1;i<argc;++i) { /* get options from command line */
115: if (strcmp(argv[i],"-ascii") == 0) {
116: ascii = YES;
117: continue;
118: }
119:
120: /* pull out maxlines here if in command line */
121: if (strncmp(argv[i],"-page=",6) == 0) {
122: if (argv[i][6] >= '0' && argv[i][6] <= '9')
123: maxlines = atoi(&argv[i][6]);
124: else {
125: fprintf(stderr,
126: "bscpr: not a numeric <%s>\n",argv[i]);
127: exit(1);
128: }
129:
130: channel[12] = maxlines;
131: if (maxused > maxlines) {
132: fprintf(stderr,"%s %d %s\n",
133: "bscpr: line assignment for channel",usedin,
134: "is greater than page length");
135: exit(1);
136: }
137: continue;
138: }
139:
140: /* get channel assignments */
141: if ((pos=index(argv[i],'=')) != NULL) {
142: if (argv[i][0] >= '0' && argv[i][0] <= '9' &&
143: pos[1] >= '0' && pos[1] <= '9') {
144: chan = atoi(argv[i]);
145: lineno = atoi(&pos[1]);
146: } else {
147: fprintf(stderr,
148: "bscpr: not a numeric <%s>\n",argv[i]);
149: exit(1);
150: }
151:
152: if (chan < 2 || chan > 12) {
153: fprintf(stderr,
154: "bscpr: channel number not 2 to 12 <%s>\n",
155: argv[i]);
156: exit(1);
157: }
158: /* check that assignment's less than page length */
159: if (lineno > maxlines) {
160: fprintf(stderr,"%s %d %s\n",
161: "bscpr: line assignment for channel",chan,
162: "is greater than page length");
163: exit(1);
164: }
165:
166: channel[chan] = lineno;
167: if (lineno > maxused) { /* set max line# used */
168: maxused = lineno;
169: usedin = chan;
170: }
171: continue;
172: }
173:
174: /* ...get filename (if any specified)...
175: first check that, if this arg isn't a flag or a
176: channel assignment, that it's the last arg. If it
177: isn't, it's an illegal option specification */
178:
179:
180: if (argv[i][0] == '-' || i < argc-1) {
181: fprintf(stderr,
182: "bscpr: unrecognized option (%s)\n",argv[i]);
183: exit(1);
184: }
185:
186: /* open it if it's okay */
187: if ((bscfile=fopen(argv[i],"r")) == NULL) {
188: fprintf(stderr,"bscpr: %s not found\n",argv[i]);
189: exit(1);
190: }
191: }
192:
193: /* now print the file */
194:
195: while (fgets(line,(RCDLN),bscfile) != NULL) {
196: s1 = line;
197: /* Check for Tab Rack: ESC HT ..... */
198: if (s1[0] == ESC && s1[1] == HT) {
199: s1 = &line[2]; /* point beyond ESC HT sequence */
200: s2 = tabrack; /* point to beginning of tabrack */
201:
202: /* set up output tabrack (used to do horizontal tabbing):
203: while the input tabrack position != newline, if the input position s1 pts to
204: is HT, then the corresponding output position s2 pts to is HT; otherwise,
205: output position is ' ' (blank). */
206:
207: while (*s1 != '\n')
208: *s2++ = (*s1++ == HT)?HT:' ';
209:
210: /* NULL-out rest of output tabrack (s2) */
211: while (s2 < &tabrack[RCDLN])
212: *s2++ = '\0';
213:
214: continue;
215: }
216:
217: output();
218:
219: /* do line feeds (dolfs): if line length<2, or there are no special instructions
220: for this line (s1 != ESC), or the ESC sequence isn't valid
221: (<alpha> less than A or greater than Z), do single spacing. Otherwise, if
222: this file is ASCII coded, get the number of line feeds to do from
223: asctab(*s1-'A'). If it's EBCDIC coded, get the number of line feeds to do
224: from ebctab(*s1-'A'). */
225:
226: if (strlen(line) < 2 || *s1 != ESC ||
227: (*s1 == ESC && (*(s1+1) < 'A' || *(s1+1) > 'Z')))
228: dolfs(1); /* do single spacing */
229: else
230: dolfs((ascii?asctab:ebctab)[s1[1]-'A']);
231: }
232: }
233:
234: /* Here is dolfs -- do linefeeds (lines get hungry too) */
235: dolfs(action)
236: register int action;
237: {
238: register int loop;
239: register int lfeeds; /* contains # of line feeds to do */
240:
241: if (action == 0) { /* do carriage return only */
242: putchar('\r');
243: return;
244: }
245:
246: if (action > 0) { /* output 'action' newlines if positive */
247: for (loop=0;loop < action;++loop) {
248: putchar('\n');
249: ++linect;
250: if (linect >= maxlines)
251: putchar('\f');
252: }
253: return;
254: }
255:
256: /* If `action' negative, skip to line given in channel table */
257: /* If already past that line, skip to top of next page */
258: if ((lfeeds = channel[-action])) {
259: if (linect >= lfeeds) {
260: putchar('\r');
261: putchar('\f');
262: linect = 1;
263: }
264: while (linect < lfeeds) {
265: putchar('\n');
266: ++linect;
267: }
268: return;
269: }
270:
271: putchar('\n');
272: ++linect;
273: }
274: /* Here is output -- the magic tab expander and character-outputter.
275: *
276: * 1. set lnptr to point to beginning of input line, tabptr to beginning of
277: * output tabrack.
278: *
279: * 2. if the first char lnptr points to is ESC, there are special instructions
280: * embedded in the line. Set lnptr to point beyond them (lnptr = &line[2]).
281: * Upon return to caller, the ESC will be handled.
282: *
283: * 3. Until reaching end of line:
284: *
285: * a. If char is HT (or '\t'):
286: * increment tabptr by counter (tabptr += counter) to set it to
287: * the current output column.
288: *
289: * use tabptr to output blanks until a corresponding HT is
290: * found in the tabrack.
291: *
292: * set counter back to zero.
293: *
294: * b. If char is VT:
295: * terminate the line, skip to channel 2, then move remainder of
296: * line to beginning of line and restart.
297: * c. If char is FF:
298: * terminate the line, skip to channel 1, then move remainder of
299: * line to beginning of line and restart.
300: * d. If char is NL:
301: * skip the character ... caller will do newlines as necessary.
302: * e. Otherwise:
303: * output lnptr's char, increment lnptr, increment counter.
304: */
305:
306: output()
307: {
308: register char *lnptr; /* points to beginning of line */
309: register char *tabptr; /* points to beginning of tabrack */
310:
311: lnptr = line;
312: tabptr = tabrack;
313:
314: if (*lnptr == DC1) /* Skip "select printer" */
315: ++lnptr;
316: if (*lnptr == ESC) /* Skip ESC, command */
317: lnptr += 2;
318: while (*lnptr) {
319: switch(*lnptr) {
320: case HT:
321: if (*tabptr == HT)
322: tabptr++;
323:
324: while (*tabptr != HT && *tabptr != '\0') {
325: putchar(' ');
326: tabptr++;
327: }
328: tabptr--;
329: break;
330:
331: case '\n':
332: break;
333:
334: default:
335: putchar(*lnptr);
336: break;
337:
338: case VT:
339: dolfs(-2);
340: goto redo;
341: case FF:
342: dolfs(-1);
343: redo:
344: strcpy(line,++lnptr);
345: lnptr = &line[-1];
346: tabptr = &tabrack[-1];
347: break;
348: }
349: ++lnptr;
350: if (*tabptr)
351: ++tabptr;
352: }
353: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.