source: git/src/readval.c @ 2c1384a

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 2c1384a was 7926772, checked in by Olly Betts <olly@…>, 18 years ago

Update German translation; change extend to use warning_in_file, etc.

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@3145 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

  • Property mode set to 100644
File size: 12.0 KB
Line 
1/* readval.c
2 * Routines to read a prefix or number from the current input file
3 * Copyright (C) 1991-2003,2005 Olly Betts
4 *
5 * This program is free software; you can redistribute it and/or modify
6 * it under the terms of the GNU General Public License as published by
7 * the Free Software Foundation; either version 2 of the License, or
8 * (at your option) any later version.
9 *
10 * This program is distributed in the hope that it will be useful,
11 * but WITHOUT ANY WARRANTY; without even the implied warranty of
12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
14 *
15 * You should have received a copy of the GNU General Public License
16 * along with this program; if not, write to the Free Software
17 * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA  02111-1307  USA
18 */
19
20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
23
24#include <limits.h>
25#include <stddef.h> /* for offsetof */
26
27#include "cavern.h"
28#include "debug.h"
29#include "filename.h"
30#include "message.h"
31#include "readval.h"
32#include "datain.h"
33#include "netbits.h"
34#include "osalloc.h"
35#include "str.h"
36
37#ifdef HAVE_SETJMP_H
38# define LONGJMP(JB) longjmp((JB), 1)
39#else
40# define LONGJMP(JB) exit(1)
41#endif
42
43int root_depr_count = 0;
44
45/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
46static prefix *
47read_prefix_(bool f_optional, bool fSurvey, bool fSuspectTypo, bool fAllowRoot)
48{
49   prefix *back_ptr, *ptr;
50   char *name;
51   size_t name_len = 32;
52   size_t i;
53   bool fNew;
54   bool fImplicitPrefix = fTrue;
55   int depth = -1;
56
57   skipblanks();
58#ifndef NO_DEPRECATED
59   if (isRoot(ch)) {
60      if (!fAllowRoot) {
61         compile_error_skip(/*ROOT is deprecated*/25);
62         LONGJMP(file.jbSkipLine);
63      }
64      if (root_depr_count < 5) {
65         compile_warning(/*ROOT is deprecated*/25);
66         if (++root_depr_count == 5)
67            compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
68      }
69      nextch();
70      ptr = root;
71      if (!isNames(ch)) {
72         if (!isSep(ch)) return ptr;
73         /* Allow optional SEPARATOR after ROOT */
74         nextch();
75      }
76      fImplicitPrefix = fFalse;
77   } else {
78      ptr = pcs->Prefix;
79   }
80#else
81   ptr = pcs->Prefix;
82#endif
83
84   i = 0;
85   name = NULL;
86   do {
87      fNew = fFalse;
88      if (isSep(ch)) fImplicitPrefix = fFalse;
89      if (name == NULL) {
90         /* Need a new name buffer */
91         name = osmalloc(name_len);
92      }
93      /* i==0 iff this is the first pass */
94      if (i) {
95         i = 0;
96         nextch();
97      }
98      while (isNames(ch)) {
99         if (i < pcs->Truncate) {
100            /* truncate name */
101            name[i++] = (pcs->Case == LOWER ? tolower(ch) :
102                         (pcs->Case == OFF ? ch : toupper(ch)));
103            if (i >= name_len) {
104               name_len = name_len + name_len;
105               name = osrealloc(name, name_len);
106            }
107         }
108         nextch();
109      }
110      if (i == 0) {
111         osfree(name);
112         if (!f_optional) {
113            if (isEol(ch)) {
114               if (fSurvey) {
115                  compile_error_skip(/*Expecting survey name*/89);
116               } else {
117                  compile_error_skip(/*Expecting station name*/28);
118               }
119            } else {
120               compile_error_skip(/*Character `%c' not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch);
121            }
122            LONGJMP(file.jbSkipLine);
123         }
124         return (prefix *)NULL;
125      }
126
127      name[i++] = '\0';
128
129      back_ptr = ptr;
130      ptr = ptr->down;
131      if (ptr == NULL) {
132         /* Special case first time around at each level */
133         name = osrealloc(name, i);
134         ptr = osnew(prefix);
135         ptr->ident = name;
136         name = NULL;
137         ptr->right = ptr->down = NULL;
138         ptr->pos = NULL;
139         ptr->shape = 0;
140         ptr->stn = NULL;
141         ptr->up = back_ptr;
142         ptr->filename = NULL;
143         ptr->min_export = ptr->max_export = 0;
144         ptr->sflags = BIT(SFLAGS_SURVEY);
145         if (fSuspectTypo && !fImplicitPrefix)
146            ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
147         back_ptr->down = ptr;
148         fNew = fTrue;
149      } else {
150         /* Use caching to speed up adding an increasing sequence to a
151          * large survey */
152         static prefix *cached_survey = NULL, *cached_station = NULL;
153         prefix *ptrPrev = NULL;
154         int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
155         if (cached_survey == back_ptr) {
156            cmp = strcmp(cached_station->ident, name);
157            if (cmp <= 0) ptr = cached_station;
158         }
159         while (ptr && (cmp = strcmp(ptr->ident, name))<0) {
160            ptrPrev = ptr;
161            ptr = ptr->right;
162         }
163         if (cmp) {
164            /* ie we got to one that was higher, or the end */
165            prefix *newptr;
166            name = osrealloc(name, i);
167            newptr = osnew(prefix);
168            newptr->ident = name;
169            name = NULL;
170            if (ptrPrev == NULL)
171               back_ptr->down = newptr;
172            else
173               ptrPrev->right = newptr;
174            newptr->right = ptr;
175            newptr->down = NULL;
176            newptr->pos = NULL;
177            newptr->shape = 0;
178            newptr->stn = NULL;
179            newptr->up = back_ptr;
180            newptr->filename = NULL;
181            newptr->min_export = newptr->max_export = 0;
182            newptr->sflags = BIT(SFLAGS_SURVEY);
183            if (fSuspectTypo && !fImplicitPrefix)
184               newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
185            ptr = newptr;
186            fNew = fTrue;
187         }
188         cached_survey = back_ptr;
189         cached_station = ptr;
190      }
191      depth++;
192      f_optional = fFalse; /* disallow after first level */
193   } while (isSep(ch));
194   if (name) osfree(name);
195
196   /* don't warn about a station that is refered to twice */
197   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);
198
199   if (fNew) {
200      /* fNew means SFLAGS_SURVEY is currently set */
201      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
202      if (!fSurvey) {
203         ptr->sflags &= ~BIT(SFLAGS_SURVEY);
204         if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
205      }
206   } else {
207      /* check that the same name isn't being used for a survey and station */
208      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
209         compile_error(/*`%s' can't be both a station and a survey*/27,
210                       sprint_prefix(ptr));
211      }
212      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
213   }
214
215   /* check the export level */
216#if 0
217   printf("R min %d max %d depth %d pfx %s\n",
218          ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr));
219#endif
220   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
221      if (depth > ptr->max_export) ptr->max_export = depth;
222   } else if (ptr->max_export < depth) {
223      const char *filename_store = file.filename;
224      unsigned int line_store = file.line;
225      prefix *survey = ptr;
226      char *s;
227      int level;
228      for (level = ptr->max_export + 1; level; level--) {
229         survey = survey->up;
230         SVX_ASSERT(survey);
231      }
232      s = osstrdup(sprint_prefix(survey));
233      if (survey->filename) {
234         file.filename = survey->filename;
235         file.line = survey->line;
236      }
237      compile_error(/*Station `%s' not exported from survey `%s'*/26,
238                    sprint_prefix(ptr), s);
239      if (survey->filename) {
240         file.filename = filename_store;
241         file.line = line_store;
242      }
243      osfree(s);
244#if 0
245      printf(" *** pfx %s warning not exported enough depth %d "
246             "ptr->max_export %d\n", sprint_prefix(ptr),
247             depth, ptr->max_export);
248#endif
249   }
250   return ptr;
251}
252
253/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
254extern prefix *
255read_prefix_survey(bool f_optional, bool fAllowRoot)
256{
257   return read_prefix_(f_optional, fTrue, fFalse, fAllowRoot);
258}
259
260/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
261extern prefix *
262read_prefix_stn(bool f_optional, bool fAllowRoot)
263{
264   return read_prefix_(f_optional, fFalse, fFalse, fAllowRoot);
265}
266
267/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
268/* Same as read_prefix_stn but implicit checks are made */
269extern prefix *
270read_prefix_stn_check_implicit(bool f_optional, bool fAllowRoot)
271{
272   return read_prefix_(f_optional, fFalse, fTrue, fAllowRoot);
273}
274
275/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
276static real
277read_number(bool f_optional)
278{
279   bool fPositive, fDigits = fFalse;
280   real n = (real)0.0;
281   filepos fp;
282   int ch_old;
283
284   get_pos(&fp);
285   ch_old = ch;
286   fPositive = !isMinus(ch);
287   if (isSign(ch)) nextch();
288
289   while (isdigit(ch)) {
290      n = n * (real)10.0 + (char)(ch - '0');
291      nextch();
292      fDigits = fTrue;
293   }
294
295   if (isDecimal(ch)) {
296      real mult = (real)1.0;
297      nextch();
298      while (isdigit(ch)) {
299         mult *= (real).1;
300         n += (char)(ch - '0') * mult;
301         fDigits = fTrue;
302         nextch();
303      }
304   }
305
306   /* !'fRead' => !fDigits so fDigits => 'fRead' */
307   if (fDigits) return (fPositive ? n : -n);
308
309   /* didn't read a valid number.  If it's optional, reset filepos & return */
310   if (f_optional) {
311      set_pos(&fp);
312      return HUGE_REAL;
313   }
314
315   if (isOmit(ch_old)) {
316      compile_error(/*Field may not be omitted*/8);
317   } else {
318      compile_error_token(/*Expecting numeric field, found `%s'*/9);
319   }
320   LONGJMP(file.jbSkipLine);
321   return 0.0; /* for brain-fried compilers */
322}
323
324extern real
325read_numeric(bool f_optional, int *p_n_readings)
326{
327   size_t n_readings = 0;
328   real tot = (real)0.0;
329
330   skipblanks();
331   if (!isOpen(ch)) {
332      real r = read_number(f_optional);
333      if (p_n_readings) *p_n_readings = (r == HUGE_REAL ? 0 : 1);
334      return r;
335   }
336   nextch();
337
338   skipblanks();
339   do {
340      tot += read_number(fFalse);
341      ++n_readings;
342      skipblanks();
343   } while (!isClose(ch));
344   nextch();
345
346   if (p_n_readings) *p_n_readings = n_readings;
347   /* FIXME: special averaging for bearings ... */
348   /* And for percentage gradient */
349   return tot / n_readings;
350}
351
352/* read numeric expr or omit (return HUGE_REAL); else longjmp */
353extern real
354read_numeric_or_omit(int *p_n_readings)
355{
356   real v = read_numeric(fTrue, p_n_readings);
357   if (v == HUGE_REAL) {
358      if (!isOmit(ch)) {
359         compile_error_token(/*Expecting numeric field, found `%s'*/9);
360         LONGJMP(file.jbSkipLine);
361         return 0.0; /* for brain-fried compilers */
362      }
363      nextch();
364   }
365   return v;
366}
367
368/* Don't skip blanks, variable error code */
369static unsigned int
370read_uint_internal(int errmsg, filepos *fp)
371{
372   unsigned int n = 0;
373   if (!isdigit(ch)) {
374      if (fp) set_pos(fp);
375      compile_error_token(errmsg);
376      LONGJMP(file.jbSkipLine);
377   }
378   while (isdigit(ch)) {
379      n = n * 10 + (char)(ch - '0');
380      nextch();
381   }
382   return n;
383}
384
385extern unsigned int
386read_uint(void)
387{
388   skipblanks();
389   return read_uint_internal(/*Expecting numeric field, found `%s'*/9, NULL);
390}
391
392extern void
393read_string(char **pstr, int *plen)
394{
395   s_zero(pstr);
396
397   skipblanks();
398   if (ch == '\"') {
399      /* String quoted in "" */
400      nextch();
401      while (1) {
402         if (isEol(ch)) {
403            compile_error_skip(/*Missing &quot;*/69);
404            return;
405         }
406
407         if (ch == '\"') break;
408
409         s_catchar(pstr, plen, ch);
410         nextch();
411      }
412   } else {
413      /* Unquoted string */
414      while (1) {
415         if (isEol(ch) || isComm(ch)) {
416            if (!*pstr || !(*pstr)[0]) {
417               compile_error_skip(/*Expecting string field*/121);
418            }
419            return;
420         }
421
422         if (isBlank(ch)) break;
423
424         s_catchar(pstr, plen, ch);
425         nextch();
426      }
427   }
428
429   nextch();
430}
431
432static int lastday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
433
434extern int
435last_day(int year, int month)
436{
437    SVX_ASSERT(month >= 1 && month <= 12);
438    return (month == 2 && is_leap_year(year)) ? 29 : lastday[month - 1];
439}
440
441extern void
442read_date(int *py, int *pm, int *pd)
443{
444   int y = 0, m = 0, d = 0;
445   filepos fp;
446
447   skipblanks();
448
449   get_pos(&fp);
450   y = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
451   /* Two digit year is 19xx. */
452   if (y < 100) y += 1900;
453   if (y < 1970 || y > 2037) {
454      compile_error_skip(/*Invalid year (< 1970 or > 2037)*/58);
455      LONGJMP(file.jbSkipLine);
456      return; /* for brain-fried compilers */
457   }
458   if (ch == '.') {
459      nextch();
460      m = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
461      if (m < 1 || m > 12) {
462         compile_error_skip(/*Invalid month*/86);
463         LONGJMP(file.jbSkipLine);
464         return; /* for brain-fried compilers */
465      }
466      if (ch == '.') {
467         nextch();
468         d = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
469         if (d < 1 || d > last_day(y, m)) {
470            compile_error_skip(/*Invalid day of the month*/87);
471            LONGJMP(file.jbSkipLine);
472            return; /* for brain-fried compilers */
473         }
474      }
475   }
476   if (py) *py = y;
477   if (pm) *pm = m;
478   if (pd) *pd = d;
479}
Note: See TracBrowser for help on using the repository browser.