xref: /minix/usr.bin/fpr/fpr.c (revision ebfedea0)
1 /*	$NetBSD: fpr.c,v 1.9 2011/09/04 20:26:17 joerg Exp $	*/
2 
3 /*
4  * Copyright (c) 1989, 1993
5  *	The Regents of the University of California.  All rights reserved.
6  *
7  * This code is derived from software contributed to Berkeley by
8  * Robert Corbett.
9  *
10  * Redistribution and use in source and binary forms, with or without
11  * modification, are permitted provided that the following conditions
12  * are met:
13  * 1. Redistributions of source code must retain the above copyright
14  *    notice, this list of conditions and the following disclaimer.
15  * 2. Redistributions in binary form must reproduce the above copyright
16  *    notice, this list of conditions and the following disclaimer in the
17  *    documentation and/or other materials provided with the distribution.
18  * 3. Neither the name of the University nor the names of its contributors
19  *    may be used to endorse or promote products derived from this software
20  *    without specific prior written permission.
21  *
22  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
23  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
24  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
25  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
26  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
27  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
28  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
29  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
30  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
31  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
32  * SUCH DAMAGE.
33  */
34 
35 #include <sys/cdefs.h>
36 #ifndef lint
37 __COPYRIGHT("@(#) Copyright (c) 1989, 1993\
38  The Regents of the University of California.  All rights reserved.");
39 #endif				/* not lint */
40 
41 #ifndef lint
42 #if 0
43 static char sccsid[] = "@(#)fpr.c	8.1 (Berkeley) 6/6/93";
44 #endif
45 __RCSID("$NetBSD: fpr.c,v 1.9 2011/09/04 20:26:17 joerg Exp $");
46 #endif				/* not lint */
47 
48 #include <err.h>
49 #include <stdio.h>
50 #include <stdlib.h>
51 
52 #define BLANK ' '
53 #define TAB '\t'
54 #define NUL '\000'
55 #define FF '\f'
56 #define BS '\b'
57 #define CR '\r'
58 #define VTAB '\013'
59 #define EOL '\n'
60 
61 #define TRUE 1
62 #define FALSE 0
63 
64 #define MAXCOL 170
65 #define TABSIZE 8
66 #define INITWIDTH 8
67 
68 typedef
69 struct column {
70 	int     count;
71 	int     width;
72 	char   *str;
73 }
74         COLUMN;
75 
76 static char    cc;
77 static char    saved;
78 static int     length;
79 static char   *text;
80 static int     highcol;
81 static COLUMN *line;
82 static int     maxpos;
83 static int     maxcol;
84 
85 static void	flush(void);
86 static void	get_text(void);
87 static void	init(void);
88 __dead static void	nospace(void);
89 static void	savech(int);
90 
91 int
92 main(int argc, char **argv)
93 {
94 	int ch;
95 	char ateof;
96 	int i;
97 	int errorcount;
98 
99 	init();
100 	errorcount = 0;
101 	ateof = FALSE;
102 
103 	switch (ch = getchar()) {
104 	case EOF:
105 		exit(0);
106 	case EOL:
107 		cc = NUL;
108 		ungetc((int) EOL, stdin);
109 		break;
110 	case BLANK:
111 		cc = NUL;
112 		break;
113 	case '1':
114 		cc = FF;
115 		break;
116 	case '0':
117 		cc = EOL;
118 		break;
119 	case '+':
120 		cc = CR;
121 		break;
122 	default:
123 		errorcount = 1;
124 		cc = NUL;
125 		ungetc(ch, stdin);
126 		break;
127 	}
128 
129 	while (!ateof) {
130 		get_text();
131 		switch (ch = getchar()) {
132 		case EOF:
133 			flush();
134 			ateof = TRUE;
135 			break;
136 		case EOL:
137 			flush();
138 			cc = NUL;
139 			ungetc((int) EOL, stdin);
140 			break;
141 		case BLANK:
142 			flush();
143 			cc = NUL;
144 			break;
145 		case '1':
146 			flush();
147 			cc = FF;
148 			break;
149 		case '0':
150 			flush();
151 			cc = EOL;
152 			break;
153 		case '+':
154 			for (i = 0; i < length; i++)
155 				savech(i);
156 			break;
157 		default:
158 			errorcount++;
159 			flush();
160 			cc = NUL;
161 			ungetc(ch, stdin);
162 			break;
163 		}
164 	}
165 
166 	if (errorcount)
167 		fprintf(stderr, "Illegal carriage control - %d line%s.\n",
168 		    errorcount, errorcount == 1 ? "" : "s");
169 
170 	exit(0);
171 }
172 
173 static void
174 init(void)
175 {
176 	COLUMN *cp;
177 	COLUMN *cend;
178 	char *sp;
179 
180 	length = 0;
181 	maxpos = MAXCOL;
182 	sp = malloc((unsigned) maxpos);
183 	if (sp == NULL)
184 		nospace();
185 	text = sp;
186 
187 	highcol = -1;
188 	maxcol = MAXCOL;
189 	line = calloc(maxcol, sizeof(COLUMN));
190 	if (line == NULL)
191 		nospace();
192 	cp = line;
193 	cend = line + (maxcol - 1);
194 	while (cp <= cend) {
195 		cp->width = INITWIDTH;
196 		sp = calloc(INITWIDTH, sizeof(char));
197 		if (sp == NULL)
198 			nospace();
199 		cp->str = sp;
200 		cp++;
201 	}
202 }
203 
204 static void
205 get_text(void)
206 {
207 	int i;
208 	char ateol;
209 	int ch;
210 	int pos;
211 	char *n;
212 
213 	i = 0;
214 	ateol = FALSE;
215 
216 	while (!ateol) {
217 		switch (ch = getchar()) {
218 		case EOL:
219 		case EOF:
220 			ateol = TRUE;
221 			break;
222 		case TAB:
223 			pos = (1 + i / TABSIZE) * TABSIZE;
224 			if (pos > maxpos) {
225 				n = realloc(text, (unsigned)(pos + 10));
226 				if (n == NULL)
227 					nospace();
228 				text = n;
229 				maxpos = pos + 10;
230 			}
231 			while (i < pos) {
232 				text[i] = BLANK;
233 				i++;
234 			}
235 			break;
236 		case BS:
237 			if (i > 0) {
238 				i--;
239 				savech(i);
240 			}
241 			break;
242 		case CR:
243 			while (i > 0) {
244 				i--;
245 				savech(i);
246 			}
247 			break;
248 		case FF:
249 		case VTAB:
250 			flush();
251 			cc = ch;
252 			i = 0;
253 			break;
254 		default:
255 			if (i >= maxpos) {
256 				n = realloc(text, (unsigned)(i + 10));
257 				if (n == NULL)
258 					nospace();
259 				maxpos = i + 10;
260 			}
261 			text[i] = ch;
262 			i++;
263 			break;
264 		}
265 	}
266 
267 	length = i;
268 }
269 
270 static void
271 savech(int col)
272 {
273 	char ch;
274 	int oldmax;
275 	COLUMN *cp;
276 	COLUMN *cend;
277 	char *sp;
278 	int newcount;
279 	COLUMN *newline;
280 
281 	ch = text[col];
282 	if (ch == BLANK)
283 		return;
284 
285 	saved = TRUE;
286 
287 	if (col >= highcol)
288 		highcol = col;
289 
290 	if (col >= maxcol) {
291 		newline = realloc(line, (unsigned) (col + 10) * sizeof(COLUMN));
292 		if (newline == NULL)
293 			nospace();
294 		line = newline;
295 		oldmax = maxcol;
296 		maxcol = col + 10;
297 		cp = line + oldmax;
298 		cend = line + (maxcol - 1);
299 		while (cp <= cend) {
300 			cp->width = INITWIDTH;
301 			cp->count = 0;
302 			sp = calloc(INITWIDTH, sizeof(char));
303 			if (sp == NULL)
304 				nospace();
305 			cp->str = sp;
306 			cp++;
307 		}
308 	}
309 	cp = line + col;
310 	newcount = cp->count + 1;
311 	if (newcount > cp->width) {
312 		cp->width = newcount;
313 		sp = realloc(cp->str, (unsigned) newcount * sizeof(char));
314 		if (sp == NULL)
315 			nospace();
316 		cp->str = sp;
317 	}
318 	cp->count = newcount;
319 	cp->str[newcount - 1] = ch;
320 }
321 
322 static void
323 flush(void)
324 {
325 	int i;
326 	int anchor;
327 	int height;
328 	int j;
329 
330 	if (cc != NUL)
331 		putchar(cc);
332 
333 	if (!saved) {
334 		i = length;
335 		while (i > 0 && text[i - 1] == BLANK)
336 			i--;
337 		length = i;
338 		for (i = 0; i < length; i++)
339 			putchar(text[i]);
340 		putchar(EOL);
341 		return;
342 	}
343 	for (i = 0; i < length; i++)
344 		savech(i);
345 
346 	anchor = 0;
347 	while (anchor <= highcol) {
348 		height = line[anchor].count;
349 		if (height == 0) {
350 			putchar(BLANK);
351 			anchor++;
352 		} else if (height == 1) {
353 			putchar(*(line[anchor].str));
354 			line[anchor].count = 0;
355 			anchor++;
356 		} else {
357 			i = anchor;
358 			while (i < highcol && line[i + 1].count > 1)
359 				i++;
360 			for (j = anchor; j <= i; j++) {
361 				height = line[j].count - 1;
362 				putchar(line[j].str[height]);
363 				line[j].count = height;
364 			}
365 			for (j = anchor; j <= i; j++)
366 				putchar(BS);
367 		}
368 	}
369 
370 	putchar(EOL);
371 	highcol = -1;
372 }
373 
374 static void
375 nospace(void)
376 {
377 	errx(1, "Storage limit exceeded.");
378 }
379