Explicitly write out inference rule for .c.o
[tabular.git] / src / tabular.c
blob215a1e2a8a4d1da2b47049dfe47c8254bb0f08ef
1 /*-
2 * SPDX-License-Identifier: BSD-2-Clause
4 * Copyright (c) 2021 Alessio Chiapperini
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 * 1. Redistributions of source code must retain the above copyright
10 * notice, this list of conditions and the following disclaimer.
11 * 2. Redistributions in binary form must reproduce the above copyright
12 * notice, this list of conditions and the following disclaimer in the
13 * documentation and/or other materials provided with the distribution.
15 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND
16 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
17 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
18 * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
19 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
20 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
21 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
22 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
23 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
24 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
25 * SUCH DAMAGE.
28 #ifndef _POSIX_C_SOURCE
29 # define _POSIX_C_SOURCE 200112L
30 #elif _POSIX_C_SOURCE < 200112L
31 # error incompatible _POSIX_C_SOURCE level
32 #endif
34 #include <errno.h>
35 #include <limits.h>
36 #include <stdlib.h>
37 #include <string.h>
38 #include <unistd.h>
40 #include "parser.h"
42 struct tbl {
43 char **list; /* Columns */
44 int *width; /* Width of each column */
45 size_t cols; /* Number of columns */
48 static char **list; /* Array of records */
49 static size_t entries; /* Number of records */
50 static size_t maxentries = BUFSIZ; /* Upper bound on number of records */
52 static void
53 usage(void)
55 (void)fprintf(stderr, "usage: tabular [-s sep] [files ...]\n");
56 exit(1);
59 static int
60 input(const char *path)
62 char **nlist = 0;
63 FILE *fp = stdin;
64 char *buf;
65 int ret = 1;
67 if (path[0] != '-') {
68 fp = fopen(path, "r");
69 if (fp == 0) {
70 ret = 0;
71 perror("tabular");
72 goto open_err;
76 if (list == 0) {
77 list = calloc(maxentries, sizeof *list);
78 if (list == 0) {
79 ret = 0;
80 perror("tabular");
81 goto alloc_err;
85 while ((buf = parser_readline(fp)) != 0) {
86 if (entries == maxentries) {
87 nlist = realloc(list, (maxentries + BUFSIZ) *
88 sizeof(*nlist));
90 if (nlist == 0) {
91 ret = 0;
92 perror("tabular");
93 goto alloc_err;
96 (void)memset(nlist + maxentries, 0, (sizeof *nlist) *
97 BUFSIZ);
98 maxentries += BUFSIZ;
99 list = nlist;
101 list[entries++] = buf;
104 alloc_err:
105 (void)fclose(fp);
106 open_err:
107 return (ret);
110 static int
111 maketbl(const char *sep)
113 struct tbl *t, *tbl;
114 char **cols, **ncols;
115 char **lp;
116 int *width, *nwidth;
117 size_t cnt;
118 size_t coloff;
119 size_t maxcols;
120 size_t nfields;
121 int pstat;
122 int ret;
124 ret = 1;
125 maxcols = MAX_FIELDS;
126 t = tbl = calloc(entries, sizeof *t);
127 cols = calloc(maxcols, sizeof *cols);
128 width = calloc(maxcols, sizeof *width);
129 if (tbl == 0 || cols == 0 || width == 0) {
130 ret = 0;
131 perror("tabular");
132 goto alloc_err;
135 lp = list;
136 for (cnt = 0, nfields = 0; cnt < entries; cnt++, lp++, t++) {
137 nfields = parser_parse(list[cnt], sep, cols, &pstat);
139 if (nfields > maxcols) {
140 ncols = realloc(cols, (maxcols + MAX_FIELDS) *
141 (sizeof *ncols));
142 nwidth = realloc(width, (maxcols + MAX_FIELDS) *
143 (sizeof *nwidth));
145 if (ncols == 0 || nwidth == 0) {
146 ret = 1;
147 perror("tabular");
148 goto alloc_err;
151 cols = ncols;
152 width = nwidth;
154 (void)memset(cols + maxcols, 0, MAX_FIELDS *
155 (sizeof *cols));
156 (void)memset(width + maxcols, 0, MAX_FIELDS *
157 (sizeof *width));
159 maxcols += MAX_FIELDS;
162 if (pstat == ENOMEM) {
163 ret = 1;
164 errno = pstat;
165 perror("tabular");
166 errno = 0;
167 goto parse_err;
170 t->list = calloc(nfields, sizeof *(t->list));
171 t->width = calloc(nfields, sizeof *(t->width));
172 t->cols = nfields;
173 if (t->list == 0 || t->width == 0) {
174 ret = 1;
175 perror("tabular");
176 goto alloc_err;
179 for (coloff = 0; coloff < nfields; coloff++) {
180 t->list[coloff] = cols[coloff];
181 t->width[coloff] = (int)strlen(cols[coloff]);
183 if (t->width[coloff] > width[coloff]) {
184 width[coloff] = t->width[coloff];
189 for (cnt = 0, t = tbl; cnt < entries; cnt++, t++) {
190 if (t != 0) {
191 for (coloff = 0; coloff < t->cols; coloff++) {
192 if (coloff < t->cols - 1) {
193 (void)printf("%s%*s", t->list[coloff],
194 width[coloff] - t->width[coloff] +
195 2, " ");
196 } else {
197 (void)printf("%s\n", t->list[coloff]);
203 parse_err:
204 alloc_err:
205 for (cnt = 0, t = tbl; cnt < entries; cnt++, t++) {
206 free(t->list);
207 free(t->width);
209 free(tbl);
210 free(cols);
211 free(width);
212 return (ret);
215 static void
216 freelist(void)
218 for (size_t i = 0; i < maxentries; i++) {
219 free(list[i]);
220 list[i] = 0;
222 free(list);
223 list = 0;
227 main(int argc, char *argv[])
229 int opt;
230 char sep[] = ",";
231 size_t len;
233 while ((opt = getopt(argc, argv, "s:")) != -1) {
234 switch (opt) {
235 case 's':
236 len = strlen(optarg);
237 if (len > 1) {
238 errno = EINVAL;
239 perror("tabular");
240 return (1);
242 (void)memcpy(sep, optarg, len);
243 break;
244 case '?':
245 /* FALLTHROUGH */
246 default:
247 usage();
251 argc -= optind;
252 argv += optind;
254 char *def[] = { "-" };
255 if (argc == 0) {
256 argc = 1;
257 argv = def;
260 for (int i = 0; i < argc; i++) {
261 if (input(argv[i]) == 0) {
262 goto cleanup;
264 if (maketbl(sep) == 0) {
265 goto cleanup;
267 freelist();
270 return (0);
271 /* UNREACHABLE*/
272 cleanup:
273 freelist();
274 return (1);