GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/rs/rs.c Lines: 0 217 0.0 %
Date: 2016-12-06 Branches: 0 199 0.0 %

Line Branch Exec Source
1
/*	$OpenBSD: rs.c,v 1.30 2015/12/03 12:23:15 schwarze Exp $	*/
2
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 <ctype.h>
39
#include <err.h>
40
#include <errno.h>
41
#include <limits.h>
42
#include <locale.h>
43
#include <stdio.h>
44
#include <stdlib.h>
45
#include <string.h>
46
#include <unistd.h>
47
48
struct	entry {
49
	int	 w;  /* Display width. */
50
	char	*s;  /* Multibyte string. */
51
};
52
53
long	flags;
54
#define	TRANSPOSE	000001
55
#define	MTRANSPOSE	000002
56
#define	ONEPERLINE	000004
57
#define	ONEISEPONLY	000010
58
#define	ONEOSEPONLY	000020
59
#define	NOTRIMENDCOL	000040
60
#define	SQUEEZE		000100
61
#define	SHAPEONLY	000200
62
#define	DETAILSHAPE	000400
63
#define	RIGHTADJUST	001000
64
#define	NULLPAD		002000
65
#define	RECYCLE		004000
66
#define	SKIPPRINT	010000
67
#define ONEPERCHAR	0100000
68
#define NOARGS		0200000
69
70
short	*colwidths;
71
int	nelem;
72
struct entry *elem;
73
struct entry *endelem;
74
char	*curline;
75
int	allocsize = BUFSIZ;
76
int	irows, icols;
77
int	orows, ocols;
78
int	maxwidth;
79
int	skip;
80
int	propgutter;
81
char	isep = ' ', osep = ' ';
82
int	owidth = 80, gutter = 2;
83
84
int	  mbsavis(char **, const char *);
85
86
void	  usage(void);
87
void	  getargs(int, char *[]);
88
void	  getfile(void);
89
int	  get_line(void);
90
struct entry *getptrs(struct entry *);
91
void	  prepfile(void);
92
void	  prints(struct entry *, int);
93
void	  putfile(void);
94
95
#define INCR(ep) do {			\
96
	if (++ep >= endelem)		\
97
		ep = getptrs(ep);	\
98
} while(0)
99
100
int
101
main(int argc, char *argv[])
102
{
103
	setlocale(LC_CTYPE, "");
104
105
	if (pledge("stdio wpath cpath rpath", NULL) == -1)
106
		err(1, "pledge");
107
108
	getargs(argc, argv);
109
	getfile();
110
	if (flags & SHAPEONLY) {
111
		printf("%d %d\n", irows, icols);
112
		exit(0);
113
	}
114
	prepfile();
115
	putfile();
116
	exit(0);
117
}
118
119
void
120
getfile(void)
121
{
122
	const char delim[2] = { isep, '\0' };
123
	char *p;
124
	struct entry *ep;
125
	int multisep = (flags & ONEISEPONLY ? 0 : 1);
126
	int nullpad = flags & NULLPAD;
127
	struct entry *padto;
128
129
	curline = NULL;
130
	while (skip--) {
131
		if (get_line() == EOF)
132
			return;
133
		if (flags & SKIPPRINT)
134
			puts(curline);
135
	}
136
	if (get_line() == EOF)
137
		return;
138
	if (flags & NOARGS && strlen(curline) < (size_t)owidth)
139
		flags |= ONEPERLINE;
140
	if (flags & ONEPERLINE)
141
		icols = 1;
142
	else				/* count cols on first line */
143
		for (p = curline; *p != '\0'; p++) {
144
			if (*p == isep && multisep)
145
				continue;
146
			icols++;
147
			while (*p && *p != isep)
148
				p++;
149
		}
150
	ep = getptrs(NULL);
151
	p = curline;
152
	do {
153
		if (flags & ONEPERLINE) {
154
			ep->w = mbsavis(&ep->s, curline);
155
			if (maxwidth < ep->w)
156
				maxwidth = ep->w;
157
			INCR(ep);		/* prepare for next entry */
158
			irows++;
159
			continue;
160
		}
161
		p = curline;
162
		while (p != NULL && *p != '\0') {
163
			if (*p == isep) {
164
				p++;
165
				if (multisep)
166
					continue;
167
				ep->s = "";	/* empty column */
168
				ep->w = 0;
169
			} else
170
				ep->w = mbsavis(&ep->s, strsep(&p, delim));
171
			if (maxwidth < ep->w)
172
				maxwidth = ep->w;
173
			INCR(ep);		/* prepare for next entry */
174
		}
175
		irows++;			/* update row count */
176
		if (nullpad) {			/* pad missing entries */
177
			padto = elem + irows * icols;
178
			while (ep < padto) {
179
				ep->s = "";
180
				ep->w = 0;
181
				INCR(ep);
182
			}
183
		}
184
	} while (get_line() != EOF);
185
	nelem = ep - elem;
186
}
187
188
void
189
putfile(void)
190
{
191
	struct entry *ep;
192
	int i, j, n;
193
194
	ep = elem;
195
	if (flags & TRANSPOSE) {
196
		for (i = 0; i < orows; i++) {
197
			for (j = i; j < nelem; j += orows)
198
				prints(ep + j, (j - i) / orows);
199
			putchar('\n');
200
		}
201
	} else {
202
		for (n = 0, i = 0; i < orows && n < nelem; i++) {
203
			for (j = 0; j < ocols; j++) {
204
				if (n++ >= nelem)
205
					break;
206
				prints(ep++, j);
207
			}
208
			putchar('\n');
209
		}
210
	}
211
}
212
213
void
214
prints(struct entry *ep, int col)
215
{
216
	int n;
217
218
	n = (flags & ONEOSEPONLY ? 1 : colwidths[col] - ep->w);
219
	if (flags & RIGHTADJUST)
220
		while (n-- > 0)
221
			putchar(osep);
222
	fputs(ep->s, stdout);
223
	while (n-- > 0)
224
		putchar(osep);
225
}
226
227
void
228
usage(void)
229
{
230
	extern char *__progname;
231
232
	fprintf(stderr,
233
	    "usage: %s [-CcSs[x]] [-GgKkw N] [-EeHhjmnTtyz] [rows [cols]]\n",
234
	    __progname);
235
	exit(1);
236
}
237
238
void
239
prepfile(void)
240
{
241
	struct entry *ep;
242
	int  i;
243
	int  j;
244
	struct entry *lp;
245
	int colw;
246
	int max = 0;
247
	int n;
248
249
	if (!nelem)
250
		exit(0);
251
	gutter += maxwidth * propgutter / 100.0;
252
	colw = maxwidth + gutter;
253
	if (flags & MTRANSPOSE) {
254
		orows = icols;
255
		ocols = irows;
256
	}
257
	else if (orows == 0 && ocols == 0) {	/* decide rows and cols */
258
		ocols = owidth / colw;
259
		if (ocols == 0) {
260
			warnx("Display width %d is less than column width %d",
261
			    owidth, colw);
262
			ocols = 1;
263
		}
264
		if (ocols > nelem)
265
			ocols = nelem;
266
		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
267
	}
268
	else if (orows == 0)			/* decide on rows */
269
		orows = nelem / ocols + (nelem % ocols ? 1 : 0);
270
	else if (ocols == 0)			/* decide on cols */
271
		ocols = nelem / orows + (nelem % orows ? 1 : 0);
272
	while ((lp = elem + orows * ocols) > endelem)
273
	     (void)getptrs(NULL);
274
	if (flags & RECYCLE) {
275
		for (ep = elem + nelem; ep < lp; ep++)
276
			memcpy(ep, ep - nelem, sizeof(*ep));
277
		nelem = lp - elem;
278
	}
279
	if (!(colwidths = calloc(ocols, sizeof(short))))
280
		errx(1, "malloc:  No gutter space");
281
	if (flags & SQUEEZE) {
282
		for (ep = elem, i = 0; i < ocols; i++) {
283
			max = 0;
284
			if (flags & TRANSPOSE) {
285
				for (j = 0; j < orows; j++, ep++)
286
					if (ep->w > max)
287
						max = ep->w;
288
			} else {
289
				for (j = i; j < nelem; j += ocols)
290
					if (ep[j].w > max)
291
						max = ep[j].w;
292
			}
293
			colwidths[i] = max + gutter;
294
		}
295
	} else {
296
		for (i = 0; i < ocols; i++)
297
			colwidths[i] = colw;
298
	}
299
	if (!(flags & NOTRIMENDCOL)) {
300
		if (flags & RIGHTADJUST)
301
			colwidths[0] -= gutter;
302
		else
303
			colwidths[ocols - 1] = 0;
304
	}
305
	n = orows * ocols;
306
	if (n > nelem && (flags & RECYCLE))
307
		nelem = n;
308
}
309
310
int
311
get_line(void)
312
{
313
	static	size_t	 cursz;
314
	static	ssize_t	 curlen;
315
316
	if (irows > 0 && flags & DETAILSHAPE)
317
		printf(" %zd line %d\n", curlen, irows);
318
319
	if ((curlen = getline(&curline, &cursz, stdin)) == EOF) {
320
		if (ferror(stdin))
321
			err(1, NULL);
322
		return EOF;
323
	}
324
	if (curlen > 0 && curline[curlen - 1] == '\n')
325
		curline[--curlen] = '\0';
326
327
	return 0;
328
}
329
330
struct entry *
331
getptrs(struct entry *sp)
332
{
333
	struct entry *p;
334
	int newsize;
335
336
	newsize = allocsize * 2;
337
	p = reallocarray(elem, newsize, sizeof(*p));
338
	if (p == NULL)
339
		err(1, "no memory");
340
341
	allocsize = newsize;
342
	sp = sp == NULL ? p : p + (sp - elem);
343
	elem = p;
344
	endelem = elem + allocsize;
345
	return(sp);
346
}
347
348
void
349
getargs(int ac, char *av[])
350
{
351
	int ch;
352
	const char *errstr;
353
354
	if (ac == 1)
355
		flags |= NOARGS | TRANSPOSE;
356
	while ((ch = getopt(ac, av, "c::C::s::S::k:K:g:G:w:tTeEnyjhHmz")) != -1) {
357
		switch (ch) {
358
		case 'T':
359
			flags |= MTRANSPOSE;
360
			/* FALLTHROUGH */
361
		case 't':
362
			flags |= TRANSPOSE;
363
			break;
364
		case 'c':		/* input col. separator */
365
			flags |= ONEISEPONLY;
366
			/* FALLTHROUGH */
367
		case 's':		/* one or more allowed */
368
			if (optarg == NULL)
369
				isep = '\t';	/* default is ^I */
370
			else if (optarg[1] != '\0')
371
				usage();	/* single char only */
372
			else
373
				isep = *optarg;
374
			break;
375
		case 'C':
376
			flags |= ONEOSEPONLY;
377
			/* FALLTHROUGH */
378
		case 'S':
379
			if (optarg == NULL)
380
				osep = '\t';	/* default is ^I */
381
			else if (optarg[1] != '\0')
382
				usage();	/* single char only */
383
			else
384
				osep = *optarg;
385
			break;
386
		case 'w':		/* window width, default 80 */
387
			owidth = strtonum(optarg, 1, INT_MAX, &errstr);
388
			if (errstr) {
389
				warnx("width %s", errstr);
390
				usage();
391
			}
392
			break;
393
		case 'K':			/* skip N lines */
394
			flags |= SKIPPRINT;
395
			/* FALLTHROUGH */
396
		case 'k':			/* skip, do not print */
397
			skip = strtonum(optarg, 0, INT_MAX, &errstr);
398
			if (errstr) {
399
				warnx("skip value %s", errstr);
400
				usage();
401
			}
402
			if (skip == 0)
403
				skip = 1;
404
			break;
405
		case 'm':
406
			flags |= NOTRIMENDCOL;
407
			break;
408
		case 'g':		/* gutter width */
409
			gutter = strtonum(optarg, 0, INT_MAX, &errstr);
410
			if (errstr) {
411
				warnx("gutter width %s", errstr);
412
				usage();
413
			}
414
			break;
415
		case 'G':
416
			propgutter = strtonum(optarg, 0, INT_MAX, &errstr);
417
			if (errstr) {
418
				warnx("gutter proportion %s", errstr);
419
				usage();
420
			}
421
			break;
422
		case 'e':		/* each line is an entry */
423
			flags |= ONEPERLINE;
424
			break;
425
		case 'E':
426
			flags |= ONEPERCHAR;
427
			break;
428
		case 'j':			/* right adjust */
429
			flags |= RIGHTADJUST;
430
			break;
431
		case 'n':	/* null padding for missing values */
432
			flags |= NULLPAD;
433
			break;
434
		case 'y':
435
			flags |= RECYCLE;
436
			break;
437
		case 'H':			/* print shape only */
438
			flags |= DETAILSHAPE;
439
			/* FALLTHROUGH */
440
		case 'h':
441
			flags |= SHAPEONLY;
442
			break;
443
		case 'z':			/* squeeze col width */
444
			flags |= SQUEEZE;
445
			break;
446
		default:
447
			usage();
448
		}
449
	}
450
	ac -= optind;
451
	av += optind;
452
453
	switch (ac) {
454
	case 2:
455
		ocols = strtonum(av[1], 0, INT_MAX, &errstr);
456
		if (errstr) {
457
			warnx("columns value %s", errstr);
458
			usage();
459
		}
460
		/* FALLTHROUGH */
461
	case 1:
462
		orows = strtonum(av[0], 0, INT_MAX, &errstr);
463
		if (errstr) {
464
			warnx("columns value %s", errstr);
465
			usage();
466
		}
467
		/* FALLTHROUGH */
468
	case 0:
469
		break;
470
	default:
471
		usage();
472
	}
473
}