Annotation of src/usr.bin/rs/rs.c, Revision 1.1.1.1
1.1 deraadt 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: }