Annotation of src/usr.bin/rs/rs.c, Revision 1.30
1.30 ! schwarze 1: /* $OpenBSD: rs.c,v 1.29 2015/11/14 17:03:02 schwarze Exp $ */
1.3 deraadt 2:
1.1 deraadt 3: /*-
4: * Copyright (c) 1993
5: * The Regents of the University of California. All rights reserved.
6: *
7: * Redistribution and use in source and binary forms, with or without
8: * modification, are permitted provided that the following conditions
9: * are met:
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.
1.8 millert 15: * 3. Neither the name of the University nor the names of its contributors
1.1 deraadt 16: * may be used to endorse or promote products derived from this software
17: * without specific prior written permission.
18: *
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
29: * SUCH DAMAGE.
30: */
31:
32: /*
33: * rs - reshape a data array
34: * Author: John Kunze, Office of Comp. Affairs, UCB
35: * BEWARE: lots of unfinished edges
36: */
37:
38: #include <ctype.h>
1.4 millert 39: #include <err.h>
1.14 millert 40: #include <errno.h>
41: #include <limits.h>
1.30 ! schwarze 42: #include <locale.h>
1.1 deraadt 43: #include <stdio.h>
44: #include <stdlib.h>
45: #include <string.h>
1.23 millert 46: #include <unistd.h>
1.1 deraadt 47:
1.30 ! schwarze 48: struct entry {
! 49: int w; /* Display width. */
! 50: char *s; /* Multibyte string. */
! 51: };
! 52:
1.1 deraadt 53: long flags;
54: #define TRANSPOSE 000001
55: #define MTRANSPOSE 000002
56: #define ONEPERLINE 000004
57: #define ONEISEPONLY 000010
58: #define ONEOSEPONLY 000020
59: #define NOTRIMENDCOL 000040
60: #define SQUEEZE 000100
61: #define SHAPEONLY 000200
62: #define DETAILSHAPE 000400
63: #define RIGHTADJUST 001000
64: #define NULLPAD 002000
65: #define RECYCLE 004000
66: #define SKIPPRINT 010000
67: #define ONEPERCHAR 0100000
68: #define NOARGS 0200000
69:
70: short *colwidths;
71: int nelem;
1.30 ! schwarze 72: struct entry *elem;
! 73: struct entry *endelem;
1.1 deraadt 74: char *curline;
75: int allocsize = BUFSIZ;
76: int irows, icols;
77: int orows, ocols;
1.30 ! schwarze 78: int maxwidth;
1.1 deraadt 79: int skip;
80: int propgutter;
81: char isep = ' ', osep = ' ';
82: int owidth = 80, gutter = 2;
83:
1.30 ! schwarze 84: int mbsavis(char **, const char *);
! 85:
1.12 millert 86: void usage(void);
1.7 millert 87: void getargs(int, char *[]);
88: void getfile(void);
1.21 fgsch 89: int get_line(void);
1.30 ! schwarze 90: struct entry *getptrs(struct entry *);
1.7 millert 91: void prepfile(void);
1.30 ! schwarze 92: void prints(struct entry *, int);
1.7 millert 93: void putfile(void);
1.1 deraadt 94:
1.2 deraadt 95: #define INCR(ep) do { \
96: if (++ep >= endelem) \
97: ep = getptrs(ep); \
98: } while(0)
99:
1.1 deraadt 100: int
1.9 deraadt 101: main(int argc, char *argv[])
1.1 deraadt 102: {
1.30 ! schwarze 103: setlocale(LC_CTYPE, "");
! 104:
1.27 deraadt 105: if (pledge("stdio", NULL) == -1)
106: err(1, "pledge");
1.26 deraadt 107:
1.1 deraadt 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
1.9 deraadt 120: getfile(void)
1.1 deraadt 121: {
1.30 ! schwarze 122: const char delim[2] = { isep, '\0' };
1.6 mpech 123: char *p;
1.30 ! schwarze 124: struct entry *ep;
1.1 deraadt 125: int multisep = (flags & ONEISEPONLY ? 0 : 1);
126: int nullpad = flags & NULLPAD;
1.30 ! schwarze 127: struct entry *padto;
1.1 deraadt 128:
1.30 ! schwarze 129: curline = NULL;
1.1 deraadt 130: while (skip--) {
1.28 schwarze 131: if (get_line() == EOF)
132: return;
1.1 deraadt 133: if (flags & SKIPPRINT)
134: puts(curline);
135: }
1.28 schwarze 136: if (get_line() == EOF)
137: return;
1.30 ! schwarze 138: if (flags & NOARGS && strlen(curline) < (size_t)owidth)
1.1 deraadt 139: flags |= ONEPERLINE;
140: if (flags & ONEPERLINE)
141: icols = 1;
142: else /* count cols on first line */
1.30 ! schwarze 143: for (p = curline; *p != '\0'; p++) {
1.1 deraadt 144: if (*p == isep && multisep)
145: continue;
146: icols++;
147: while (*p && *p != isep)
148: p++;
149: }
1.30 ! schwarze 150: ep = getptrs(NULL);
1.1 deraadt 151: p = curline;
152: do {
153: if (flags & ONEPERLINE) {
1.30 ! schwarze 154: ep->w = mbsavis(&ep->s, curline);
! 155: if (maxwidth < ep->w)
! 156: maxwidth = ep->w;
1.2 deraadt 157: INCR(ep); /* prepare for next entry */
1.1 deraadt 158: irows++;
159: continue;
160: }
1.30 ! schwarze 161: p = curline;
! 162: while (p != NULL && *p != '\0') {
! 163: if (*p == isep) {
! 164: p++;
! 165: if (multisep)
! 166: continue;
! 167: ep->s = ""; /* empty column */
! 168: ep->w = 0;
! 169: } else
! 170: ep->w = mbsavis(&ep->s, strsep(&p, delim));
! 171: if (maxwidth < ep->w)
! 172: maxwidth = ep->w;
1.2 deraadt 173: INCR(ep); /* prepare for next entry */
1.1 deraadt 174: }
175: irows++; /* update row count */
176: if (nullpad) { /* pad missing entries */
177: padto = elem + irows * icols;
1.2 deraadt 178: while (ep < padto) {
1.30 ! schwarze 179: ep->s = "";
! 180: ep->w = 0;
1.2 deraadt 181: INCR(ep);
182: }
1.1 deraadt 183: }
1.21 fgsch 184: } while (get_line() != EOF);
1.1 deraadt 185: nelem = ep - elem;
186: }
187:
188: void
1.9 deraadt 189: putfile(void)
1.1 deraadt 190: {
1.30 ! schwarze 191: struct entry *ep;
1.6 mpech 192: int i, j, n;
1.1 deraadt 193:
194: ep = elem;
1.2 deraadt 195: if (flags & TRANSPOSE) {
1.1 deraadt 196: for (i = 0; i < orows; i++) {
197: for (j = i; j < nelem; j += orows)
1.30 ! schwarze 198: prints(ep + j, (j - i) / orows);
1.1 deraadt 199: putchar('\n');
200: }
1.2 deraadt 201: } else {
202: for (n = 0, i = 0; i < orows && n < nelem; i++) {
203: for (j = 0; j < ocols; j++) {
204: if (n++ >= nelem)
205: break;
1.30 ! schwarze 206: prints(ep++, j);
1.2 deraadt 207: }
1.1 deraadt 208: putchar('\n');
209: }
1.2 deraadt 210: }
1.1 deraadt 211: }
212:
213: void
1.30 ! schwarze 214: prints(struct entry *ep, int col)
1.1 deraadt 215: {
1.6 mpech 216: int n;
1.1 deraadt 217:
1.30 ! schwarze 218: n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - ep->w);
1.1 deraadt 219: if (flags & RIGHTADJUST)
220: while (n-- > 0)
221: putchar(osep);
1.30 ! schwarze 222: fputs(ep->s, stdout);
1.1 deraadt 223: while (n-- > 0)
224: putchar(osep);
225: }
226:
227: void
1.12 millert 228: usage(void)
1.1 deraadt 229: {
1.12 millert 230: extern char *__progname;
231:
1.1 deraadt 232: fprintf(stderr,
1.19 sobrado 233: "usage: %s [-CcSs[x]] [-GgKkw N] [-EeHhjmnTtyz] [rows [cols]]\n",
1.12 millert 234: __progname);
1.1 deraadt 235: exit(1);
236: }
237:
238: void
1.9 deraadt 239: prepfile(void)
1.1 deraadt 240: {
1.30 ! schwarze 241: struct entry *ep;
1.6 mpech 242: int i;
243: int j;
1.30 ! schwarze 244: struct entry *lp;
1.1 deraadt 245: int colw;
246: int max = 0;
247: int n;
248:
249: if (!nelem)
250: exit(0);
1.30 ! schwarze 251: gutter += maxwidth * propgutter / 100.0;
! 252: colw = maxwidth + gutter;
1.1 deraadt 253: if (flags & MTRANSPOSE) {
254: orows = icols;
255: ocols = irows;
256: }
257: else if (orows == 0 && ocols == 0) { /* decide rows and cols */
258: ocols = owidth / colw;
1.2 deraadt 259: if (ocols == 0) {
1.4 millert 260: warnx("Display width %d is less than column width %d",
261: owidth, colw);
1.2 deraadt 262: ocols = 1;
263: }
1.1 deraadt 264: if (ocols > nelem)
265: ocols = nelem;
266: orows = nelem / ocols + (nelem % ocols ? 1 : 0);
267: }
268: else if (orows == 0) /* decide on rows */
269: orows = nelem / ocols + (nelem % ocols ? 1 : 0);
270: else if (ocols == 0) /* decide on cols */
271: ocols = nelem / orows + (nelem % orows ? 1 : 0);
1.30 ! schwarze 272: while ((lp = elem + orows * ocols) > endelem)
! 273: (void)getptrs(NULL);
1.1 deraadt 274: if (flags & RECYCLE) {
275: for (ep = elem + nelem; ep < lp; ep++)
1.30 ! schwarze 276: memcpy(ep, ep - nelem, sizeof(*ep));
1.1 deraadt 277: nelem = lp - elem;
278: }
1.25 deraadt 279: if (!(colwidths = calloc(ocols, sizeof(short))))
1.2 deraadt 280: errx(1, "malloc: No gutter space");
1.1 deraadt 281: if (flags & SQUEEZE) {
1.29 schwarze 282: for (ep = elem, i = 0; i < ocols; i++) {
283: max = 0;
284: if (flags & TRANSPOSE) {
1.30 ! schwarze 285: for (j = 0; j < orows; j++, ep++)
! 286: if (ep->w > max)
! 287: max = ep->w;
1.29 schwarze 288: } else {
1.1 deraadt 289: for (j = i; j < nelem; j += ocols)
1.30 ! schwarze 290: if (ep[j].w > max)
! 291: max = ep[j].w;
1.1 deraadt 292: }
1.29 schwarze 293: colwidths[i] = max + gutter;
294: }
1.13 millert 295: } else {
1.1 deraadt 296: for (i = 0; i < ocols; i++)
297: colwidths[i] = colw;
1.13 millert 298: }
1.1 deraadt 299: if (!(flags & NOTRIMENDCOL)) {
300: if (flags & RIGHTADJUST)
301: colwidths[0] -= gutter;
302: else
303: colwidths[ocols - 1] = 0;
304: }
305: n = orows * ocols;
306: if (n > nelem && (flags & RECYCLE))
307: nelem = n;
308: }
309:
310: int
1.30 ! schwarze 311: get_line(void)
1.1 deraadt 312: {
1.30 ! schwarze 313: static size_t cursz;
! 314: static ssize_t curlen;
1.28 schwarze 315:
316: if (irows > 0 && flags & DETAILSHAPE)
317: printf(" %zd line %d\n", curlen, irows);
318:
1.30 ! schwarze 319: if ((curlen = getline(&curline, &cursz, stdin)) == EOF) {
1.28 schwarze 320: if (ferror(stdin))
321: err(1, NULL);
322: return EOF;
323: }
1.30 ! schwarze 324: if (curlen > 0 && curline[curlen - 1] == '\n')
! 325: curline[--curlen] = '\0';
1.28 schwarze 326:
327: return 0;
1.1 deraadt 328: }
329:
1.30 ! schwarze 330: struct entry *
! 331: getptrs(struct entry *sp)
1.1 deraadt 332: {
1.30 ! schwarze 333: struct entry *p;
1.22 otto 334: int newsize;
1.1 deraadt 335:
1.10 tedu 336: newsize = allocsize * 2;
1.30 ! schwarze 337: p = reallocarray(elem, newsize, sizeof(*p));
1.10 tedu 338: if (p == NULL)
1.2 deraadt 339: err(1, "no memory");
340:
1.22 otto 341: allocsize = newsize;
1.30 ! schwarze 342: sp = sp == NULL ? p : p + (sp - elem);
1.10 tedu 343: elem = p;
344: endelem = elem + allocsize;
1.2 deraadt 345: return(sp);
1.1 deraadt 346: }
347:
348: void
1.9 deraadt 349: getargs(int ac, char *av[])
1.1 deraadt 350: {
1.12 millert 351: int ch;
1.14 millert 352: const char *errstr;
1.1 deraadt 353:
1.12 millert 354: if (ac == 1)
1.1 deraadt 355: flags |= NOARGS | TRANSPOSE;
1.12 millert 356: while ((ch = getopt(ac, av, "c::C::s::S::k:K:g:G:w:tTeEnyjhHmz")) != -1) {
357: switch (ch) {
358: case 'T':
359: flags |= MTRANSPOSE;
360: /* FALLTHROUGH */
361: case 't':
362: flags |= TRANSPOSE;
363: break;
364: case 'c': /* input col. separator */
365: flags |= ONEISEPONLY;
366: /* FALLTHROUGH */
367: case 's': /* one or more allowed */
368: if (optarg == NULL)
369: isep = '\t'; /* default is ^I */
370: else if (optarg[1] != '\0')
371: usage(); /* single char only */
372: else
373: isep = *optarg;
374: break;
375: case 'C':
376: flags |= ONEOSEPONLY;
377: /* FALLTHROUGH */
378: case 'S':
379: if (optarg == NULL)
380: osep = '\t'; /* default is ^I */
381: else if (optarg[1] != '\0')
382: usage(); /* single char only */
383: else
384: osep = *optarg;
385: break;
386: case 'w': /* window width, default 80 */
1.14 millert 387: owidth = strtonum(optarg, 1, INT_MAX, &errstr);
388: if (errstr) {
389: warnx("width %s", errstr);
1.12 millert 390: usage();
391: }
392: break;
393: case 'K': /* skip N lines */
394: flags |= SKIPPRINT;
395: /* FALLTHROUGH */
396: case 'k': /* skip, do not print */
1.14 millert 397: skip = strtonum(optarg, 0, INT_MAX, &errstr);
398: if (errstr) {
399: warnx("skip value %s", errstr);
400: usage();
401: }
402: if (skip == 0)
1.12 millert 403: skip = 1;
404: break;
405: case 'm':
406: flags |= NOTRIMENDCOL;
407: break;
1.14 millert 408: case 'g': /* gutter width */
409: gutter = strtonum(optarg, 0, INT_MAX, &errstr);
410: if (errstr) {
411: warnx("gutter width %s", errstr);
412: usage();
413: }
1.12 millert 414: break;
415: case 'G':
1.14 millert 416: propgutter = strtonum(optarg, 0, INT_MAX, &errstr);
417: if (errstr) {
418: warnx("gutter proportion %s", errstr);
419: usage();
420: }
1.12 millert 421: break;
422: case 'e': /* each line is an entry */
423: flags |= ONEPERLINE;
424: break;
425: case 'E':
426: flags |= ONEPERCHAR;
427: break;
428: case 'j': /* right adjust */
429: flags |= RIGHTADJUST;
430: break;
431: case 'n': /* null padding for missing values */
432: flags |= NULLPAD;
433: break;
434: case 'y':
435: flags |= RECYCLE;
436: break;
437: case 'H': /* print shape only */
438: flags |= DETAILSHAPE;
439: /* FALLTHROUGH */
440: case 'h':
441: flags |= SHAPEONLY;
442: break;
443: case 'z': /* squeeze col width */
444: flags |= SQUEEZE;
445: break;
446: default:
447: usage();
448: }
1.1 deraadt 449: }
1.12 millert 450: ac -= optind;
451: av += optind;
452:
1.1 deraadt 453: switch (ac) {
454: case 2:
1.14 millert 455: ocols = strtonum(av[1], 0, INT_MAX, &errstr);
456: if (errstr) {
457: warnx("columns value %s", errstr);
458: usage();
459: }
1.17 moritz 460: /* FALLTHROUGH */
1.1 deraadt 461: case 1:
1.14 millert 462: orows = strtonum(av[0], 0, INT_MAX, &errstr);
463: if (errstr) {
464: warnx("columns value %s", errstr);
465: usage();
466: }
1.17 moritz 467: /* FALLTHROUGH */
1.1 deraadt 468: case 0:
469: break;
470: default:
1.12 millert 471: usage();
1.1 deraadt 472: }
473: }