1/*	$NetBSD: fpr.c,v 1.8 2008/07/21 14:19:22 lukem 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
43static char sccsid[] = "@(#)fpr.c	8.1 (Berkeley) 6/6/93";
44#endif
45__RCSID("$NetBSD: fpr.c,v 1.8 2008/07/21 14:19:22 lukem 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
68typedef
69struct column {
70	int     count;
71	int     width;
72	char   *str;
73}
74        COLUMN;
75
76static char    cc;
77static char    saved;
78static int     length;
79static char   *text;
80static int     highcol;
81static COLUMN *line;
82static int     maxpos;
83static int     maxcol;
84
85static void	flush(void);
86static void	get_text(void);
87static void	init(void);
88__dead static void	nospace(void);
89static void	savech(int);
90
91int
92main(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
173static void
174init(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
204static void
205get_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
270static void
271savech(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
322static void
323flush(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
374static void
375nospace(void)
376{
377	errx(1, "Storage limit exceeded.");
378}
379