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