xref: /csrg-svn/usr.bin/rs/rs.c (revision 62213)
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