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