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