xref: /csrg-svn/usr.bin/rs/rs.c (revision 13852)
1*13852Ssam /* Copyright (c) 1983 Regents of the University of California */
2*13852Ssam 
3*13852Ssam #ifndef lint
4*13852Ssam static char sccsid[] = "@(#)rs.c	4.1	(Berkeley)	07/08/83";
5*13852Ssam #endif not lint
6*13852Ssam 
7*13852Ssam /*
8*13852Ssam  *	rs - reshape a data array
9*13852Ssam  *	Author:  John Kunze, Office of Comp. Affairs, UCB
10*13852Ssam  *		BEWARE: lots of unfinished edges
11*13852Ssam  */
12*13852Ssam 
13*13852Ssam #include <stdio.h>
14*13852Ssam #include <ctype.h>
15*13852Ssam 
16*13852Ssam long	flags;
17*13852Ssam #define	TRANSPOSE	000001
18*13852Ssam #define	MTRANSPOSE	000002
19*13852Ssam #define	ONEPERLINE	000004
20*13852Ssam #define	ONEISEPONLY	000010
21*13852Ssam #define	ONEOSEPONLY	000020
22*13852Ssam #define	NOTRIMENDCOL	000040
23*13852Ssam #define	SQUEEZE		000100
24*13852Ssam #define	SHAPEONLY	000200
25*13852Ssam #define	DETAILSHAPE	000400
26*13852Ssam #define	RIGHTADJUST	001000
27*13852Ssam #define	NULLPAD		002000
28*13852Ssam #define	RECYCLE		004000
29*13852Ssam #define	SKIPPRINT	010000
30*13852Ssam #define	ICOLBOUNDS	020000
31*13852Ssam #define	OCOLBOUNDS	040000
32*13852Ssam #define ONEPERCHAR	0100000
33*13852Ssam 
34*13852Ssam char	buf[BUFSIZ];
35*13852Ssam short	*colwidths;
36*13852Ssam short	*cord;
37*13852Ssam short	*icbd;
38*13852Ssam short	*ocbd;
39*13852Ssam int	nelem;
40*13852Ssam char	**elem;
41*13852Ssam char	**endelem;
42*13852Ssam char	*curline;
43*13852Ssam int	allocsize = BUFSIZ;
44*13852Ssam int	curlen;
45*13852Ssam int	irows, icols;
46*13852Ssam int	orows, ocols;
47*13852Ssam int	maxlen;
48*13852Ssam int	skip;
49*13852Ssam int	propgutter;
50*13852Ssam char	isep = ' ', osep = ' ';
51*13852Ssam int	owidth = 80, gutter = 2;
52*13852Ssam 
53*13852Ssam char	**getptrs();
54*13852Ssam 
55*13852Ssam main(argc, argv)
56*13852Ssam int	argc;
57*13852Ssam char	**argv;
58*13852Ssam {
59*13852Ssam 	setbuf(stdout, buf);
60*13852Ssam 	getargs(argc, argv);
61*13852Ssam 	getfile();
62*13852Ssam 	if (flags & SHAPEONLY) {
63*13852Ssam 		printf("%d %d\n", irows, icols);
64*13852Ssam 		exit(0);
65*13852Ssam 	}
66*13852Ssam 	prepfile();
67*13852Ssam 	/*fprintf(stderr, "#irows %d icols %d orows %d ocols %d\n",irows,icols,orows,ocols);*/
68*13852Ssam 	putfile();
69*13852Ssam }
70*13852Ssam 
71*13852Ssam getfile()
72*13852Ssam {
73*13852Ssam 	register char	*p;
74*13852Ssam 	register char	*endp;
75*13852Ssam 	register char	**ep = 0;
76*13852Ssam 	int	multisep = (flags & ONEISEPONLY ? 0 : 1);
77*13852Ssam 	int	nullpad = flags & NULLPAD;
78*13852Ssam 	char	**padto;
79*13852Ssam 
80*13852Ssam 	while (skip--) {
81*13852Ssam 		getline();
82*13852Ssam 		if (flags & SKIPPRINT)
83*13852Ssam 			puts(curline);
84*13852Ssam 	}
85*13852Ssam 	getline();
86*13852Ssam 	if (flags & ONEPERLINE)
87*13852Ssam 		icols = 1;
88*13852Ssam 	else				/* count cols on first line */
89*13852Ssam 		for (p = curline, endp = curline + curlen; p < endp; p++) {
90*13852Ssam 			if (*p == isep && multisep)
91*13852Ssam 				continue;
92*13852Ssam 			icols++;
93*13852Ssam 			while (*p && *p != isep)
94*13852Ssam 				p++;
95*13852Ssam 		}
96*13852Ssam 	ep = getptrs(elem);
97*13852Ssam 	p = curline;
98*13852Ssam 	do {
99*13852Ssam 		if (flags & ONEPERLINE) {
100*13852Ssam 			*ep++ = curline;
101*13852Ssam 			if (maxlen < curlen)
102*13852Ssam 				maxlen = curlen;
103*13852Ssam 			irows++;
104*13852Ssam 			continue;
105*13852Ssam 		}
106*13852Ssam 		for (p = curline, endp = curline + curlen; p < endp; p++) {
107*13852Ssam 			if (*p == isep && multisep)
108*13852Ssam 				continue;	/* eat up column separators */
109*13852Ssam 			if (*p == isep)		/* must be an empty column */
110*13852Ssam 				*ep = "";
111*13852Ssam 			else			/* store column entry */
112*13852Ssam 				*ep = p;
113*13852Ssam 			while (p < endp && *p != isep)
114*13852Ssam 				p++;		/* find end of entry */
115*13852Ssam 			*p = '\0';		/* mark end of entry */
116*13852Ssam 			if (maxlen < p - *ep)	/* update maxlen */
117*13852Ssam 				maxlen = p - *ep;
118*13852Ssam 			ep++;			/* prepare for next entry */
119*13852Ssam 		}
120*13852Ssam 		irows++;			/* update row count */
121*13852Ssam 		if (nullpad) {			/* pad missing entries */
122*13852Ssam 			padto = elem + irows * icols;
123*13852Ssam 			while  (ep < padto)
124*13852Ssam 				*ep++ = "";
125*13852Ssam 		}
126*13852Ssam 	if (ep > endelem)			/* if low on pointers */
127*13852Ssam 		ep = getptrs(ep);		/* get some more */
128*13852Ssam 	} while (getline() != EOF);
129*13852Ssam 	*ep = 0;				/* mark end of pointers */
130*13852Ssam 	nelem = ep - elem;
131*13852Ssam }
132*13852Ssam 
133*13852Ssam putfile()
134*13852Ssam {
135*13852Ssam 	register char	**ep;
136*13852Ssam 	register int	i;
137*13852Ssam 	register int	j;
138*13852Ssam 
139*13852Ssam 	ep = elem;
140*13852Ssam 	if (flags & TRANSPOSE)
141*13852Ssam 		for (i = 0; i < orows; i++) {
142*13852Ssam 			for (j = i; j < nelem; j += orows)
143*13852Ssam 				prints(ep[j], (j - i) / orows);
144*13852Ssam 			putchar('\n');
145*13852Ssam 		}
146*13852Ssam 	else
147*13852Ssam 		for (i = 0; i < orows; i++) {
148*13852Ssam 			for (j = 0; j < ocols; j++)
149*13852Ssam 				prints(*ep++, j);
150*13852Ssam 			putchar('\n');
151*13852Ssam 		}
152*13852Ssam }
153*13852Ssam 
154*13852Ssam prints(s, col)
155*13852Ssam char	*s;
156*13852Ssam int	col;
157*13852Ssam {
158*13852Ssam 	register char	*p = s;
159*13852Ssam 	register int	n;
160*13852Ssam 
161*13852Ssam 	while (*p)
162*13852Ssam 		p++;
163*13852Ssam 	n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
164*13852Ssam 	if (flags & RIGHTADJUST)
165*13852Ssam 		while (n-- > 0)
166*13852Ssam 			putchar(osep);
167*13852Ssam 	for (p = s; *p; p++)
168*13852Ssam 		putchar(*p);
169*13852Ssam 	while (n-- > 0)
170*13852Ssam 		putchar(osep);
171*13852Ssam }
172*13852Ssam 
173*13852Ssam error(msg, s)
174*13852Ssam char	*msg;
175*13852Ssam char	*s;
176*13852Ssam {
177*13852Ssam 	fprintf(stderr, "rs:  ");
178*13852Ssam 	fprintf(stderr, msg, s);
179*13852Ssam 	fprintf(stderr, "\nUsage:  rs [ -[csCS][x][kKgGw][N]tTeEnyjhHm ] [ rows [ cols ] ]\n");
180*13852Ssam 	exit(1);
181*13852Ssam }
182*13852Ssam 
183*13852Ssam prepfile()
184*13852Ssam {
185*13852Ssam 	register char	**ep;
186*13852Ssam 	register int 	i;
187*13852Ssam 	register int 	j;
188*13852Ssam 	char	**lp;
189*13852Ssam 	int	colw;
190*13852Ssam 	int	max = 0;
191*13852Ssam 	int	n;
192*13852Ssam 
193*13852Ssam 	if (!nelem)
194*13852Ssam 		exit(0);
195*13852Ssam 	gutter += maxlen * propgutter / 100.0;
196*13852Ssam 	colw = maxlen + gutter;
197*13852Ssam 	if (flags & MTRANSPOSE) {
198*13852Ssam 		orows = icols;
199*13852Ssam 		ocols = irows;
200*13852Ssam 	}
201*13852Ssam 	else if (orows == 0 && ocols == 0) {	/* decide rows and cols */
202*13852Ssam 		ocols = owidth / colw;		/* not a good idea */
203*13852Ssam 		if (ocols > nelem)
204*13852Ssam 			ocols = nelem;
205*13852Ssam 		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
206*13852Ssam 	}
207*13852Ssam 	else if (orows == 0)			/* decide on rows */
208*13852Ssam 		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
209*13852Ssam 	else if (ocols == 0)			/* decide on cols */
210*13852Ssam 		ocols = nelem / orows + (nelem % orows ? 1 : 0);
211*13852Ssam 	lp = elem + orows * ocols;
212*13852Ssam 	while (lp > endelem) {
213*13852Ssam 		getptrs(elem + nelem);
214*13852Ssam 		lp = elem + orows * ocols;
215*13852Ssam 	}
216*13852Ssam 	if (flags & RECYCLE) {
217*13852Ssam 		for (ep = elem + nelem; ep < lp; ep++)
218*13852Ssam 			*ep = *(ep - nelem);
219*13852Ssam 		nelem = lp - elem;
220*13852Ssam 	}
221*13852Ssam 	if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
222*13852Ssam 		error("malloc:  No gutter space", "");
223*13852Ssam 	if (flags & SQUEEZE) {
224*13852Ssam 		if (flags & TRANSPOSE)
225*13852Ssam 			for (ep = elem, i = 0; i < ocols; i++) {
226*13852Ssam 				for (j = 0; j < orows; j++)
227*13852Ssam 					if ((n = strlen(*ep++)) > max)
228*13852Ssam 						max = n;
229*13852Ssam 				colwidths[i] = max + gutter;
230*13852Ssam 			}
231*13852Ssam 		else
232*13852Ssam 			for (i = 0; i < ocols; i++) {
233*13852Ssam 				for (j = i; j < nelem; j += ocols)
234*13852Ssam 					if ((n = strlen(ep[j])) > max)
235*13852Ssam 						max = n;
236*13852Ssam 				colwidths[i] = max + gutter;
237*13852Ssam 			}
238*13852Ssam 	}
239*13852Ssam 	/*	for (i = 0; i < orows; i++) {
240*13852Ssam 			for (j = i; j < nelem; j += orows)
241*13852Ssam 				prints(ep[j], (j - i) / orows);
242*13852Ssam 			putchar('\n');
243*13852Ssam 		}
244*13852Ssam 	else
245*13852Ssam 		for (i = 0; i < orows; i++) {
246*13852Ssam 			for (j = 0; j < ocols; j++)
247*13852Ssam 				prints(*ep++, j);
248*13852Ssam 			putchar('\n');
249*13852Ssam 		}*/
250*13852Ssam 	else
251*13852Ssam 		for (i = 0; i < ocols; i++)
252*13852Ssam 			colwidths[i] = colw;
253*13852Ssam 	if (!(flags & NOTRIMENDCOL)) {
254*13852Ssam 		if (flags & RIGHTADJUST)
255*13852Ssam 			colwidths[0] -= gutter;
256*13852Ssam 		else
257*13852Ssam 			colwidths[ocols - 1] = 0;
258*13852Ssam 	}
259*13852Ssam 	n = orows * ocols;
260*13852Ssam 	if (n > nelem && (flags & RECYCLE))
261*13852Ssam 		nelem = n;
262*13852Ssam 	/*for (i = 0; i < ocols; i++)
263*13852Ssam 		fprintf(stderr, "%d ",colwidths[i]);
264*13852Ssam 	fprintf(stderr, "is colwidths, nelem %d\n", nelem);*/
265*13852Ssam }
266*13852Ssam 
267*13852Ssam #define	BSIZE	2048
268*13852Ssam char	ibuf[BSIZE];		/* two screenfuls should do */
269*13852Ssam 
270*13852Ssam getline()	/* get line; maintain curline, curlen; manage storage */
271*13852Ssam {
272*13852Ssam 	register char	*p;
273*13852Ssam 	register int	c;
274*13852Ssam 	register int	i;
275*13852Ssam 	static	int	putlength;
276*13852Ssam 	static	char	*endblock = ibuf + BSIZE;
277*13852Ssam 
278*13852Ssam 	if (!irows) {
279*13852Ssam 		curline = ibuf;
280*13852Ssam 		putlength = flags & DETAILSHAPE;
281*13852Ssam 	}
282*13852Ssam 	else if (skip <= 0) {			/* don't waste storage */
283*13852Ssam 		curline += curlen + 1;
284*13852Ssam 		if (putlength)		/* print length, recycle storage */
285*13852Ssam 			printf(" %d line %d\n", curlen, irows);
286*13852Ssam 	}
287*13852Ssam 	if (!putlength && endblock - curline < BUFSIZ) {   /* need storage */
288*13852Ssam 		/*ww = endblock-curline; tt += ww;*/
289*13852Ssam 		/*printf("#wasted %d total %d\n",ww,tt);*/
290*13852Ssam 		if (!(curline = (char *) malloc(BSIZE)))
291*13852Ssam 			error("File too large", "");
292*13852Ssam 		endblock = curline + BSIZE;
293*13852Ssam 		/*printf("#endb %d curline %d\n",endblock,curline);*/
294*13852Ssam 	}
295*13852Ssam 	for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
296*13852Ssam 		if ((c = getchar()) == EOF || c == '\n')
297*13852Ssam 			break;
298*13852Ssam 	*p = '\0';
299*13852Ssam 	curlen = i - 1;
300*13852Ssam 	return(c);
301*13852Ssam }
302*13852Ssam 
303*13852Ssam char	**
304*13852Ssam getptrs(sp)
305*13852Ssam char	**sp;
306*13852Ssam {
307*13852Ssam 	register char	**p;
308*13852Ssam 	register char	**ep;
309*13852Ssam 
310*13852Ssam 	for (;;) {
311*13852Ssam 		allocsize += allocsize;
312*13852Ssam 		if (!(p = (char **) malloc(allocsize * sizeof(char *)))) {
313*13852Ssam 			perror("rs");
314*13852Ssam 			exit(1);
315*13852Ssam 		}
316*13852Ssam 		if ((endelem = p + allocsize - icols) <= p) {
317*13852Ssam 			free(p);
318*13852Ssam 			continue;
319*13852Ssam 		}
320*13852Ssam 		if (elem != 0)
321*13852Ssam 			free(elem);
322*13852Ssam 		ep = elem;
323*13852Ssam 		elem = p;
324*13852Ssam 		while (ep < sp)
325*13852Ssam 			*p++ = *ep++;
326*13852Ssam 		return(p);
327*13852Ssam 	}
328*13852Ssam }
329*13852Ssam 
330*13852Ssam getargs(ac, av)
331*13852Ssam int	ac;
332*13852Ssam char	**av;
333*13852Ssam {
334*13852Ssam 	register char	*p;
335*13852Ssam 	char	*getnum(), *getlist();
336*13852Ssam 
337*13852Ssam 	if (ac == 1) {
338*13852Ssam 		flags |= ONEPERLINE | TRANSPOSE;
339*13852Ssam 	}
340*13852Ssam 	while (--ac && **++av == '-')
341*13852Ssam 		for (p = *av+1; *p; p++)
342*13852Ssam 			switch (*p) {
343*13852Ssam 			case 'T':
344*13852Ssam 				flags |= MTRANSPOSE;
345*13852Ssam 			case 't':
346*13852Ssam 				flags |= TRANSPOSE;
347*13852Ssam 				break;
348*13852Ssam 			case 'c':		/* input col. separator */
349*13852Ssam 				flags |= ONEISEPONLY;
350*13852Ssam 			case 's':		/* one or more allowed */
351*13852Ssam 				if (p[1])
352*13852Ssam 					isep = *++p;
353*13852Ssam 				else
354*13852Ssam 					isep = '\t';	/* default is ^I */
355*13852Ssam 				break;
356*13852Ssam 			case 'C':
357*13852Ssam 				flags |= ONEOSEPONLY;
358*13852Ssam 			case 'S':
359*13852Ssam 				if (p[1])
360*13852Ssam 					osep = *++p;
361*13852Ssam 				else
362*13852Ssam 					osep = '\t';	/* default is ^I */
363*13852Ssam 				break;
364*13852Ssam 			case 'w':		/* window width, default 80 */
365*13852Ssam 				p = getnum(&owidth, p, 0);
366*13852Ssam 				if (owidth <= 0)
367*13852Ssam 					error("Width must be a positive integer", "");
368*13852Ssam 				break;
369*13852Ssam 			case 'K':			/* skip N lines */
370*13852Ssam 				flags |= SKIPPRINT;
371*13852Ssam 			case 'k':			/* skip, do not print */
372*13852Ssam 				p = getnum(&skip, p, 0);
373*13852Ssam 				if (!skip)
374*13852Ssam 					skip = 1;
375*13852Ssam 				break;
376*13852Ssam 			case 'm':
377*13852Ssam 				flags |= NOTRIMENDCOL;
378*13852Ssam 				break;
379*13852Ssam 			case 'g':		/* gutter space */
380*13852Ssam 				p = getnum(&gutter, p, 0);
381*13852Ssam 				break;
382*13852Ssam 			case 'G':
383*13852Ssam 				p = getnum(&propgutter, p, 0);
384*13852Ssam 				break;
385*13852Ssam 			case 'e':		/* each line is an entry */
386*13852Ssam 				flags |= ONEPERLINE;
387*13852Ssam 				break;
388*13852Ssam 			case 'E':
389*13852Ssam 				flags |= ONEPERCHAR;
390*13852Ssam 				break;
391*13852Ssam 			case 'j':			/* right adjust */
392*13852Ssam 				flags |= RIGHTADJUST;
393*13852Ssam 				break;
394*13852Ssam 			case 'n':	/* null padding for missing values */
395*13852Ssam 				flags |= NULLPAD;
396*13852Ssam 				break;
397*13852Ssam 			case 'y':
398*13852Ssam 				flags |= RECYCLE;
399*13852Ssam 				break;
400*13852Ssam 			case 'H':			/* print shape only */
401*13852Ssam 				flags |= DETAILSHAPE;
402*13852Ssam 			case 'h':
403*13852Ssam 				flags |= SHAPEONLY;
404*13852Ssam 				break;
405*13852Ssam 			case 'z':			/* squeeze col width */
406*13852Ssam 				flags |= SQUEEZE;
407*13852Ssam 				break;
408*13852Ssam 			/*case 'p':
409*13852Ssam 				ipagespace = atoi(++p);	(default is 1)
410*13852Ssam 				break;*/
411*13852Ssam 			case 'o':			/* col order */
412*13852Ssam 				p = getlist(&cord, p);
413*13852Ssam 				break;
414*13852Ssam 			case 'b':
415*13852Ssam 				flags |= ICOLBOUNDS;
416*13852Ssam 				p = getlist(&icbd, p);
417*13852Ssam 				break;
418*13852Ssam 			case 'B':
419*13852Ssam 				flags |= OCOLBOUNDS;
420*13852Ssam 				p = getlist(&ocbd, p);
421*13852Ssam 				break;
422*13852Ssam 			default:
423*13852Ssam 				error("Bad flag:  %.1s", p);
424*13852Ssam 			}
425*13852Ssam 	/*if (!osep)
426*13852Ssam 		osep = isep;*/
427*13852Ssam 	switch (ac) {
428*13852Ssam 	/*case 3:
429*13852Ssam 		opages = atoi(av[2]);*/
430*13852Ssam 	case 2:
431*13852Ssam 		ocols = atoi(av[1]);
432*13852Ssam 	case 1:
433*13852Ssam 		orows = atoi(av[0]);
434*13852Ssam 	case 0:
435*13852Ssam 		break;
436*13852Ssam 	default:
437*13852Ssam 		error("Too many arguments.  What do you mean by `%s'?", av[3]);
438*13852Ssam 	}
439*13852Ssam }
440*13852Ssam 
441*13852Ssam char	*
442*13852Ssam getlist(list, p)
443*13852Ssam short	**list;
444*13852Ssam char	*p;
445*13852Ssam {
446*13852Ssam 	register char	*t;
447*13852Ssam 	register int	count = 1;
448*13852Ssam 
449*13852Ssam 	for (t = p + 1; *t; t++) {
450*13852Ssam 		if (!isdigit(*t))
451*13852Ssam 			error("Option %.1s requires a list of unsigned numbers separated by commas", t);
452*13852Ssam 		count++;
453*13852Ssam 		while (*t && isdigit(*t))
454*13852Ssam 			t++;
455*13852Ssam 		if (*t != ',')
456*13852Ssam 			break;
457*13852Ssam 	}
458*13852Ssam 	if (!(*list = (short *) malloc(count * sizeof(short))))
459*13852Ssam 		error("No list space", "");
460*13852Ssam 	count = 0;
461*13852Ssam 	for (t = p + 1; *t; t++) {
462*13852Ssam 		(*list)[count++] = atoi(t);
463*13852Ssam 		printf("++ %d ", (*list)[count-1]);
464*13852Ssam 		fflush(stdout);
465*13852Ssam 		while (*t && isdigit(*t))
466*13852Ssam 			t++;
467*13852Ssam 		if (*t != ',')
468*13852Ssam 			break;
469*13852Ssam 	}
470*13852Ssam 	(*list)[count] = 0;
471*13852Ssam 	return(t - 1);
472*13852Ssam }
473*13852Ssam 
474*13852Ssam char	*
475*13852Ssam getnum(num, p, strict)	/* num = number p points to; if (strict) complain */
476*13852Ssam int	*num;				/* returns pointer to end of num */
477*13852Ssam char	*p;
478*13852Ssam int	strict;
479*13852Ssam {
480*13852Ssam 	register char	*t = p;
481*13852Ssam 
482*13852Ssam 	if (!isdigit(*++t)) {
483*13852Ssam 		if (strict || *t == '-' || *t == '+')
484*13852Ssam 			error("Option %.1s requires an unsigned integer", p);
485*13852Ssam 		*num = 0;
486*13852Ssam 		return(p);
487*13852Ssam 	}
488*13852Ssam 	*num = atoi(t);
489*13852Ssam 	while (*++t)
490*13852Ssam 		if (!isdigit(*t))
491*13852Ssam 			break;
492*13852Ssam 	return(--t);
493*13852Ssam }
494