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