source: git/src/readval.c @ 4c83f84

faster-cavernloglog-selectwalls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since 4c83f84 was 4c83f84, checked in by Olly Betts <olly@…>, 5 months ago

Don't check HAVE_CONFIG_H in most cases

This check is only useful for img.c, which is intended to be usable
outside of Survex (and had fallbacks for functions which may not be
available which will get used if built in a non-autotools project).
For all the other source files it's just useless boilerplate.

  • Property mode set to 100644
File size: 19.0 KB
RevLine 
[6974a34]1/* readval.c
[0395657]2 * Routines to read a prefix or number from the current input file
[5b9b9d4]3 * Copyright (C) 1991-2024 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
[4c83f84]20#include <config.h>
[d1b1380]21
[c00c74a9]22#include <limits.h>
[be97baf]23#include <stddef.h> /* for offsetof */
[c00c74a9]24
[a420b49]25#include "cavern.h"
[5a0ab6a]26#include "commands.h" /* For match_tok(), etc */
[1ee204e]27#include "date.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
[710ecc1]45static prefix *
[a2c33ae]46new_anon_station(void)
[710ecc1]47{
[a2c33ae]48    prefix *name = osnew(prefix);
49    name->pos = NULL;
50    name->ident = NULL;
51    name->shape = 0;
52    name->stn = NULL;
53    name->up = pcs->Prefix;
54    name->down = NULL;
55    name->filename = file.filename;
56    name->line = file.line;
[5fc783b]57    name->min_export = name->max_export = 0;
[a2c33ae]58    name->sflags = BIT(SFLAGS_ANON);
59    /* Keep linked list of anon stations for node stats. */
60    name->right = anon_list;
61    anon_list = name;
62    return name;
[710ecc1]63}
64
[c458cf7]65/* if prefix is omitted: if PFX_OPT set return NULL, otherwise use longjmp */
66extern prefix *
67read_prefix(unsigned pfx_flags)
[a420b49]68{
[c458cf7]69   bool f_optional = !!(pfx_flags & PFX_OPT);
70   bool fSurvey = !!(pfx_flags & PFX_SURVEY);
71   bool fSuspectTypo = !!(pfx_flags & PFX_SUSPECT_TYPO);
[4a6a094]72   prefix *back_ptr, *ptr;
[a420b49]73   char *name;
74   size_t name_len = 32;
[eb18f4d]75   size_t i;
[647407d]76   bool fNew;
[63d4f07]77   bool fImplicitPrefix = true;
[932f7e9]78   int depth = -1;
[5b4085b]79   filepos fp_firstsep;
[a420b49]80
81   skipblanks();
[7f1ab95]82#ifndef NO_DEPRECATED
[a420b49]83   if (isRoot(ch)) {
[c458cf7]84      if (!(pfx_flags & PFX_ALLOW_ROOT)) {
[cab0f26]85         compile_diagnostic(DIAG_ERR|DIAG_COL, /*ROOT is deprecated*/25);
[421b7d2]86         LONGJMP(file.jbSkipLine);
[84c60fc]87      }
[c86cc71]88      if (root_depr_count < 5) {
[cab0f26]89         compile_diagnostic(DIAG_WARN|DIAG_COL, /*ROOT is deprecated*/25);
[c86cc71]90         if (++root_depr_count == 5)
[cab0f26]91            compile_diagnostic(DIAG_WARN, /*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]92      }
[d1b1380]93      nextch();
[a420b49]94      ptr = root;
95      if (!isNames(ch)) {
96         if (!isSep(ch)) return ptr;
[27b8b59]97         /* Allow optional SEPARATOR after ROOT */
[5b4085b]98         get_pos(&fp_firstsep);
[a420b49]99         nextch();
100      }
[63d4f07]101      fImplicitPrefix = false;
[710ecc1]102#else
103   if (0) {
104#endif
[a420b49]105   } else {
[dcbcae0]106      if ((pfx_flags & PFX_ANON) &&
107          (isSep(ch) || (pcs->dash_for_anon_wall_station && ch == '-'))) {
108         int first_ch = ch;
[710ecc1]109         filepos here;
110         get_pos(&here);
111         nextch();
112         if (isBlank(ch) || isEol(ch)) {
[dcbcae0]113            if (!isSep(first_ch))
114               goto anon_wall_station;
115            /* A single separator alone ('.' by default) is an anonymous
116             * station which is on a point inside the passage and implies
117             * the leg to it is a splay.
118             */
119            if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
[9f55538]120               set_pos(&here);
[d0be687d]121               compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Can't have a leg between two anonymous stations*/3);
[dcbcae0]122               LONGJMP(file.jbSkipLine);
[710ecc1]123            }
[dcbcae0]124            pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
[a2c33ae]125            return new_anon_station();
[710ecc1]126         }
[dcbcae0]127         if (isSep(first_ch) && ch == first_ch) {
128            nextch();
129            if (isBlank(ch) || isEol(ch)) {
130               /* A double separator ('..' by default) is an anonymous station
131                * which is on the wall and implies the leg to it is a splay.
132                */
133               prefix * pfx;
134anon_wall_station:
135               if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
[9f55538]136                  set_pos(&here);
[d0be687d]137                  compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Can't have a leg between two anonymous stations*/3);
[dcbcae0]138                  LONGJMP(file.jbSkipLine);
139               }
[da65891]140               pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
[dcbcae0]141               pfx = new_anon_station();
142               pfx->sflags |= BIT(SFLAGS_WALL);
143               return pfx;
144            }
145            if (ch == first_ch) {
146               nextch();
147               if (isBlank(ch) || isEol(ch)) {
148                  /* A triple separator ('...' by default) is an anonymous
149                   * station, but otherwise not handled specially (e.g. for
150                   * a single leg down an unexplored side passage to a station
151                   * which isn't refindable).
152                   */
153                  if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
[9f55538]154                     set_pos(&here);
[d0be687d]155                     compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Can't have a leg between two anonymous stations*/3);
[dcbcae0]156                     LONGJMP(file.jbSkipLine);
157                  }
158                  pcs->flags |= BIT(FLAGS_ANON_ONE_END);
159                  return new_anon_station();
160               }
161            }
162         }
[710ecc1]163         set_pos(&here);
164      }
[a420b49]165      ptr = pcs->Prefix;
166   }
167
168   i = 0;
[be97baf]169   name = NULL;
[a420b49]170   do {
[63d4f07]171      fNew = false;
[be97baf]172      if (name == NULL) {
173         /* Need a new name buffer */
174         name = osmalloc(name_len);
175      }
[a420b49]176      /* i==0 iff this is the first pass */
177      if (i) {
178         i = 0;
179         nextch();
180      }
181      while (isNames(ch)) {
182         if (i < pcs->Truncate) {
183            /* truncate name */
[1157304]184            name[i++] = (pcs->Case == LOWER ? tolower(ch) :
185                         (pcs->Case == OFF ? ch : toupper(ch)));
[a420b49]186            if (i >= name_len) {
187               name_len = name_len + name_len;
188               name = osrealloc(name, name_len);
189            }
[8cf2e04]190         }
[a420b49]191         nextch();
[8cf2e04]192      }
[5b4085b]193      if (isSep(ch)) {
[63d4f07]194         fImplicitPrefix = false;
[5b4085b]195         get_pos(&fp_firstsep);
196      }
[a420b49]197      if (i == 0) {
198         osfree(name);
[21c226e]199         if (!f_optional) {
[ee1d81f]200            if (isEol(ch)) {
[84c60fc]201               if (fSurvey) {
[cab0f26]202                  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting survey name*/89);
[84c60fc]203               } else {
[cab0f26]204                  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting station name*/28);
[84c60fc]205               }
[ee1d81f]206            } else {
[736f7df]207               /* TRANSLATORS: Here "station" is a survey station, not a train station. */
[cab0f26]208               compile_diagnostic(DIAG_ERR|DIAG_COL, /*Character “%c” not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch);
[ee1d81f]209            }
[647407d]210            LONGJMP(file.jbSkipLine);
211         }
[a420b49]212         return (prefix *)NULL;
[d1b1380]213      }
[a420b49]214
[76bb277a]215      name[i++] = '\0';
[cb3d1e2]216
[a420b49]217      back_ptr = ptr;
218      ptr = ptr->down;
219      if (ptr == NULL) {
220         /* Special case first time around at each level */
[be97baf]221         name = osrealloc(name, i);
[a420b49]222         ptr = osnew(prefix);
223         ptr->ident = name;
[be97baf]224         name = NULL;
[a420b49]225         ptr->right = ptr->down = NULL;
226         ptr->pos = NULL;
[6adb88c]227         ptr->shape = 0;
[a420b49]228         ptr->stn = NULL;
229         ptr->up = back_ptr;
[d333899]230         ptr->filename = file.filename;
231         ptr->line = file.line;
[932f7e9]232         ptr->min_export = ptr->max_export = 0;
[95c3272]233         ptr->sflags = BIT(SFLAGS_SURVEY);
234         if (fSuspectTypo && !fImplicitPrefix)
235            ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[a420b49]236         back_ptr->down = ptr;
[63d4f07]237         fNew = true;
[a420b49]238      } else {
[be97baf]239         /* Use caching to speed up adding an increasing sequence to a
240          * large survey */
241         static prefix *cached_survey = NULL, *cached_station = NULL;
[a420b49]242         prefix *ptrPrev = NULL;
[76bb277a]243         int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
[be97baf]244         if (cached_survey == back_ptr) {
245            cmp = strcmp(cached_station->ident, name);
246            if (cmp <= 0) ptr = cached_station;
247         }
248         while (ptr && (cmp = strcmp(ptr->ident, name))<0) {
[a420b49]249            ptrPrev = ptr;
250            ptr = ptr->right;
251         }
252         if (cmp) {
253            /* ie we got to one that was higher, or the end */
[be97baf]254            prefix *newptr;
255            name = osrealloc(name, i);
256            newptr = osnew(prefix);
[647407d]257            newptr->ident = name;
[be97baf]258            name = NULL;
[a420b49]259            if (ptrPrev == NULL)
[647407d]260               back_ptr->down = newptr;
[a420b49]261            else
[647407d]262               ptrPrev->right = newptr;
263            newptr->right = ptr;
264            newptr->down = NULL;
265            newptr->pos = NULL;
[6adb88c]266            newptr->shape = 0;
[647407d]267            newptr->stn = NULL;
268            newptr->up = back_ptr;
[d333899]269            newptr->filename = file.filename;
270            newptr->line = file.line;
[421b7d2]271            newptr->min_export = newptr->max_export = 0;
[95c3272]272            newptr->sflags = BIT(SFLAGS_SURVEY);
273            if (fSuspectTypo && !fImplicitPrefix)
274               newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
[647407d]275            ptr = newptr;
[63d4f07]276            fNew = true;
[a420b49]277         }
[be97baf]278         cached_survey = back_ptr;
279         cached_station = ptr;
[d1b1380]280      }
[fb2e93c]281      depth++;
[63d4f07]282      f_optional = false; /* disallow after first level */
[5b4085b]283      if (isSep(ch)) get_pos(&fp_firstsep);
[a420b49]284   } while (isSep(ch));
[be97baf]285   if (name) osfree(name);
286
[d40f787]287   /* don't warn about a station that is referred to twice */
[95c3272]288   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);
[421b7d2]289
[6430f0e]290   if (fNew) {
[95c3272]291      /* fNew means SFLAGS_SURVEY is currently set */
[4c07c51]292      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
[c00c74a9]293      if (!fSurvey) {
294         ptr->sflags &= ~BIT(SFLAGS_SURVEY);
[27b8b59]295         if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[c00c74a9]296      }
[6430f0e]297   } else {
298      /* check that the same name isn't being used for a survey and station */
[95c3272]299      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
[0b8c321]300         /* TRANSLATORS: Here "station" is a survey station, not a train station.
301          *
302          * Here "survey" is a "cave map" rather than list of questions - it should be
303          * translated to the terminology that cavers using the language would use.
304          */
[cab0f26]305         compile_diagnostic(DIAG_ERR, /*“%s” can’t be both a station and a survey*/27,
306                            sprint_prefix(ptr));
[6430f0e]307      }
[27b8b59]308      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
[051a72b]309   }
310
[932f7e9]311   /* check the export level */
312#if 0
313   printf("R min %d max %d depth %d pfx %s\n",
314          ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr));
315#endif
[c00c74a9]316   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
[932f7e9]317      if (depth > ptr->max_export) ptr->max_export = depth;
318   } else if (ptr->max_export < depth) {
[dd5b1a8]319      prefix *survey = ptr;
320      char *s;
[93e3492]321      const char *p;
[dd5b1a8]322      int level;
323      for (level = ptr->max_export + 1; level; level--) {
324         survey = survey->up;
[4c07c51]325         SVX_ASSERT(survey);
[dd5b1a8]326      }
327      s = osstrdup(sprint_prefix(survey));
[93e3492]328      p = sprint_prefix(ptr);
[016068a]329      if (survey->filename) {
[cab0f26]330         compile_diagnostic_pfx(DIAG_ERR, survey,
331                                /*Station “%s” not exported from survey “%s”*/26,
332                                p, s);
[93e3492]333      } else {
[cab0f26]334         compile_diagnostic(DIAG_ERR, /*Station “%s” not exported from survey “%s”*/26, p, s);
[016068a]335      }
[dd5b1a8]336      osfree(s);
[932f7e9]337#if 0
338      printf(" *** pfx %s warning not exported enough depth %d "
[421b7d2]339             "ptr->max_export %d\n", sprint_prefix(ptr),
[932f7e9]340             depth, ptr->max_export);
341#endif
342   }
[0fa7aac]343   if (!fImplicitPrefix && (pfx_flags & PFX_WARN_SEPARATOR)) {
[5b4085b]344      filepos fp_tmp;
345      get_pos(&fp_tmp);
346      set_pos(&fp_firstsep);
347      compile_diagnostic(DIAG_WARN|DIAG_COL, /*Separator in survey name*/392);
348      set_pos(&fp_tmp);
[0fa7aac]349   }
[a420b49]350   return ptr;
[d1b1380]351}
352
[21c226e]353/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
354static real
[5a0ab6a]355read_number(bool f_optional, bool f_unsigned)
[a420b49]356{
[63d4f07]357   bool fPositive = true, fDigits = false;
[a420b49]358   real n = (real)0.0;
[c80bd34]359   filepos fp;
360   int ch_old;
[a420b49]361
[c80bd34]362   get_pos(&fp);
363   ch_old = ch;
[5a0ab6a]364   if (!f_unsigned) {
365      fPositive = !isMinus(ch);
366      if (isSign(ch)) nextch();
367   }
[a420b49]368
369   while (isdigit(ch)) {
[6974a34]370      n = n * (real)10.0 + (char)(ch - '0');
[d1b1380]371      nextch();
[63d4f07]372      fDigits = true;
[a420b49]373   }
374
375   if (isDecimal(ch)) {
376      real mult = (real)1.0;
377      nextch();
378      while (isdigit(ch)) {
379         mult *= (real).1;
380         n += (char)(ch - '0') * mult;
[63d4f07]381         fDigits = true;
[a420b49]382         nextch();
383      }
384   }
385
386   /* !'fRead' => !fDigits so fDigits => 'fRead' */
387   if (fDigits) return (fPositive ? n : -n);
388
389   /* didn't read a valid number.  If it's optional, reset filepos & return */
[4fb15a1]390   set_pos(&fp);
[21c226e]391   if (f_optional) {
[a420b49]392      return HUGE_REAL;
393   }
394
[c80bd34]395   if (isOmit(ch_old)) {
[cab0f26]396      compile_diagnostic(DIAG_ERR|DIAG_COL, /*Field may not be omitted*/8);
[647407d]397   } else {
[cab0f26]398      compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found “%s”*/9);
[647407d]399   }
400   LONGJMP(file.jbSkipLine);
[a420b49]401   return 0.0; /* for brain-fried compilers */
[d1b1380]402}
[647407d]403
[5a0ab6a]404static real
[4ca3219]405read_quadrant(bool f_optional)
406{
[5a0ab6a]407   enum {
408      POINT_N = 0,
409      POINT_E = 1,
410      POINT_S = 2,
411      POINT_W = 3,
412      POINT_NONE = -1
413   };
414   static const sztok pointtab[] = {
415        {"E", POINT_E },
416        {"N", POINT_N },
417        {"S", POINT_S },
418        {"W", POINT_W },
419        {NULL, POINT_NONE }
420   };
421   static const sztok pointewtab[] = {
422        {"E", POINT_E },
423        {"W", POINT_W },
424        {NULL, POINT_NONE }
425   };
426   if (f_optional && isOmit(ch)) {
427      return HUGE_REAL;
428   }
[9d9bee9]429   const int quad = 90;
430   filepos fp;
431   get_pos(&fp);
[5a0ab6a]432   get_token_no_blanks();
433   int first_point = match_tok(pointtab, TABSIZE(pointtab));
434   if (first_point == POINT_NONE) {
435      set_pos(&fp);
436      if (isOmit(ch)) {
437         compile_diagnostic(DIAG_ERR|DIAG_COL, /*Field may not be omitted*/8);
438      }
439      compile_diagnostic_token_show(DIAG_ERR, /*Expecting quadrant bearing, found “%s”*/483);
440      LONGJMP(file.jbSkipLine);
441      return 0.0; /* for brain-fried compilers */
[9d9bee9]442   }
[63d4f07]443   real r = read_number(true, true);
[5a0ab6a]444   if (r == HUGE_REAL) {
445      if (isSign(ch) || isDecimal(ch)) {
446         /* Give better errors for S-0E, N+10W, N.E, etc. */
[9d9bee9]447         set_pos(&fp);
[728874f9]448         compile_diagnostic_token_show(DIAG_ERR, /*Expecting quadrant bearing, found “%s”*/483);
[9d9bee9]449         LONGJMP(file.jbSkipLine);
450         return 0.0; /* for brain-fried compilers */
451      }
[5a0ab6a]452      /* N, S, E or W. */
453      return first_point * quad;
454   }
455   if (first_point == POINT_E || first_point == POINT_W) {
[9d9bee9]456      set_pos(&fp);
[728874f9]457      compile_diagnostic_token_show(DIAG_ERR, /*Expecting quadrant bearing, found “%s”*/483);
[9d9bee9]458      LONGJMP(file.jbSkipLine);
459      return 0.0; /* for brain-fried compilers */
[4ca3219]460   }
[5a0ab6a]461
[eb429bf]462   get_token_no_blanks();
463   int second_point = match_tok(pointewtab, TABSIZE(pointewtab));
464   if (second_point == POINT_NONE) {
[5a0ab6a]465      set_pos(&fp);
466      compile_diagnostic_token_show(DIAG_ERR, /*Expecting quadrant bearing, found “%s”*/483);
467      LONGJMP(file.jbSkipLine);
468      return 0.0; /* for brain-fried compilers */
[4ca3219]469   }
[5a0ab6a]470
[eb429bf]471   if (r > quad) {
[5a0ab6a]472      set_pos(&fp);
[eb429bf]473      compile_diagnostic_token_show(DIAG_ERR|DIAG_COL, /*Suspicious compass reading*/59);
[5a0ab6a]474      LONGJMP(file.jbSkipLine);
475      return 0.0; /* for brain-fried compilers */
[4ca3219]476   }
[5a0ab6a]477
478   if (first_point == POINT_N) {
479      if (second_point == POINT_W) {
480         r = quad * 4 - r;
481      }
482   } else {
483      if (second_point == POINT_W) {
484         r += quad * 2;
485      } else {
486         r = quad * 2 - r;
487      }
488   }
489   return r;
[4ca3219]490}
491
[21c226e]492extern real
[d3241e6]493read_numeric(bool f_optional)
494{
495   skipblanks();
[63d4f07]496   return read_number(f_optional, false);
[d3241e6]497}
498
499extern real
[61513b57]500read_numeric_multi(bool f_optional, bool f_quadrants, int *p_n_readings)
[21c226e]501{
502   size_t n_readings = 0;
503   real tot = (real)0.0;
504
505   skipblanks();
506   if (!isOpen(ch)) {
[4699c40]507      real r = 0;
[61513b57]508      if (!f_quadrants)
[63d4f07]509          r = read_number(f_optional, false);
[61513b57]510      else
[5a0ab6a]511          r = read_quadrant(f_optional);
[21c226e]512      if (p_n_readings) *p_n_readings = (r == HUGE_REAL ? 0 : 1);
513      return r;
514   }
515   nextch();
516
517   skipblanks();
518   do {
[9d9bee9]519      if (!f_quadrants)
[63d4f07]520         tot += read_number(false, false);
[61513b57]521      else
[63d4f07]522         tot += read_quadrant(false);
[21c226e]523      ++n_readings;
524      skipblanks();
525   } while (!isClose(ch));
526   nextch();
527
528   if (p_n_readings) *p_n_readings = n_readings;
529   /* FIXME: special averaging for bearings ... */
530   /* And for percentage gradient */
531   return tot / n_readings;
532}
533
[2aa2f3f]534/* read numeric expr or omit (return HUGE_REAL); else longjmp */
535extern real
[00b10c1]536read_bearing_multi_or_omit(bool f_quadrants, int *p_n_readings)
[2aa2f3f]537{
[9d9bee9]538   real v;
[63d4f07]539   v = read_numeric_multi(true, f_quadrants, p_n_readings);
[9d9bee9]540   if (v == HUGE_REAL) {
541      if (!isOmit(ch)) {
542         compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found “%s”*/9);
543         LONGJMP(file.jbSkipLine);
544         return 0.0; /* for brain-fried compilers */
[2aa2f3f]545      }
546      nextch();
547   }
548   return v;
549}
550
[950a829]551/* Don't skip blanks, variable error code */
552static unsigned int
[75e67ab]553read_uint_internal(int errmsg, const filepos *fp)
[647407d]554{
[421b7d2]555   unsigned int n = 0;
[647407d]556   if (!isdigit(ch)) {
[029cc3f]557      if (fp) set_pos(fp);
[cab0f26]558      compile_diagnostic_token_show(DIAG_ERR, errmsg);
[647407d]559      LONGJMP(file.jbSkipLine);
560   }
561   while (isdigit(ch)) {
562      n = n * 10 + (char)(ch - '0');
563      nextch();
564   }
565   return n;
566}
[76bb277a]567
[950a829]568extern unsigned int
569read_uint(void)
570{
571   skipblanks();
[0804fbe]572   return read_uint_internal(/*Expecting numeric field, found “%s”*/9, NULL);
[950a829]573}
574
[5b9b9d4]575extern int
576read_int(int min_val, int max_val)
577{
578    skipblanks();
579    unsigned n = 0;
580    filepos fp;
581
582    get_pos(&fp);
[1000d9d]583    bool negated = isMinus(ch);
584    unsigned limit;
585    if (negated) {
586        limit = (unsigned)(min_val == INT_MIN ? INT_MIN : -min_val);
587    } else {
588        limit = (unsigned)max_val;
589    }
[5b9b9d4]590    if (isSign(ch)) nextch();
591
592    if (!isdigit(ch)) {
593bad_value:
594        set_pos(&fp);
595        /* TRANSLATORS: The first %d will be replaced by the (inclusive) lower
596         * bound and the second by the (inclusive) upper bound, for example:
597         * Expecting integer in range -60 to 60
598         */
599        compile_diagnostic(DIAG_ERR|DIAG_NUM, /*Expecting integer in range %d to %d*/489);
600        LONGJMP(file.jbSkipLine);
601    }
602
603    while (isdigit(ch)) {
604        unsigned old_n = n;
605        n = n * 10 + (char)(ch - '0');
606        if (n > limit || n < old_n) {
607            goto bad_value;
608        }
609        nextch();
610    }
611    if (isDecimal(ch)) goto bad_value;
612
613    if (negated) {
614        if (n > (unsigned)INT_MAX) {
615            // Avoid unportable casting.
616            return INT_MIN;
617        }
618        return -(int)n;
619    }
620    return (int)n;
621}
622
[76bb277a]623extern void
[0532954]624read_string(string *pstr)
[76bb277a]625{
[0532954]626   s_clear(pstr);
[76bb277a]627
628   skipblanks();
629   if (ch == '\"') {
[1157304]630      /* String quoted in "" */
[76bb277a]631      nextch();
[457a390]632      while (1) {
633         if (isEol(ch)) {
[cab0f26]634            compile_diagnostic(DIAG_ERR|DIAG_COL, /*Missing \"*/69);
[4fb15a1]635            LONGJMP(file.jbSkipLine);
[457a390]636         }
637
638         if (ch == '\"') break;
639
[0532954]640         s_catchar(pstr, ch);
[457a390]641         nextch();
642      }
[66f5fc4]643      nextch();
[457a390]644   } else {
[1157304]645      /* Unquoted string */
[457a390]646      while (1) {
647         if (isEol(ch) || isComm(ch)) {
[0532954]648            if (s_empty(pstr)) {
[cab0f26]649               compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting string field*/121);
[6f61f83]650               LONGJMP(file.jbSkipLine);
[b97d134]651            }
[457a390]652            return;
[76bb277a]653         }
654
[457a390]655         if (isBlank(ch)) break;
[76bb277a]656
[0532954]657         s_catchar(pstr, ch);
[457a390]658         nextch();
659      }
[76bb277a]660   }
661}
[950a829]662
663extern void
[b5a3219]664read_date(int *py, int *pm, int *pd)
[950a829]665{
[734f5f4]666   unsigned int y = 0, m = 0, d = 0;
[1d74718]667   filepos fp_date;
[950a829]668
669   skipblanks();
[029cc3f]670
[1d74718]671   get_pos(&fp_date);
672   y = read_uint_internal(/*Expecting date, found “%s”*/198, &fp_date);
[e0c7cd1]673   /* Two digit year is 19xx. */
[734f5f4]674   if (y < 100) {
675      filepos fp_save;
676      get_pos(&fp_save);
677      y += 1900;
678      set_pos(&fp_date);
679      /* TRANSLATORS: %d will be replaced by the assumed year, e.g. 1918 */
680      compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Assuming 2 digit year is %d*/76, y);
681      set_pos(&fp_save);
682   }
[1ee204e]683   if (y < 1900 || y > 2078) {
[1d74718]684      set_pos(&fp_date);
[c270761]685      compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid year (< 1900 or > 2078)*/58);
[e0c7cd1]686      LONGJMP(file.jbSkipLine);
687      return; /* for brain-fried compilers */
688   }
[950a829]689   if (ch == '.') {
[1d74718]690      filepos fp;
[950a829]691      nextch();
[1d74718]692      get_pos(&fp);
693      m = read_uint_internal(/*Expecting date, found “%s”*/198, &fp_date);
[e0c7cd1]694      if (m < 1 || m > 12) {
[1d74718]695         set_pos(&fp);
[c270761]696         compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid month*/86);
[e0c7cd1]697         LONGJMP(file.jbSkipLine);
698         return; /* for brain-fried compilers */
[79d84d9]699      }
[950a829]700      if (ch == '.') {
701         nextch();
[1d74718]702         get_pos(&fp);
703         d = read_uint_internal(/*Expecting date, found “%s”*/198, &fp_date);
[e0c7cd1]704         if (d < 1 || d > last_day(y, m)) {
[1d74718]705            set_pos(&fp);
[736f7df]706            /* TRANSLATORS: e.g. 31st of April, or 32nd of any month */
[c270761]707            compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid day of the month*/87);
[e0c7cd1]708            LONGJMP(file.jbSkipLine);
709            return; /* for brain-fried compilers */
710         }
[950a829]711      }
712   }
[b5a3219]713   if (py) *py = y;
714   if (pm) *pm = m;
715   if (pd) *pd = d;
[950a829]716}
Note: See TracBrowser for help on using the repository browser.