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
main(int argc,char ** argv)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
init(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
get_text(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
savech(int col)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
flush(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
nospace(void)375 nospace(void)
376 {
377           errx(1, "Storage limit exceeded.");
378 }
379