source: trunk/third/rs/rs.c @ 24143

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