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