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