]> CyberLeo.Net >> Repos - FreeBSD/FreeBSD.git/blob - usr.bin/rs/rs.cc
Merge llvm-project release/17.x llvmorg-17.0.3-0-g888437e1b600
[FreeBSD/FreeBSD.git] / usr.bin / rs / rs.cc
1 /*-
2  * SPDX-License-Identifier: BSD-3-Clause
3  *
4  * Copyright (c) 1993
5  *      The Regents of the University of California.  All rights reserved.
6  *
7  * Redistribution and use in source and binary forms, with or without
8  * modification, are permitted provided that the following conditions
9  * are met:
10  * 1. Redistributions of source code must retain the above copyright
11  *    notice, this list of conditions and the following disclaimer.
12  * 2. Redistributions in binary form must reproduce the above copyright
13  *    notice, this list of conditions and the following disclaimer in the
14  *    documentation and/or other materials provided with the distribution.
15  * 3. Neither the name of the University nor the names of its contributors
16  *    may be used to endorse or promote products derived from this software
17  *    without specific prior written permission.
18  *
19  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
20  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
21  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
22  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
23  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
24  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
25  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
26  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
27  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
28  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
29  * SUCH DAMAGE.
30  */
31
32 /*
33  *      rs - reshape a data array
34  *      Author:  John Kunze, Office of Comp. Affairs, UCB
35  *              BEWARE: lots of unfinished edges
36  */
37
38 #include <err.h>
39 #include <ctype.h>
40 #include <limits.h>
41 #include <stdio.h>
42 #include <stdlib.h>
43 #include <string.h>
44 #include <unistd.h>
45 #include <vector>
46
47 static long     flags;
48 #define TRANSPOSE       000001
49 #define MTRANSPOSE      000002
50 #define ONEPERLINE      000004
51 #define ONEISEPONLY     000010
52 #define ONEOSEPONLY     000020
53 #define NOTRIMENDCOL    000040
54 #define SQUEEZE         000100
55 #define SHAPEONLY       000200
56 #define DETAILSHAPE     000400
57 #define RIGHTADJUST     001000
58 #define NULLPAD         002000
59 #define RECYCLE         004000
60 #define SKIPPRINT       010000
61 #define ICOLBOUNDS      020000
62 #define OCOLBOUNDS      040000
63 #define ONEPERCHAR      0100000
64 #define NOARGS          0200000
65
66 static short    *colwidths;
67 static std::vector<char *> elem;
68 static char     *curline;
69 static size_t   curlen;
70 static size_t   irows, icols;
71 static size_t   orows = 0, ocols = 0;
72 static size_t   maxlen;
73 static int      skip;
74 static int      propgutter;
75 static char     isep = ' ', osep = ' ';
76 static char     blank[] = "";
77 static size_t   owidth = 80, gutter = 2;
78
79 static void       getargs(int, char *[]);
80 static void       getfile(void);
81 static int        get_line(void);
82 static long       getnum(const char *);
83 static void       prepfile(void);
84 static void       prints(char *, int);
85 static void       putfile(void);
86 static void usage(void);
87
88 int
89 main(int argc, char *argv[])
90 {
91         getargs(argc, argv);
92         getfile();
93         if (flags & SHAPEONLY) {
94                 printf("%zu %zu\n", irows, icols);
95                 exit(0);
96         }
97         prepfile();
98         putfile();
99         exit(0);
100 }
101
102 static void
103 getfile(void)
104 {
105         char *p, *sp;
106         char *endp;
107         int c;
108         int multisep = (flags & ONEISEPONLY ? 0 : 1);
109         int nullpad = flags & NULLPAD;
110         size_t len, padto;
111
112         while (skip--) {
113                 c = get_line();
114                 if (flags & SKIPPRINT)
115                         puts(curline);
116                 if (c == EOF)
117                         return;
118         }
119         get_line();
120         if (flags & NOARGS && curlen < owidth)
121                 flags |= ONEPERLINE;
122         if (flags & ONEPERLINE)
123                 icols = 1;
124         else                            /* count cols on first line */
125                 for (p = curline, endp = curline + curlen; p < endp; p++) {
126                         if (*p == isep && multisep)
127                                 continue;
128                         icols++;
129                         while (*p && *p != isep)
130                                 p++;
131                 }
132         do {
133                 if (flags & ONEPERLINE) {
134                         elem.push_back(curline);
135                         if (maxlen < curlen)
136                                 maxlen = curlen;
137                         irows++;
138                         continue;
139                 }
140                 for (p = curline, endp = curline + curlen; p < endp; p++) {
141                         if (*p == isep && multisep)
142                                 continue;       /* eat up column separators */
143                         if (*p == isep)         /* must be an empty column */
144                                 elem.push_back(blank);
145                         else                    /* store column entry */
146                                 elem.push_back(p);
147                         sp = p;
148                         while (p < endp && *p != isep)
149                                 p++;            /* find end of entry */
150                         *p = '\0';              /* mark end of entry */
151                         len = p - sp;
152                         if (maxlen < len)       /* update maxlen */
153                                 maxlen = len;
154                 }
155                 irows++;                        /* update row count */
156                 if (nullpad) {                  /* pad missing entries */
157                         padto = irows * icols;
158                         elem.resize(padto, blank);
159                 }
160         } while (get_line() != EOF);
161 }
162
163 static void
164 putfile(void)
165 {
166         size_t i, j, k;
167
168         if (flags & TRANSPOSE)
169                 for (i = 0; i < orows; i++) {
170                         for (j = i; j < elem.size(); j += orows)
171                                 prints(elem[j], (j - i) / orows);
172                         putchar('\n');
173                 }
174         else
175                 for (i = k = 0; i < orows; i++) {
176                         for (j = 0; j < ocols; j++, k++)
177                                 if (k < elem.size())
178                                         prints(elem[k], j);
179                         putchar('\n');
180                 }
181 }
182
183 static void
184 prints(char *s, int col)
185 {
186         int n;
187         char *p = s;
188
189         while (*p)
190                 p++;
191         n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - (p - s));
192         if (flags & RIGHTADJUST)
193                 while (n-- > 0)
194                         putchar(osep);
195         for (p = s; *p; p++)
196                 putchar(*p);
197         while (n-- > 0)
198                 putchar(osep);
199 }
200
201 static void
202 usage(void)
203 {
204         fprintf(stderr,
205                 "usage: rs [-[csCS][x][kKgGw][N]tTeEnyjhHmz] [rows [cols]]\n");
206         exit(1);
207 }
208
209 static void
210 prepfile(void)
211 {
212         size_t i, j;
213         size_t colw, max, n, orig_size, padto;
214
215         if (elem.empty())
216                 exit(0);
217         gutter += maxlen * propgutter / 100.0;
218         colw = maxlen + gutter;
219         if (flags & MTRANSPOSE) {
220                 orows = icols;
221                 ocols = irows;
222         }
223         else if (orows == 0 && ocols == 0) {    /* decide rows and cols */
224                 ocols = owidth / colw;
225                 if (ocols == 0) {
226                         warnx("display width %zu is less than column width %zu",
227                                         owidth, colw);
228                         ocols = 1;
229                 }
230                 if (ocols > elem.size())
231                         ocols = elem.size();
232                 orows = elem.size() / ocols + (elem.size() % ocols ? 1 : 0);
233         }
234         else if (orows == 0)                    /* decide on rows */
235                 orows = elem.size() / ocols + (elem.size() % ocols ? 1 : 0);
236         else if (ocols == 0)                    /* decide on cols */
237                 ocols = elem.size() / orows + (elem.size() % orows ? 1 : 0);
238         padto = orows * ocols;
239         orig_size = elem.size();
240         if (flags & RECYCLE) {
241                 for (i = 0; elem.size() < padto; i++)
242                         elem.push_back(elem[i % orig_size]);
243         }
244         if (!(colwidths = (short *) malloc(ocols * sizeof(short))))
245                 errx(1, "malloc");
246         if (flags & SQUEEZE) {
247                 if (flags & TRANSPOSE) {
248                         auto it = elem.begin();
249                         for (i = 0; i < ocols; i++) {
250                                 max = 0;
251                                 for (j = 0; it != elem.end() && j < orows; j++)
252                                         if ((n = strlen(*it++)) > max)
253                                                 max = n;
254                                 colwidths[i] = max + gutter;
255                         }
256                 } else {
257                         for (i = 0; i < ocols; i++) {
258                                 max = 0;
259                                 for (j = i; j < elem.size(); j += ocols)
260                                         if ((n = strlen(elem[j])) > max)
261                                                 max = n;
262                                 colwidths[i] = max + gutter;
263                         }
264                 }
265         }
266         /*      for (i = 0; i < orows; i++) {
267                         for (j = i; j < elem.size(); j += orows)
268                                 prints(elem[j], (j - i) / orows);
269                         putchar('\n');
270                 }
271         else {
272                 auto it = elem.begin();
273                 for (i = 0; i < orows; i++) {
274                         for (j = 0; j < ocols; j++)
275                                 prints(*it++, j);
276                         putchar('\n');
277                 }*/
278         else
279                 for (i = 0; i < ocols; i++)
280                         colwidths[i] = colw;
281         if (!(flags & NOTRIMENDCOL)) {
282                 if (flags & RIGHTADJUST)
283                         colwidths[0] -= gutter;
284                 else
285                         colwidths[ocols - 1] = 0;
286         }
287         /*for (i = 0; i < ocols; i++)
288                 warnx("%d is colwidths, nelem %zu", colwidths[i], elem.size());*/
289 }
290
291 #define BSIZE   (LINE_MAX * 2)
292 static char     ibuf[BSIZE];
293
294 static int
295 get_line(void)  /* get line; maintain curline, curlen; manage storage */
296 {
297         static  int putlength;
298         static  char *endblock = ibuf + BSIZE;
299         char *p;
300         int c, i;
301
302         if (irows == 0) {
303                 curline = ibuf;
304                 putlength = flags & DETAILSHAPE;
305         }
306         else if (skip <= 0) {                   /* don't waste storage */
307                 curline += curlen + 1;
308                 if (putlength) {        /* print length, recycle storage */
309                         printf(" %zu line %zu\n", curlen, irows);
310                         curline = ibuf;
311                 }
312         }
313         if (!putlength && endblock - curline < LINE_MAX + 1) { /* need storage */
314                 /*ww = endblock-curline; tt += ww;*/
315                 /*printf("#wasted %d total %d\n",ww,tt);*/
316                 if (!(curline = (char *) malloc(BSIZE)))
317                         errx(1, "file too large");
318                 endblock = curline + BSIZE;
319                 /*printf("#endb %d curline %d\n",endblock,curline);*/
320         }
321         for (p = curline, i = 0;; *p++ = c, i++) {
322                 if ((c = getchar()) == EOF)
323                         break;
324                 if (i >= LINE_MAX)
325                         errx(1, "maximum line length (%d) exceeded", LINE_MAX);
326                 if (c == '\n')
327                         break;
328         }
329         *p = '\0';
330         curlen = i;
331         return(c);
332 }
333
334 static void
335 getargs(int ac, char *av[])
336 {
337         long val;
338         int ch;
339
340         if (ac == 1) {
341                 flags |= NOARGS | TRANSPOSE;
342         }
343
344         while ((ch = getopt(ac, av, "C::EG:HK:S::Tc::eg:hjk:mns::tw:yz")) != -1)
345                 switch (ch) {
346                 case 'T':
347                         flags |= MTRANSPOSE;
348                         /* FALLTHROUGH */
349                 case 't':
350                         flags |= TRANSPOSE;
351                         break;
352                 case 'c':               /* input col. separator */
353                         flags |= ONEISEPONLY;
354                         /* FALLTHROUGH */
355                 case 's':               /* one or more allowed */
356                         if (optarg != NULL)
357                                 isep = *optarg;
358                         else
359                                 isep = '\t';    /* default is ^I */
360                         break;
361                 case 'C':
362                         flags |= ONEOSEPONLY;
363                         /* FALLTHROUGH */
364                 case 'S':
365                         if (optarg != NULL)
366                                 osep = *optarg;
367                         else
368                                 osep = '\t';    /* default is ^I */
369                         break;
370                 case 'w':               /* window width, default 80 */
371                         val = getnum(optarg);
372                         if (val <= 0)
373                                 errx(1, "width must be a positive integer");
374                         owidth = val;
375                         break;
376                 case 'K':                       /* skip N lines */
377                         flags |= SKIPPRINT;
378                         /* FALLTHROUGH */
379                 case 'k':                       /* skip, do not print */
380                         skip = getnum(optarg);
381                         if (skip < 1)
382                                 skip = 1;
383                         break;
384                 case 'm':
385                         flags |= NOTRIMENDCOL;
386                         break;
387                 case 'g':               /* gutter space */
388                         gutter = getnum(optarg);
389                         break;
390                 case 'G':
391                         propgutter = getnum(optarg);
392                         break;
393                 case 'e':               /* each line is an entry */
394                         flags |= ONEPERLINE;
395                         break;
396                 case 'E':
397                         flags |= ONEPERCHAR;
398                         break;
399                 case 'j':                       /* right adjust */
400                         flags |= RIGHTADJUST;
401                         break;
402                 case 'n':       /* null padding for missing values */
403                         flags |= NULLPAD;
404                         break;
405                 case 'y':
406                         flags |= RECYCLE;
407                         break;
408                 case 'H':                       /* print shape only */
409                         flags |= DETAILSHAPE;
410                         /* FALLTHROUGH */
411                 case 'h':
412                         flags |= SHAPEONLY;
413                         break;
414                 case 'z':                       /* squeeze col width */
415                         flags |= SQUEEZE;
416                         break;
417                 /*case 'p':
418                         ipagespace = atoi(optarg);      (default is 1)
419                         break;*/
420                 default:
421                         usage();
422                 }
423
424         av += optind;
425         ac -= optind;
426
427         /*if (!osep)
428                 osep = isep;*/
429         switch (ac) {
430 #if 0
431         case 3:
432                 opages = atoi(av[2]);
433                 /* FALLTHROUGH */
434 #endif
435         case 2:
436                 val = strtol(av[1], NULL, 10);
437                 if (val >= 0)
438                         ocols = val;
439                 /* FALLTHROUGH */
440         case 1:
441                 val = strtol(av[0], NULL, 10);
442                 if (val >= 0)
443                         orows = val;
444                 /* FALLTHROUGH */
445         case 0:
446                 break;
447         default:
448                 errx(1, "too many arguments");
449         }
450 }
451
452 static long
453 getnum(const char *p)
454 {
455         char *ep;
456         long val;
457
458         val = strtol(p, &ep, 10);
459         if (*ep != '\0')
460                 errx(1, "invalid integer %s", p);
461         return (val);
462 }