Explicitly write out inference rule for .c.o
[tabular.git] / src / parser.c
blob20d99eefac714eb8beae8b3e30fb4add6ee1d9d7
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>
39 #include "parser.h"
42 * Check for \r, \n, \r\n or EOF and consume it.
44 static int
45 endofline(FILE *fp, int c)
47 int eol = (c == '\r' || c == '\n');
48 if (c == '\r') {
49 c = getc(fp);
50 if (c != '\n' || c != EOF) {
51 ungetc(c, fp);
55 return (eol);
59 * Reads one line from the input file fp assuming that lines are terminated by
60 * \r, \n, \r\n or EOF.
61 * On success, returns a pointer to the line with terminator removed, otherwise
62 * 0 if EOF occurred.
64 * NOTE: reads at most LINE_MAX bytes. The caller is responsible for disposing
65 * the returned pointer.
67 char *
68 parser_readline(FILE *fp)
70 char *line;
71 size_t i;
72 int c;
74 line = calloc(LINE_MAX, 1);
75 if (line == 0) {
76 goto alloc_err;
79 for (i = 0, c = 0;
80 i < LINE_MAX - 1 && (c = getc(fp)) != EOF && !endofline(fp, c);
81 i++) {
82 line[i] = (char)c;
85 line[i] = '\0';
87 if (c == EOF && i == 0) {
88 free(line);
89 line = 0;
92 alloc_err:
93 return (line);
96 /* Returns a pointer to the next separator that ends the quoted field. */
97 static char *
98 advquoted(char *p, const char *sep)
100 size_t i, j, k;
102 for (i = j = 0; p[j] != '\0'; i++, j++) {
103 if (p[j] == '"' && p[++j] != '"') {
104 /* Copy up to next separator or \0 */
105 k = strcspn(p+j, sep);
106 memmove(p+i, p+j, k);
107 i += k;
108 j += k;
109 break;
111 p[i] = p[j];
113 p[i] = '\0';
114 return (p + j);
118 * Parses a line whose elements are separated by `sep`. Each element can contain
119 * quotes, which can in turn contain the separator character.
121 * On success, the number of fields parsed is returned which are contained in
122 * the `fields` parameter. On failure, either 0 or -ENOMEM is returned.
124 * NOTE: there's no upper bound on the number of elements that each line can
125 * have.
127 size_t
128 parser_parse(char *line, const char *sep, char **fields, int *status)
130 size_t nfields;
131 char *p, **newf;
132 char *sepp; /* pointer to temporary separator character */
133 int sepc; /* temporary separator character */
135 *status = 1;
136 nfields = 0;
137 if (line == 0 || line[0] == '\0') {
138 *status = ENODATA;
139 return (0);
141 p = line;
143 do {
144 if (nfields >= MAX_FIELDS) {
145 newf = realloc(fields,
146 MAX_FIELDS * 2 * sizeof(fields[0]));
147 if (newf == 0) {
148 *status = ENOMEM;
149 return (0);
151 fields = newf;
154 if (*p == '"') {
155 sepp = advquoted(++p, sep);
156 } else {
157 sepp = p + strcspn(p, sep);
159 sepc = sepp[0];
160 sepp[0] = '\0';
161 fields[nfields++] = p;
162 p = sepp + 1;
163 } while (sepc == sep[0]);
165 return (nfields);