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

Revision 26014, 12.3 KB checked in by achernya, 11 years ago (diff)
Patches are hard
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 * 4. 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 const 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 const 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 <sys/cdefs.h>
47__FBSDID("$FreeBSD$");
48
49#include <err.h>
50#include <ctype.h>
51#include <limits.h>
52#include <stdio.h>
53#include <stdlib.h>
54#include <string.h>
55
56static long     flags;
57#define TRANSPOSE       000001
58#define MTRANSPOSE      000002
59#define ONEPERLINE      000004
60#define ONEISEPONLY     000010
61#define ONEOSEPONLY     000020
62#define NOTRIMENDCOL    000040
63#define SQUEEZE         000100
64#define SHAPEONLY       000200
65#define DETAILSHAPE     000400
66#define RIGHTADJUST     001000
67#define NULLPAD         002000
68#define RECYCLE         004000
69#define SKIPPRINT       010000
70#define ICOLBOUNDS      020000
71#define OCOLBOUNDS      040000
72#define ONEPERCHAR      0100000
73#define NOARGS          0200000
74
75static short    *colwidths;
76static short    *cord;
77static short    *icbd;
78static short    *ocbd;
79static int      nelem;
80static char     **elem;
81static char     **endelem;
82static char     *curline;
83static int      allocsize = BUFSIZ;
84static int      curlen;
85static int      irows, icols;
86static int      orows = 0, ocols = 0;
87static int      maxlen;
88static int      skip;
89static int      propgutter;
90static char     isep = ' ', osep = ' ';
91static char     blank[] = "";
92static int      owidth = 80, gutter = 2;
93
94static void       getargs(int, char *[]);
95static void       getfile(void);
96static int        getline(void);
97static char      *getlist(short **, char *);
98static char      *getnum(int *, char *, int);
99static char     **getptrs(char **);
100static void       prepfile(void);
101static void       prints(char *, int);
102static void       putfile(void);
103static void usage(void);
104
105#define INCR(ep) do {                   \
106        if (++ep >= endelem)            \
107                ep = getptrs(ep);       \
108} while(0)
109
110int
111main(int argc, char *argv[])
112{
113        getargs(argc, argv);
114        getfile();
115        if (flags & SHAPEONLY) {
116                printf("%d %d\n", irows, icols);
117                exit(0);
118        }
119        prepfile();
120        putfile();
121        exit(0);
122}
123
124static void
125getfile(void)
126{
127        char *p;
128        char *endp;
129        char **ep;
130        int c;
131        int multisep = (flags & ONEISEPONLY ? 0 : 1);
132        int nullpad = flags & NULLPAD;
133        char **padto;
134
135        while (skip--) {
136                c = getline();
137                if (flags & SKIPPRINT)
138                        puts(curline);
139                if (c == EOF)
140                        return;
141        }
142        getline();
143        if (flags & NOARGS && curlen < owidth)
144                flags |= ONEPERLINE;
145        if (flags & ONEPERLINE)
146                icols = 1;
147        else                            /* count cols on first line */
148                for (p = curline, endp = curline + curlen; p < endp; p++) {
149                        if (*p == isep && multisep)
150                                continue;
151                        icols++;
152                        while (*p && *p != isep)
153                                p++;
154                }
155        ep = getptrs(elem);
156        do {
157                if (flags & ONEPERLINE) {
158                        *ep = curline;
159                        INCR(ep);               /* prepare for next entry */
160                        if (maxlen < curlen)
161                                maxlen = curlen;
162                        irows++;
163                        continue;
164                }
165                for (p = curline, endp = curline + curlen; p < endp; p++) {
166                        if (*p == isep && multisep)
167                                continue;       /* eat up column separators */
168                        if (*p == isep)         /* must be an empty column */
169                                *ep = blank;
170                        else                    /* store column entry */
171                                *ep = p;
172                        while (p < endp && *p != isep)
173                                p++;            /* find end of entry */
174                        *p = '\0';              /* mark end of entry */
175                        if (maxlen < p - *ep)   /* update maxlen */
176                                maxlen = p - *ep;
177                        INCR(ep);               /* prepare for next entry */
178                }
179                irows++;                        /* update row count */
180                if (nullpad) {                  /* pad missing entries */
181                        padto = elem + irows * icols;
182                        while (ep < padto) {
183                                *ep = blank;
184                                INCR(ep);
185                        }
186                }
187        } while (getline() != EOF);
188        *ep = 0;                                /* mark end of pointers */
189        nelem = ep - elem;
190}
191
192static void
193putfile(void)
194{
195        char **ep;
196        int i, j, k;
197
198        ep = elem;
199        if (flags & TRANSPOSE)
200                for (i = 0; i < orows; i++) {
201                        for (j = i; j < nelem; j += orows)
202                                prints(ep[j], (j - i) / orows);
203                        putchar('\n');
204                }
205        else
206                for (i = k = 0; i < orows; i++) {
207                        for (j = 0; j < ocols; j++, k++)
208                                if (k < nelem)
209                                        prints(ep[k], j);
210                        putchar('\n');
211                }
212}
213
214static void
215prints(char *s, int col)
216{
217        int n;
218        char *p = s;
219
220        while (*p)
221                p++;
222        n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
223        if (flags & RIGHTADJUST)
224                while (n-- > 0)
225                        putchar(osep);
226        for (p = s; *p; p++)
227                putchar(*p);
228        while (n-- > 0)
229                putchar(osep);
230}
231
232static void
233usage(void)
234{
235        fprintf(stderr,
236                "usage: rs [-[csCS][x][kKgGw][N]tTeEnyjhHmz] [rows [cols]]\n");
237        exit(1);
238}
239
240static void
241prepfile(void)
242{
243        char **ep;
244        int  i;
245        int  j;
246        char **lp;
247        int colw;
248        int max;
249        int n;
250
251        if (!nelem)
252                exit(0);
253        gutter += maxlen * propgutter / 100.0;
254        colw = maxlen + gutter;
255        if (flags & MTRANSPOSE) {
256                orows = icols;
257                ocols = irows;
258        }
259        else if (orows == 0 && ocols == 0) {    /* decide rows and cols */
260                ocols = owidth / colw;
261                if (ocols == 0) {
262                        warnx("display width %d is less than column width %d",
263                                        owidth, colw);
264                        ocols = 1;
265                }
266                if (ocols > nelem)
267                        ocols = nelem;
268                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
269        }
270        else if (orows == 0)                    /* decide on rows */
271                orows = nelem / ocols + (nelem % ocols ? 1 : 0);
272        else if (ocols == 0)                    /* decide on cols */
273                ocols = nelem / orows + (nelem % orows ? 1 : 0);
274        lp = elem + orows * ocols;
275        while (lp > endelem) {
276                getptrs(elem + nelem);
277                lp = elem + orows * ocols;
278        }
279        if (flags & RECYCLE) {
280                for (ep = elem + nelem; ep < lp; ep++)
281                        *ep = *(ep - nelem);
282                nelem = lp - elem;
283        }
284        if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
285                errx(1, "malloc");
286        if (flags & SQUEEZE) {
287                ep = elem;
288                if (flags & TRANSPOSE)
289                        for (i = 0; i < ocols; i++) {
290                                max = 0;
291                                for (j = 0; *ep != NULL && j < orows; j++)
292                                        if ((n = strlen(*ep++)) > max)
293                                                max = n;
294                                colwidths[i] = max + gutter;
295                        }
296                else
297                        for (i = 0; i < ocols; i++) {
298                                max = 0;
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                warnx("%d is colwidths, nelem %d", colwidths[i], nelem);*/
330}
331
332#define BSIZE   (LINE_MAX * 2)
333static char     ibuf[BSIZE];
334
335static int
336getline(void)   /* get line; maintain curline, curlen; manage storage */
337{
338        static  int putlength;
339        static  char *endblock = ibuf + BSIZE;
340        char *p;
341        int c, i;
342
343        if (!irows) {
344                curline = ibuf;
345                putlength = flags & DETAILSHAPE;
346        }
347        else if (skip <= 0) {                   /* don't waste storage */
348                curline += curlen + 1;
349                if (putlength) {        /* print length, recycle storage */
350                        printf(" %d line %d\n", curlen, irows);
351                        curline = ibuf;
352                }
353        }
354        if (!putlength && endblock - curline < LINE_MAX + 1) { /* need storage */
355                /*ww = endblock-curline; tt += ww;*/
356                /*printf("#wasted %d total %d\n",ww,tt);*/
357                if (!(curline = (char *) malloc(BSIZE)))
358                        errx(1, "file too large");
359                endblock = curline + BSIZE;
360                /*printf("#endb %d curline %d\n",endblock,curline);*/
361        }
362        for (p = curline, i = 0;; *p++ = c, i++) {
363                if ((c = getchar()) == EOF)
364                        break;
365                if (i >= LINE_MAX)
366                        errx(1, "maximum line length (%d) exceeded", LINE_MAX);
367                if (c == '\n')
368                        break;
369        }
370        *p = '\0';
371        curlen = i;
372        return(c);
373}
374
375static char **
376getptrs(char **sp)
377{
378        char **p;
379
380        allocsize += allocsize;
381        p = (char **)realloc(elem, allocsize * sizeof(char *));
382        if (p == NULL)
383                err(1, "no memory");
384
385        sp += (p - elem);
386        endelem = (elem = p) + allocsize;
387        return(sp);
388}
389
390static void
391getargs(int ac, char *av[])
392{
393        char *p;
394
395        if (ac == 1) {
396                flags |= NOARGS | TRANSPOSE;
397        }
398        while (--ac && **++av == '-')
399                for (p = *av+1; *p; p++)
400                        switch (*p) {
401                        case 'T':
402                                flags |= MTRANSPOSE;
403                        case 't':
404                                flags |= TRANSPOSE;
405                                break;
406                        case 'c':               /* input col. separator */
407                                flags |= ONEISEPONLY;
408                        case 's':               /* one or more allowed */
409                                if (p[1])
410                                        isep = *++p;
411                                else
412                                        isep = '\t';    /* default is ^I */
413                                break;
414                        case 'C':
415                                flags |= ONEOSEPONLY;
416                        case 'S':
417                                if (p[1])
418                                        osep = *++p;
419                                else
420                                        osep = '\t';    /* default is ^I */
421                                break;
422                        case 'w':               /* window width, default 80 */
423                                p = getnum(&owidth, p, 0);
424                                if (owidth <= 0)
425                                        errx(1, "width must be a positive integer");
426                                break;
427                        case 'K':                       /* skip N lines */
428                                flags |= SKIPPRINT;
429                        case 'k':                       /* skip, do not print */
430                                p = getnum(&skip, p, 0);
431                                if (!skip)
432                                        skip = 1;
433                                break;
434                        case 'm':
435                                flags |= NOTRIMENDCOL;
436                                break;
437                        case 'g':               /* gutter space */
438                                p = getnum(&gutter, p, 0);
439                                break;
440                        case 'G':
441                                p = getnum(&propgutter, p, 0);
442                                break;
443                        case 'e':               /* each line is an entry */
444                                flags |= ONEPERLINE;
445                                break;
446                        case 'E':
447                                flags |= ONEPERCHAR;
448                                break;
449                        case 'j':                       /* right adjust */
450                                flags |= RIGHTADJUST;
451                                break;
452                        case 'n':       /* null padding for missing values */
453                                flags |= NULLPAD;
454                                break;
455                        case 'y':
456                                flags |= RECYCLE;
457                                break;
458                        case 'H':                       /* print shape only */
459                                flags |= DETAILSHAPE;
460                        case 'h':
461                                flags |= SHAPEONLY;
462                                break;
463                        case 'z':                       /* squeeze col width */
464                                flags |= SQUEEZE;
465                                break;
466                        /*case 'p':
467                                ipagespace = atoi(++p); (default is 1)
468                                break;*/
469                        case 'o':                       /* col order */
470                                p = getlist(&cord, p);
471                                break;
472                        case 'b':
473                                flags |= ICOLBOUNDS;
474                                p = getlist(&icbd, p);
475                                break;
476                        case 'B':
477                                flags |= OCOLBOUNDS;
478                                p = getlist(&ocbd, p);
479                                break;
480                        default:
481                                usage();
482                        }
483        /*if (!osep)
484                osep = isep;*/
485        switch (ac) {
486        /*case 3:
487                opages = atoi(av[2]);*/
488        case 2:
489                if ((ocols = atoi(av[1])) < 0)
490                        ocols = 0;
491        case 1:
492                if ((orows = atoi(av[0])) < 0)
493                        orows = 0;
494        case 0:
495                break;
496        default:
497                errx(1, "too many arguments");
498        }
499}
500
501static char *
502getlist(short **list, char *p)
503{
504        int count = 1;
505        char *t;
506
507        for (t = p + 1; *t; t++) {
508                if (!isdigit((unsigned char)*t))
509                        errx(1,
510        "option %.1s requires a list of unsigned numbers separated by commas", t);
511                count++;
512                while (*t && isdigit((unsigned char)*t))
513                        t++;
514                if (*t != ',')
515                        break;
516        }
517        if (!(*list = (short *) malloc(count * sizeof(short))))
518                errx(1, "no list space");
519        count = 0;
520        for (t = p + 1; *t; t++) {
521                (*list)[count++] = atoi(t);
522                printf("++ %d ", (*list)[count-1]);
523                fflush(stdout);
524                while (*t && isdigit((unsigned char)*t))
525                        t++;
526                if (*t != ',')
527                        break;
528        }
529        (*list)[count] = 0;
530        return(t - 1);
531}
532
533/*
534 * num = number p points to; if (strict) complain
535 * returns pointer to end of num
536 */
537static char *
538getnum(int *num, char *p, int strict)
539{
540        char *t = p;
541
542        if (!isdigit((unsigned char)*++t)) {
543                if (strict || *t == '-' || *t == '+')
544                        errx(1, "option %.1s requires an unsigned integer", p);
545                *num = 0;
546                return(p);
547        }
548        *num = atoi(t);
549        while (*++t)
550                if (!isdigit((unsigned char)*t))
551                        break;
552        return(--t);
553}
Note: See TracBrowser for help on using the repository browser.