source: git/src/readval.c @ d333899

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

Give an error if a cross-section is specified for a station which doesn't
exist.

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

  • Property mode set to 100644
File size: 12.1 KB
RevLine 
[6974a34]1/* readval.c
[0395657]2 * Routines to read a prefix or number from the current input file
[d333899]3 * Copyright (C) 1991-2003,2005,2006 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
[d333899]17 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA  02110-1301 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;
[d333899]142         ptr->filename = file.filename;
143         ptr->line = file.line;
[932f7e9]144         ptr->min_export = ptr->max_export = 0;
[95c3272]145         ptr->sflags = BIT(SFLAGS_SURVEY);
146         if (fSuspectTypo && !fImplicitPrefix)
147            ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[a420b49]148         back_ptr->down = ptr;
[647407d]149         fNew = fTrue;
[a420b49]150      } else {
[be97baf]151         /* Use caching to speed up adding an increasing sequence to a
152          * large survey */
153         static prefix *cached_survey = NULL, *cached_station = NULL;
[a420b49]154         prefix *ptrPrev = NULL;
[76bb277a]155         int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
[be97baf]156         if (cached_survey == back_ptr) {
157            cmp = strcmp(cached_station->ident, name);
158            if (cmp <= 0) ptr = cached_station;
159         }
160         while (ptr && (cmp = strcmp(ptr->ident, name))<0) {
[a420b49]161            ptrPrev = ptr;
162            ptr = ptr->right;
163         }
164         if (cmp) {
165            /* ie we got to one that was higher, or the end */
[be97baf]166            prefix *newptr;
167            name = osrealloc(name, i);
168            newptr = osnew(prefix);
[647407d]169            newptr->ident = name;
[be97baf]170            name = NULL;
[a420b49]171            if (ptrPrev == NULL)
[647407d]172               back_ptr->down = newptr;
[a420b49]173            else
[647407d]174               ptrPrev->right = newptr;
175            newptr->right = ptr;
176            newptr->down = NULL;
177            newptr->pos = NULL;
[6adb88c]178            newptr->shape = 0;
[647407d]179            newptr->stn = NULL;
180            newptr->up = back_ptr;
[d333899]181            newptr->filename = file.filename;
182            newptr->line = file.line;
[421b7d2]183            newptr->min_export = newptr->max_export = 0;
[95c3272]184            newptr->sflags = BIT(SFLAGS_SURVEY);
185            if (fSuspectTypo && !fImplicitPrefix)
186               newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[647407d]187            ptr = newptr;
188            fNew = fTrue;
[a420b49]189         }
[be97baf]190         cached_survey = back_ptr;
191         cached_station = ptr;
[d1b1380]192      }
[fb2e93c]193      depth++;
[21c226e]194      f_optional = fFalse; /* disallow after first level */
[a420b49]195   } while (isSep(ch));
[be97baf]196   if (name) osfree(name);
197
[fb2e93c]198   /* don't warn about a station that is refered to twice */
[95c3272]199   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);
[421b7d2]200
[6430f0e]201   if (fNew) {
[95c3272]202      /* fNew means SFLAGS_SURVEY is currently set */
[4c07c51]203      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
[c00c74a9]204      if (!fSurvey) {
205         ptr->sflags &= ~BIT(SFLAGS_SURVEY);
[27b8b59]206         if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[c00c74a9]207      }
[6430f0e]208   } else {
209      /* check that the same name isn't being used for a survey and station */
[95c3272]210      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
[6430f0e]211         compile_error(/*`%s' can't be both a station and a survey*/27,
212                       sprint_prefix(ptr));
213      }
[27b8b59]214      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[051a72b]215   }
216
[932f7e9]217   /* check the export level */
218#if 0
219   printf("R min %d max %d depth %d pfx %s\n",
220          ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr));
221#endif
[c00c74a9]222   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
[932f7e9]223      if (depth > ptr->max_export) ptr->max_export = depth;
224   } else if (ptr->max_export < depth) {
[016068a]225      const char *filename_store = file.filename;
226      unsigned int line_store = file.line;
[dd5b1a8]227      prefix *survey = ptr;
228      char *s;
229      int level;
230      for (level = ptr->max_export + 1; level; level--) {
231         survey = survey->up;
[4c07c51]232         SVX_ASSERT(survey);
[dd5b1a8]233      }
234      s = osstrdup(sprint_prefix(survey));
[016068a]235      if (survey->filename) {
236         file.filename = survey->filename;
237         file.line = survey->line;
238      }
[dd5b1a8]239      compile_error(/*Station `%s' not exported from survey `%s'*/26,
240                    sprint_prefix(ptr), s);
[016068a]241      if (survey->filename) {
242         file.filename = filename_store;
243         file.line = line_store;
244      }
[dd5b1a8]245      osfree(s);
[932f7e9]246#if 0
247      printf(" *** pfx %s warning not exported enough depth %d "
[421b7d2]248             "ptr->max_export %d\n", sprint_prefix(ptr),
[932f7e9]249             depth, ptr->max_export);
250#endif
251   }
[a420b49]252   return ptr;
[d1b1380]253}
254
[21c226e]255/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[647407d]256extern prefix *
[21c226e]257read_prefix_survey(bool f_optional, bool fAllowRoot)
[051a72b]258{
[21c226e]259   return read_prefix_(f_optional, fTrue, fFalse, fAllowRoot);
[051a72b]260}
261
[21c226e]262/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[051a72b]263extern prefix *
[21c226e]264read_prefix_stn(bool f_optional, bool fAllowRoot)
[647407d]265{
[21c226e]266   return read_prefix_(f_optional, fFalse, fFalse, fAllowRoot);
[647407d]267}
268
[21c226e]269/* if prefix is omitted: if f_optional return NULL, otherwise use longjmp */
[051a72b]270/* Same as read_prefix_stn but implicit checks are made */
[647407d]271extern prefix *
[21c226e]272read_prefix_stn_check_implicit(bool f_optional, bool fAllowRoot)
[647407d]273{
[21c226e]274   return read_prefix_(f_optional, fFalse, fTrue, fAllowRoot);
[647407d]275}
276
[21c226e]277/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
278static real
279read_number(bool f_optional)
[a420b49]280{
281   bool fPositive, fDigits = fFalse;
282   real n = (real)0.0;
[c80bd34]283   filepos fp;
284   int ch_old;
[a420b49]285
[c80bd34]286   get_pos(&fp);
287   ch_old = ch;
[a420b49]288   fPositive = !isMinus(ch);
289   if (isSign(ch)) nextch();
290
291   while (isdigit(ch)) {
[6974a34]292      n = n * (real)10.0 + (char)(ch - '0');
[d1b1380]293      nextch();
[a420b49]294      fDigits = fTrue;
295   }
296
297   if (isDecimal(ch)) {
298      real mult = (real)1.0;
299      nextch();
300      while (isdigit(ch)) {
301         mult *= (real).1;
302         n += (char)(ch - '0') * mult;
303         fDigits = fTrue;
304         nextch();
305      }
306   }
307
308   /* !'fRead' => !fDigits so fDigits => 'fRead' */
309   if (fDigits) return (fPositive ? n : -n);
310
311   /* didn't read a valid number.  If it's optional, reset filepos & return */
[21c226e]312   if (f_optional) {
[c80bd34]313      set_pos(&fp);
[a420b49]314      return HUGE_REAL;
315   }
316
[c80bd34]317   if (isOmit(ch_old)) {
[647407d]318      compile_error(/*Field may not be omitted*/8);
319   } else {
[39fba51]320      compile_error_token(/*Expecting numeric field, found `%s'*/9);
[647407d]321   }
322   LONGJMP(file.jbSkipLine);
[a420b49]323   return 0.0; /* for brain-fried compilers */
[d1b1380]324}
[647407d]325
[21c226e]326extern real
327read_numeric(bool f_optional, int *p_n_readings)
328{
329   size_t n_readings = 0;
330   real tot = (real)0.0;
331
332   skipblanks();
333   if (!isOpen(ch)) {
334      real r = read_number(f_optional);
335      if (p_n_readings) *p_n_readings = (r == HUGE_REAL ? 0 : 1);
336      return r;
337   }
338   nextch();
339
340   skipblanks();
341   do {
342      tot += read_number(fFalse);
343      ++n_readings;
344      skipblanks();
345   } while (!isClose(ch));
346   nextch();
347
348   if (p_n_readings) *p_n_readings = n_readings;
349   /* FIXME: special averaging for bearings ... */
350   /* And for percentage gradient */
351   return tot / n_readings;
352}
353
[2aa2f3f]354/* read numeric expr or omit (return HUGE_REAL); else longjmp */
355extern real
[21c226e]356read_numeric_or_omit(int *p_n_readings)
[2aa2f3f]357{
[21c226e]358   real v = read_numeric(fTrue, p_n_readings);
[2aa2f3f]359   if (v == HUGE_REAL) {
360      if (!isOmit(ch)) {
[39fba51]361         compile_error_token(/*Expecting numeric field, found `%s'*/9);
[2aa2f3f]362         LONGJMP(file.jbSkipLine);
363         return 0.0; /* for brain-fried compilers */
364      }
365      nextch();
366   }
367   return v;
368}
369
[950a829]370/* Don't skip blanks, variable error code */
371static unsigned int
[029cc3f]372read_uint_internal(int errmsg, filepos *fp)
[647407d]373{
[421b7d2]374   unsigned int n = 0;
[647407d]375   if (!isdigit(ch)) {
[029cc3f]376      if (fp) set_pos(fp);
[39fba51]377      compile_error_token(errmsg);
[647407d]378      LONGJMP(file.jbSkipLine);
379   }
380   while (isdigit(ch)) {
381      n = n * 10 + (char)(ch - '0');
382      nextch();
383   }
384   return n;
385}
[76bb277a]386
[950a829]387extern unsigned int
388read_uint(void)
389{
390   skipblanks();
[029cc3f]391   return read_uint_internal(/*Expecting numeric field, found `%s'*/9, NULL);
[950a829]392}
393
[76bb277a]394extern void
395read_string(char **pstr, int *plen)
396{
397   s_zero(pstr);
398
399   skipblanks();
400   if (ch == '\"') {
[1157304]401      /* String quoted in "" */
[76bb277a]402      nextch();
[457a390]403      while (1) {
404         if (isEol(ch)) {
[fa42426]405            compile_error_skip(/*Missing &quot;*/69);
[457a390]406            return;
407         }
408
409         if (ch == '\"') break;
410
411         s_catchar(pstr, plen, ch);
412         nextch();
413      }
414   } else {
[1157304]415      /* Unquoted string */
[457a390]416      while (1) {
417         if (isEol(ch) || isComm(ch)) {
[b97d134]418            if (!*pstr || !(*pstr)[0]) {
[fa42426]419               compile_error_skip(/*Expecting string field*/121);
[b97d134]420            }
[457a390]421            return;
[76bb277a]422         }
423
[457a390]424         if (isBlank(ch)) break;
[76bb277a]425
[457a390]426         s_catchar(pstr, plen, ch);
427         nextch();
428      }
[76bb277a]429   }
[421b7d2]430
[76bb277a]431   nextch();
432}
[950a829]433
[e0c7cd1]434static int lastday[12] = { 31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
435
436extern int
437last_day(int year, int month)
438{
439    SVX_ASSERT(month >= 1 && month <= 12);
440    return (month == 2 && is_leap_year(year)) ? 29 : lastday[month - 1];
441}
442
[950a829]443extern void
[b5a3219]444read_date(int *py, int *pm, int *pd)
[950a829]445{
446   int y = 0, m = 0, d = 0;
[029cc3f]447   filepos fp;
[950a829]448
449   skipblanks();
[029cc3f]450
451   get_pos(&fp);
452   y = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]453   /* Two digit year is 19xx. */
454   if (y < 100) y += 1900;
455   if (y < 1970 || y > 2037) {
456      compile_error_skip(/*Invalid year (< 1970 or > 2037)*/58);
457      LONGJMP(file.jbSkipLine);
458      return; /* for brain-fried compilers */
459   }
[950a829]460   if (ch == '.') {
461      nextch();
[029cc3f]462      m = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]463      if (m < 1 || m > 12) {
464         compile_error_skip(/*Invalid month*/86);
465         LONGJMP(file.jbSkipLine);
466         return; /* for brain-fried compilers */
467      }
[950a829]468      if (ch == '.') {
469         nextch();
[029cc3f]470         d = read_uint_internal(/*Expecting date, found `%s'*/198, &fp);
[e0c7cd1]471         if (d < 1 || d > last_day(y, m)) {
[7926772]472            compile_error_skip(/*Invalid day of the month*/87);
[e0c7cd1]473            LONGJMP(file.jbSkipLine);
474            return; /* for brain-fried compilers */
475         }
[950a829]476      }
477   }
[b5a3219]478   if (py) *py = y;
479   if (pm) *pm = m;
480   if (pd) *pd = d;
[950a829]481}
Note: See TracBrowser for help on using the repository browser.