1: /* Copyright (c) 1983 Regents of the University of California */ 2: 3: #ifndef lint 4: static char sccsid[] = "@(#)rs.c 4.3 (Berkeley) 4/5/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: }