xref: /csrg-svn/usr.bin/rs/rs.c (revision 16036)
113852Ssam /* Copyright (c) 1983 Regents of the University of California */
213852Ssam 
313852Ssam #ifndef lint
4*16036Sjak static char sccsid[] = "@(#)rs.c	4.2	(Berkeley)	02/11/84";
513852Ssam #endif not lint
613852Ssam 
713852Ssam /*
813852Ssam  *	rs - reshape a data array
913852Ssam  *	Author:  John Kunze, Office of Comp. Affairs, UCB
1013852Ssam  *		BEWARE: lots of unfinished edges
1113852Ssam  */
1213852Ssam 
1313852Ssam #include <stdio.h>
1413852Ssam #include <ctype.h>
1513852Ssam 
1613852Ssam long	flags;
1713852Ssam #define	TRANSPOSE	000001
1813852Ssam #define	MTRANSPOSE	000002
1913852Ssam #define	ONEPERLINE	000004
2013852Ssam #define	ONEISEPONLY	000010
2113852Ssam #define	ONEOSEPONLY	000020
2213852Ssam #define	NOTRIMENDCOL	000040
2313852Ssam #define	SQUEEZE		000100
2413852Ssam #define	SHAPEONLY	000200
2513852Ssam #define	DETAILSHAPE	000400
2613852Ssam #define	RIGHTADJUST	001000
2713852Ssam #define	NULLPAD		002000
2813852Ssam #define	RECYCLE		004000
2913852Ssam #define	SKIPPRINT	010000
3013852Ssam #define	ICOLBOUNDS	020000
3113852Ssam #define	OCOLBOUNDS	040000
3213852Ssam #define ONEPERCHAR	0100000
33*16036Sjak #define NOARGS		0200000
3413852Ssam 
3513852Ssam char	buf[BUFSIZ];
3613852Ssam short	*colwidths;
3713852Ssam short	*cord;
3813852Ssam short	*icbd;
3913852Ssam short	*ocbd;
4013852Ssam int	nelem;
4113852Ssam char	**elem;
4213852Ssam char	**endelem;
4313852Ssam char	*curline;
4413852Ssam int	allocsize = BUFSIZ;
4513852Ssam int	curlen;
4613852Ssam int	irows, icols;
4713852Ssam int	orows, ocols;
4813852Ssam int	maxlen;
4913852Ssam int	skip;
5013852Ssam int	propgutter;
5113852Ssam char	isep = ' ', osep = ' ';
5213852Ssam int	owidth = 80, gutter = 2;
5313852Ssam 
5413852Ssam char	**getptrs();
5513852Ssam 
5613852Ssam main(argc, argv)
5713852Ssam int	argc;
5813852Ssam char	**argv;
5913852Ssam {
6013852Ssam 	setbuf(stdout, buf);
6113852Ssam 	getargs(argc, argv);
6213852Ssam 	getfile();
6313852Ssam 	if (flags & SHAPEONLY) {
6413852Ssam 		printf("%d %d\n", irows, icols);
6513852Ssam 		exit(0);
6613852Ssam 	}
6713852Ssam 	prepfile();
6813852Ssam 	/*fprintf(stderr, "#irows %d icols %d orows %d ocols %d\n",irows,icols,orows,ocols);*/
6913852Ssam 	putfile();
7013852Ssam }
7113852Ssam 
7213852Ssam getfile()
7313852Ssam {
7413852Ssam 	register char	*p;
7513852Ssam 	register char	*endp;
7613852Ssam 	register char	**ep = 0;
7713852Ssam 	int	multisep = (flags & ONEISEPONLY ? 0 : 1);
7813852Ssam 	int	nullpad = flags & NULLPAD;
7913852Ssam 	char	**padto;
8013852Ssam 
8113852Ssam 	while (skip--) {
8213852Ssam 		getline();
8313852Ssam 		if (flags & SKIPPRINT)
8413852Ssam 			puts(curline);
8513852Ssam 	}
8613852Ssam 	getline();
87*16036Sjak 	if (flags & NOARGS && curlen < owidth)
88*16036Sjak 		flags |= ONEPERLINE;
8913852Ssam 	if (flags & ONEPERLINE)
9013852Ssam 		icols = 1;
9113852Ssam 	else				/* count cols on first line */
9213852Ssam 		for (p = curline, endp = curline + curlen; p < endp; p++) {
9313852Ssam 			if (*p == isep && multisep)
9413852Ssam 				continue;
9513852Ssam 			icols++;
9613852Ssam 			while (*p && *p != isep)
9713852Ssam 				p++;
9813852Ssam 		}
9913852Ssam 	ep = getptrs(elem);
10013852Ssam 	p = curline;
10113852Ssam 	do {
10213852Ssam 		if (flags & ONEPERLINE) {
10313852Ssam 			*ep++ = curline;
10413852Ssam 			if (maxlen < curlen)
10513852Ssam 				maxlen = curlen;
10613852Ssam 			irows++;
10713852Ssam 			continue;
10813852Ssam 		}
10913852Ssam 		for (p = curline, endp = curline + curlen; p < endp; p++) {
11013852Ssam 			if (*p == isep && multisep)
11113852Ssam 				continue;	/* eat up column separators */
11213852Ssam 			if (*p == isep)		/* must be an empty column */
11313852Ssam 				*ep = "";
11413852Ssam 			else			/* store column entry */
11513852Ssam 				*ep = p;
11613852Ssam 			while (p < endp && *p != isep)
11713852Ssam 				p++;		/* find end of entry */
11813852Ssam 			*p = '\0';		/* mark end of entry */
11913852Ssam 			if (maxlen < p - *ep)	/* update maxlen */
12013852Ssam 				maxlen = p - *ep;
12113852Ssam 			ep++;			/* prepare for next entry */
12213852Ssam 		}
12313852Ssam 		irows++;			/* update row count */
12413852Ssam 		if (nullpad) {			/* pad missing entries */
12513852Ssam 			padto = elem + irows * icols;
12613852Ssam 			while  (ep < padto)
12713852Ssam 				*ep++ = "";
12813852Ssam 		}
12913852Ssam 	if (ep > endelem)			/* if low on pointers */
13013852Ssam 		ep = getptrs(ep);		/* get some more */
13113852Ssam 	} while (getline() != EOF);
13213852Ssam 	*ep = 0;				/* mark end of pointers */
13313852Ssam 	nelem = ep - elem;
13413852Ssam }
13513852Ssam 
13613852Ssam putfile()
13713852Ssam {
13813852Ssam 	register char	**ep;
13913852Ssam 	register int	i;
14013852Ssam 	register int	j;
14113852Ssam 
14213852Ssam 	ep = elem;
14313852Ssam 	if (flags & TRANSPOSE)
14413852Ssam 		for (i = 0; i < orows; i++) {
14513852Ssam 			for (j = i; j < nelem; j += orows)
14613852Ssam 				prints(ep[j], (j - i) / orows);
14713852Ssam 			putchar('\n');
14813852Ssam 		}
14913852Ssam 	else
15013852Ssam 		for (i = 0; i < orows; i++) {
15113852Ssam 			for (j = 0; j < ocols; j++)
15213852Ssam 				prints(*ep++, j);
15313852Ssam 			putchar('\n');
15413852Ssam 		}
15513852Ssam }
15613852Ssam 
15713852Ssam prints(s, col)
15813852Ssam char	*s;
15913852Ssam int	col;
16013852Ssam {
16113852Ssam 	register char	*p = s;
16213852Ssam 	register int	n;
16313852Ssam 
16413852Ssam 	while (*p)
16513852Ssam 		p++;
16613852Ssam 	n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
16713852Ssam 	if (flags & RIGHTADJUST)
16813852Ssam 		while (n-- > 0)
16913852Ssam 			putchar(osep);
17013852Ssam 	for (p = s; *p; p++)
17113852Ssam 		putchar(*p);
17213852Ssam 	while (n-- > 0)
17313852Ssam 		putchar(osep);
17413852Ssam }
17513852Ssam 
17613852Ssam error(msg, s)
17713852Ssam char	*msg;
17813852Ssam char	*s;
17913852Ssam {
18013852Ssam 	fprintf(stderr, "rs:  ");
18113852Ssam 	fprintf(stderr, msg, s);
18213852Ssam 	fprintf(stderr, "\nUsage:  rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n");
18313852Ssam 	exit(1);
18413852Ssam }
18513852Ssam 
18613852Ssam prepfile()
18713852Ssam {
18813852Ssam 	register char	**ep;
18913852Ssam 	register int 	i;
19013852Ssam 	register int 	j;
19113852Ssam 	char	**lp;
19213852Ssam 	int	colw;
19313852Ssam 	int	max = 0;
19413852Ssam 	int	n;
19513852Ssam 
19613852Ssam 	if (!nelem)
19713852Ssam 		exit(0);
19813852Ssam 	gutter += maxlen * propgutter / 100.0;
19913852Ssam 	colw = maxlen + gutter;
20013852Ssam 	if (flags & MTRANSPOSE) {
20113852Ssam 		orows = icols;
20213852Ssam 		ocols = irows;
20313852Ssam 	}
20413852Ssam 	else if (orows == 0 && ocols == 0) {	/* decide rows and cols */
205*16036Sjak 		ocols = owidth / colw;
206*16036Sjak 		if (ocols == 0)
207*16036Sjak 			fprintf(stderr, "Display width %d is less than column width %d\n", owidth, colw);
20813852Ssam 		if (ocols > nelem)
20913852Ssam 			ocols = nelem;
21013852Ssam 		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
21113852Ssam 	}
21213852Ssam 	else if (orows == 0)			/* decide on rows */
21313852Ssam 		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
21413852Ssam 	else if (ocols == 0)			/* decide on cols */
21513852Ssam 		ocols = nelem / orows + (nelem % orows ? 1 : 0);
21613852Ssam 	lp = elem + orows * ocols;
21713852Ssam 	while (lp > endelem) {
21813852Ssam 		getptrs(elem + nelem);
21913852Ssam 		lp = elem + orows * ocols;
22013852Ssam 	}
22113852Ssam 	if (flags & RECYCLE) {
22213852Ssam 		for (ep = elem + nelem; ep < lp; ep++)
22313852Ssam 			*ep = *(ep - nelem);
22413852Ssam 		nelem = lp - elem;
22513852Ssam 	}
22613852Ssam 	if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
22713852Ssam 		error("malloc:  No gutter space", "");
22813852Ssam 	if (flags & SQUEEZE) {
22913852Ssam 		if (flags & TRANSPOSE)
23013852Ssam 			for (ep = elem, i = 0; i < ocols; i++) {
23113852Ssam 				for (j = 0; j < orows; j++)
23213852Ssam 					if ((n = strlen(*ep++)) > max)
23313852Ssam 						max = n;
23413852Ssam 				colwidths[i] = max + gutter;
23513852Ssam 			}
23613852Ssam 		else
23713852Ssam 			for (i = 0; i < ocols; i++) {
23813852Ssam 				for (j = i; j < nelem; j += ocols)
23913852Ssam 					if ((n = strlen(ep[j])) > max)
24013852Ssam 						max = n;
24113852Ssam 				colwidths[i] = max + gutter;
24213852Ssam 			}
24313852Ssam 	}
24413852Ssam 	/*	for (i = 0; i < orows; i++) {
24513852Ssam 			for (j = i; j < nelem; j += orows)
24613852Ssam 				prints(ep[j], (j - i) / orows);
24713852Ssam 			putchar('\n');
24813852Ssam 		}
24913852Ssam 	else
25013852Ssam 		for (i = 0; i < orows; i++) {
25113852Ssam 			for (j = 0; j < ocols; j++)
25213852Ssam 				prints(*ep++, j);
25313852Ssam 			putchar('\n');
25413852Ssam 		}*/
25513852Ssam 	else
25613852Ssam 		for (i = 0; i < ocols; i++)
25713852Ssam 			colwidths[i] = colw;
25813852Ssam 	if (!(flags & NOTRIMENDCOL)) {
25913852Ssam 		if (flags & RIGHTADJUST)
26013852Ssam 			colwidths[0] -= gutter;
26113852Ssam 		else
26213852Ssam 			colwidths[ocols - 1] = 0;
26313852Ssam 	}
26413852Ssam 	n = orows * ocols;
26513852Ssam 	if (n > nelem && (flags & RECYCLE))
26613852Ssam 		nelem = n;
26713852Ssam 	/*for (i = 0; i < ocols; i++)
26813852Ssam 		fprintf(stderr, "%d ",colwidths[i]);
26913852Ssam 	fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/
27013852Ssam }
27113852Ssam 
27213852Ssam #define	BSIZE	2048
27313852Ssam char	ibuf[BSIZE];		/* two screenfuls should do */
27413852Ssam 
27513852Ssam getline()	/* get line; maintain curline, curlen; manage storage */
27613852Ssam {
27713852Ssam 	register char	*p;
27813852Ssam 	register int	c;
27913852Ssam 	register int	i;
28013852Ssam 	static	int	putlength;
28113852Ssam 	static	char	*endblock = ibuf + BSIZE;
28213852Ssam 
28313852Ssam 	if (!irows) {
28413852Ssam 		curline = ibuf;
28513852Ssam 		putlength = flags & DETAILSHAPE;
28613852Ssam 	}
28713852Ssam 	else if (skip <= 0) {			/* don't waste storage */
28813852Ssam 		curline += curlen + 1;
28913852Ssam 		if (putlength)		/* print length, recycle storage */
29013852Ssam 			printf(" %d line %d\n", curlen, irows);
29113852Ssam 	}
29213852Ssam 	if (!putlength && endblock - curline < BUFSIZ) {   /* need storage */
29313852Ssam 		/*ww = endblock-curline; tt += ww;*/
29413852Ssam 		/*printf("#wasted %d total %d\n",ww,tt);*/
29513852Ssam 		if (!(curline = (char *) malloc(BSIZE)))
29613852Ssam 			error("File too large", "");
29713852Ssam 		endblock = curline + BSIZE;
29813852Ssam 		/*printf("#endb %d curline %d\n",endblock,curline);*/
29913852Ssam 	}
30013852Ssam 	for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
30113852Ssam 		if ((c = getchar()) == EOF || c == '\n')
30213852Ssam 			break;
30313852Ssam 	*p = '\0';
30413852Ssam 	curlen = i - 1;
30513852Ssam 	return(c);
30613852Ssam }
30713852Ssam 
30813852Ssam char	**
30913852Ssam getptrs(sp)
31013852Ssam char	**sp;
31113852Ssam {
31213852Ssam 	register char	**p;
31313852Ssam 	register char	**ep;
31413852Ssam 
31513852Ssam 	for (;;) {
31613852Ssam 		allocsize += allocsize;
31713852Ssam 		if (!(p = (char **) malloc(allocsize * sizeof(char *)))) {
31813852Ssam 			perror("rs");
31913852Ssam 			exit(1);
32013852Ssam 		}
32113852Ssam 		if ((endelem = p + allocsize - icols) <= p) {
32213852Ssam 			free(p);
32313852Ssam 			continue;
32413852Ssam 		}
32513852Ssam 		if (elem != 0)
32613852Ssam 			free(elem);
32713852Ssam 		ep = elem;
32813852Ssam 		elem = p;
32913852Ssam 		while (ep < sp)
33013852Ssam 			*p++ = *ep++;
33113852Ssam 		return(p);
33213852Ssam 	}
33313852Ssam }
33413852Ssam 
33513852Ssam getargs(ac, av)
33613852Ssam int	ac;
33713852Ssam char	**av;
33813852Ssam {
33913852Ssam 	register char	*p;
34013852Ssam 	char	*getnum(), *getlist();
34113852Ssam 
34213852Ssam 	if (ac == 1) {
343*16036Sjak 		flags |= NOARGS | TRANSPOSE;
34413852Ssam 	}
34513852Ssam 	while (--ac && **++av == '-')
34613852Ssam 		for (p = *av+1; *p; p++)
34713852Ssam 			switch (*p) {
34813852Ssam 			case 'T':
34913852Ssam 				flags |= MTRANSPOSE;
35013852Ssam 			case 't':
35113852Ssam 				flags |= TRANSPOSE;
35213852Ssam 				break;
35313852Ssam 			case 'c':		/* input col. separator */
35413852Ssam 				flags |= ONEISEPONLY;
35513852Ssam 			case 's':		/* one or more allowed */
35613852Ssam 				if (p[1])
35713852Ssam 					isep = *++p;
35813852Ssam 				else
35913852Ssam 					isep = '\t';	/* default is ^I */
36013852Ssam 				break;
36113852Ssam 			case 'C':
36213852Ssam 				flags |= ONEOSEPONLY;
36313852Ssam 			case 'S':
36413852Ssam 				if (p[1])
36513852Ssam 					osep = *++p;
36613852Ssam 				else
36713852Ssam 					osep = '\t';	/* default is ^I */
36813852Ssam 				break;
36913852Ssam 			case 'w':		/* window width, default 80 */
37013852Ssam 				p = getnum(&owidth, p, 0);
37113852Ssam 				if (owidth <= 0)
37213852Ssam 					error("Width must be a positive integer", "");
37313852Ssam 				break;
37413852Ssam 			case 'K':			/* skip N lines */
37513852Ssam 				flags |= SKIPPRINT;
37613852Ssam 			case 'k':			/* skip, do not print */
37713852Ssam 				p = getnum(&skip, p, 0);
37813852Ssam 				if (!skip)
37913852Ssam 					skip = 1;
38013852Ssam 				break;
38113852Ssam 			case 'm':
38213852Ssam 				flags |= NOTRIMENDCOL;
38313852Ssam 				break;
38413852Ssam 			case 'g':		/* gutter space */
38513852Ssam 				p = getnum(&gutter, p, 0);
38613852Ssam 				break;
38713852Ssam 			case 'G':
38813852Ssam 				p = getnum(&propgutter, p, 0);
38913852Ssam 				break;
39013852Ssam 			case 'e':		/* each line is an entry */
39113852Ssam 				flags |= ONEPERLINE;
39213852Ssam 				break;
39313852Ssam 			case 'E':
39413852Ssam 				flags |= ONEPERCHAR;
39513852Ssam 				break;
39613852Ssam 			case 'j':			/* right adjust */
39713852Ssam 				flags |= RIGHTADJUST;
39813852Ssam 				break;
39913852Ssam 			case 'n':	/* null padding for missing values */
40013852Ssam 				flags |= NULLPAD;
40113852Ssam 				break;
40213852Ssam 			case 'y':
40313852Ssam 				flags |= RECYCLE;
40413852Ssam 				break;
40513852Ssam 			case 'H':			/* print shape only */
40613852Ssam 				flags |= DETAILSHAPE;
40713852Ssam 			case 'h':
40813852Ssam 				flags |= SHAPEONLY;
40913852Ssam 				break;
41013852Ssam 			case 'z':			/* squeeze col width */
41113852Ssam 				flags |= SQUEEZE;
41213852Ssam 				break;
41313852Ssam 			/*case 'p':
41413852Ssam 				ipagespace = atoi(++p);	(default is 1)
41513852Ssam 				break;*/
41613852Ssam 			case 'o':			/* col order */
41713852Ssam 				p = getlist(&cord, p);
41813852Ssam 				break;
41913852Ssam 			case 'b':
42013852Ssam 				flags |= ICOLBOUNDS;
42113852Ssam 				p = getlist(&icbd, p);
42213852Ssam 				break;
42313852Ssam 			case 'B':
42413852Ssam 				flags |= OCOLBOUNDS;
42513852Ssam 				p = getlist(&ocbd, p);
42613852Ssam 				break;
42713852Ssam 			default:
42813852Ssam 				error("Bad flag:  %.1s", p);
42913852Ssam 			}
43013852Ssam 	/*if (!osep)
43113852Ssam 		osep = isep;*/
43213852Ssam 	switch (ac) {
43313852Ssam 	/*case 3:
43413852Ssam 		opages = atoi(av[2]);*/
43513852Ssam 	case 2:
43613852Ssam 		ocols = atoi(av[1]);
43713852Ssam 	case 1:
43813852Ssam 		orows = atoi(av[0]);
43913852Ssam 	case 0:
44013852Ssam 		break;
44113852Ssam 	default:
44213852Ssam 		error("Too many arguments.  What do you mean by `%s'?", av[3]);
44313852Ssam 	}
44413852Ssam }
44513852Ssam 
44613852Ssam char	*
44713852Ssam getlist(list, p)
44813852Ssam short	**list;
44913852Ssam char	*p;
45013852Ssam {
45113852Ssam 	register char	*t;
45213852Ssam 	register int	count = 1;
45313852Ssam 
45413852Ssam 	for (t = p + 1; *t; t++) {
45513852Ssam 		if (!isdigit(*t))
45613852Ssam 			error("Option %.1s requires a list of unsigned numbers separated by commas", t);
45713852Ssam 		count++;
45813852Ssam 		while (*t && isdigit(*t))
45913852Ssam 			t++;
46013852Ssam 		if (*t != ',')
46113852Ssam 			break;
46213852Ssam 	}
46313852Ssam 	if (!(*list = (short *) malloc(count * sizeof(short))))
46413852Ssam 		error("No list space", "");
46513852Ssam 	count = 0;
46613852Ssam 	for (t = p + 1; *t; t++) {
46713852Ssam 		(*list)[count++] = atoi(t);
46813852Ssam 		printf("++ %d ", (*list)[count-1]);
46913852Ssam 		fflush(stdout);
47013852Ssam 		while (*t && isdigit(*t))
47113852Ssam 			t++;
47213852Ssam 		if (*t != ',')
47313852Ssam 			break;
47413852Ssam 	}
47513852Ssam 	(*list)[count] = 0;
47613852Ssam 	return(t - 1);
47713852Ssam }
47813852Ssam 
47913852Ssam char	*
48013852Ssam getnum(num, p, strict)	/* num = number p points to; if (strict) complain */
48113852Ssam int	*num;				/* returns pointer to end of num */
48213852Ssam char	*p;
48313852Ssam int	strict;
48413852Ssam {
48513852Ssam 	register char	*t = p;
48613852Ssam 
48713852Ssam 	if (!isdigit(*++t)) {
48813852Ssam 		if (strict || *t == '-' || *t == '+')
48913852Ssam 			error("Option %.1s requires an unsigned integer", p);
49013852Ssam 		*num = 0;
49113852Ssam 		return(p);
49213852Ssam 	}
49313852Ssam 	*num = atoi(t);
49413852Ssam 	while (*++t)
49513852Ssam 		if (!isdigit(*t))
49613852Ssam 			break;
49713852Ssam 	return(--t);
49813852Ssam }
499