1*60484Sbostic /*- 2*60484Sbostic * Copyright (c) 1993 The Regents of the University of California. 3*60484Sbostic * All rights reserved. 4*60484Sbostic * 5*60484Sbostic * %sccs.include.redist.c% 6*60484Sbostic */ 713852Ssam 813852Ssam #ifndef lint 9*60484Sbostic char copyright[] = 10*60484Sbostic "@(#) Copyright (c) 1993 The Regents of the University of California.\n\ 11*60484Sbostic All rights reserved.\n"; 12*60484Sbostic #endif /* not lint */ 1313852Ssam 14*60484Sbostic #ifndef lint 15*60484Sbostic static char sccsid[] = "@(#)rs.c 4.4 (Berkeley) 05/26/93"; 16*60484Sbostic #endif /* not lint */ 17*60484Sbostic 1813852Ssam /* 1913852Ssam * rs - reshape a data array 2013852Ssam * Author: John Kunze, Office of Comp. Affairs, UCB 2113852Ssam * BEWARE: lots of unfinished edges 2213852Ssam */ 2313852Ssam 24*60484Sbostic #include <ctype.h> 2513852Ssam #include <stdio.h> 26*60484Sbostic #include <stdlib.h> 2713852Ssam 2813852Ssam long flags; 2913852Ssam #define TRANSPOSE 000001 3013852Ssam #define MTRANSPOSE 000002 3113852Ssam #define ONEPERLINE 000004 3213852Ssam #define ONEISEPONLY 000010 3313852Ssam #define ONEOSEPONLY 000020 3413852Ssam #define NOTRIMENDCOL 000040 3513852Ssam #define SQUEEZE 000100 3613852Ssam #define SHAPEONLY 000200 3713852Ssam #define DETAILSHAPE 000400 3813852Ssam #define RIGHTADJUST 001000 3913852Ssam #define NULLPAD 002000 4013852Ssam #define RECYCLE 004000 4113852Ssam #define SKIPPRINT 010000 4213852Ssam #define ICOLBOUNDS 020000 4313852Ssam #define OCOLBOUNDS 040000 4413852Ssam #define ONEPERCHAR 0100000 4516036Sjak #define NOARGS 0200000 4613852Ssam 4713852Ssam short *colwidths; 4813852Ssam short *cord; 4913852Ssam short *icbd; 5013852Ssam short *ocbd; 5113852Ssam int nelem; 5213852Ssam char **elem; 5313852Ssam char **endelem; 5413852Ssam char *curline; 5513852Ssam int allocsize = BUFSIZ; 5613852Ssam int curlen; 5713852Ssam int irows, icols; 5813852Ssam int orows, ocols; 5913852Ssam int maxlen; 6013852Ssam int skip; 6113852Ssam int propgutter; 6213852Ssam char isep = ' ', osep = ' '; 6313852Ssam int owidth = 80, gutter = 2; 6413852Ssam 65*60484Sbostic void error __P((char *, char *)); 66*60484Sbostic void getargs __P((int, char *[])); 67*60484Sbostic void getfile __P((void)); 68*60484Sbostic int getline __P((void)); 69*60484Sbostic char *getlist __P((short **, char *)); 70*60484Sbostic char *getnum __P((int *, char *, int)); 71*60484Sbostic char **getptrs __P((char **)); 72*60484Sbostic void prepfile __P((void)); 73*60484Sbostic void prints __P((char *, int)); 74*60484Sbostic void putfile __P((void)); 7513852Ssam 76*60484Sbostic int 7713852Ssam main(argc, argv) 78*60484Sbostic int argc; 79*60484Sbostic char *argv[]; 8013852Ssam { 8113852Ssam getargs(argc, argv); 8213852Ssam getfile(); 8313852Ssam if (flags & SHAPEONLY) { 8413852Ssam printf("%d %d\n", irows, icols); 8513852Ssam exit(0); 8613852Ssam } 8713852Ssam prepfile(); 8813852Ssam putfile(); 8927015Slepreau exit(0); 9013852Ssam } 9113852Ssam 92*60484Sbostic void 9313852Ssam getfile() 9413852Ssam { 95*60484Sbostic register char *p; 96*60484Sbostic register char *endp; 97*60484Sbostic register char **ep = 0; 98*60484Sbostic int multisep = (flags & ONEISEPONLY ? 0 : 1); 99*60484Sbostic int nullpad = flags & NULLPAD; 100*60484Sbostic char **padto; 10113852Ssam 10213852Ssam while (skip--) { 10313852Ssam getline(); 10413852Ssam if (flags & SKIPPRINT) 10513852Ssam puts(curline); 10613852Ssam } 10713852Ssam getline(); 10816036Sjak if (flags & NOARGS && curlen < owidth) 10916036Sjak flags |= ONEPERLINE; 11013852Ssam if (flags & ONEPERLINE) 11113852Ssam icols = 1; 11213852Ssam else /* count cols on first line */ 11313852Ssam for (p = curline, endp = curline + curlen; p < endp; p++) { 11413852Ssam if (*p == isep && multisep) 11513852Ssam continue; 11613852Ssam icols++; 11713852Ssam while (*p && *p != isep) 11813852Ssam p++; 11913852Ssam } 12013852Ssam ep = getptrs(elem); 12113852Ssam p = curline; 12213852Ssam do { 12313852Ssam if (flags & ONEPERLINE) { 12413852Ssam *ep++ = curline; 12513852Ssam if (maxlen < curlen) 12613852Ssam maxlen = curlen; 12713852Ssam irows++; 12813852Ssam continue; 12913852Ssam } 13013852Ssam for (p = curline, endp = curline + curlen; p < endp; p++) { 13113852Ssam if (*p == isep && multisep) 13213852Ssam continue; /* eat up column separators */ 13313852Ssam if (*p == isep) /* must be an empty column */ 13413852Ssam *ep = ""; 13513852Ssam else /* store column entry */ 13613852Ssam *ep = p; 13713852Ssam while (p < endp && *p != isep) 13813852Ssam p++; /* find end of entry */ 13913852Ssam *p = '\0'; /* mark end of entry */ 14013852Ssam if (maxlen < p - *ep) /* update maxlen */ 14113852Ssam maxlen = p - *ep; 14213852Ssam ep++; /* prepare for next entry */ 14313852Ssam } 14413852Ssam irows++; /* update row count */ 14513852Ssam if (nullpad) { /* pad missing entries */ 14613852Ssam padto = elem + irows * icols; 14713852Ssam while (ep < padto) 14813852Ssam *ep++ = ""; 14913852Ssam } 15013852Ssam if (ep > endelem) /* if low on pointers */ 15113852Ssam ep = getptrs(ep); /* get some more */ 15213852Ssam } while (getline() != EOF); 15313852Ssam *ep = 0; /* mark end of pointers */ 15413852Ssam nelem = ep - elem; 15513852Ssam } 15613852Ssam 157*60484Sbostic void 15813852Ssam putfile() 15913852Ssam { 160*60484Sbostic register char **ep; 161*60484Sbostic register int i, j; 16213852Ssam 16313852Ssam ep = elem; 16413852Ssam if (flags & TRANSPOSE) 16513852Ssam for (i = 0; i < orows; i++) { 16613852Ssam for (j = i; j < nelem; j += orows) 16713852Ssam prints(ep[j], (j - i) / orows); 16813852Ssam putchar('\n'); 16913852Ssam } 17013852Ssam else 17113852Ssam for (i = 0; i < orows; i++) { 17213852Ssam for (j = 0; j < ocols; j++) 17313852Ssam prints(*ep++, j); 17413852Ssam putchar('\n'); 17513852Ssam } 17613852Ssam } 17713852Ssam 178*60484Sbostic void 17913852Ssam prints(s, col) 180*60484Sbostic char *s; 181*60484Sbostic int col; 18213852Ssam { 183*60484Sbostic register int n; 184*60484Sbostic register char *p = s; 18513852Ssam 18613852Ssam while (*p) 18713852Ssam p++; 18813852Ssam n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s)); 18913852Ssam if (flags & RIGHTADJUST) 19013852Ssam while (n-- > 0) 19113852Ssam putchar(osep); 19213852Ssam for (p = s; *p; p++) 19313852Ssam putchar(*p); 19413852Ssam while (n-- > 0) 19513852Ssam putchar(osep); 19613852Ssam } 19713852Ssam 198*60484Sbostic void 19913852Ssam error(msg, s) 200*60484Sbostic char *msg, *s; 20113852Ssam { 20213852Ssam fprintf(stderr, "rs: "); 20313852Ssam fprintf(stderr, msg, s); 204*60484Sbostic fprintf(stderr, 205*60484Sbostic "\nUsage: rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n"); 20613852Ssam exit(1); 20713852Ssam } 20813852Ssam 209*60484Sbostic void 21013852Ssam prepfile() 21113852Ssam { 212*60484Sbostic register char **ep; 213*60484Sbostic register int i; 214*60484Sbostic register int j; 215*60484Sbostic char **lp; 216*60484Sbostic int colw; 217*60484Sbostic int max = 0; 218*60484Sbostic int n; 21913852Ssam 22013852Ssam if (!nelem) 22113852Ssam exit(0); 22213852Ssam gutter += maxlen * propgutter / 100.0; 22313852Ssam colw = maxlen + gutter; 22413852Ssam if (flags & MTRANSPOSE) { 22513852Ssam orows = icols; 22613852Ssam ocols = irows; 22713852Ssam } 22813852Ssam else if (orows == 0 && ocols == 0) { /* decide rows and cols */ 22916036Sjak ocols = owidth / colw; 23016036Sjak if (ocols == 0) 23116036Sjak fprintf(stderr, "Display width %d is less than column width %d\n", owidth, colw); 23213852Ssam if (ocols > nelem) 23313852Ssam ocols = nelem; 23413852Ssam orows = nelem / ocols + (nelem % ocols ? 1 : 0); 23513852Ssam } 23613852Ssam else if (orows == 0) /* decide on rows */ 23713852Ssam orows = nelem / ocols + (nelem % ocols ? 1 : 0); 23813852Ssam else if (ocols == 0) /* decide on cols */ 23913852Ssam ocols = nelem / orows + (nelem % orows ? 1 : 0); 24013852Ssam lp = elem + orows * ocols; 24113852Ssam while (lp > endelem) { 24213852Ssam getptrs(elem + nelem); 24313852Ssam lp = elem + orows * ocols; 24413852Ssam } 24513852Ssam if (flags & RECYCLE) { 24613852Ssam for (ep = elem + nelem; ep < lp; ep++) 24713852Ssam *ep = *(ep - nelem); 24813852Ssam nelem = lp - elem; 24913852Ssam } 25013852Ssam if (!(colwidths = (short *) malloc(ocols * sizeof(short)))) 25113852Ssam error("malloc: No gutter space", ""); 25213852Ssam if (flags & SQUEEZE) { 25313852Ssam if (flags & TRANSPOSE) 25413852Ssam for (ep = elem, i = 0; i < ocols; i++) { 25513852Ssam for (j = 0; j < orows; j++) 25613852Ssam if ((n = strlen(*ep++)) > max) 25713852Ssam max = n; 25813852Ssam colwidths[i] = max + gutter; 25913852Ssam } 26013852Ssam else 26113852Ssam for (i = 0; i < ocols; i++) { 26213852Ssam for (j = i; j < nelem; j += ocols) 26313852Ssam if ((n = strlen(ep[j])) > max) 26413852Ssam max = n; 26513852Ssam colwidths[i] = max + gutter; 26613852Ssam } 26713852Ssam } 26813852Ssam /* for (i = 0; i < orows; i++) { 26913852Ssam for (j = i; j < nelem; j += orows) 27013852Ssam prints(ep[j], (j - i) / orows); 27113852Ssam putchar('\n'); 27213852Ssam } 27313852Ssam else 27413852Ssam for (i = 0; i < orows; i++) { 27513852Ssam for (j = 0; j < ocols; j++) 27613852Ssam prints(*ep++, j); 27713852Ssam putchar('\n'); 27813852Ssam }*/ 27913852Ssam else 28013852Ssam for (i = 0; i < ocols; i++) 28113852Ssam colwidths[i] = colw; 28213852Ssam if (!(flags & NOTRIMENDCOL)) { 28313852Ssam if (flags & RIGHTADJUST) 28413852Ssam colwidths[0] -= gutter; 28513852Ssam else 28613852Ssam colwidths[ocols - 1] = 0; 28713852Ssam } 28813852Ssam n = orows * ocols; 28913852Ssam if (n > nelem && (flags & RECYCLE)) 29013852Ssam nelem = n; 29113852Ssam /*for (i = 0; i < ocols; i++) 29213852Ssam fprintf(stderr, "%d ",colwidths[i]); 29313852Ssam fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/ 29413852Ssam } 29513852Ssam 29613852Ssam #define BSIZE 2048 29713852Ssam char ibuf[BSIZE]; /* two screenfuls should do */ 29813852Ssam 299*60484Sbostic int 30013852Ssam getline() /* get line; maintain curline, curlen; manage storage */ 30113852Ssam { 302*60484Sbostic static int putlength; 303*60484Sbostic static char *endblock = ibuf + BSIZE; 304*60484Sbostic register char *p; 305*60484Sbostic register int c, i; 30613852Ssam 30713852Ssam if (!irows) { 30813852Ssam curline = ibuf; 30913852Ssam putlength = flags & DETAILSHAPE; 31013852Ssam } 31113852Ssam else if (skip <= 0) { /* don't waste storage */ 31213852Ssam curline += curlen + 1; 31313852Ssam if (putlength) /* print length, recycle storage */ 31413852Ssam printf(" %d line %d\n", curlen, irows); 31513852Ssam } 31613852Ssam if (!putlength && endblock - curline < BUFSIZ) { /* need storage */ 31713852Ssam /*ww = endblock-curline; tt += ww;*/ 31813852Ssam /*printf("#wasted %d total %d\n",ww,tt);*/ 31913852Ssam if (!(curline = (char *) malloc(BSIZE))) 32013852Ssam error("File too large", ""); 32113852Ssam endblock = curline + BSIZE; 32213852Ssam /*printf("#endb %d curline %d\n",endblock,curline);*/ 32313852Ssam } 32413852Ssam for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++) 32513852Ssam if ((c = getchar()) == EOF || c == '\n') 32613852Ssam break; 32713852Ssam *p = '\0'; 32813852Ssam curlen = i - 1; 32913852Ssam return(c); 33013852Ssam } 33113852Ssam 332*60484Sbostic char ** 33313852Ssam getptrs(sp) 334*60484Sbostic char **sp; 33513852Ssam { 336*60484Sbostic register char **p, **ep; 33713852Ssam 33813852Ssam for (;;) { 33913852Ssam allocsize += allocsize; 34013852Ssam if (!(p = (char **) malloc(allocsize * sizeof(char *)))) { 34113852Ssam perror("rs"); 34213852Ssam exit(1); 34313852Ssam } 34413852Ssam if ((endelem = p + allocsize - icols) <= p) { 34513852Ssam free(p); 34613852Ssam continue; 34713852Ssam } 34813852Ssam if (elem != 0) 34913852Ssam free(elem); 35013852Ssam ep = elem; 35113852Ssam elem = p; 35213852Ssam while (ep < sp) 35313852Ssam *p++ = *ep++; 35413852Ssam return(p); 35513852Ssam } 35613852Ssam } 35713852Ssam 358*60484Sbostic void 35913852Ssam getargs(ac, av) 360*60484Sbostic int ac; 361*60484Sbostic char *av[]; 36213852Ssam { 363*60484Sbostic register char *p; 36413852Ssam 36513852Ssam if (ac == 1) { 36616036Sjak flags |= NOARGS | TRANSPOSE; 36713852Ssam } 36813852Ssam while (--ac && **++av == '-') 36913852Ssam for (p = *av+1; *p; p++) 37013852Ssam switch (*p) { 37113852Ssam case 'T': 37213852Ssam flags |= MTRANSPOSE; 37313852Ssam case 't': 37413852Ssam flags |= TRANSPOSE; 37513852Ssam break; 37613852Ssam case 'c': /* input col. separator */ 37713852Ssam flags |= ONEISEPONLY; 37813852Ssam case 's': /* one or more allowed */ 37913852Ssam if (p[1]) 38013852Ssam isep = *++p; 38113852Ssam else 38213852Ssam isep = '\t'; /* default is ^I */ 38313852Ssam break; 38413852Ssam case 'C': 38513852Ssam flags |= ONEOSEPONLY; 38613852Ssam case 'S': 38713852Ssam if (p[1]) 38813852Ssam osep = *++p; 38913852Ssam else 39013852Ssam osep = '\t'; /* default is ^I */ 39113852Ssam break; 39213852Ssam case 'w': /* window width, default 80 */ 39313852Ssam p = getnum(&owidth, p, 0); 39413852Ssam if (owidth <= 0) 395*60484Sbostic error("Width must be a positive integer", ""); 39613852Ssam break; 39713852Ssam case 'K': /* skip N lines */ 39813852Ssam flags |= SKIPPRINT; 39913852Ssam case 'k': /* skip, do not print */ 40013852Ssam p = getnum(&skip, p, 0); 40113852Ssam if (!skip) 40213852Ssam skip = 1; 40313852Ssam break; 40413852Ssam case 'm': 40513852Ssam flags |= NOTRIMENDCOL; 40613852Ssam break; 40713852Ssam case 'g': /* gutter space */ 40813852Ssam p = getnum(&gutter, p, 0); 40913852Ssam break; 41013852Ssam case 'G': 41113852Ssam p = getnum(&propgutter, p, 0); 41213852Ssam break; 41313852Ssam case 'e': /* each line is an entry */ 41413852Ssam flags |= ONEPERLINE; 41513852Ssam break; 41613852Ssam case 'E': 41713852Ssam flags |= ONEPERCHAR; 41813852Ssam break; 41913852Ssam case 'j': /* right adjust */ 42013852Ssam flags |= RIGHTADJUST; 42113852Ssam break; 42213852Ssam case 'n': /* null padding for missing values */ 42313852Ssam flags |= NULLPAD; 42413852Ssam break; 42513852Ssam case 'y': 42613852Ssam flags |= RECYCLE; 42713852Ssam break; 42813852Ssam case 'H': /* print shape only */ 42913852Ssam flags |= DETAILSHAPE; 43013852Ssam case 'h': 43113852Ssam flags |= SHAPEONLY; 43213852Ssam break; 43313852Ssam case 'z': /* squeeze col width */ 43413852Ssam flags |= SQUEEZE; 43513852Ssam break; 43613852Ssam /*case 'p': 43713852Ssam ipagespace = atoi(++p); (default is 1) 43813852Ssam break;*/ 43913852Ssam case 'o': /* col order */ 44013852Ssam p = getlist(&cord, p); 44113852Ssam break; 44213852Ssam case 'b': 44313852Ssam flags |= ICOLBOUNDS; 44413852Ssam p = getlist(&icbd, p); 44513852Ssam break; 44613852Ssam case 'B': 44713852Ssam flags |= OCOLBOUNDS; 44813852Ssam p = getlist(&ocbd, p); 44913852Ssam break; 45013852Ssam default: 45113852Ssam error("Bad flag: %.1s", p); 45213852Ssam } 45313852Ssam /*if (!osep) 45413852Ssam osep = isep;*/ 45513852Ssam switch (ac) { 45613852Ssam /*case 3: 45713852Ssam opages = atoi(av[2]);*/ 45813852Ssam case 2: 45913852Ssam ocols = atoi(av[1]); 46013852Ssam case 1: 46113852Ssam orows = atoi(av[0]); 46213852Ssam case 0: 46313852Ssam break; 46413852Ssam default: 46513852Ssam error("Too many arguments. What do you mean by `%s'?", av[3]); 46613852Ssam } 46713852Ssam } 46813852Ssam 469*60484Sbostic char * 47013852Ssam getlist(list, p) 471*60484Sbostic short **list; 472*60484Sbostic char *p; 47313852Ssam { 474*60484Sbostic register int count = 1; 475*60484Sbostic register char *t; 47613852Ssam 47713852Ssam for (t = p + 1; *t; t++) { 47813852Ssam if (!isdigit(*t)) 47913852Ssam error("Option %.1s requires a list of unsigned numbers separated by commas", t); 48013852Ssam count++; 48113852Ssam while (*t && isdigit(*t)) 48213852Ssam t++; 48313852Ssam if (*t != ',') 48413852Ssam break; 48513852Ssam } 48613852Ssam if (!(*list = (short *) malloc(count * sizeof(short)))) 48713852Ssam error("No list space", ""); 48813852Ssam count = 0; 48913852Ssam for (t = p + 1; *t; t++) { 49013852Ssam (*list)[count++] = atoi(t); 49113852Ssam printf("++ %d ", (*list)[count-1]); 49213852Ssam fflush(stdout); 49313852Ssam while (*t && isdigit(*t)) 49413852Ssam t++; 49513852Ssam if (*t != ',') 49613852Ssam break; 49713852Ssam } 49813852Ssam (*list)[count] = 0; 49913852Ssam return(t - 1); 50013852Ssam } 50113852Ssam 502*60484Sbostic char * 50313852Ssam getnum(num, p, strict) /* num = number p points to; if (strict) complain */ 504*60484Sbostic int *num, strict; /* returns pointer to end of num */ 505*60484Sbostic char *p; 50613852Ssam { 507*60484Sbostic register char *t = p; 50813852Ssam 50913852Ssam if (!isdigit(*++t)) { 51013852Ssam if (strict || *t == '-' || *t == '+') 51113852Ssam error("Option %.1s requires an unsigned integer", p); 51213852Ssam *num = 0; 51313852Ssam return(p); 51413852Ssam } 51513852Ssam *num = atoi(t); 51613852Ssam while (*++t) 51713852Ssam if (!isdigit(*t)) 51813852Ssam break; 51913852Ssam return(--t); 52013852Ssam } 521