1 /* $OpenBSD: rs.c,v 1.21 2012/03/04 04:05:15 fgsch Exp $ */
5 * The Regents of the University of California. All rights reserved.
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
10 * 1. Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * 2. Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * 3. Neither the name of the University nor the names of its contributors
16 * may be used to endorse or promote products derived from this software
17 * without specific prior written permission.
19 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
33 * rs - reshape a data array
34 * Author: John Kunze, Office of Comp. Affairs, UCB
35 * BEWARE: lots of unfinished edges
49 #define __dead __attribute__((__noreturn__))
53 __RCSID("$MirOS: src/usr.bin/rs/rs.c,v 1.5 2012/03/25 13:47:52 tg Exp $");
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 ONEPERCHAR 0100000
70 #define NOARGS 0200000
77 int allocsize = BUFSIZ;
84 char isep = ' ', osep = ' ';
85 int owidth = 80, gutter = 2;
87 void usage(void) __dead;
88 void getargs(int, char *[]);
91 const char **getptrs(const char **);
93 void prints(const char *, int);
96 #define INCR(ep) do { \
97 if (++ep >= endelem) \
102 main(int argc, char *argv[])
106 if (flags & SHAPEONLY) {
107 printf("%d %d\n", irows, icols);
120 const char **ep = NULL;
121 int multisep = (flags & ONEISEPONLY ? 0 : 1);
122 int nullpad = flags & NULLPAD;
127 if (flags & SKIPPRINT)
131 if (flags & NOARGS && curlen < owidth)
133 if (flags & ONEPERLINE)
135 else /* count cols on first line */
136 for (p = curline, endp = curline + curlen; p < endp; p++) {
137 if (*p == isep && multisep)
140 while (*p && *p != isep)
146 if (flags & ONEPERLINE) {
148 INCR(ep); /* prepare for next entry */
154 for (p = curline, endp = curline + curlen; p < endp; p++) {
155 if (*p == isep && multisep)
156 continue; /* eat up column separators */
157 if (*p == isep) /* must be an empty column */
159 else /* store column entry */
161 while (p < endp && *p != isep)
162 p++; /* find end of entry */
163 *p = '\0'; /* mark end of entry */
164 if (maxlen < p - *ep) /* update maxlen */
166 INCR(ep); /* prepare for next entry */
168 irows++; /* update row count */
169 if (nullpad) { /* pad missing entries */
170 padto = elem + irows * icols;
176 } while (get_line() != EOF);
177 *ep = NULL; /* mark end of pointers */
188 if (flags & TRANSPOSE) {
189 for (i = 0; i < orows; i++) {
190 for (j = i; j < nelem; j += orows)
191 prints(ep[j], (j - i) / orows);
195 for (n = 0, i = 0; i < orows && n < nelem; i++) {
196 for (j = 0; j < ocols; j++) {
207 prints(const char *s, int col)
214 n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
215 if (flags & RIGHTADJUST)
227 extern char *__progname;
230 "usage: %s [-CcSs[x]] [-GgKkw N] [-EeHhjmnTtyz] [rows [cols]]\n",
238 int i, j, colw, max, n;
239 const char **ep, **lp;
243 gutter += maxlen * propgutter / 100.0;
244 colw = maxlen + gutter;
245 if (flags & MTRANSPOSE) {
249 else if (orows == 0 && ocols == 0) { /* decide rows and cols */
250 ocols = owidth / colw;
252 warnx("Display width %d is less than column width %d",
258 orows = nelem / ocols + (nelem % ocols ? 1 : 0);
260 else if (orows == 0) /* decide on rows */
261 orows = nelem / ocols + (nelem % ocols ? 1 : 0);
262 else if (ocols == 0) /* decide on cols */
263 ocols = nelem / orows + (nelem % orows ? 1 : 0);
264 lp = elem + orows * ocols;
265 while (lp > endelem) {
266 getptrs(elem + nelem);
267 lp = elem + orows * ocols;
269 if (flags & RECYCLE) {
270 for (ep = elem + nelem; ep < lp; ep++)
274 if (!(colwidths = (short *) calloc(ocols, sizeof(short))))
275 errx(1, "malloc: No gutter space");
276 if (flags & SQUEEZE) {
277 if (flags & TRANSPOSE)
278 for (ep = elem, i = 0; i < ocols; i++) {
280 for (j = 0; j < orows; j++)
281 if ((n = strlen(*ep++)) > max)
283 colwidths[i] = max + gutter;
286 for (ep = elem, i = 0; i < ocols; i++) {
288 for (j = i; j < nelem; j += ocols)
289 if ((n = strlen(ep[j])) > max)
291 colwidths[i] = max + gutter;
294 for (i = 0; i < ocols; i++)
297 if (!(flags & NOTRIMENDCOL)) {
298 if (flags & RIGHTADJUST)
299 colwidths[0] -= gutter;
301 colwidths[ocols - 1] = 0;
304 if (n > nelem && (flags & RECYCLE))
309 char ibuf[BSIZE]; /* two screenfuls should do */
312 get_line(void) /* get line; maintain curline, curlen; manage storage */
314 static int putlength;
315 static char *endblock = ibuf + BSIZE;
321 putlength = flags & DETAILSHAPE;
323 else if (skip <= 0) { /* don't waste storage */
324 curline += curlen + 1;
325 if (putlength) /* print length, recycle storage */
326 printf(" %d line %d\n", curlen, irows);
328 if (!putlength && endblock - curline < BUFSIZ) { /* need storage */
329 if (!(curline = (char *) malloc(BSIZE)))
330 errx(1, "File too large");
331 endblock = curline + BSIZE;
333 for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
334 if ((c = getchar()) == EOF || c == '\n')
342 getptrs(const char **sp)
347 newsize = allocsize * 2;
348 p = realloc(elem, newsize * sizeof(char *));
356 endelem = elem + allocsize;
361 getargs(int ac, char *av[])
367 flags |= NOARGS | TRANSPOSE;
368 while ((ch = getopt(ac, av, "c::C::s::S::k:K:g:G:w:tTeEnyjhHmz")) != -1) {
376 case 'c': /* input col. separator */
377 flags |= ONEISEPONLY;
379 case 's': /* one or more allowed */
381 isep = '\t'; /* default is ^I */
382 else if (optarg[1] != '\0')
383 usage(); /* single char only */
388 flags |= ONEOSEPONLY;
392 osep = '\t'; /* default is ^I */
393 else if (optarg[1] != '\0')
394 usage(); /* single char only */
398 case 'w': /* window width, default 80 */
399 owidth = strtonum(optarg, 1, INT_MAX, &errstr);
401 warnx("width %s", errstr);
405 case 'K': /* skip N lines */
408 case 'k': /* skip, do not print */
409 skip = strtonum(optarg, 0, INT_MAX, &errstr);
411 warnx("skip value %s", errstr);
418 flags |= NOTRIMENDCOL;
420 case 'g': /* gutter width */
421 gutter = strtonum(optarg, 0, INT_MAX, &errstr);
423 warnx("gutter width %s", errstr);
428 propgutter = strtonum(optarg, 0, INT_MAX, &errstr);
430 warnx("gutter proportion %s", errstr);
434 case 'e': /* each line is an entry */
440 case 'j': /* right adjust */
441 flags |= RIGHTADJUST;
443 case 'n': /* null padding for missing values */
449 case 'H': /* print shape only */
450 flags |= DETAILSHAPE;
455 case 'z': /* squeeze col width */
467 ocols = strtonum(av[1], 0, INT_MAX, &errstr);
469 warnx("columns value %s", errstr);
474 orows = strtonum(av[0], 0, INT_MAX, &errstr);
476 warnx("columns value %s", errstr);