160484Sbostic /*-
2*62213Sbostic * Copyright (c) 1993
3*62213Sbostic * The Regents of the University of California. All rights reserved.
460484Sbostic *
560484Sbostic * %sccs.include.redist.c%
660484Sbostic */
713852Ssam
813852Ssam #ifndef lint
9*62213Sbostic static char copyright[] =
10*62213Sbostic "@(#) Copyright (c) 1993\n\
11*62213Sbostic The Regents of the University of California. All rights reserved.\n";
1260484Sbostic #endif /* not lint */
1313852Ssam
1460484Sbostic #ifndef lint
15*62213Sbostic static char sccsid[] = "@(#)rs.c 8.1 (Berkeley) 06/06/93";
1660484Sbostic #endif /* not lint */
1760484Sbostic
1813852Ssam /*
1913852Ssam * rs - reshape a data array
2013852Ssam * Author: John Kunze, Office of Comp. Affairs, UCB
2113852Ssam * BEWARE: lots of unfinished edges
2213852Ssam */
2313852Ssam
2460484Sbostic #include <ctype.h>
2513852Ssam #include <stdio.h>
2660484Sbostic #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
6560484Sbostic void error __P((char *, char *));
6660484Sbostic void getargs __P((int, char *[]));
6760484Sbostic void getfile __P((void));
6860484Sbostic int getline __P((void));
6960484Sbostic char *getlist __P((short **, char *));
7060484Sbostic char *getnum __P((int *, char *, int));
7160484Sbostic char **getptrs __P((char **));
7260484Sbostic void prepfile __P((void));
7360484Sbostic void prints __P((char *, int));
7460484Sbostic void putfile __P((void));
7513852Ssam
7660484Sbostic int
main(argc,argv)7713852Ssam main(argc, argv)
7860484Sbostic int argc;
7960484Sbostic 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
9260484Sbostic void
getfile()9313852Ssam getfile()
9413852Ssam {
9560484Sbostic register char *p;
9660484Sbostic register char *endp;
9760484Sbostic register char **ep = 0;
9860484Sbostic int multisep = (flags & ONEISEPONLY ? 0 : 1);
9960484Sbostic int nullpad = flags & NULLPAD;
10060484Sbostic 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
15760484Sbostic void
putfile()15813852Ssam putfile()
15913852Ssam {
16060484Sbostic register char **ep;
16160484Sbostic 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
17860484Sbostic void
prints(s,col)17913852Ssam prints(s, col)
18060484Sbostic char *s;
18160484Sbostic int col;
18213852Ssam {
18360484Sbostic register int n;
18460484Sbostic 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
19860484Sbostic void
error(msg,s)19913852Ssam error(msg, s)
20060484Sbostic char *msg, *s;
20113852Ssam {
20213852Ssam fprintf(stderr, "rs: ");
20313852Ssam fprintf(stderr, msg, s);
20460484Sbostic fprintf(stderr,
20560484Sbostic "\nUsage: rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n");
20613852Ssam exit(1);
20713852Ssam }
20813852Ssam
20960484Sbostic void
prepfile()21013852Ssam prepfile()
21113852Ssam {
21260484Sbostic register char **ep;
21360484Sbostic register int i;
21460484Sbostic register int j;
21560484Sbostic char **lp;
21660484Sbostic int colw;
21760484Sbostic int max = 0;
21860484Sbostic 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
29960484Sbostic int
getline()30013852Ssam getline() /* get line; maintain curline, curlen; manage storage */
30113852Ssam {
30260484Sbostic static int putlength;
30360484Sbostic static char *endblock = ibuf + BSIZE;
30460484Sbostic register char *p;
30560484Sbostic 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
33260484Sbostic char **
getptrs(sp)33313852Ssam getptrs(sp)
33460484Sbostic char **sp;
33513852Ssam {
33660484Sbostic 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
35860484Sbostic void
getargs(ac,av)35913852Ssam getargs(ac, av)
36060484Sbostic int ac;
36160484Sbostic char *av[];
36213852Ssam {
36360484Sbostic 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)
39560484Sbostic 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
46960484Sbostic char *
getlist(list,p)47013852Ssam getlist(list, p)
47160484Sbostic short **list;
47260484Sbostic char *p;
47313852Ssam {
47460484Sbostic register int count = 1;
47560484Sbostic 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
50260484Sbostic char *
getnum(num,p,strict)50313852Ssam getnum(num, p, strict) /* num = number p points to; if (strict) complain */
50460484Sbostic int *num, strict; /* returns pointer to end of num */
50560484Sbostic char *p;
50613852Ssam {
50760484Sbostic 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