Annotation of src/usr.bin/rs/rs.c, Revision 1.17
1.17 ! moritz 1: /* $OpenBSD: rs.c,v 1.16 2005/05/15 13:19:14 jmc 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: #ifndef lint
1.12 millert 33: static const char copyright[] =
1.1 deraadt 34: "@(#) Copyright (c) 1993\n\
35: The Regents of the University of California. All rights reserved.\n";
36: #endif /* not lint */
37:
38: #ifndef lint
1.12 millert 39: #if 0
40: static const char sccsid[] = "@(#)rs.c 8.1 (Berkeley) 6/6/93";
41: #else
1.17 ! moritz 42: static const char rcsid[] = "$OpenBSD: rs.c,v 1.16 2005/05/15 13:19:14 jmc Exp $";
1.12 millert 43: #endif
1.1 deraadt 44: #endif /* not lint */
45:
46: /*
47: * rs - reshape a data array
48: * Author: John Kunze, Office of Comp. Affairs, UCB
49: * BEWARE: lots of unfinished edges
50: */
51:
52: #include <ctype.h>
1.4 millert 53: #include <err.h>
1.14 millert 54: #include <errno.h>
55: #include <limits.h>
1.1 deraadt 56: #include <stdio.h>
57: #include <stdlib.h>
58: #include <string.h>
59:
60: long flags;
61: #define TRANSPOSE 000001
62: #define MTRANSPOSE 000002
63: #define ONEPERLINE 000004
64: #define ONEISEPONLY 000010
65: #define ONEOSEPONLY 000020
66: #define NOTRIMENDCOL 000040
67: #define SQUEEZE 000100
68: #define SHAPEONLY 000200
69: #define DETAILSHAPE 000400
70: #define RIGHTADJUST 001000
71: #define NULLPAD 002000
72: #define RECYCLE 004000
73: #define SKIPPRINT 010000
74: #define ONEPERCHAR 0100000
75: #define NOARGS 0200000
76:
77: short *colwidths;
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:
1.12 millert 92: void usage(void);
1.7 millert 93: void getargs(int, char *[]);
94: void getfile(void);
95: int getline(void);
96: char **getptrs(char **);
97: void prepfile(void);
98: void prints(char *, int);
99: void putfile(void);
1.1 deraadt 100:
1.2 deraadt 101: #define INCR(ep) do { \
102: if (++ep >= endelem) \
103: ep = getptrs(ep); \
104: } while(0)
105:
1.1 deraadt 106: int
1.9 deraadt 107: main(int argc, char *argv[])
1.1 deraadt 108: {
109: getargs(argc, argv);
110: getfile();
111: if (flags & SHAPEONLY) {
112: printf("%d %d\n", irows, icols);
113: exit(0);
114: }
115: prepfile();
116: putfile();
117: exit(0);
118: }
119:
120: void
1.9 deraadt 121: getfile(void)
1.1 deraadt 122: {
1.6 mpech 123: char *p;
124: char *endp;
1.11 tedu 125: char **ep = NULL;
1.1 deraadt 126: int multisep = (flags & ONEISEPONLY ? 0 : 1);
127: int nullpad = flags & NULLPAD;
128: char **padto;
129:
130: while (skip--) {
131: getline();
132: if (flags & SKIPPRINT)
133: puts(curline);
134: }
135: getline();
136: if (flags & NOARGS && curlen < owidth)
137: flags |= ONEPERLINE;
138: if (flags & ONEPERLINE)
139: icols = 1;
140: else /* count cols on first line */
141: for (p = curline, endp = curline + curlen; p < endp; p++) {
142: if (*p == isep && multisep)
143: continue;
144: icols++;
145: while (*p && *p != isep)
146: p++;
147: }
148: ep = getptrs(elem);
149: p = curline;
150: do {
151: if (flags & ONEPERLINE) {
1.2 deraadt 152: *ep = curline;
153: INCR(ep); /* prepare for next entry */
1.1 deraadt 154: if (maxlen < curlen)
155: maxlen = curlen;
156: irows++;
157: continue;
158: }
159: for (p = curline, endp = curline + curlen; p < endp; p++) {
160: if (*p == isep && multisep)
161: continue; /* eat up column separators */
162: if (*p == isep) /* must be an empty column */
163: *ep = "";
164: else /* store column entry */
165: *ep = p;
166: while (p < endp && *p != isep)
167: p++; /* find end of entry */
168: *p = '\0'; /* mark end of entry */
169: if (maxlen < p - *ep) /* update maxlen */
170: maxlen = p - *ep;
1.2 deraadt 171: INCR(ep); /* prepare for next entry */
1.1 deraadt 172: }
173: irows++; /* update row count */
174: if (nullpad) { /* pad missing entries */
175: padto = elem + irows * icols;
1.2 deraadt 176: while (ep < padto) {
177: *ep = "";
178: INCR(ep);
179: }
1.1 deraadt 180: }
181: } while (getline() != EOF);
1.11 tedu 182: *ep = NULL; /* mark end of pointers */
1.1 deraadt 183: nelem = ep - elem;
184: }
185:
186: void
1.9 deraadt 187: putfile(void)
1.1 deraadt 188: {
1.6 mpech 189: char **ep;
190: int i, j, n;
1.1 deraadt 191:
192: ep = elem;
1.2 deraadt 193: if (flags & TRANSPOSE) {
1.1 deraadt 194: for (i = 0; i < orows; i++) {
195: for (j = i; j < nelem; j += orows)
196: prints(ep[j], (j - i) / orows);
197: putchar('\n');
198: }
1.2 deraadt 199: } else {
200: for (n = 0, i = 0; i < orows && n < nelem; i++) {
201: for (j = 0; j < ocols; j++) {
202: if (n++ >= nelem)
203: break;
1.1 deraadt 204: prints(*ep++, j);
1.2 deraadt 205: }
1.1 deraadt 206: putchar('\n');
207: }
1.2 deraadt 208: }
1.1 deraadt 209: }
210:
211: void
1.9 deraadt 212: prints(char *s, int col)
1.1 deraadt 213: {
1.6 mpech 214: int n;
215: char *p = s;
1.1 deraadt 216:
217: while (*p)
218: p++;
219: n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
220: if (flags & RIGHTADJUST)
221: while (n-- > 0)
222: putchar(osep);
223: for (p = s; *p; p++)
224: putchar(*p);
225: while (n-- > 0)
226: putchar(osep);
227: }
228:
229: void
1.12 millert 230: usage(void)
1.1 deraadt 231: {
1.12 millert 232: extern char *__progname;
233:
1.1 deraadt 234: fprintf(stderr,
1.16 jmc 235: "usage: %s [-CcSs[x]] [-KkGgw N] [-EeHhjmnTtyz] [rows [cols]]\n",
1.12 millert 236: __progname);
1.1 deraadt 237: exit(1);
238: }
239:
240: void
1.9 deraadt 241: prepfile(void)
1.1 deraadt 242: {
1.6 mpech 243: char **ep;
244: int i;
245: int j;
1.1 deraadt 246: char **lp;
247: int colw;
248: int max = 0;
249: int n;
250:
251: if (!nelem)
252: exit(0);
253: gutter += maxlen * propgutter / 100.0;
254: colw = maxlen + gutter;
255: if (flags & MTRANSPOSE) {
256: orows = icols;
257: ocols = irows;
258: }
259: else if (orows == 0 && ocols == 0) { /* decide rows and cols */
260: ocols = owidth / colw;
1.2 deraadt 261: if (ocols == 0) {
1.4 millert 262: warnx("Display width %d is less than column width %d",
263: owidth, colw);
1.2 deraadt 264: ocols = 1;
265: }
1.1 deraadt 266: if (ocols > nelem)
267: ocols = nelem;
268: orows = nelem / ocols + (nelem % ocols ? 1 : 0);
269: }
270: else if (orows == 0) /* decide on rows */
271: orows = nelem / ocols + (nelem % ocols ? 1 : 0);
272: else if (ocols == 0) /* decide on cols */
273: ocols = nelem / orows + (nelem % orows ? 1 : 0);
274: lp = elem + orows * ocols;
275: while (lp > endelem) {
276: getptrs(elem + nelem);
277: lp = elem + orows * ocols;
278: }
279: if (flags & RECYCLE) {
280: for (ep = elem + nelem; ep < lp; ep++)
281: *ep = *(ep - nelem);
282: nelem = lp - elem;
283: }
284: if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
1.2 deraadt 285: errx(1, "malloc: No gutter space");
1.1 deraadt 286: if (flags & SQUEEZE) {
287: if (flags & TRANSPOSE)
288: for (ep = elem, i = 0; i < ocols; i++) {
289: for (j = 0; j < orows; j++)
290: if ((n = strlen(*ep++)) > max)
291: max = n;
292: colwidths[i] = max + gutter;
293: }
294: else
1.5 deraadt 295: for (ep = elem, i = 0; i < ocols; i++) {
1.1 deraadt 296: for (j = i; j < nelem; j += ocols)
297: if ((n = strlen(ep[j])) > max)
298: max = n;
299: colwidths[i] = max + gutter;
300: }
1.13 millert 301: } else {
1.1 deraadt 302: for (i = 0; i < ocols; i++)
303: colwidths[i] = colw;
1.13 millert 304: }
1.1 deraadt 305: if (!(flags & NOTRIMENDCOL)) {
306: if (flags & RIGHTADJUST)
307: colwidths[0] -= gutter;
308: else
309: colwidths[ocols - 1] = 0;
310: }
311: n = orows * ocols;
312: if (n > nelem && (flags & RECYCLE))
313: nelem = n;
314: }
315:
316: #define BSIZE 2048
317: char ibuf[BSIZE]; /* two screenfuls should do */
318:
319: int
1.9 deraadt 320: getline(void) /* get line; maintain curline, curlen; manage storage */
1.1 deraadt 321: {
322: static int putlength;
323: static char *endblock = ibuf + BSIZE;
1.6 mpech 324: char *p;
325: int c, i;
1.1 deraadt 326:
327: if (!irows) {
328: curline = ibuf;
329: putlength = flags & DETAILSHAPE;
330: }
331: else if (skip <= 0) { /* don't waste storage */
332: curline += curlen + 1;
333: if (putlength) /* print length, recycle storage */
334: printf(" %d line %d\n", curlen, irows);
335: }
336: if (!putlength && endblock - curline < BUFSIZ) { /* need storage */
337: if (!(curline = (char *) malloc(BSIZE)))
1.2 deraadt 338: errx(1, "File too large");
1.1 deraadt 339: endblock = curline + BSIZE;
340: }
341: for (p = curline, i = 1; i < BUFSIZ; *p++ = c, i++)
342: if ((c = getchar()) == EOF || c == '\n')
343: break;
344: *p = '\0';
345: curlen = i - 1;
346: return(c);
347: }
348:
349: char **
1.9 deraadt 350: getptrs(char **sp)
1.1 deraadt 351: {
1.6 mpech 352: char **p;
1.10 tedu 353: int newsize, gap;
1.1 deraadt 354:
1.10 tedu 355: newsize = allocsize * 2;
356: p = realloc(elem, newsize * sizeof(char *));
357: if (p == NULL)
1.2 deraadt 358: err(1, "no memory");
359:
1.10 tedu 360: gap = p - elem;
361: elem = p;
362: allocsize = newsize;
363: sp += gap;
364: endelem = elem + allocsize;
1.2 deraadt 365: return(sp);
1.1 deraadt 366: }
367:
368: void
1.9 deraadt 369: getargs(int ac, char *av[])
1.1 deraadt 370: {
1.12 millert 371: int ch;
1.14 millert 372: const char *errstr;
1.1 deraadt 373:
1.12 millert 374: if (ac == 1)
1.1 deraadt 375: flags |= NOARGS | TRANSPOSE;
1.12 millert 376: while ((ch = getopt(ac, av, "c::C::s::S::k:K:g:G:w:tTeEnyjhHmz")) != -1) {
377: switch (ch) {
378: case 'T':
379: flags |= MTRANSPOSE;
380: /* FALLTHROUGH */
381: case 't':
382: flags |= TRANSPOSE;
383: break;
384: case 'c': /* input col. separator */
385: flags |= ONEISEPONLY;
386: /* FALLTHROUGH */
387: case 's': /* one or more allowed */
388: if (optarg == NULL)
389: isep = '\t'; /* default is ^I */
390: else if (optarg[1] != '\0')
391: usage(); /* single char only */
392: else
393: isep = *optarg;
394: break;
395: case 'C':
396: flags |= ONEOSEPONLY;
397: /* FALLTHROUGH */
398: case 'S':
399: if (optarg == NULL)
400: osep = '\t'; /* default is ^I */
401: else if (optarg[1] != '\0')
402: usage(); /* single char only */
403: else
404: osep = *optarg;
405: break;
406: case 'w': /* window width, default 80 */
1.14 millert 407: owidth = strtonum(optarg, 1, INT_MAX, &errstr);
408: if (errstr) {
409: warnx("width %s", errstr);
1.12 millert 410: usage();
411: }
412: break;
413: case 'K': /* skip N lines */
414: flags |= SKIPPRINT;
415: /* FALLTHROUGH */
416: case 'k': /* skip, do not print */
1.14 millert 417: skip = strtonum(optarg, 0, INT_MAX, &errstr);
418: if (errstr) {
419: warnx("skip value %s", errstr);
420: usage();
421: }
422: if (skip == 0)
1.12 millert 423: skip = 1;
424: break;
425: case 'm':
426: flags |= NOTRIMENDCOL;
427: break;
1.14 millert 428: case 'g': /* gutter width */
429: gutter = strtonum(optarg, 0, INT_MAX, &errstr);
430: if (errstr) {
431: warnx("gutter width %s", errstr);
432: usage();
433: }
1.12 millert 434: break;
435: case 'G':
1.14 millert 436: propgutter = strtonum(optarg, 0, INT_MAX, &errstr);
437: if (errstr) {
438: warnx("gutter proportion %s", errstr);
439: usage();
440: }
1.12 millert 441: break;
442: case 'e': /* each line is an entry */
443: flags |= ONEPERLINE;
444: break;
445: case 'E':
446: flags |= ONEPERCHAR;
447: break;
448: case 'j': /* right adjust */
449: flags |= RIGHTADJUST;
450: break;
451: case 'n': /* null padding for missing values */
452: flags |= NULLPAD;
453: break;
454: case 'y':
455: flags |= RECYCLE;
456: break;
457: case 'H': /* print shape only */
458: flags |= DETAILSHAPE;
459: /* FALLTHROUGH */
460: case 'h':
461: flags |= SHAPEONLY;
462: break;
463: case 'z': /* squeeze col width */
464: flags |= SQUEEZE;
465: break;
466: default:
467: usage();
468: }
1.1 deraadt 469: }
1.12 millert 470: ac -= optind;
471: av += optind;
472:
1.1 deraadt 473: switch (ac) {
474: case 2:
1.14 millert 475: ocols = strtonum(av[1], 0, INT_MAX, &errstr);
476: if (errstr) {
477: warnx("columns value %s", errstr);
478: usage();
479: }
1.17 ! moritz 480: /* FALLTHROUGH */
1.1 deraadt 481: case 1:
1.14 millert 482: orows = strtonum(av[0], 0, INT_MAX, &errstr);
483: if (errstr) {
484: warnx("columns value %s", errstr);
485: usage();
486: }
1.17 ! moritz 487: /* FALLTHROUGH */
1.1 deraadt 488: case 0:
489: break;
490: default:
1.12 millert 491: usage();
1.1 deraadt 492: }
493: }