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