xref: /original-bsd/usr.bin/col/col.c (revision 39c8fdd5)
1 static char *sccsid = "@(#)col.c	4.1 (Berkeley) 10/01/80";
2 # include <stdio.h>
3 # define PL 256
4 # define ESC '\033'
5 # define RLF '\013'
6 # define SI '\017'
7 # define SO '\016'
8 # define GREEK 0200
9 # define LINELN 800
10 
11 char *page[PL];
12 char lbuff [LINELN], *line;
13 int bflag, hflag, fflag;
14 int half;
15 int cp, lp;
16 int ll, llh, mustwr;
17 int pcp = 0;
18 char *pgmname;
19 char	*strcpy();
20 
21 main (argc, argv)
22 	int argc; char **argv;
23 {
24 	int i;
25 	int greek;
26 	register int c;
27 	char fbuff[BUFSIZ];
28 
29 	setbuf (stdout, fbuff);
30 	pgmname = argv[0];
31 
32 	for (i = 1; i < argc; i++) {
33 		register char *p;
34 		if (*argv[i] != '-') {
35 			fprintf (stderr, "%s: bad option %s\n",
36 				pgmname, argv[i]);
37 			exit (2);
38 		}
39 		for (p = argv[i]+1; *p; p++) {
40 			switch (*p) {
41 			case 'b':
42 				bflag++;
43 				break;
44 
45 			case 'h':
46 				hflag++;
47 				break;
48 
49 			case 'f':
50 				fflag++;
51 				break;
52 
53 			default:
54 				fprintf (stderr, "%s: bad option letter %c\n",
55 					pgmname, *p);
56 				exit (2);
57 			}
58 		}
59 	}
60 
61 	for (ll=0; ll<PL; ll++)
62 		page[ll] = 0;
63 
64 	cp = 0;
65 	ll = 0;
66 	greek = 0;
67 	mustwr = PL;
68 	line = lbuff;
69 
70 	while ((c = getchar()) != EOF) {
71 		switch (c) {
72 		case '\n':
73 			incr();
74 			incr();
75 			cp = 0;
76 			continue;
77 
78 		case '\0':
79 			continue;
80 
81 		case ESC:
82 			c = getchar();
83 			switch (c) {
84 			case '7':	/* reverse full line feed */
85 				decr();
86 				decr();
87 				break;
88 
89 			case '8':	/* reverse half line feed */
90 				if (fflag)
91 					decr();
92 				else {
93 					if (--half < -1) {
94 						decr();
95 						decr();
96 						half += 2;
97 					}
98 				}
99 				break;
100 
101 			case '9':	/* forward half line feed */
102 				if (fflag)
103 					incr();
104 				else {
105 					if (++half > 0) {
106 						incr();
107 						incr();
108 						half -= 2;
109 					}
110 				}
111 				break;
112 			}
113 			continue;
114 
115 		case SO:
116 			greek = GREEK;
117 			continue;
118 
119 		case SI:
120 			greek = 0;
121 			continue;
122 
123 		case RLF:
124 			decr();
125 			decr();
126 			continue;
127 
128 		case '\r':
129 			cp = 0;
130 			continue;
131 
132 		case '\t':
133 			cp = (cp + 8) & -8;
134 			continue;
135 
136 		case '\b':
137 			if (cp > 0)
138 				cp--;
139 			continue;
140 
141 		case ' ':
142 			cp++;
143 			continue;
144 
145 		default:
146 			c &= 0177;
147 			if (c > 040 && c < 0177) {	/* if printable */
148 				outc(c | greek);
149 				cp++;
150 			}
151 			continue;
152 		}
153 	}
154 
155 	for (i=0; i<PL; i++)
156 		if (page[(mustwr+i)%PL] != 0)
157 			emit (page[(mustwr+i) % PL], mustwr+i-PL);
158 	emit (" ", (llh + 1) & -2);
159 	exit(0);
160 }
161 
162 outc (c)
163 	register char c;
164 {
165 	if (lp > cp) {
166 		line = lbuff;
167 		lp = 0;
168 	}
169 
170 	while (lp < cp) {
171 		switch (*line) {
172 		case '\0':
173 			*line = ' ';
174 			lp++;
175 			break;
176 
177 		case '\b':
178 			lp--;
179 			break;
180 
181 		default:
182 			lp++;
183 		}
184 		line++;
185 	}
186 	while (*line == '\b') {
187 		line += 2;
188 	}
189 	if (bflag || *line == '\0' || *line == ' ')
190 		*line = c;
191 	else {
192 		register char c1, c2, c3;
193 		c1 = *++line;
194 		*line++ = '\b';
195 		c2 = *line;
196 		*line++ = c;
197 		while (c1) {
198 			c3 = *line;
199 			*line++ = c1;
200 			c1 = c2;
201 			c2 = c3;
202 		}
203 		lp = 0;
204 		line = lbuff;
205 	}
206 }
207 
208 store (lno)
209 {
210 	char *malloc();
211 
212 	lno %= PL;
213 	if (page[lno] != 0)
214 		free (page[lno]);
215 	page[lno] = malloc((unsigned)strlen(lbuff) + 2);
216 	if (page[lno] == 0) {
217 		fprintf (stderr, "%s: no storage\n", pgmname);
218 		exit (2);
219 	}
220 	strcpy (page[lno],lbuff);
221 }
222 
223 fetch(lno)
224 {
225 	register char *p;
226 
227 	lno %= PL;
228 	p = lbuff;
229 	while (*p)
230 		*p++ = '\0';
231 	line = lbuff;
232 	lp = 0;
233 	if (page[lno])
234 		strcpy (line, page[lno]);
235 }
236 emit (s, lineno)
237 	char *s;
238 	int lineno;
239 {
240 	static int cline = 0;
241 	register int ncp;
242 	register char *p;
243 	static int gflag = 0;
244 
245 	if (*s) {
246 		while (cline < lineno - 1) {
247 			putchar ('\n');
248 			pcp = 0;
249 			cline += 2;
250 		}
251 		if (cline != lineno) {
252 			putchar (ESC);
253 			putchar ('9');
254 			cline++;
255 		}
256 		if (pcp)
257 			putchar ('\r');
258 		pcp = 0;
259 		p = s;
260 		while (*p) {
261 			ncp = pcp;
262 			while (*p++ == ' ') {
263 				if ((++ncp & 7) == 0 && hflag) {
264 					pcp = ncp;
265 					putchar ('\t');
266 				}
267 			}
268 			if (!*--p)
269 				break;
270 			while (pcp < ncp) {
271 				putchar (' ');
272 				pcp++;
273 			}
274 			if (gflag != (*p & GREEK) && *p != '\b') {
275 				if (gflag)
276 					putchar (SI);
277 				else
278 					putchar (SO);
279 				gflag ^= GREEK;
280 			}
281 			putchar (*p & ~GREEK);
282 			if (*p++ == '\b')
283 				pcp--;
284 			else
285 				pcp++;
286 		}
287 	}
288 }
289 
290 incr()
291 {
292 	store (ll++);
293 	if (ll > llh)
294 		llh = ll;
295 	if (ll >= mustwr && page[ll%PL]) {
296 		emit (page[ll%PL], ll - PL);
297 		mustwr++;
298 		free (page[ll%PL]);
299 		page[ll%PL] = 0;
300 	}
301 	fetch (ll);
302 }
303 
304 decr()
305 {
306 	if (ll > mustwr - PL) {
307 		store (ll--);
308 		fetch (ll);
309 	}
310 }
311