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

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernlogstereowalls-datawalls-data-hanging-as-warning
Last change on this file since 2c1384a was 7926772, checked in by Olly Betts <olly@…>, 19 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
RevLine 
[6974a34]1/* readval.c
[0395657]2 * Routines to read a prefix or number from the current input file
[a4ae909]3 * Copyright (C) 1991-2003,2005 Olly Betts
[846746e]4 *
[89231c4]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.
[846746e]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
[89231c4]12 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13 * GNU General Public License for more details.
[846746e]14 *
[89231c4]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
[d1b1380]18 */
19
[a420b49]20#ifdef HAVE_CONFIG_H
21# include <config.h>
22#endif
[d1b1380]23
[c00c74a9]24#include <limits.h>
[be97baf]25#include <stddef.h> /* for offsetof */
[c00c74a9]26
[a420b49]27#include "cavern.h"
[dd5b1a8]28#include "debug.h"
[a1706d1]29#include "filename.h"
30#include "message.h"
[d1b1380]31#include "readval.h"
32#include "datain.h"
[fb2e93c]33#include "netbits.h"
[8cf2e04]34#include "osalloc.h"
[76bb277a]35#include "str.h"
[d1b1380]36
[7d5f3c0]37#ifdef HAVE_SETJMP_H
[647407d]38# define LONGJMP(JB) longjmp((JB), 1)
39#else
40# define LONGJMP(JB) exit(1)
41#endif
42
[c86cc71]43int root_depr_count = 0;
44
[21c226e]45/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[647407d]46static prefix *
[21c226e]47read_prefix_(bool f_optional, bool fSurvey, bool fSuspectTypo, bool fAllowRoot)
[a420b49]48{
[4a6a094]49   prefix *back_ptr, *ptr;
[a420b49]50   char *name;
51   size_t name_len = 32;
[eb18f4d]52   size_t i;
[647407d]53   bool fNew;
[d6274ba]54   bool fImplicitPrefix = fTrue;
[932f7e9]55   int depth = -1;
[a420b49]56
57   skipblanks();
[7f1ab95]58#ifndef NO_DEPRECATED
[a420b49]59   if (isRoot(ch)) {
[84c60fc]60      if (!fAllowRoot) {
[fa42426]61         compile_error_skip(/*ROOT is deprecated*/25);
[421b7d2]62         LONGJMP(file.jbSkipLine);
[84c60fc]63      }
[c86cc71]64      if (root_depr_count < 5) {
65         compile_warning(/*ROOT is deprecated*/25);
66         if (++root_depr_count == 5)
[c40038a]67            compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]68      }
[d1b1380]69      nextch();
[a420b49]70      ptr = root;
71      if (!isNames(ch)) {
72         if (!isSep(ch)) return ptr;
[27b8b59]73         /* Allow optional SEPARATOR after ROOT */
[a420b49]74         nextch();
75      }
[647407d]76      fImplicitPrefix = fFalse;
[a420b49]77   } else {
78      ptr = pcs->Prefix;
79   }
[7f1ab95]80#else
81   ptr = pcs->Prefix;
82#endif
[a420b49]83
84   i = 0;
[be97baf]85   name = NULL;
[a420b49]86   do {
[647407d]87      fNew = fFalse;
88      if (isSep(ch)) fImplicitPrefix = fFalse;
[be97baf]89      if (name == NULL) {
90         /* Need a new name buffer */
91         name = osmalloc(name_len);
92      }
[a420b49]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 */
[1157304]101            name[i++] = (pcs->Case == LOWER ? tolower(ch) :
102                         (pcs->Case == OFF ? ch : toupper(ch)));
[a420b49]103            if (i >= name_len) {
104               name_len = name_len + name_len;
105               name = osrealloc(name, name_len);
106            }
[8cf2e04]107         }
[a420b49]108         nextch();
[8cf2e04]109      }
[a420b49]110      if (i == 0) {
111         osfree(name);
[21c226e]112         if (!f_optional) {
[ee1d81f]113            if (isEol(ch)) {
[84c60fc]114               if (fSurvey) {
[fa42426]115                  compile_error_skip(/*Expecting survey name*/89);
[84c60fc]116               } else {
[fa42426]117                  compile_error_skip(/*Expecting station name*/28);
[84c60fc]118               }
[ee1d81f]119            } else {
[fa42426]120               compile_error_skip(/*Character `%c' not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch);
[ee1d81f]121            }
[647407d]122            LONGJMP(file.jbSkipLine);
123         }
[a420b49]124         return (prefix *)NULL;
[d1b1380]125      }
[a420b49]126
[76bb277a]127      name[i++] = '\0';
[cb3d1e2]128
[a420b49]129      back_ptr = ptr;
130      ptr = ptr->down;
131      if (ptr == NULL) {
132         /* Special case first time around at each level */
[be97baf]133         name = osrealloc(name, i);
[a420b49]134         ptr = osnew(prefix);
135         ptr->ident = name;
[be97baf]136         name = NULL;
[a420b49]137         ptr->right = ptr->down = NULL;
138         ptr->pos = NULL;
[6adb88c]139         ptr->shape = 0;
[a420b49]140         ptr->stn = NULL;
141         ptr->up = back_ptr;
[4d9eecd]142         ptr->filename = NULL;
[932f7e9]143         ptr->min_export = ptr->max_export = 0;
[95c3272]144         ptr->sflags = BIT(SFLAGS_SURVEY);
145         if (fSuspectTypo && !fImplicitPrefix)
146            ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[a420b49]147         back_ptr->down = ptr;
[647407d]148         fNew = fTrue;
[a420b49]149      } else {
[be97baf]150         /* Use caching to speed up adding an increasing sequence to a
151          * large survey */
152         static prefix *cached_survey = NULL, *cached_station = NULL;
[a420b49]153         prefix *ptrPrev = NULL;
[76bb277a]154         int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
[be97baf]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) {
[a420b49]160            ptrPrev = ptr;
161            ptr = ptr->right;
162         }
163         if (cmp) {
164            /* ie we got to one that was higher, or the end */
[be97baf]165            prefix *newptr;
166            name = osrealloc(name, i);
167            newptr = osnew(prefix);
[647407d]168            newptr->ident = name;
[be97baf]169            name = NULL;
[a420b49]170            if (ptrPrev == NULL)
[647407d]171               back_ptr->down = newptr;
[a420b49]172            else
[647407d]173               ptrPrev->right = newptr;
174            newptr->right = ptr;
175            newptr->down = NULL;
176            newptr->pos = NULL;
[6adb88c]177            newptr->shape = 0;
[647407d]178            newptr->stn = NULL;
179            newptr->up = back_ptr;
180            newptr->filename = NULL;
[421b7d2]181            newptr->min_export = newptr->max_export = 0;
[95c3272]182            newptr->sflags = BIT(SFLAGS_SURVEY);
183            if (fSuspectTypo && !fImplicitPrefix)
184               newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[647407d]185            ptr = newptr;
186            fNew = fTrue;
[a420b49]187         }
[be97baf]188         cached_survey = back_ptr;
189         cached_station = ptr;
[d1b1380]190      }
[fb2e93c]191      depth++;
[21c226e]192      f_optional = fFalse; /* disallow after first level */
[a420b49]193   } while (isSep(ch));
[be97baf]194   if (name) osfree(name);
195
[fb2e93c]196   /* don't warn about a station that is refered to twice */
[95c3272]197   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);
[421b7d2]198
[6430f0e]199   if (fNew) {
[95c3272]200      /* fNew means SFLAGS_SURVEY is currently set */
[4c07c51]201      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
[c00c74a9]202      if (!fSurvey) {
203         ptr->sflags &= ~BIT(SFLAGS_SURVEY);
[27b8b59]204         if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[c00c74a9]205      }
[6430f0e]206   } else {
207      /* check that the same name isn't being used for a survey and station */
[95c3272]208      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
[6430f0e]209         compile_error(/*`%s' can't be both a station and a survey*/27,
210                       sprint_prefix(ptr));
211      }
[27b8b59]212      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[051a72b]213   }
214
[932f7e9]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
[c00c74a9]220   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
[932f7e9]221      if (depth > ptr->max_export) ptr->max_export = depth;
222   } else if (ptr->max_export < depth) {
[016068a]223      const char *filename_store = file.filename;
224      unsigned int line_store = file.line;
[dd5b1a8]225      prefix *survey = ptr;
226      char *s;
227      int level;
228      for (level = ptr->max_export + 1; level; level--) {
229         survey = survey->up;
[4c07c51]230         SVX_ASSERT(survey);
[dd5b1a8]231      }
232      s = osstrdup(sprint_prefix(survey));
[016068a]233      if (survey->filename) {
234         file.filename = survey->filename;
235         file.line = survey->line;
236      }
[dd5b1a8]237      compile_error(/*Station `%s' not exported from survey `%s'*/26,
238                    sprint_prefix(ptr), s);
[016068a]239      if (survey->filename) {
240         file.filename = filename_store;
241         file.line = line_store;
242      }
[dd5b1a8]243      osfree(s);
[932f7e9]244#if 0
245      printf(" *** pfx %s warning not exported enough depth %d "
[421b7d2]246             "ptr->max_export %d\n", sprint_prefix(ptr),
[932f7e9]247             depth, ptr->max_export);
248#endif
249   }
[a420b49]250   return ptr;
[d1b1380]251}
252
[21c226e]253/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[647407d]254extern prefix *
[21c226e]255read_prefix_survey(bool f_optional, bool fAllowRoot)
[051a72b]256{
[21c226e]257   return read_prefix_(f_optional, fTrue, fFalse, fAllowRoot);
[051a72b]258}
259
[21c226e]260/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[051a72b]261extern prefix *
[21c226e]262read_prefix_stn(bool f_optional, bool fAllowRoot)
[647407d]263{
[21c226e]264   return read_prefix_(f_optional, fFalse, fFalse, fAllowRoot);
[647407d]265}
266
[21c226e]267/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[051a72b]268/* Same as read_prefix_stn but implicit checks are made */
[647407d]269extern prefix *
[21c226e]270read_prefix_stn_check_implicit(bool f_optional, bool fAllowRoot)
[647407d]271{
[21c226e]272   return read_prefix_(f_optional, fFalse, fTrue, fAllowRoot);
[647407d]273}
274
[21c226e]275/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
276static real
277read_number(bool f_optional)
[a420b49]278{
279   bool fPositive, fDigits = fFalse;
280   real n = (real)0.0;
[c80bd34]281   filepos fp;
282   int ch_old;
[a420b49]283
[c80bd34]284   get_pos(&fp);
285   ch_old = ch;
[a420b49]286   fPositive = !isMinus(ch);
287   if (isSign(ch)) nextch();
288
289   while (isdigit(ch)) {
[6974a34]290      n = n * (real)10.0 + (char)(ch - '0');
[d1b1380]291      nextch();
[a420b49]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 */
[21c226e]310   if (f_optional) {
[c80bd34]311      set_pos(&fp);
[a420b49]312      return HUGE_REAL;
313   }
314
[c80bd34]315   if (isOmit(ch_old)) {
[647407d]316      compile_error(/*Field may not be omitted*/8);
317   } else {
[39fba51]318      compile_error_token(/*Expecting numeric field, found `%s'*/9);
[647407d]319   }
320   LONGJMP(file.jbSkipLine);
[a420b49]321   return 0.0; /* for brain-fried compilers */
[d1b1380]322}
[647407d]323
[21c226e]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
[2aa2f3f]352/* read numeric expr or omit (return HUGE_REAL); else longjmp */
353extern real
[21c226e]354read_numeric_or_omit(int *p_n_readings)
[2aa2f3f]355{
[21c226e]356   real v = read_numeric(fTrue, p_n_readings);
[2aa2f3f]357   if (v == HUGE_REAL) {
358      if (!isOmit(ch)) {
[39fba51]359         compile_error_token(/*Expecting numeric field, found `%s'*/9);
[2aa2f3f]360         LONGJMP(file.jbSkipLine);
361         return 0.0; /* for brain-fried compilers */
362      }
363      nextch();
364   }
365   return v;
366}
367
[950a829]368/* Don't skip blanks, variable error code */
369static unsigned int
[029cc3f]370read_uint_internal(int errmsg, filepos *fp)
[647407d]371{
[421b7d2]372   unsigned int n = 0;
[647407d]373   if (!isdigit(ch)) {
[029cc3f]374      if (fp) set_pos(fp);
[39fba51]375      compile_error_token(errmsg);
[647407d]376      LONGJMP(file.jbSkipLine);
377   }
378   while (isdigit(ch)) {
379      n = n * 10 + (char)(ch - '0');
380      nextch();
381   }
382   return n;
383}
[76bb277a]384
[950a829]385extern unsigned int
386read_uint(void)
387{
388   skipblanks();
[029cc3f]389   return read_uint_internal(/*Expecting numeric field, found `%s'*/9, NULL);
[950a829]390}
391
[76bb277a]392extern void
393read_string(char **pstr, int *plen)
394{
395   s_zero(pstr);
396
397   skipblanks();
398   if (ch == '\"') {
[1157304]399      /* String quoted in "" */
[76bb277a]400      nextch();
[457a390]401      while (1) {
402         if (isEol(ch)) {
[fa42426]403            compile_error_skip(/*Missing &quot;*/69);
[457a390]404            return;
405         }
406
407         if (ch == '\"') break;
408
409         s_catchar(pstr, plen, ch);
410         nextch();
411      }
412   } else {
[1157304]413      /* Unquoted string */
[457a390]414      while (1) {
415         if (isEol(ch) || isComm(ch)) {
[b97d134]416            if (!*pstr || !(*pstr)[0]) {
[fa42426]417               compile_error_skip(/*Expecting string field*/121);
[b97d134]418            }
[457a390]419            return;
[76bb277a]420         }
421
[457a390]422         if (isBlank(ch)) break;
[76bb277a]423
[457a390]424         s_catchar(pstr, plen, ch);
425         nextch();
426      }
[76bb277a]427   }
[421b7d2]428
[76bb277a]429   nextch();
430}
[950a829]431
[e0c7cd1]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
[950a829]441extern void
[b5a3219]442read_date(int *py, int *pm, int *pd)
[950a829]443{
444   int y = 0, m = 0, d = 0;
[029cc3f]445   filepos fp;
[950a829]446
447   skipblanks();
[029cc3f]448
449   get_pos(&fp);
450   y = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]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   }
[950a829]458   if (ch == '.') {
459      nextch();
[029cc3f]460      m = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]461      if (m < 1 || m > 12) {
462         compile_error_skip(/*Invalid month*/86);
463         LONGJMP(file.jbSkipLine);
464         return; /* for brain-fried compilers */
465      }
[950a829]466      if (ch == '.') {
467         nextch();
[029cc3f]468         d = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]469         if (d < 1 || d > last_day(y, m)) {
[7926772]470            compile_error_skip(/*Invalid day of the month*/87);
[e0c7cd1]471            LONGJMP(file.jbSkipLine);
472            return; /* for brain-fried compilers */
473         }
[950a829]474      }
475   }
[b5a3219]476   if (py) *py = y;
477   if (pm) *pm = m;
478   if (pd) *pd = d;
[950a829]479}
Note: See TracBrowser for help on using the repository browser.