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