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