source: git/src/readval.c @ 728f877

RELEASE/1.0
Last change on this file since 728f877 was 728f877, checked in by Olly Betts <olly@…>, 13 years ago

Backport change from 1.2.0:
src/readval.c: Fix comment typo.

git-svn-id: file:///home/survex-svn/survex/branches/1.0@3720 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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