source: git/src/readval.c @ b60659c

RELEASE/1.0RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernlogstereowalls-datawalls-data-hanging-as-warning
Last change on this file since b60659c was 1cbf5a1, checked in by Olly Betts <olly@…>, 22 years ago

Cache the previously read survey station, and if possible use it to jump
start the linear search through the lowest level of the survey tree.

git-svn-id: file:///home/survex-svn/survex/trunk@2225 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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