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