1 | /* |
---|
2 | o---------------------------------------------------------------------o |
---|
3 | | |
---|
4 | | Numdiff |
---|
5 | | |
---|
6 | | Copyright (c) 2012+ laurent.deniau@cern.ch |
---|
7 | | Gnu General Public License |
---|
8 | | |
---|
9 | o---------------------------------------------------------------------o |
---|
10 | |
---|
11 | Purpose: |
---|
12 | create constraints content |
---|
13 | print, scan constraints from file |
---|
14 | |
---|
15 | o---------------------------------------------------------------------o |
---|
16 | */ |
---|
17 | |
---|
18 | #include <assert.h> |
---|
19 | #include <string.h> |
---|
20 | #include <ctype.h> |
---|
21 | #include "constraint.h" |
---|
22 | #include "utils.h" |
---|
23 | #include "error.h" |
---|
24 | #include "args.h" |
---|
25 | |
---|
26 | #define T struct constraint |
---|
27 | |
---|
28 | // ----- constants |
---|
29 | |
---|
30 | const char * const eps_cmd_cstr[] = { |
---|
31 | [eps_invalid] = "invalid", |
---|
32 | [eps_dig] = "dig", |
---|
33 | [eps_rel] = "rel", |
---|
34 | [eps_rel|eps_dig] = "rel&dig", |
---|
35 | [eps_abs] = "abs", |
---|
36 | [eps_abs|eps_dig] = "abs&dig", |
---|
37 | [eps_abs|eps_rel] = "abs&rel", |
---|
38 | [eps_abs|eps_rel|eps_dig] = "abs&rel&dig", |
---|
39 | [eps_equ] = "equ", |
---|
40 | [eps_ign] = "ign", |
---|
41 | [eps_omit] = "omit", |
---|
42 | [eps_skip] = "skip", |
---|
43 | [eps_goto] = "goto", |
---|
44 | }; |
---|
45 | |
---|
46 | // ----- private |
---|
47 | |
---|
48 | static void |
---|
49 | printSlc(const struct slice *s, FILE *out) |
---|
50 | { |
---|
51 | if (slice_first(s) <= 1 && slice_isInfinite(s) && slice_isDense(s)) { |
---|
52 | putc('*', out); |
---|
53 | return; |
---|
54 | } |
---|
55 | |
---|
56 | fprintf(out, "%u", slice_first(s)); |
---|
57 | |
---|
58 | if (slice_isUnit(s)) return; |
---|
59 | |
---|
60 | if (slice_isInfinite(s)) { |
---|
61 | putc('-', out); |
---|
62 | putc('$', out); |
---|
63 | } else |
---|
64 | fprintf(out, "-%u", slice_last(s)); |
---|
65 | |
---|
66 | if (slice_stride(s) != 1) |
---|
67 | fprintf(out, "/%u", slice_stride(s)); |
---|
68 | } |
---|
69 | |
---|
70 | static int |
---|
71 | readSlcOrRng(struct slice *s, FILE *in) |
---|
72 | { |
---|
73 | int c, r = 1; |
---|
74 | uint first=0, last=0, stride=1; |
---|
75 | |
---|
76 | // skip spaces |
---|
77 | while((c = getc(in)) != EOF && isblank(c)) ; |
---|
78 | if (c == EOF) return EOF; |
---|
79 | |
---|
80 | // ('*'|num) |
---|
81 | if (c == '*') { last = UINT_MAX; goto finish; } |
---|
82 | else { |
---|
83 | ungetc(c, in); |
---|
84 | if (fscanf(in, "%u", &first) != 1) return EOF; |
---|
85 | } |
---|
86 | |
---|
87 | // (':'|'-')? |
---|
88 | c = getc(in); |
---|
89 | if (c == ':') r = 0; // slice |
---|
90 | else if (c == '-') ; // range |
---|
91 | else { ungetc(c, in); last = first; goto finish; } |
---|
92 | |
---|
93 | // ('$'|num) |
---|
94 | c = getc(in); |
---|
95 | if (c == '$') last = UINT_MAX; |
---|
96 | else { |
---|
97 | ungetc(c, in); |
---|
98 | if (fscanf(in, "%u", &last) != 1) return EOF; |
---|
99 | } |
---|
100 | |
---|
101 | // ('/'num)? |
---|
102 | c = getc(in); |
---|
103 | if (c != '/') { ungetc(c, in); stride = 1; goto finish; } |
---|
104 | else |
---|
105 | if (fscanf(in, "%u", &stride) != 1) return EOF; |
---|
106 | |
---|
107 | finish: |
---|
108 | if (r) |
---|
109 | *s = slice_initLastStride(first, last, stride); |
---|
110 | else |
---|
111 | *s = slice_initSizeStride(first, last, stride); |
---|
112 | |
---|
113 | trace("<-readSlcOrRng %u%c%u/%u", first, r ? '-' : ':', last, stride); |
---|
114 | |
---|
115 | return 0; |
---|
116 | } |
---|
117 | |
---|
118 | static int |
---|
119 | readEps(struct eps *e, FILE *in, int row) |
---|
120 | { |
---|
121 | int c = 0, n = 0, cmd = eps_invalid; |
---|
122 | char str[16]; |
---|
123 | |
---|
124 | while (1) { |
---|
125 | // parse next constraint |
---|
126 | *str = 0; |
---|
127 | n = fscanf(in, "%*[ \t]%10[^= \t\n\r!#]", str); |
---|
128 | if (n == EOF || *str == 0) break; |
---|
129 | |
---|
130 | if (strcmp(str, "skip") == 0) { |
---|
131 | cmd |= eps_skip; trace("[%d] skip", row); |
---|
132 | } |
---|
133 | else if (strcmp(str, "ign") == 0) { |
---|
134 | cmd |= eps_ign; trace("[%d] ign", row); |
---|
135 | } |
---|
136 | else if (strcmp(str, "equ") == 0) { |
---|
137 | cmd |= eps_equ; trace("[%d] equ", row); |
---|
138 | } |
---|
139 | else if (strcmp(str, "either") == 0) { |
---|
140 | e->either = 1; trace("[%d] either", row); |
---|
141 | } |
---|
142 | else if (strcmp(str, "dig") == 0 && (n = fscanf(in, "=%lf", &e->dig)) == 1) { |
---|
143 | cmd |= eps_dig; trace("[%d] dig=%g", row, e->dig); |
---|
144 | ensure(e->dig > 1.0, "invalid digital error (%s.cfg:%d)", option.indexed_filename, row); |
---|
145 | } |
---|
146 | else if (strcmp(str, "rel") == 0 && (n = fscanf(in, "=%lf", &e->rel)) == 1) { |
---|
147 | cmd |= eps_rel; trace("[%d] rel=%g", row, e->rel); |
---|
148 | ensure(e->rel > 0.0 && (option.largerr || e->rel < 1.0), "invalid relative constraint (%s.cfg:%d)", option.indexed_filename, row); |
---|
149 | } |
---|
150 | else if (strcmp(str, "abs") == 0 && (n = fscanf(in, "=%lf", &e->abs)) == 1) { |
---|
151 | cmd |= eps_abs; trace("[%d] abs=%g", row, e->abs); |
---|
152 | ensure(e->abs > 0.0 && (option.largerr || e->abs < 1.0), "invalid absolute constraint (%s.cfg:%d)", option.indexed_filename, row); |
---|
153 | } |
---|
154 | else if (strcmp(str, "omit") == 0 && (n = fscanf(in, "='%48[^']'", e->tag)) == 1) { |
---|
155 | cmd |= eps_omit | eps_equ; e->tag[sizeof e->tag-1] = 0; |
---|
156 | trace("[%d] omit='%s'", row, e->tag); |
---|
157 | ensure(*e->tag, "invalid empty tag (%s.cfg:%d)", option.indexed_filename, row); |
---|
158 | } |
---|
159 | else if (strcmp(str, "goto") == 0 && (n = fscanf(in, "='%48[^']'", e->tag)) == 1) { |
---|
160 | cmd |= eps_goto; e->tag[sizeof e->tag-1] = 0; |
---|
161 | trace("[%d] goto='%s'", row, e->tag); |
---|
162 | ensure(*e->tag, "invalid empty tag (%s.cfg:%d)", option.indexed_filename, row); |
---|
163 | } |
---|
164 | else { |
---|
165 | trace("[%d] invalid '%s'", row, str); |
---|
166 | cmd = eps_invalid; |
---|
167 | break; |
---|
168 | } |
---|
169 | |
---|
170 | // next char |
---|
171 | ungetc((c = getc(in)), in); |
---|
172 | if (c == EOF || (isspace(c) && !isblank(c)) || c == '#' || c == '!') break; |
---|
173 | } |
---|
174 | |
---|
175 | e->cmd = (enum eps_cmd)cmd; // because of icc spurious warnings |
---|
176 | |
---|
177 | trace("<-readEps cmd = %d, str = '%s', c = '%c'", cmd, str, c); |
---|
178 | |
---|
179 | return cmd == eps_invalid || n == EOF ? EOF : 0; |
---|
180 | } |
---|
181 | |
---|
182 | // ----- interface |
---|
183 | |
---|
184 | void |
---|
185 | constraint_print(const T* cst, FILE *out) |
---|
186 | { |
---|
187 | if (!out) out = stdout; |
---|
188 | if (!cst) { fprintf(out, "(null)"); return; } |
---|
189 | |
---|
190 | printSlc(&cst->row, out); |
---|
191 | putc(' ', out); |
---|
192 | printSlc(&cst->col, out); |
---|
193 | putc(' ', out); |
---|
194 | |
---|
195 | if (cst->eps.either) fprintf(out, "either "); |
---|
196 | if (cst->eps.cmd & eps_dig) fprintf(out, "dig=%g ", cst->eps.dig); |
---|
197 | if (cst->eps.cmd & eps_rel) fprintf(out, "rel=%g ", cst->eps.rel); |
---|
198 | if (cst->eps.cmd & eps_abs) fprintf(out, "abs=%g ", cst->eps.abs); |
---|
199 | if (cst->eps.cmd & eps_equ) fprintf(out, "equ "); |
---|
200 | if (cst->eps.cmd & eps_ign) fprintf(out, "ign "); |
---|
201 | if (cst->eps.cmd & eps_omit) fprintf(out, "omit='%s' ", cst->eps.tag); |
---|
202 | if (cst->eps.cmd & eps_skip) fprintf(out, "skip "); |
---|
203 | if (cst->eps.cmd & eps_goto) fprintf(out, "goto='%s' ", cst->eps.tag); |
---|
204 | } |
---|
205 | |
---|
206 | void |
---|
207 | constraint_scan(T* cst, FILE *in, int *row) |
---|
208 | { |
---|
209 | int c; |
---|
210 | assert(cst && row); |
---|
211 | |
---|
212 | *cst = (T){ .eps.cmd = (enum eps_cmd)eps_invalid }; // because of icc spurious warnings |
---|
213 | |
---|
214 | if (!in) in = stdin; |
---|
215 | |
---|
216 | retry: |
---|
217 | |
---|
218 | while((c = getc(in)) != EOF && isblank(c)) ; |
---|
219 | |
---|
220 | // end of file |
---|
221 | if (c == EOF) return; |
---|
222 | |
---|
223 | ungetc(c, in); |
---|
224 | |
---|
225 | // comment or empty line |
---|
226 | if (c == '\n' || c == '\r' || c == '#' || c == '!') { |
---|
227 | if (skipLine(in, 0) == '\n') ++*row; |
---|
228 | goto retry; |
---|
229 | } |
---|
230 | |
---|
231 | cst->line = *row; |
---|
232 | ensure(readSlcOrRng(&cst->row, in ) != EOF, "invalid row range (%s.cfg:%d)" , option.indexed_filename, *row); |
---|
233 | ensure(readSlcOrRng(&cst->col, in ) != EOF, "invalid column range (%s.cfg:%d)", option.indexed_filename, *row); |
---|
234 | ensure(readEps (&cst->eps, in, *row) != EOF, "invalid constraint or command (%s.cfg:%d)", option.indexed_filename, *row); |
---|
235 | if (skipLine(in, 0) == '\n') ++*row; |
---|
236 | } |
---|
237 | |
---|