1 /* Copyright (c) 1983 Regents of the University of California */ 2 3 #ifndef lint 4 static char sccsid[] = "@(#)rs.c 4.2 (Berkeley) 02/11/84"; 5 #endif not lint 6 7 /* 8 * rs - reshape a data array 9 * Author: John Kunze, Office of Comp. Affairs, UCB 10 * BEWARE: lots of unfinished edges 11 */ 12 13 #include <stdio.h> 14 #include <ctype.h> 15 16 long flags; 17 #define TRANSPOSE 000001 18 #define MTRANSPOSE 000002 19 #define ONEPERLINE 000004 20 #define ONEISEPONLY 000010 21 #define ONEOSEPONLY 000020 22 #define NOTRIMENDCOL 000040 23 #define SQUEEZE 000100 24 #define SHAPEONLY 000200 25 #define DETAILSHAPE 000400 26 #define RIGHTADJUST 001000 27 #define NULLPAD 002000 28 #define RECYCLE 004000 29 #define SKIPPRINT 010000 30 #define ICOLBOUNDS 020000 31 #define OCOLBOUNDS 040000 32 #define ONEPERCHAR 0100000 33 #define NOARGS 0200000 34 35 char buf[BUFSIZ]; 36 short *colwidths; 37 short *cord; 38 short *icbd; 39 short *ocbd; 40 int nelem; 41 char **elem; 42 char **endelem; 43 char *curline; 44 int allocsize = BUFSIZ; 45 int curlen; 46 int irows, icols; 47 int orows, ocols; 48 int maxlen; 49 int skip; 50 int propgutter; 51 char isep = ' ', osep = ' '; 52 int owidth = 80, gutter = 2; 53 54 char **getptrs(); 55 56 main(argc, argv) 57 int argc; 58 char **argv; 59 { 60 setbuf(stdout, buf); 61 getargs(argc, argv); 62 getfile(); 63 if (flags & SHAPEONLY) { 64 printf("%d %d\n", irows, icols); 65 exit(0); 66 } 67 prepfile(); 68 /*fprintf(stderr, "#irows %d icols %d orows %d ocols %d\n",irows,icols,orows,ocols);*/ 69 putfile(); 70 } 71 72 getfile() 73 { 74 register char *p; 75 register char *endp; 76 register char **ep = 0; 77 int multisep = (flags & ONEISEPONLY ? 0 : 1); 78 int nullpad = flags & NULLPAD; 79 char **padto; 80 81 while (skip--) { 82 getline(); 83 if (flags & SKIPPRINT) 84 puts(curline); 85 } 86 getline(); 87 if (flags & NOARGS && curlen < owidth) 88 flags |= ONEPERLINE; 89 if (flags & ONEPERLINE) 90 icols = 1; 91 else /* count cols on first line */ 92 for (p = curline, endp = curline + curlen; p < endp; p++) { 93 if (*p == isep && multisep) 94 continue; 95 icols++; 96 while (*p && *p != isep) 97 p++; 98 } 99 ep = getptrs(elem); 100 p = curline; 101 do { 102 if (flags & ONEPERLINE) { 103 *ep++ = curline; 104 if (maxlen < curlen) 105 maxlen = curlen; 106 irows++; 107 continue; 108 } 109 for (p = curline, endp = curline + curlen; p < endp; p++) { 110 if (*p == isep && multisep) 111 continue; /* eat up column separators */ 112 if (*p == isep) /* must be an empty column */ 113 *ep = ""; 114 else /* store column entry */ 115 *ep = p; 116 while (p < endp && *p != isep) 117 p++; /* find end of entry */ 118 *p = '\0'; /* mark end of entry */ 119 if (maxlen < p - *ep) /* update maxlen */ 120 maxlen = p - *ep; 121 ep++; /* prepare for next entry */ 122 } 123 irows++; /* update row count */ 124 if (nullpad) { /* pad missing entries */ 125 padto = elem + irows * icols; 126 while (ep < padto) 127 *ep++ = ""; 128 } 129 if (ep > endelem) /* if low on pointers */ 130 ep = getptrs(ep); /* get some more */ 131 } while (getline() != EOF); 132 *ep = 0; /* mark end of pointers */ 133 nelem = ep - elem; 134 } 135 136 putfile() 137 { 138 register char **ep; 139 register int i; 140 register int j; 141 142 ep = elem; 143 if (flags & TRANSPOSE) 144 for (i = 0; i < orows; i++) { 145 for (j = i; j < nelem; j += orows) 146 prints(ep[j], (j - i) / orows); 147 putchar('\n'); 148 } 149 else 150 for (i = 0; i < orows; i++) { 151 for (j = 0; j < ocols; j++) 152 prints(*ep++, j); 153 putchar('\n'); 154 } 155 } 156 157 prints(s, col) 158 char *s; 159 int col; 160 { 161 register char *p = s; 162 register int n; 163 164 while (*p) 165 p++; 166 n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s)); 167 if (flags & RIGHTADJUST) 168 while (n-- > 0) 169 putchar(osep); 170 for (p = s; *p; p++) 171 putchar(*p); 172 while (n-- > 0) 173 putchar(osep); 174 } 175 176 error(msg, s) 177 char *msg; 178 char *s; 179 { 180 fprintf(stderr, "rs: "); 181 fprintf(stderr, msg, s); 182 fprintf(stderr, "\nUsage: rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n"); 183 exit(1); 184 } 185 186 prepfile() 187 { 188 register char **ep; 189 register int i; 190 register int j; 191 char **lp; 192 int colw; 193 int max = 0; 194 int n; 195 196 if (!nelem) 197 exit(0); 198 gutter += maxlen * propgutter / 100.0; 199 colw = maxlen + gutter; 200 if (flags & MTRANSPOSE) { 201 orows = icols; 202 ocols = irows; 203 } 204 else if (orows == 0 && ocols == 0) { /* decide rows and cols */ 205 ocols = owidth / colw; 206 if (ocols == 0) 207 fprintf(stderr, "Display width %d is less than column width %d\n", owidth, colw); 208 if (ocols > nelem) 209 ocols = nelem; 210 orows = nelem / ocols + (nelem % ocols ? 1 : 0); 211 } 212 else if (orows == 0) /* decide on rows */ 213 orows = nelem / ocols + (nelem % ocols ? 1 : 0); 214 else if (ocols == 0) /* decide on cols */ 215 ocols = nelem / orows + (nelem % orows ? 1 : 0); 216 lp = elem + orows * ocols; 217 while (lp > endelem) { 218 getptrs(elem + nelem); 219 lp = elem + orows * ocols; 220 } 221 if (flags & RECYCLE) { 222 for (ep = elem + nelem; ep < lp; ep++) 223 *ep = *(ep - nelem); 224 nelem = lp - elem; 225 } 226 if (!(colwidths = (short *) malloc(ocols * sizeof(short)))) 227 error("malloc: No gutter space", ""); 228 if (flags & SQUEEZE) { 229 if (flags & TRANSPOSE) 230 for (ep = elem, i = 0; i < ocols; i++) { 231 for (j = 0; j < orows; j++) 232 if ((n = strlen(*ep++)) > max) 233 max = n; 234 colwidths[i] = max + gutter; 235 } 236 else 237 for (i = 0; i < ocols; i++) { 238 for (j = i; j < nelem; j += ocols) 239 if ((n = strlen(ep[j])) > max) 240 max = n; 241 colwidths[i] = max + gutter; 242 } 243 } 244 /* for (i = 0; i < orows; i++) { 245 for (j = i; j < nelem; j += orows) 246 prints(ep[j], (j - i) / orows); 247 putchar('\n'); 248 } 249 else 250 for (i = 0; i < orows; i++) { 251 for (j = 0; j < ocols; j++) 252 prints(*ep++, j); 253 putchar('\n'); 254 }*/ 255 else 256 for (i = 0; i < ocols; i++) 257 colwidths[i] = colw; 258 if (!(flags & NOTRIMENDCOL)) { 259 if (flags & RIGHTADJUST) 260 colwidths[0] -= gutter; 261 else 262 colwidths[ocols - 1] = 0; 263 } 264 n = orows * ocols; 265 if (n > nelem && (flags & RECYCLE)) 266 nelem = n; 267 /*for (i = 0; i < ocols; i++) 268 fprintf(stderr, "%d ",colwidths[i]); 269 fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/ 270 } 271 272 #define BSIZE 2048 273 char ibuf[BSIZE]; /* two screenfuls should do */ 274 275 getline() /* get line; maintain curline, curlen; manage storage */ 276 { 277 register char *p; 278 register int c; 279 register int i; 280 static int putlength; 281 static char *endblock = ibuf + BSIZE; 282 283 if (!irows) { 284 curline = ibuf; 285 putlength = flags & DETAILSHAPE; 286 } 287 else if (skip <= 0) { /* don't waste storage */ 288 curline += curlen + 1; 289 if (putlength) /* print length, recycle storage */ 290 printf(" %d line %d\n", curlen, irows); 291 } 292 if (!putlength && endblock - curline < BUFSIZ) { /* need storage */ 293 /*ww = endblock-curline; tt += ww;*/ 294 /*printf("#wasted %d total %d\n",ww,tt);*/ 295 if (!(curline = (char *) malloc(BSIZE))) 296 error("File too large", ""); 297 endblock = curline + BSIZE; 298 /*printf("#endb %d curline %d\n",endblock,curline);*/ 299 } 300 for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++) 301 if ((c = getchar()) == EOF || c == '\n') 302 break; 303 *p = '\0'; 304 curlen = i - 1; 305 return(c); 306 } 307 308 char ** 309 getptrs(sp) 310 char **sp; 311 { 312 register char **p; 313 register char **ep; 314 315 for (;;) { 316 allocsize += allocsize; 317 if (!(p = (char **) malloc(allocsize * sizeof(char *)))) { 318 perror("rs"); 319 exit(1); 320 } 321 if ((endelem = p + allocsize - icols) <= p) { 322 free(p); 323 continue; 324 } 325 if (elem != 0) 326 free(elem); 327 ep = elem; 328 elem = p; 329 while (ep < sp) 330 *p++ = *ep++; 331 return(p); 332 } 333 } 334 335 getargs(ac, av) 336 int ac; 337 char **av; 338 { 339 register char *p; 340 char *getnum(), *getlist(); 341 342 if (ac == 1) { 343 flags |= NOARGS | TRANSPOSE; 344 } 345 while (--ac && **++av == '-') 346 for (p = *av+1; *p; p++) 347 switch (*p) { 348 case 'T': 349 flags |= MTRANSPOSE; 350 case 't': 351 flags |= TRANSPOSE; 352 break; 353 case 'c': /* input col. separator */ 354 flags |= ONEISEPONLY; 355 case 's': /* one or more allowed */ 356 if (p[1]) 357 isep = *++p; 358 else 359 isep = '\t'; /* default is ^I */ 360 break; 361 case 'C': 362 flags |= ONEOSEPONLY; 363 case 'S': 364 if (p[1]) 365 osep = *++p; 366 else 367 osep = '\t'; /* default is ^I */ 368 break; 369 case 'w': /* window width, default 80 */ 370 p = getnum(&owidth, p, 0); 371 if (owidth <= 0) 372 error("Width must be a positive integer", ""); 373 break; 374 case 'K': /* skip N lines */ 375 flags |= SKIPPRINT; 376 case 'k': /* skip, do not print */ 377 p = getnum(&skip, p, 0); 378 if (!skip) 379 skip = 1; 380 break; 381 case 'm': 382 flags |= NOTRIMENDCOL; 383 break; 384 case 'g': /* gutter space */ 385 p = getnum(&gutter, p, 0); 386 break; 387 case 'G': 388 p = getnum(&propgutter, p, 0); 389 break; 390 case 'e': /* each line is an entry */ 391 flags |= ONEPERLINE; 392 break; 393 case 'E': 394 flags |= ONEPERCHAR; 395 break; 396 case 'j': /* right adjust */ 397 flags |= RIGHTADJUST; 398 break; 399 case 'n': /* null padding for missing values */ 400 flags |= NULLPAD; 401 break; 402 case 'y': 403 flags |= RECYCLE; 404 break; 405 case 'H': /* print shape only */ 406 flags |= DETAILSHAPE; 407 case 'h': 408 flags |= SHAPEONLY; 409 break; 410 case 'z': /* squeeze col width */ 411 flags |= SQUEEZE; 412 break; 413 /*case 'p': 414 ipagespace = atoi(++p); (default is 1) 415 break;*/ 416 case 'o': /* col order */ 417 p = getlist(&cord, p); 418 break; 419 case 'b': 420 flags |= ICOLBOUNDS; 421 p = getlist(&icbd, p); 422 break; 423 case 'B': 424 flags |= OCOLBOUNDS; 425 p = getlist(&ocbd, p); 426 break; 427 default: 428 error("Bad flag: %.1s", p); 429 } 430 /*if (!osep) 431 osep = isep;*/ 432 switch (ac) { 433 /*case 3: 434 opages = atoi(av[2]);*/ 435 case 2: 436 ocols = atoi(av[1]); 437 case 1: 438 orows = atoi(av[0]); 439 case 0: 440 break; 441 default: 442 error("Too many arguments. What do you mean by `%s'?", av[3]); 443 } 444 } 445 446 char * 447 getlist(list, p) 448 short **list; 449 char *p; 450 { 451 register char *t; 452 register int count = 1; 453 454 for (t = p + 1; *t; t++) { 455 if (!isdigit(*t)) 456 error("Option %.1s requires a list of unsigned numbers separated by commas", t); 457 count++; 458 while (*t && isdigit(*t)) 459 t++; 460 if (*t != ',') 461 break; 462 } 463 if (!(*list = (short *) malloc(count * sizeof(short)))) 464 error("No list space", ""); 465 count = 0; 466 for (t = p + 1; *t; t++) { 467 (*list)[count++] = atoi(t); 468 printf("++ %d ", (*list)[count-1]); 469 fflush(stdout); 470 while (*t && isdigit(*t)) 471 t++; 472 if (*t != ',') 473 break; 474 } 475 (*list)[count] = 0; 476 return(t - 1); 477 } 478 479 char * 480 getnum(num, p, strict) /* num = number p points to; if (strict) complain */ 481 int *num; /* returns pointer to end of num */ 482 char *p; 483 int strict; 484 { 485 register char *t = p; 486 487 if (!isdigit(*++t)) { 488 if (strict || *t == '-' || *t == '+') 489 error("Option %.1s requires an unsigned integer", p); 490 *num = 0; 491 return(p); 492 } 493 *num = atoi(t); 494 while (*++t) 495 if (!isdigit(*t)) 496 break; 497 return(--t); 498 } 499