source: git/src/commands.c @ 53496ab3

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

src/commands.c: Fix ordering of the style masks to reflect swapping
of STYLE_NOSURVEY and STYLE_PASSAGE.

  • Property mode set to 100644
File size: 44.1 KB
RevLine 
[ff6cfe1]1/* commands.c
[d1b1380]2 * Code for directives
[f15cde77]3 * Copyright (C) 1991-2003,2004,2005,2006,2010,2011,2012,2013 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
24#include <assert.h>
[a420b49]25#include <limits.h>
[be97baf]26#include <stddef.h> /* for offsetof */
[a420b49]27
28#include "cavern.h"
[d1b1380]29#include "commands.h"
30#include "datain.h"
[1ee204e]31#include "date.h"
[d1b1380]32#include "debug.h"
[5853657]33#include "filename.h"
34#include "message.h"
35#include "netbits.h"
36#include "netskel.h"
[5f1e194]37#include "out.h"
[5853657]38#include "readval.h"
[69c920d]39#include "str.h"
[a420b49]40
41static void
42default_grade(settings *s)
43{
[770157e]44   /* Values correspond to those in bcra5.svx */
45   s->Var[Q_POS] = (real)sqrd(0.05);
46   s->Var[Q_LENGTH] = (real)sqrd(0.05);
47   s->Var[Q_COUNT] = (real)sqrd(0.05);
48   s->Var[Q_DX] = s->Var[Q_DY] = s->Var[Q_DZ] = (real)sqrd(0.05);
49   s->Var[Q_BEARING] = (real)sqrd(rad(0.5));
50   s->Var[Q_GRADIENT] = (real)sqrd(rad(0.5));
51   s->Var[Q_BACKBEARING] = (real)sqrd(rad(0.5));
52   s->Var[Q_BACKGRADIENT] = (real)sqrd(rad(0.5));
[a420b49]53   /* SD of plumbed legs (0.25 degrees?) */
54   s->Var[Q_PLUMB] = (real)sqrd(rad(0.25));
[6b7079f]55   /* SD of level legs (0.25 degrees?) */
56   s->Var[Q_LEVEL] = (real)sqrd(rad(0.25));
[770157e]57   s->Var[Q_DEPTH] = (real)sqrd(0.05);
[a420b49]58}
59
60static void
61default_truncate(settings *s)
62{
63   s->Truncate = INT_MAX;
64}
65
66static void
67default_case(settings *s)
68{
69   s->Case = LOWER;
70}
71
[27b8b59]72static reading default_order[] = { Fr, To, Tape, Comp, Clino, End };
[a420b49]73
74static void
75default_style(settings *s)
76{
[107b8bd]77   s->style = STYLE_NORMAL;
[a420b49]78   s->ordering = default_order;
[dcbcae0]79   s->dash_for_anon_wall_station = fFalse;
[a420b49]80}
81
82static void
83default_prefix(settings *s)
84{
85   s->Prefix = root;
86}
87
88static void
89default_translate(settings *s)
90{
91   int i;
92   short *t;
93   if (s->next && s->next->Translate == s->Translate) {
94      t = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
95      memcpy(t - 1, s->Translate - 1, sizeof(short) * 257);
96      s->Translate = t;
97   }
[4c07c51]98/*  SVX_ASSERT(EOF==-1);*/ /* important, since we rely on this */
[a420b49]99   t = s->Translate;
[be97baf]100   memset(t - 1, 0, sizeof(short) * 257);
101   for (i = '0'; i <= '9'; i++) t[i] = SPECIAL_NAMES;
102   for (i = 'A'; i <= 'Z'; i++) t[i] = SPECIAL_NAMES;
103   for (i = 'a'; i <= 'z'; i++) t[i] = SPECIAL_NAMES;
[a420b49]104
105   t['\t'] |= SPECIAL_BLANK;
106   t[' '] |= SPECIAL_BLANK;
107   t[','] |= SPECIAL_BLANK;
108   t[';'] |= SPECIAL_COMMENT;
109   t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */
110   t[EOF] |= SPECIAL_EOL;
111   t['\n'] |= SPECIAL_EOL;
112   t['\r'] |= SPECIAL_EOL;
113   t['*'] |= SPECIAL_KEYWORD;
114   t['-'] |= SPECIAL_OMIT;
115   t['\\'] |= SPECIAL_ROOT;
116   t['.'] |= SPECIAL_SEPARATOR;
117   t['_'] |= SPECIAL_NAMES;
[f3ac7d4]118   t['-'] |= SPECIAL_NAMES; /* Added in 0.97 prerelease 4 */
[a420b49]119   t['.'] |= SPECIAL_DECIMAL;
120   t['-'] |= SPECIAL_MINUS;
121   t['+'] |= SPECIAL_PLUS;
[3593388]122#if 0 /* FIXME */
[7d40549]123   t['{'] |= SPECIAL_OPEN;
124   t['}'] |= SPECIAL_CLOSE;
[3593388]125#endif
[a420b49]126}
127
[be97baf]128void
[a420b49]129default_units(settings *s)
130{
131   int quantity;
132   for (quantity = 0; quantity < Q_MAC; quantity++) {
[7f08c83]133      if (TSTBIT(ANG_QMASK, quantity))
[bca0071]134         s->units[quantity] = (real)(M_PI / 180.0); /* degrees */
[a420b49]135      else
136         s->units[quantity] = (real)1.0; /* metres */
137   }
[fa42426]138   s->f_clino_percent = s->f_backclino_percent = fFalse;
[a420b49]139}
140
[be97baf]141void
[a420b49]142default_calib(settings *s)
143{
144   int quantity;
145   for (quantity = 0; quantity < Q_MAC; quantity++) {
146      s->z[quantity] = (real)0.0;
147      s->sc[quantity] = (real)1.0;
148   }
149}
150
[5c3c61a]151static void
152default_flags(settings *s)
153{
154   s->flags = 0;
155}
156
[a420b49]157extern void
158default_all(settings *s)
159{
160   default_truncate(s);
[27b8b59]161   s->infer = 0;
[a420b49]162   default_case(s);
163   default_style(s);
164   default_prefix(s);
165   default_translate(s);
166   default_grade(s);
167   default_units(s);
168   default_calib(s);
[5c3c61a]169   default_flags(s);
[a420b49]170}
171
[ee1ec59]172char *buffer = NULL;
[ee7bafa]173static int buf_len;
[d1b1380]174
[cfe093e]175static char *ucbuffer = NULL;
[5f1e194]176
[647407d]177/* read token */
[a420b49]178extern void
179get_token(void)
180{
[be97baf]181   int i = -1;
182
[cfe093e]183   s_zero(&buffer);
184   osfree(ucbuffer);
[5f1e194]185   skipblanks();
186   while (isalpha(ch)) {
[63dc4eb]187      s_catchar(&buffer, &buf_len, (char)ch);
[5f1e194]188      nextch();
189   }
[cfe093e]190
[be97baf]191   if (!buffer) s_catchar(&buffer, &buf_len, '\0');
192
[cfe093e]193   ucbuffer = osmalloc(buf_len);
[be97baf]194   do {
195      i++;
196      ucbuffer[i] = toupper(buffer[i]);
197   } while (buffer[i]);
[cfe093e]198#if 0
[0804fbe]199   printf("get_token() got “%s”\n", buffer);
[cfe093e]200#endif
[d1b1380]201}
202
[dcbcae0]203/* read word */
204static void
205get_word(void)
206{
207   s_zero(&buffer);
208   skipblanks();
209   while (!isBlank(ch) && !isEol(ch)) {
210      s_catchar(&buffer, &buf_len, (char)ch);
211      nextch();
212   }
213
214   if (!buffer) s_catchar(&buffer, &buf_len, '\0');
215#if 0
216   printf("get_word() got “%s”\n", buffer);
217#endif
218}
219
[d1b1380]220/* match_tok() now uses binary chop
221 * tab argument should be alphabetically sorted (ascending)
222 */
[a420b49]223extern int
224match_tok(const sztok *tab, int tab_size)
225{
[5f1e194]226   int a = 0, b = tab_size - 1, c;
227   int r;
228   assert(tab_size > 0); /* catch empty table */
[d1b1380]229/*  printf("[%d,%d]",a,b); */
[5f1e194]230   while (a <= b) {
231      c = (unsigned)(a + b) / 2;
[d1b1380]232/*     printf(" %d",c); */
[647407d]233      r = strcmp(tab[c].sz, ucbuffer);
[5f1e194]234      if (r == 0) return tab[c].tok; /* match */
235      if (r < 0)
236         a = c + 1;
237      else
238         b = c - 1;
239   }
240   return tab[tab_size].tok; /* no match */
[d1b1380]241}
242
[fb2e93c]243typedef enum {
[dcbcae0]244   CMD_NULL = -1, CMD_ALIAS, CMD_BEGIN, CMD_CALIBRATE, CMD_CASE, CMD_COPYRIGHT,
[dfb4240]245   CMD_DATA, CMD_DATE, CMD_DEFAULT, CMD_END, CMD_ENTRANCE, CMD_EQUATE,
246   CMD_EXPORT, CMD_FIX, CMD_FLAGS, CMD_INCLUDE, CMD_INFER, CMD_INSTRUMENT,
[82be646]247   CMD_PREFIX, CMD_REQUIRE, CMD_SD, CMD_SET, CMD_SOLVE,
[13a48f6]248   CMD_TEAM, CMD_TITLE, CMD_TRUNCATE, CMD_UNITS
[5f1e194]249} cmds;
[cb3d1e2]250
[5f1e194]251static sztok cmd_tab[] = {
[dcbcae0]252     {"ALIAS",     CMD_ALIAS},
[5f1e194]253     {"BEGIN",     CMD_BEGIN},
254     {"CALIBRATE", CMD_CALIBRATE},
[a420b49]255     {"CASE",      CMD_CASE},
[13a48f6]256     {"COPYRIGHT", CMD_COPYRIGHT},
[5f1e194]257     {"DATA",      CMD_DATA},
[13a48f6]258     {"DATE",      CMD_DATE},
[a7d5f1c]259#ifndef NO_DEPRECATED
[5f1e194]260     {"DEFAULT",   CMD_DEFAULT},
[a7d5f1c]261#endif
[5f1e194]262     {"END",       CMD_END},
[dfb4240]263     {"ENTRANCE",  CMD_ENTRANCE},
[5f1e194]264     {"EQUATE",    CMD_EQUATE},
[fb2e93c]265     {"EXPORT",    CMD_EXPORT},
[5f1e194]266     {"FIX",       CMD_FIX},
[5c3c61a]267     {"FLAGS",     CMD_FLAGS},
[5f1e194]268     {"INCLUDE",   CMD_INCLUDE},
[a420b49]269     {"INFER",     CMD_INFER},
[ec6a4b3]270     {"INSTRUMENT",CMD_INSTRUMENT},
[a7d5f1c]271#ifndef NO_DEPRECATED
[5f1e194]272     {"PREFIX",    CMD_PREFIX},
[a7d5f1c]273#endif
[647407d]274     {"REQUIRE",   CMD_REQUIRE},
[a4ae909]275     {"SD",        CMD_SD},
[5f1e194]276     {"SET",       CMD_SET},
277     {"SOLVE",     CMD_SOLVE},
[13a48f6]278     {"TEAM",      CMD_TEAM},
[a420b49]279     {"TITLE",     CMD_TITLE},
280     {"TRUNCATE",  CMD_TRUNCATE},
[5f1e194]281     {"UNITS",     CMD_UNITS},
[a4ae909]282     {NULL,        CMD_NULL}
[5f1e194]283};
284
[fa42426]285/* masks for units which are length and angles respectively */
286#define LEN_UMASK (BIT(UNITS_METRES) | BIT(UNITS_FEET) | BIT(UNITS_YARDS))
287#define ANG_UMASK (BIT(UNITS_DEGS) | BIT(UNITS_GRADS) | BIT(UNITS_MINUTES))
288
289/* ordering must be the same as the units enum */
290static real factor_tab[] = {
291   1.0, METRES_PER_FOOT, (METRES_PER_FOOT*3.0),
292   (M_PI/180.0), (M_PI/200.0), 0.01, (M_PI/180.0/60.0)
293};
294
[a420b49]295static int
[fa42426]296get_units(unsigned long qmask, bool percent_ok)
[a420b49]297{
[5f1e194]298   static sztok utab[] = {
299        {"DEGREES",       UNITS_DEGS },
[a4ae909]300        {"DEGS",          UNITS_DEGS },
301        {"FEET",          UNITS_FEET },
302        {"GRADS",         UNITS_GRADS },
303        {"METERS",        UNITS_METRES },
304        {"METRES",        UNITS_METRES },
305        {"METRIC",        UNITS_METRES },
306        {"MILS",          UNITS_GRADS },
307        {"MINUTES",       UNITS_MINUTES },
308        {"PERCENT",       UNITS_PERCENT },
[5f1e194]309        {"PERCENTAGE",    UNITS_PERCENT },
[a4ae909]310        {"YARDS",         UNITS_YARDS },
311        {NULL,            UNITS_NULL }
[5f1e194]312   };
[3a33d12]313   int units;
314   get_token();
315   units = match_tok(utab, TABSIZE(utab));
[647407d]316   if (units == UNITS_NULL) {
[da96015]317      file.lpos += strlen(buffer);
318      compile_error_skip(-/*Unknown units “%s”*/35, buffer);
[fa42426]319      return UNITS_NULL;
320   }
321   if (units == UNITS_PERCENT && percent_ok &&
322       !(qmask & ~(BIT(Q_GRADIENT)|BIT(Q_BACKGRADIENT)))) {
323      return units;
324   }
325   if (((qmask & LEN_QMASK) && !TSTBIT(LEN_UMASK, units)) ||
326       ((qmask & ANG_QMASK) && !TSTBIT(ANG_UMASK, units))) {
[da96015]327      file.lpos += strlen(buffer);
328      compile_error_skip(-/*Invalid units “%s” for quantity*/37, buffer);
[fa42426]329      return UNITS_NULL;
[647407d]330   }
[5f1e194]331   return units;
[d1b1380]332}
333
334/* returns mask with bit x set to indicate quantity x specified */
[67508f0]335static unsigned long
[46cb98f]336get_qlist(unsigned long mask_bad)
[a420b49]337{
[5f1e194]338   static sztok qtab[] = {
[9b5d785]339        {"ALTITUDE",     Q_DZ },
[b14f44f]340        {"BACKBEARING",  Q_BACKBEARING },
341        {"BACKCLINO",    Q_BACKGRADIENT },    /* alternative name */
342        {"BACKCOMPASS",  Q_BACKBEARING },     /* alternative name */
343        {"BACKGRADIENT", Q_BACKGRADIENT },
[5f1e194]344        {"BEARING",      Q_BEARING },
[ee05463]345        {"CEILING",      Q_UP },          /* alternative name */
[a4ae909]346        {"CLINO",        Q_GRADIENT },    /* alternative name */
[5f1e194]347        {"COMPASS",      Q_BEARING },     /* alternative name */
[a4ae909]348        {"COUNT",        Q_COUNT },
[5f1e194]349        {"COUNTER",      Q_COUNT },       /* alternative name */
350        {"DECLINATION",  Q_DECLINATION },
[a420b49]351        {"DEFAULT",      Q_DEFAULT }, /* not a real quantity... */
[a4ae909]352        {"DEPTH",        Q_DEPTH },
[ee05463]353        {"DOWN",         Q_DOWN },
[a4ae909]354        {"DX",           Q_DX },          /* alternative name */
355        {"DY",           Q_DY },          /* alternative name */
356        {"DZ",           Q_DZ },          /* alternative name */
357        {"EASTING",      Q_DX },
[ee05463]358        {"FLOOR",        Q_DOWN },        /* alternative name */
[5f1e194]359        {"GRADIENT",     Q_GRADIENT },
[ee05463]360        {"LEFT",         Q_LEFT },
[5f1e194]361        {"LENGTH",       Q_LENGTH },
[a4ae909]362        {"LEVEL",        Q_LEVEL},
[9b5d785]363        {"NORTHING",     Q_DY },
[a4ae909]364        {"PLUMB",        Q_PLUMB},
[5f1e194]365        {"POSITION",     Q_POS },
[ee05463]366        {"RIGHT",        Q_RIGHT },
[a4ae909]367        {"TAPE",         Q_LENGTH },      /* alternative name */
[ee05463]368        {"UP",           Q_UP },
[a4ae909]369        {NULL,           Q_NULL }
[5f1e194]370   };
[67508f0]371   unsigned long qmask = 0;
[5f1e194]372   int tok;
[3a33d12]373   filepos fp;
374
[a420b49]375   while (1) {
[3a33d12]376      get_pos(&fp);
[a420b49]377      get_token();
[5f1e194]378      tok = match_tok(qtab, TABSIZE(qtab));
[da96015]379      if (tok == Q_DEFAULT && !(mask_bad & BIT(Q_DEFAULT))) {
380          /* Only recognise DEFAULT if it is the first quantity, and then don't
381           * look for any more. */
382          if (qmask == 0)
383              return BIT(Q_DEFAULT);
384          break;
385      }
[5f1e194]386      /* bail out if we reach the table end with no match */
387      if (tok == Q_NULL) break;
388      qmask |= BIT(tok);
[da96015]389      if (qmask & mask_bad) {
390         file.lpos += strlen(buffer);
391         compile_error_skip(-/*Unknown instrument “%s”*/39, buffer);
[46cb98f]392         return 0;
393      }
[5f1e194]394   }
[3a33d12]395
[647407d]396   if (qmask == 0) {
[da96015]397      file.lpos += strlen(buffer);
398      compile_error_skip(-/*Unknown quantity “%s”*/34, buffer);
[3a33d12]399   } else {
400      set_pos(&fp);
[647407d]401   }
[3a33d12]402
[5f1e194]403   return qmask;
[d1b1380]404}
405
406#define SPECIAL_UNKNOWN 0
[a420b49]407static void
[eb18f4d]408cmd_set(void)
[a420b49]409{
[5f1e194]410   static sztok chartab[] = {
411        {"BLANK",     SPECIAL_BLANK },
[3593388]412/*FIXME {"CLOSE",     SPECIAL_CLOSE }, */
[5f1e194]413        {"COMMENT",   SPECIAL_COMMENT },
414        {"DECIMAL",   SPECIAL_DECIMAL },
415        {"EOL",       SPECIAL_EOL }, /* EOL won't work well */
416        {"KEYWORD",   SPECIAL_KEYWORD },
417        {"MINUS",     SPECIAL_MINUS },
418        {"NAMES",     SPECIAL_NAMES },
419        {"OMIT",      SPECIAL_OMIT },
[3593388]420/*FIXME {"OPEN",      SPECIAL_OPEN }, */
[5f1e194]421        {"PLUS",      SPECIAL_PLUS },
[7f1ab95]422#ifndef NO_DEPRECATED
[5f1e194]423        {"ROOT",      SPECIAL_ROOT },
[7f1ab95]424#endif
[5f1e194]425        {"SEPARATOR", SPECIAL_SEPARATOR },
[a4ae909]426        {NULL,        SPECIAL_UNKNOWN }
[5f1e194]427   };
428   int mask;
429   int i;
[b15eeda]430
[a420b49]431   get_token();
[5f1e194]432   mask = match_tok(chartab, TABSIZE(chartab));
[b15eeda]433
[f74d0cb]434   if (mask == SPECIAL_UNKNOWN) {
[da96015]435      file.lpos += strlen(buffer);
436      compile_error_skip(-/*Unknown character class “%s”*/42, buffer);
[5f1e194]437      return;
438   }
[b15eeda]439
[7f1ab95]440#ifndef NO_DEPRECATED
[c86cc71]441   if (mask == SPECIAL_ROOT) {
442      if (root_depr_count < 5) {
[da96015]443         file.lpos += strlen(buffer);
444         compile_warning(-/*ROOT is deprecated*/25);
[c86cc71]445         if (++root_depr_count == 5)
[c40038a]446            compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]447      }
448   }
[7f1ab95]449#endif
[b15eeda]450
[5f1e194]451   /* if we're currently using an inherited translation table, allocate a new
452    * table, and copy old one into it */
453   if (pcs->next && pcs->next->Translate == pcs->Translate) {
454      short *p;
455      p = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
456      memcpy(p - 1, pcs->Translate - 1, sizeof(short) * 257);
457      pcs->Translate = p;
458   }
[11f9067]459
460   skipblanks();
461
[5f1e194]462   /* clear this flag for all non-alphanums */
[a420b49]463   for (i = 0; i < 256; i++)
464      if (!isalnum(i)) pcs->Translate[i] &= ~mask;
[11f9067]465
[5f1e194]466   /* now set this flag for all specified chars */
467   while (!isEol(ch)) {
[11f9067]468      if (!isalnum(ch)) {
469         pcs->Translate[ch] |= mask;
470      } else if (tolower(ch) == 'x') {
471         int hex;
472         filepos fp;
473         get_pos(&fp);
474         nextch();
475         if (!isxdigit(ch)) {
476            set_pos(&fp);
477            break;
478         }
479         hex = isdigit(ch) ? ch - '0' : tolower(ch) - 'a';
480         nextch();
481         if (!isxdigit(ch)) {
482            set_pos(&fp);
483            break;
484         }
485         hex = hex << 4 | (isdigit(ch) ? ch - '0' : tolower(ch) - 'a');
486         pcs->Translate[hex] |= mask;
487      } else {
488         break;
489      }
[5f1e194]490      nextch();
491   }
[d1b1380]492}
493
[4d9eecd]494static void
495check_reentry(prefix *tag)
496{
[91912b4]497   /* Don't try to check "*prefix \" or "*begin \" */
498   if (!tag->up) return;
[d333899]499   if (TSTBIT(tag->sflags, SFLAGS_PREFIX_ENTERED)) {
[4d9eecd]500      if (tag->line != file.line ||
501          strcmp(tag->filename, file.filename) != 0) {
[a63fb408]502         const char *filename_store = file.filename;
503         unsigned int line_store = file.line;
[c86cc71]504         static int reenter_depr_count = 0;
505
506         if (reenter_depr_count < 5) {
507            compile_warning(/*Reentering an existing prefix level is deprecated*/29);
508            if (++reenter_depr_count == 5)
[c40038a]509               compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]510         }
511
[a63fb408]512         file.filename = tag->filename;
513         file.line = tag->line;
514         compile_warning(/*Originally entered here*/30);
515         file.filename = filename_store;
516         file.line = line_store;
[4d9eecd]517      }
518   } else {
[d333899]519      tag->sflags |= BIT(SFLAGS_PREFIX_ENTERED);
[4d9eecd]520      tag->filename = file.filename;
521      tag->line = file.line;
522   }
523}
524
[7f1ab95]525#ifndef NO_DEPRECATED
[a420b49]526static void
[eb18f4d]527cmd_prefix(void)
[a420b49]528{
[c86cc71]529   static int prefix_depr_count = 0;
[91912b4]530   prefix *tag;
531   /* Issue warning first, so "*prefix \" warns first that *prefix is
532    * deprecated and then that ROOT is...
533    */
[c86cc71]534   if (prefix_depr_count < 5) {
[da96015]535      compile_warning(-/**prefix is deprecated - use *begin and *end instead*/6);
[c86cc71]536      if (++prefix_depr_count == 5)
[c40038a]537         compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]538   }
[c458cf7]539   tag = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT);
[4d9eecd]540   pcs->Prefix = tag;
[d53b0f5]541   check_reentry(tag);
[d1b1380]542}
[7f1ab95]543#endif
[d1b1380]544
[dcbcae0]545static void
546cmd_alias(void)
547{
[45dcea2]548   /* Currently only two forms are supported:
[dcbcae0]549    * *alias station - ..
[45dcea2]550    * *alias station -
[dcbcae0]551    */
552   get_token();
553   if (strcmp(ucbuffer, "STATION") != 0)
554      goto bad;
555   get_word();
556   if (strcmp(buffer, "-") != 0)
557      goto bad;
558   get_word();
559   if (*buffer && strcmp(buffer, "..") != 0)
560      goto bad;
561   pcs->dash_for_anon_wall_station = (*buffer != '\0');
562   return;
563bad:
564   compile_error_skip(/*Bad *alias command*/397);
565}
566
[a420b49]567static void
[eb18f4d]568cmd_begin(void)
[a420b49]569{
[4be360f]570   prefix *tag;
[5f1e194]571   settings *pcsNew;
[4be360f]572
[5f1e194]573   pcsNew = osnew(settings);
574   *pcsNew = *pcs; /* copy contents */
[47c7a94]575   pcsNew->begin_lineno = file.line;
[5f1e194]576   pcsNew->next = pcs;
577   pcs = pcsNew;
[4be360f]578
[0fa7aac]579   tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT|PFX_WARN_SEPARATOR);
[4be360f]580   pcs->tag = tag;
[4d9eecd]581   if (tag) {
582      pcs->Prefix = tag;
583      check_reentry(tag);
[4dcd3af]584      f_export_ok = fTrue;
[d53b0f5]585   }
[647407d]586}
587
588extern void
[eb18f4d]589free_settings(settings *p) {
[647407d]590   /* don't free default ordering or ordering used by parent */
[0395657]591   reading *order = p->ordering;
[0580c6a]592   if (order != default_order && (!p->next || order != p->next->ordering))
593      osfree(order);
[cb3d1e2]594
[647407d]595   /* free Translate if not used by parent */
[0580c6a]596   if (!p->next || p->Translate != p->next->Translate)
597      osfree(p->Translate - 1);
[647407d]598
[b5a3219]599   /* free meta is not used by parent, or in this block */
600   if (p->meta && p->meta != p->next->meta && p->meta->ref_count == 0)
601       osfree(p->meta);
602
[eb18f4d]603   osfree(p);
[d1b1380]604}
605
[4be360f]606static void
[eb18f4d]607cmd_end(void)
[a420b49]608{
[5f1e194]609   settings *pcsParent;
[4be360f]610   prefix *tag, *tagBegin;
611
[5f1e194]612   pcsParent = pcs->next;
[4be360f]613
[47c7a94]614   if (pcs->begin_lineno == 0) {
[4be360f]615      if (pcsParent == NULL) {
616         /* more ENDs than BEGINs */
[fa42426]617         compile_error_skip(/*No matching BEGIN*/192);
[4be360f]618      } else {
[fa42426]619         compile_error_skip(/*END with no matching BEGIN in this file*/22);
[4be360f]620      }
621      return;
622   }
623
624   tagBegin = pcs->tag;
[647407d]625
[4c07c51]626   SVX_ASSERT(pcsParent);
[647407d]627   free_settings(pcs);
[5f1e194]628   pcs = pcsParent;
[d1b1380]629
[84c60fc]630   /* note need to read using root *before* BEGIN */
[c458cf7]631   tag = read_prefix(PFX_SURVEY|PFX_OPT|PFX_ALLOW_ROOT);
[5f1e194]632   if (tag != tagBegin) {
[a420b49]633      if (tag) {
[647407d]634         if (!tagBegin) {
635            /* "*begin" / "*end foo" */
[da96015]636            compile_error_skip(-/*Matching BEGIN tag has no prefix*/36);
[647407d]637         } else {
638            /* tag mismatch */
[da96015]639            compile_error_skip(-/*Prefix tag doesn’t match BEGIN*/193);
[647407d]640         }
[a420b49]641      } else {
[5f1e194]642         /* close tag omitted; open tag given */
[da96015]643         compile_warning(-/*Closing prefix omitted from END*/194);
[a420b49]644      }
[5f1e194]645   }
646}
[d1b1380]647
[dfb4240]648static void
649cmd_entrance(void)
650{
[c458cf7]651   prefix *pfx = read_prefix(PFX_STATION);
[dfb4240]652   pfx->sflags |= BIT(SFLAGS_ENTRANCE);
653}
654
[a420b49]655static void
[eb18f4d]656cmd_fix(void)
[a420b49]657{
[5f1e194]658   prefix *fix_name;
[153f951]659   node *stn = NULL;
[5f1e194]660   static node *stnOmitAlready = NULL;
[a420b49]661   real x, y, z;
[21c226e]662   int nx, ny, nz;
[c80bd34]663   filepos fp;
[5f1e194]664
[c458cf7]665   fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
[dfb4240]666   fix_name->sflags |= BIT(SFLAGS_FIXED);
[5f1e194]667
[c80bd34]668   get_pos(&fp);
[647407d]669   get_token();
[c80bd34]670   if (strcmp(ucbuffer, "REFERENCE") == 0) {
[f15cde77]671      /* suppress "unused fixed point" warnings for this station */
672      fix_name->sflags |= BIT(SFLAGS_USED);
[c80bd34]673   } else {
674      if (*ucbuffer) set_pos(&fp);
[647407d]675   }
[c80bd34]676
[21c226e]677   x = read_numeric(fTrue, &nx);
[2aa2f3f]678   if (x == HUGE_REAL) {
679      /* If the end of the line isn't blank, read a number after all to
680       * get a more helpful error message */
[21c226e]681      if (!isEol(ch) && !isComm(ch)) x = read_numeric(fFalse, &nx);
[2aa2f3f]682   }
[5f1e194]683   if (x == HUGE_REAL) {
684      if (stnOmitAlready) {
[c80bd34]685         if (fix_name != stnOmitAlready->name) {
[fa42426]686            compile_error_skip(/*More than one FIX command with no coordinates*/56);
[c80bd34]687         } else {
[a420b49]688            compile_warning(/*Same station fixed twice with no coordinates*/61);
[c80bd34]689         }
[5f1e194]690         return;
691      }
[153f951]692      stn = StnFromPfx(fix_name);
[a420b49]693      compile_warning(/*FIX command with no coordinates - fixing at (0,0,0)*/54);
[5f1e194]694      x = y = z = (real)0.0;
695      stnOmitAlready = stn;
696   } else {
[647407d]697      real sdx;
[21c226e]698      y = read_numeric(fFalse, &ny);
699      z = read_numeric(fFalse, &nz);
700      sdx = read_numeric(fTrue, NULL);
[647407d]701      if (sdx != HUGE_REAL) {
702         real sdy, sdz;
[c80bd34]703         real cxy = 0, cyz = 0, czx = 0;
[21c226e]704         sdy = read_numeric(fTrue, NULL);
[647407d]705         if (sdy == HUGE_REAL) {
706            /* only one variance given */
707            sdy = sdz = sdx;
708         } else {
[21c226e]709            sdz = read_numeric(fTrue, NULL);
[647407d]710            if (sdz == HUGE_REAL) {
711               /* two variances given - horizontal & vertical */
712               sdz = sdy;
713               sdy = sdx;
[c80bd34]714            } else {
[21c226e]715               cxy = read_numeric(fTrue, NULL);
[c80bd34]716               if (cxy != HUGE_REAL) {
717                  /* covariances given */
[21c226e]718                  cyz = read_numeric(fFalse, NULL);
719                  czx = read_numeric(fFalse, NULL);
[c2211a5]720               } else {
721                  cxy = 0;
[c80bd34]722               }
[647407d]723            }
724         }
[153f951]725         stn = StnFromPfx(fix_name);
[647407d]726         if (!fixed(stn)) {
727            node *fixpt = osnew(node);
[be97baf]728            prefix *name;
729            name = osnew(prefix);
730            name->pos = osnew(pos);
[ff6cfe1]731            name->ident = NULL;
[6adb88c]732            name->shape = 0;
[647407d]733            fixpt->name = name;
734            name->stn = fixpt;
735            name->up = NULL;
[27b8b59]736            if (TSTBIT(pcs->infer, INFER_EXPORTS)) {
[c00c74a9]737               name->min_export = USHRT_MAX;
738            } else {
739               name->min_export = 0;
740            }
741            name->max_export = 0;
[95c3272]742            name->sflags = 0;
[cb3d1e2]743            add_stn_to_list(&stnlist, fixpt);
[647407d]744            POS(fixpt, 0) = x;
745            POS(fixpt, 1) = y;
746            POS(fixpt, 2) = z;
747            fix(fixpt);
[4c45ef1]748            fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL;
[647407d]749            addfakeleg(fixpt, stn, 0, 0, 0,
750                       sdx * sdx, sdy * sdy, sdz * sdz
751#ifndef NO_COVARIANCES
[c80bd34]752                       , cxy, cyz, czx
[647407d]753#endif
754                       );
755         }
[cb3d1e2]756         return;
[647407d]757      }
[6adb88c]758      stn = StnFromPfx(fix_name);
[5f1e194]759   }
760
761   if (!fixed(stn)) {
762      POS(stn, 0) = x;
763      POS(stn, 1) = y;
764      POS(stn, 2) = z;
765      fix(stn);
766      return;
767   }
[d1b1380]768
[5f1e194]769   if (x != POS(stn, 0) || y != POS(stn, 1) || z != POS(stn, 2)) {
[a420b49]770      compile_error(/*Station already fixed or equated to a fixed point*/46);
[5f1e194]771      return;
772   }
[a420b49]773   compile_warning(/*Station already fixed at the same coordinates*/55);
[d1b1380]774}
775
[5c3c61a]776static void
777cmd_flags(void)
778{
779   static sztok flagtab[] = {
780        {"DUPLICATE", FLAGS_DUPLICATE },
781        {"NOT",       FLAGS_NOT },
[95c3272]782        {"SPLAY",     FLAGS_SPLAY },
[5c3c61a]783        {"SURFACE",   FLAGS_SURFACE },
[a4ae909]784        {NULL,        FLAGS_UNKNOWN }
[5c3c61a]785   };
786   bool fNot = fFalse;
[9881759]787   bool fEmpty = fTrue;
[5c3c61a]788   while (1) {
789      int flag;
790      get_token();
[62bb4d3]791      /* If buffer is empty, it could mean end of line, or maybe
792       * some non-letter junk which is better reported later */
[9881759]793      if (!buffer[0]) break;
[62bb4d3]794
[9881759]795      fEmpty = fFalse;
[5c3c61a]796      flag = match_tok(flagtab, TABSIZE(flagtab));
797      /* treat the second NOT in "NOT NOT" as an unknown flag */
798      if (flag == FLAGS_UNKNOWN || (fNot && flag == FLAGS_NOT)) {
[da96015]799         file.lpos += strlen(buffer);
800         compile_error(-/*FLAG “%s” unknown*/68, buffer);
[0804fbe]801         /* Recover from “*FLAGS NOT BOGUS SURFACE” by ignoring "NOT BOGUS" */
[62bb4d3]802         fNot = fFalse;
803      } else if (flag == FLAGS_NOT) {
[421b7d2]804         fNot = fTrue;
[5c3c61a]805      } else if (fNot) {
[421b7d2]806         pcs->flags &= ~BIT(flag);
807         fNot = fFalse;
[5c3c61a]808      } else {
[421b7d2]809         pcs->flags |= BIT(flag);
[5c3c61a]810      }
811   }
[9881759]812
813   if (fNot) {
[da96015]814      file.lpos += strlen(buffer);
815      compile_error(-/*Expecting “DUPLICATE”, “SPLAY”, or “SURFACE”*/188);
[9881759]816   } else if (fEmpty) {
[da96015]817      file.lpos += strlen(buffer);
818      compile_error(-/*Expecting “NOT”, “DUPLICATE”, “SPLAY”, or “SURFACE”*/189);
[9881759]819   }
[5c3c61a]820}
821
[a420b49]822static void
[eb18f4d]823cmd_equate(void)
[a420b49]824{
[5f1e194]825   prefix *name1, *name2;
826   bool fOnlyOneStn = fTrue; /* to trap eg *equate entrance.6 */
827
[c458cf7]828   name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO);
[5f1e194]829   while (fTrue) {
830      name2 = name1;
[c458cf7]831      name1 = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO|PFX_OPT);
[5f1e194]832      if (name1 == NULL) {
[11f9067]833         if (fOnlyOneStn) {
[da96015]834            compile_error_skip(-/*Only one station in EQUATE command*/33);
[11f9067]835         }
[5f1e194]836         return;
[d1b1380]837      }
[cb3d1e2]838
[be374fc]839      process_equate(name1, name2);
[5f1e194]840      fOnlyOneStn = fFalse;
841   }
[d1b1380]842}
843
[84c60fc]844static void
845report_missing_export(prefix *pfx, int depth)
846{
847   const char *filename_store = file.filename;
848   unsigned int line_store = file.line;
849   prefix *survey = pfx;
850   char *s;
851   int i;
852   for (i = depth + 1; i; i--) {
853      survey = survey->up;
[4c07c51]854      SVX_ASSERT(survey);
[84c60fc]855   }
856   s = osstrdup(sprint_prefix(survey));
857   if (survey->filename) {
858      file.filename = survey->filename;
859      file.line = survey->line;
860   }
[0804fbe]861   compile_error(/*Station “%s” not exported from survey “%s”*/26,
[84c60fc]862                 sprint_prefix(pfx), s);
863   if (survey->filename) {
864      file.filename = filename_store;
865      file.line = line_store;
866   }
867   osfree(s);
868}
869
[fb2e93c]870static void
[d1878c51]871cmd_export(void)
[fb2e93c]872{
[d1878c51]873   prefix *pfx;
874
875   fExportUsed = fTrue;
[c458cf7]876   pfx = read_prefix(PFX_STATION);
[932f7e9]877   do {
[fb2e93c]878      int depth = 0;
879      {
[421b7d2]880         prefix *p = pfx;
[fb2e93c]881         while (p != NULL && p != pcs->Prefix) {
882            depth++;
883            p = p->up;
884         }
[84c60fc]885         /* Something like: *export \foo, but we've excluded use of root */
[4c07c51]886         SVX_ASSERT(p);
[fb2e93c]887      }
[84c60fc]888      /* *export \ or similar bogus stuff */
[4c07c51]889      SVX_ASSERT(depth);
[932f7e9]890#if 0
891      printf("C min %d max %d depth %d pfx %s\n",
892             pfx->min_export, pfx->max_export, depth, sprint_prefix(pfx));
893#endif
894      if (pfx->min_export == 0) {
[421b7d2]895         /* not encountered *export for this name before */
896         if (pfx->max_export > depth) report_missing_export(pfx, depth);
897         pfx->min_export = pfx->max_export = depth;
[c00c74a9]898      } else if (pfx->min_export != USHRT_MAX) {
899         /* FIXME: what to do if a station is marked for inferred exports
900          * but is then explicitly exported?  Currently we just ignore the
901          * explicit export... */
[421b7d2]902         if (pfx->min_export - 1 > depth) {
[84c60fc]903            report_missing_export(pfx, depth);
[421b7d2]904         } else if (pfx->min_export - 1 < depth) {
[0804fbe]905            compile_error(/*Station “%s” already exported*/66,
[932f7e9]906                          sprint_prefix(pfx));
[421b7d2]907         }
908         pfx->min_export = depth;
[fb2e93c]909      }
[c458cf7]910      pfx = read_prefix(PFX_STATION|PFX_OPT);
[932f7e9]911   } while (pfx);
[fb2e93c]912}
913
[a420b49]914static void
[eb18f4d]915cmd_data(void)
[a420b49]916{
[5f1e194]917   static sztok dtab[] = {
[9b5d785]918        {"ALTITUDE",     Dz },
[5b7c1b7]919        {"BACKBEARING",  BackComp },
920        {"BACKCLINO",    BackClino }, /* alternative name */
921        {"BACKCOMPASS",  BackComp }, /* alternative name */
922        {"BACKGRADIENT", BackClino },
[5f1e194]923        {"BEARING",      Comp },
[ee05463]924        {"CEILING",      Up }, /* alternative name */
[a4ae909]925        {"CLINO",        Clino }, /* alternative name */
[a420b49]926        {"COMPASS",      Comp }, /* alternative name */
[a4ae909]927        {"COUNT",        Count }, /* FrCount&ToCount in multiline */
928        {"DEPTH",        Depth }, /* FrDepth&ToDepth in multiline */
[6114207]929        {"DEPTHCHANGE",  DepthChange },
[421b7d2]930        {"DIRECTION",    Dir },
[ee05463]931        {"DOWN",         Down },
[647407d]932        {"DX",           Dx },
933        {"DY",           Dy },
934        {"DZ",           Dz },
[9b5d785]935        {"EASTING",      Dx },
[ee05463]936        {"FLOOR",        Down }, /* alternative name */
[a4ae909]937        {"FROM",         Fr },
[647407d]938        {"FROMCOUNT",    FrCount },
[5f1e194]939        {"FROMDEPTH",    FrDepth },
940        {"GRADIENT",     Clino },
941        {"IGNORE",       Ignore },
942        {"IGNOREALL",    IgnoreAll },
[ee05463]943        {"LEFT",         Left },
[5f1e194]944        {"LENGTH",       Tape },
[a0027a2]945        {"NEWLINE",      Newline },
[9b5d785]946        {"NORTHING",     Dy },
[ee05463]947        {"RIGHT",        Right },
[421b7d2]948        {"STATION",      Station }, /* Fr&To in multiline */
[a4ae909]949        {"TAPE",         Tape }, /* alternative name */
950        {"TO",           To },
[647407d]951        {"TOCOUNT",      ToCount },
[5f1e194]952        {"TODEPTH",      ToDepth },
[ee05463]953        {"UP",           Up },
[a4ae909]954        {NULL,           End }
[5f1e194]955   };
956
[107b8bd]957#define MASK_stns BIT(Fr) | BIT(To) | BIT(Station)
958#define MASK_tape BIT(Tape) | BIT(FrCount) | BIT(ToCount) | BIT(Count)
959#define MASK_dpth BIT(FrDepth) | BIT(ToDepth) | BIT(Depth) | BIT(DepthChange)
[5b7c1b7]960#define MASK_comp BIT(Comp) | BIT(BackComp)
961#define MASK_clin BIT(Clino) | BIT(BackClino)
[5f1e194]962
[5b7c1b7]963#define MASK_NORMAL MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_clin
964#define MASK_DIVING MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_dpth
[107b8bd]965#define MASK_CARTESIAN MASK_stns | BIT(Dx) | BIT(Dy) | BIT(Dz)
[5b7c1b7]966#define MASK_CYLPOLAR  MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_dpth
[ee05463]967#define MASK_PASSAGE BIT(Station) | BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down)
[107b8bd]968#define MASK_NOSURVEY MASK_stns
[421b7d2]969
[5f1e194]970   /* readings which may be given for each style */
[6114207]971   static const unsigned long mask[] = {
[200a12c]972      MASK_NORMAL, MASK_DIVING, MASK_CARTESIAN, MASK_CYLPOLAR, MASK_NOSURVEY,
973      MASK_PASSAGE
[5f1e194]974   };
975
976   /* readings which may be omitted for each style */
[6114207]977   static const unsigned long mask_optional[] = {
[5b7c1b7]978      BIT(Dir) | BIT(Clino) | BIT(BackClino),
[276286d]979      BIT(Dir),
[86f26e2]980      0,
[54c4612]981      BIT(Dir),
[200a12c]982      0,
983      0 /* BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down), */
[5f1e194]984   };
985
[6114207]986   /* all valid readings */
987   static const unsigned long mask_all[] = {
988      MASK_NORMAL | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
989      MASK_DIVING | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
990      MASK_CARTESIAN | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
991      MASK_CYLPOLAR | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
[200a12c]992      MASK_NOSURVEY | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
993      MASK_PASSAGE | BIT(Ignore) | BIT(IgnoreAll) | BIT(End)
[6114207]994   };
[54c4612]995#define STYLE_DEFAULT   -2
996#define STYLE_UNKNOWN   -1
997
[5f1e194]998   static sztok styletab[] = {
[647407d]999        {"CARTESIAN",    STYLE_CARTESIAN },
[54c4612]1000        {"CYLPOLAR",     STYLE_CYLPOLAR },
[a420b49]1001        {"DEFAULT",      STYLE_DEFAULT },
[5f1e194]1002        {"DIVING",       STYLE_DIVING },
1003        {"NORMAL",       STYLE_NORMAL },
[647407d]1004        {"NOSURVEY",     STYLE_NOSURVEY },
[ee05463]1005        {"PASSAGE",      STYLE_PASSAGE },
[107b8bd]1006        {"TOPOFIL",      STYLE_NORMAL },
[a4ae909]1007        {NULL,           STYLE_UNKNOWN }
[5f1e194]1008   };
1009
[ee3a4ed]1010#define m_multi (BIT(Station) | BIT(Count) | BIT(Depth))
1011
[5f1e194]1012   int style, k = 0, kMac;
[0395657]1013   reading *new_order, d;
[6114207]1014   unsigned long mUsed = 0;
[1b34062]1015   char *style_name;
[5f1e194]1016
[50f6901]1017   /* after a bad *data command ignore survey data until the next
1018    * *data command to avoid an avalanche of errors */
[107b8bd]1019   pcs->style = STYLE_IGNORE;
[289b7a8]1020
[5f1e194]1021   kMac = 6; /* minimum for NORMAL style */
[0395657]1022   new_order = osmalloc(kMac * sizeof(reading));
[5f1e194]1023
[a420b49]1024   get_token();
[5f1e194]1025   style = match_tok(styletab, TABSIZE(styletab));
1026
[a420b49]1027   if (style == STYLE_DEFAULT) {
1028      default_style(pcs);
1029      return;
1030   }
1031
[5f1e194]1032   if (style == STYLE_UNKNOWN) {
[da96015]1033      file.lpos += strlen(buffer);
1034      compile_error_skip(-/*Data style “%s” unknown*/65, buffer);
[5f1e194]1035      return;
1036   }
[a420b49]1037
[5f1e194]1038   skipblanks();
[d6d3576]1039#ifndef NO_DEPRECATED
1040   /* Olde syntax had optional field for survey grade, so allow an omit
1041    * but issue a warning about it */
1042   if (isOmit(ch)) {
1043      static int data_depr_count = 0;
1044      if (data_depr_count < 5) {
[da96015]1045         file.lpos += strlen(buffer);
1046         compile_warning(-/*“*data %s %c …” is deprecated - use “*data %s …” instead*/104,
[d6d3576]1047                         buffer, ch, buffer);
1048         if (++data_depr_count == 5)
[c40038a]1049            compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[d6d3576]1050      }
1051      nextch();
1052   }
1053#endif
[d1b1380]1054
[1b34062]1055   style_name = osstrdup(buffer);
[421b7d2]1056   do {
[c80bd34]1057      filepos fp;
1058      get_pos(&fp);
[a420b49]1059      get_token();
[5f1e194]1060      d = match_tok(dtab, TABSIZE(dtab));
[90bb053f]1061      /* only token allowed after IGNOREALL is NEWLINE */
1062      if (k && new_order[k - 1] == IgnoreAll && d != Newline) {
[c80bd34]1063         set_pos(&fp);
[90bb053f]1064         break;
1065      }
[0395657]1066      /* Note: an unknown token is reported as trailing garbage */
[6114207]1067      if (!TSTBIT(mask_all[style], d)) {
[da96015]1068         file.lpos += strlen(buffer);
1069         compile_error_skip(-/*Reading “%s” not allowed in data style “%s”*/63,
[1b34062]1070                       buffer, style_name);
1071         osfree(style_name);
[a6d094f]1072         osfree(new_order);
[ee3a4ed]1073         return;
1074      }
[6114207]1075      if (TSTBIT(mUsed, Newline) && TSTBIT(m_multi, d)) {
[46cb98f]1076         /* e.g. "*data diving station newline tape depth compass" */
[da96015]1077         file.lpos += strlen(buffer);
1078         compile_error_skip(-/*Reading “%s” must occur before NEWLINE*/225, buffer);
[ee3a4ed]1079         osfree(style_name);
[a6d094f]1080         osfree(new_order);
[5f1e194]1081         return;
1082      }
[0395657]1083      /* Check for duplicates unless it's a special reading:
[ee3a4ed]1084       *   IGNOREALL,IGNORE (duplicates allowed) ; END (not possible)
[5f1e194]1085       */
[ee3a4ed]1086      if (!((BIT(Ignore) | BIT(End) | BIT(IgnoreAll)) & BIT(d))) {
[95c3272]1087         if (TSTBIT(mUsed, d)) {
[da96015]1088            file.lpos += strlen(buffer);
1089            compile_error_skip(-/*Duplicate reading “%s”*/67, buffer);
[90bb053f]1090            osfree(style_name);
[a6d094f]1091            osfree(new_order);
[90bb053f]1092            return;
[62bb4d3]1093         } else {
[5b7c1b7]1094            /* Check for previously listed readings which are incompatible
1095             * with this one - e.g. Count vs FrCount */
[90bb053f]1096            bool fBad = fFalse;
1097            switch (d) {
1098             case Station:
1099               if (mUsed & (BIT(Fr) | BIT(To))) fBad = fTrue;
1100               break;
1101             case Fr: case To:
1102               if (TSTBIT(mUsed, Station)) fBad = fTrue;
1103               break;
1104             case Count:
[107b8bd]1105               if (mUsed & (BIT(FrCount) | BIT(ToCount) | BIT(Tape)))
1106                  fBad = fTrue;
[90bb053f]1107               break;
1108             case FrCount: case ToCount:
[107b8bd]1109               if (mUsed & (BIT(Count) | BIT(Tape)))
1110                  fBad = fTrue;
[90bb053f]1111               break;
1112             case Depth:
[6114207]1113               if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(DepthChange)))
[a186573]1114                  fBad = fTrue;
[90bb053f]1115               break;
1116             case FrDepth: case ToDepth:
[6114207]1117               if (mUsed & (BIT(Depth) | BIT(DepthChange))) fBad = fTrue;
[a186573]1118               break;
[6114207]1119             case DepthChange:
[a186573]1120               if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(Depth)))
1121                  fBad = fTrue;
[90bb053f]1122               break;
[ee3a4ed]1123             case Newline:
1124               if (mUsed & ~m_multi) {
[46cb98f]1125                  /* e.g. "*data normal from to tape newline compass clino" */
[da96015]1126                  file.lpos += strlen(buffer);
1127                  compile_error_skip(-/*NEWLINE can only be preceded by STATION, DEPTH, and COUNT*/226);
[ee3a4ed]1128                  osfree(style_name);
[a6d094f]1129                  osfree(new_order);
[ee3a4ed]1130                  return;
1131               }
[6114207]1132               if (k == 0) {
[da96015]1133                  file.lpos += strlen(buffer);
1134                  compile_error_skip(-/*NEWLINE can’t be the first reading*/222);
[6114207]1135                  osfree(style_name);
1136                  osfree(new_order);
1137                  return;
1138               }
[ee3a4ed]1139               break;
[90bb053f]1140             default: /* avoid compiler warnings about unhandled enums */
1141               break;
[421b7d2]1142            }
[90bb053f]1143            if (fBad) {
[46cb98f]1144               /* Not entirely happy with phrasing this... */
[da96015]1145               file.lpos += strlen(buffer);
1146               compile_error_skip(-/*Reading “%s” duplicates previous reading(s)*/77,
[46cb98f]1147                             buffer);
[90bb053f]1148               osfree(style_name);
[a6d094f]1149               osfree(new_order);
[90bb053f]1150               return;
1151            }
[62bb4d3]1152            mUsed |= BIT(d); /* used to catch duplicates */
[a420b49]1153         }
[d1b1380]1154      }
[90bb053f]1155      if (k && new_order[k - 1] == IgnoreAll) {
[4c07c51]1156         SVX_ASSERT(d == Newline);
[90bb053f]1157         k--;
1158         d = IgnoreAllAndNewLine;
1159      }
[a420b49]1160      if (k >= kMac) {
1161         kMac = kMac * 2;
[0395657]1162         new_order = osrealloc(new_order, kMac * sizeof(reading));
[a420b49]1163      }
1164      new_order[k++] = d;
[90bb053f]1165   } while (d != End);
1166
[6114207]1167   if (k >= 2 && new_order[k - 2] == Newline) {
[da96015]1168      file.lpos += strlen(buffer);
1169      compile_error_skip(-/*NEWLINE can’t be the last reading*/223);
[6114207]1170      osfree(style_name);
1171      osfree(new_order);
1172      return;
1173   }
[421b7d2]1174
[6114207]1175   if (style == STYLE_NOSURVEY) {
1176      if (TSTBIT(mUsed, Station)) {
1177         if (k >= kMac) {
1178            kMac = kMac * 2;
1179            new_order = osrealloc(new_order, kMac * sizeof(reading));
1180         }
1181         new_order[k - 1] = Newline;
1182         new_order[k++] = End;
1183      }
[ee05463]1184   } else if (style == STYLE_PASSAGE) {
1185      /* Station doesn't mean "multiline" for STYLE_PASSAGE. */
[6114207]1186   } else if (!TSTBIT(mUsed, Newline) && (m_multi & mUsed)) {
1187      /* This is for when they write
1188       * *data normal station tape compass clino
1189       * (i.e. no newline, but interleaved readings)
1190       */
[fa42426]1191      compile_error_skip(/*Interleaved readings, but no NEWLINE*/224);
[6114207]1192      osfree(style_name);
1193      osfree(new_order);
1194      return;
1195   }
1196
[a6d094f]1197#if 0
1198   printf("mUsed = 0x%x\n", mUsed);
1199#endif
[90bb053f]1200
[5b7c1b7]1201   /* Check the supplied readings form a sufficient set. */
[ee05463]1202   if (style != STYLE_PASSAGE) {
1203       if (mUsed & (BIT(Fr) | BIT(To)))
1204           mUsed |= BIT(Station);
1205       else if (TSTBIT(mUsed, Station))
1206           mUsed |= BIT(Fr) | BIT(To);
1207   }
[a186573]1208
[5b7c1b7]1209   if (mUsed & (BIT(Comp) | BIT(BackComp)))
1210      mUsed |= BIT(Comp) | BIT(BackComp);
1211
1212   if (mUsed & (BIT(Clino) | BIT(BackClino)))
1213      mUsed |= BIT(Clino) | BIT(BackClino);
1214
[a186573]1215   if (mUsed & (BIT(FrDepth) | BIT(ToDepth)))
[6114207]1216      mUsed |= BIT(Depth) | BIT(DepthChange);
[a186573]1217   else if (TSTBIT(mUsed, Depth))
[6114207]1218      mUsed |= BIT(FrDepth) | BIT(ToDepth) | BIT(DepthChange);
1219   else if (TSTBIT(mUsed, DepthChange))
[a186573]1220      mUsed |= BIT(FrDepth) | BIT(ToDepth) | BIT(Depth);
1221
1222   if (mUsed & (BIT(FrCount) | BIT(ToCount)))
[107b8bd]1223      mUsed |= BIT(Count) | BIT(Tape);
[a186573]1224   else if (TSTBIT(mUsed, Count))
[107b8bd]1225      mUsed |= BIT(FrCount) | BIT(ToCount) | BIT(Tape);
1226   else if (TSTBIT(mUsed, Tape))
1227      mUsed |= BIT(FrCount) | BIT(ToCount) | BIT(Count);
[90bb053f]1228
[a6d094f]1229#if 0
1230   printf("mUsed = 0x%x, opt = 0x%x, mask = 0x%x\n", mUsed,
1231          mask_optional[style], mask[style]);
1232#endif
[cb3d1e2]1233
[6114207]1234   if (((mUsed &~ BIT(Newline)) | mask_optional[style]) != mask[style]) {
1235      /* Test should only fail with too few bits set, not too many */
[4c07c51]1236      SVX_ASSERT((((mUsed &~ BIT(Newline)) | mask_optional[style])
[6114207]1237              &~ mask[style]) == 0);
[0804fbe]1238      compile_error_skip(/*Too few readings for data style “%s”*/64, style_name);
[1b34062]1239      osfree(style_name);
[a6d094f]1240      osfree(new_order);
[a420b49]1241      return;
1242   }
[d1b1380]1243
[a420b49]1244   /* don't free default ordering or ordering used by parent */
1245   if (pcs->ordering != default_order &&
1246       !(pcs->next && pcs->next->ordering == pcs->ordering))
1247      osfree(pcs->ordering);
[cb3d1e2]1248
[107b8bd]1249   pcs->style = style;
[a420b49]1250   pcs->ordering = new_order;
[1b34062]1251
[421b7d2]1252   osfree(style_name);
[ee05463]1253
1254   if (style == STYLE_PASSAGE) {
1255      lrudlist * new_psg = osnew(lrudlist);
1256      new_psg->tube = NULL;
1257      new_psg->next = model;
1258      model = new_psg;
1259      next_lrud = &(new_psg->tube);
1260   }
[d1b1380]1261}
1262
[a420b49]1263static void
[eb18f4d]1264cmd_units(void)
[a420b49]1265{
[5f1e194]1266   int units, quantity;
[6114207]1267   unsigned long qmask;
1268   unsigned long m; /* mask with bit x set to indicate quantity x specified */
[5f1e194]1269   real factor;
[a420b49]1270
[da96015]1271   qmask = get_qlist(0);
[647407d]1272   if (!qmask) return;
[a420b49]1273   if (qmask == BIT(Q_DEFAULT)) {
1274      default_units(pcs);
[5f1e194]1275      return;
1276   }
[a420b49]1277
[21c226e]1278   factor = read_numeric(fTrue, NULL);
[fa42426]1279   if (factor == 0.0) {
[da96015]1280      compile_error_skip(-/**UNITS factor must be non-zero*/200);
[fa42426]1281      return;
1282   }
[6114207]1283   if (factor == HUGE_REAL) factor = (real)1.0;
[a420b49]1284
[fa42426]1285   units = get_units(qmask, fTrue);
[647407d]1286   if (units == UNITS_NULL) return;
[fa42426]1287   if (TSTBIT(qmask, Q_GRADIENT))
1288      pcs->f_clino_percent = (units == UNITS_PERCENT);
1289   if (TSTBIT(qmask, Q_BACKGRADIENT))
1290      pcs->f_backclino_percent = (units == UNITS_PERCENT);
1291
[5f1e194]1292   factor *= factor_tab[units];
1293
1294   for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1)
1295      if (qmask & m) pcs->units[quantity] = factor;
[d1b1380]1296}
1297
[a420b49]1298static void
[eb18f4d]1299cmd_calibrate(void)
[a420b49]1300{
[d6d3576]1301   real sc, z;
[67508f0]1302   unsigned long qmask, m;
[a420b49]1303   int quantity;
[46cb98f]1304
[da96015]1305   qmask = get_qlist(BIT(Q_POS)|BIT(Q_PLUMB)|BIT(Q_LEVEL));
[46cb98f]1306   if (!qmask) return; /* error already reported */
1307
[a420b49]1308   if (qmask == BIT(Q_DEFAULT)) {
1309      default_calib(pcs);
1310      return;
1311   }
[46cb98f]1312
[a420b49]1313   if (((qmask & LEN_QMASK)) && ((qmask & ANG_QMASK))) {
[ee7511a]1314      compile_error_skip(/*Can’t calibrate angular and length quantities together*/227);
[647407d]1315      return;
[a420b49]1316   }
[46cb98f]1317
[21c226e]1318   z = read_numeric(fFalse, NULL);
1319   sc = read_numeric(fTrue, NULL);
[a420b49]1320   if (sc == HUGE_REAL) sc = (real)1.0;
[647407d]1321   /* check for declination scale */
[3a33d12]1322   /* perhaps "*calibrate declination XXX" should be "*declination XXX" ? */
[95c3272]1323   if (TSTBIT(qmask, Q_DECLINATION) && sc != 1.0) {
[da96015]1324      compile_error_skip(-/*Scale factor must be 1.0 for DECLINATION*/40);
[647407d]1325      return;
1326   }
[4b14118]1327   if (sc == 0.0) {
[da96015]1328      compile_error_skip(-/*Scale factor must be non-zero*/391);
[4b14118]1329      return;
1330   }
[647407d]1331   for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1) {
[a420b49]1332      if (qmask & m) {
[647407d]1333         pcs->z[quantity] = pcs->units[quantity] * z;
[a420b49]1334         pcs->sc[quantity] = sc;
1335      }
[647407d]1336   }
[d1b1380]1337}
1338
[7f1ab95]1339#ifndef NO_DEPRECATED
[a420b49]1340static void
[eb18f4d]1341cmd_default(void)
[a420b49]1342{
[c0563da]1343   static sztok defaulttab[] = {
1344      { "CALIBRATE", CMD_CALIBRATE },
1345      { "DATA",      CMD_DATA },
1346      { "UNITS",     CMD_UNITS },
[a4ae909]1347      { NULL,        CMD_NULL }
[c0563da]1348   };
[c86cc71]1349   static int default_depr_count = 0;
1350
1351   if (default_depr_count < 5) {
[da96015]1352      compile_warning(-/**DEFAULT is deprecated - use *CALIBRATE/DATA/SD/UNITS with argument DEFAULT instead*/20);
[c86cc71]1353      if (++default_depr_count == 5)
[c40038a]1354         compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
[c86cc71]1355   }
1356
[cb3d1e2]1357   get_token();
[c0563da]1358   switch (match_tok(defaulttab, TABSIZE(defaulttab))) {
1359    case CMD_CALIBRATE:
[5f1e194]1360      default_calib(pcs);
[c0563da]1361      break;
1362    case CMD_DATA:
[5f1e194]1363      default_style(pcs);
1364      default_grade(pcs);
[c0563da]1365      break;
1366    case CMD_UNITS:
[5f1e194]1367      default_units(pcs);
[c0563da]1368      break;
1369    default:
[da96015]1370      file.lpos += strlen(buffer);
1371      compile_error_skip(-/*Unknown setting “%s”*/41, buffer);
[5f1e194]1372   }
[d1b1380]1373}
[7f1ab95]1374#endif
[d1b1380]1375
[a420b49]1376static void
[eb18f4d]1377cmd_include(void)
[a420b49]1378{
[f97076a]1379   char *pth, *fnm = NULL;
[a420b49]1380   int fnm_len;
[a882316]1381#ifndef NO_DEPRECATED
[5f1e194]1382   prefix *root_store;
[a882316]1383#endif
[5f1e194]1384   int ch_store;
1385
[f97076a]1386   pth = path_from_fnm(file.filename);
1387
[a420b49]1388   read_string(&fnm, &fnm_len);
[d1b1380]1389
[a882316]1390#ifndef NO_DEPRECATED
1391   /* Since *begin / *end nesting cannot cross file boundaries we only
1392    * need to preserve the prefix if the deprecated *prefix command
1393    * can be used */
[5f1e194]1394   root_store = root;
1395   root = pcs->Prefix; /* Root for include file is current prefix */
[a882316]1396#endif
[5f1e194]1397   ch_store = ch;
[cb3d1e2]1398
[5f1e194]1399   data_file(pth, fnm);
[a420b49]1400
[a882316]1401#ifndef NO_DEPRECATED
[5f1e194]1402   root = root_store; /* and restore root */
[647407d]1403#endif
[5f1e194]1404   ch = ch_store;
[d1b1380]1405
[a420b49]1406   s_free(&fnm);
[f97076a]1407   osfree(pth);
[d1b1380]1408}
1409
[a420b49]1410static void
[eb18f4d]1411cmd_sd(void)
[a420b49]1412{
[5f1e194]1413   real sd, variance;
1414   int units;
[67508f0]1415   unsigned long qmask, m;
[5f1e194]1416   int quantity;
[b14f44f]1417   qmask = get_qlist(BIT(Q_DECLINATION));
[46cb98f]1418   if (!qmask) return; /* no quantities found - error already reported */
1419
[a420b49]1420   if (qmask == BIT(Q_DEFAULT)) {
1421      default_grade(pcs);
[5f1e194]1422      return;
1423   }
[21c226e]1424   sd = read_numeric(fFalse, NULL);
[d6d3576]1425   if (sd <= (real)0.0) {
[da96015]1426      compile_error_skip(-/*Standard deviation must be positive*/48);
[d6d3576]1427      return;
[5f1e194]1428   }
[fa42426]1429   units = get_units(qmask, fFalse);
[647407d]1430   if (units == UNITS_NULL) return;
[5f1e194]1431
1432   sd *= factor_tab[units];
1433   variance = sqrd(sd);
1434
1435   for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1)
1436      if (qmask & m) pcs->Var[quantity] = variance;
[d1b1380]1437}
[5f1e194]1438
[a420b49]1439static void
[eb18f4d]1440cmd_title(void)
[a420b49]1441{
[1925d66]1442   if (!fExplicitTitle && pcs->Prefix == root) {
1443       /* If we don't have an explicit title yet, and we're currently in the
1444        * root prefix, use this title explicitly. */
[a420b49]1445      fExplicitTitle = fTrue;
1446      read_string(&survey_title, &survey_title_len);
1447   } else {
1448      /* parse and throw away this title (but still check rest of line) */
1449      char *s = NULL;
1450      int len;
1451      read_string(&s, &len);
1452      s_free(&s);
1453   }
1454}
1455
1456static sztok case_tab[] = {
1457     {"PRESERVE", OFF},
[c57e9da]1458     {"TOLOWER",  LOWER},
1459     {"TOUPPER",  UPPER},
[a420b49]1460     {NULL,       -1}
1461};
[cb3d1e2]1462
[a420b49]1463static void
[eb18f4d]1464cmd_case(void)
[a420b49]1465{
1466   int setting;
1467   get_token();
1468   setting = match_tok(case_tab, TABSIZE(case_tab));
1469   if (setting != -1) {
1470      pcs->Case = setting;
1471   } else {
[da96015]1472      file.lpos += strlen(buffer);
1473      compile_error_skip(-/*Found “%s”, expecting “PRESERVE”, “TOUPPER”, or “TOLOWER”*/10,
1474                         buffer);
[a420b49]1475   }
1476}
1477
1478static sztok infer_tab[] = {
[27b8b59]1479     { "EQUATES",       INFER_EQUATES },
1480     { "EXPORTS",       INFER_EXPORTS },
1481     { "PLUMBS",        INFER_PLUMBS },
1482#if 0 /* FIXME */
1483     { "SUBSURVEYS",    INFER_SUBSURVEYS },
1484#endif
1485     { NULL,            INFER_NULL }
[a420b49]1486};
[cb3d1e2]1487
[a420b49]1488static sztok onoff_tab[] = {
[27b8b59]1489     { "OFF", 0 },
1490     { "ON",  1 },
1491     { NULL, -1 }
[a420b49]1492};
[cb3d1e2]1493
[a420b49]1494static void
[eb18f4d]1495cmd_infer(void)
[a420b49]1496{
[27b8b59]1497   infer_what setting;
[a420b49]1498   int on;
1499   get_token();
1500   setting = match_tok(infer_tab, TABSIZE(infer_tab));
[27b8b59]1501   if (setting == INFER_NULL) {
[da96015]1502      file.lpos += strlen(buffer);
1503      compile_error_skip(-/*Found “%s”, expecting “EQUATES”, “EXPORTS”, or “PLUMBS”*/31, buffer);
[647407d]1504      return;
[a420b49]1505   }
1506   get_token();
1507   on = match_tok(onoff_tab, TABSIZE(onoff_tab));
1508   if (on == -1) {
[da96015]1509      file.lpos += strlen(buffer);
1510      compile_error_skip(-/*Found “%s”, expecting “ON” or “OFF”*/32, buffer);
[647407d]1511      return;
[a420b49]1512   }
[cb3d1e2]1513
[27b8b59]1514   if (on) {
1515      pcs->infer |= BIT(setting);
1516      if (setting == INFER_EXPORTS) fExportUsed = fTrue;
1517   } else {
1518      pcs->infer &= ~BIT(setting);
[a420b49]1519   }
1520}
1521
1522static void
[eb18f4d]1523cmd_truncate(void)
[a420b49]1524{
[647407d]1525   unsigned int truncate_at = 0; /* default is no truncation */
[c80bd34]1526   filepos fp;
1527
1528   get_pos(&fp);
1529
[647407d]1530   get_token();
1531   if (strcmp(ucbuffer, "OFF") != 0) {
[c80bd34]1532      if (*ucbuffer) set_pos(&fp);
[647407d]1533      truncate_at = read_uint();
1534   }
1535   /* for backward compatibility, "*truncate 0" means "*truncate off" */
1536   pcs->Truncate = (truncate_at == 0) ? INT_MAX : truncate_at;
1537}
1538
1539static void
[eb18f4d]1540cmd_require(void)
[647407d]1541{
[e2546c0]1542   const unsigned int version[] = {COMMAVERSION};
1543   const unsigned int *ver = version;
[c80bd34]1544   filepos fp;
1545
[69c920d]1546   skipblanks();
[c80bd34]1547   get_pos(&fp);
[647407d]1548   while (1) {
[e2546c0]1549      int diff = *ver++ - read_uint();
1550      if (diff > 0) break;
1551      if (diff < 0) {
[647407d]1552         size_t i, len;
1553         char *v;
[c80bd34]1554         filepos fp_tmp;
1555
[647407d]1556         /* find end of version number */
1557         while (isdigit(ch) || ch == '.') nextch();
[c80bd34]1558         get_pos(&fp_tmp);
1559         len = (size_t)(fp_tmp.offset - fp.offset);
[647407d]1560         v = osmalloc(len + 1);
[c80bd34]1561         set_pos(&fp);
[647407d]1562         for (i = 0; i < len; i++) {
1563            v[i] = ch;
[69c920d]1564            nextch();
1565         }
[647407d]1566         v[i] = '\0';
1567         fatalerror_in_file(file.filename, file.line, /*Survex version %s or greater required to process this survey data.*/2, v);
1568      }
1569      if (ch != '.') break;
1570      nextch();
[e2546c0]1571      if (!isdigit(ch) || ver == version + sizeof(version)) break;
[69c920d]1572   }
[647407d]1573   /* skip rest of version number */
1574   while (isdigit(ch) || ch == '.') nextch();
[a420b49]1575}
1576
[b5a3219]1577/* allocate new meta_data if need be */
1578void
1579copy_on_write_meta(settings *s)
1580{
1581   if (!s->meta || s->meta->ref_count != 0) {
1582       meta_data * meta_new = osnew(meta_data);
1583       if (!s->meta) {
[1ee204e]1584           meta_new->days1 = meta_new->days2 = -1;
[b5a3219]1585       } else {
1586           *meta_new = *(s->meta);
1587       }
1588       meta_new->ref_count = 0;
1589       s->meta = meta_new;
1590   }
1591}
1592
[950a829]1593static void
1594cmd_date(void)
[421b7d2]1595{
[e0c7cd1]1596    int year, month, day;
[1ee204e]1597    int days1, days2;
1598    bool implicit_range = fFalse;
[e0c7cd1]1599
1600    read_date(&year, &month, &day);
[1ee204e]1601    days1 = days_since_1900(year, month ? month : 1, day ? day : 1);
1602
1603    if (days1 > current_days_since_1900) {
[da96015]1604        compile_warning(-/*Date is in the future!*/80);
[e0c7cd1]1605    }
1606
1607    skipblanks();
1608    if (ch == '-') {
1609        nextch();
1610        read_date(&year, &month, &day);
1611    } else {
[1ee204e]1612        if (month && day) {
1613            days2 = days1;
1614            goto read;
1615        }
1616        implicit_range = fTrue;
1617    }
1618
1619    if (month == 0) month = 12;
1620    if (day == 0) day = last_day(year, month);
1621    days2 = days_since_1900(year, month, day);
1622
1623    if (!implicit_range && days2 > current_days_since_1900) {
[da96015]1624        compile_warning(-/*Date is in the future!*/80);
[e0c7cd1]1625    }
[1ee204e]1626
1627    if (days2 < days1) {
[da96015]1628        compile_error(-/*End of date range is before the start*/81);
[1ee204e]1629    }
[e0c7cd1]1630
[1ee204e]1631read:
[e0c7cd1]1632    copy_on_write_meta(pcs);
[1ee204e]1633    pcs->meta->days1 = days1;
1634    pcs->meta->days2 = days2;
[950a829]1635}
1636
[3aafcee]1637typedef void (*cmd_fn)(void);
1638
1639static cmd_fn cmd_funcs[] = {
[dcbcae0]1640   cmd_alias,
[3aafcee]1641   cmd_begin,
1642   cmd_calibrate,
1643   cmd_case,
1644   skipline, /*cmd_copyright,*/
1645   cmd_data,
[950a829]1646   cmd_date,
[7f1ab95]1647#ifndef NO_DEPRECATED
[3aafcee]1648   cmd_default,
[7f1ab95]1649#endif
[3aafcee]1650   cmd_end,
1651   cmd_entrance,
1652   cmd_equate,
1653   cmd_export,
1654   cmd_fix,
1655   cmd_flags,
1656   cmd_include,
1657   cmd_infer,
1658   skipline, /*cmd_instrument,*/
[7f1ab95]1659#ifndef NO_DEPRECATED
[3aafcee]1660   cmd_prefix,
[7f1ab95]1661#endif
[3aafcee]1662   cmd_require,
1663   cmd_sd,
1664   cmd_set,
1665   solve_network,
1666   skipline, /*cmd_team,*/
1667   cmd_title,
1668   cmd_truncate,
1669   cmd_units
1670};
1671
[a420b49]1672extern void
1673handle_command(void)
1674{
[932f7e9]1675   int cmdtok;
[a420b49]1676   get_token();
[932f7e9]1677   cmdtok = match_tok(cmd_tab, TABSIZE(cmd_tab));
1678
[3aafcee]1679   if (cmdtok < 0 || cmdtok >= (int)(sizeof(cmd_funcs) / sizeof(cmd_fn))) {
[da96015]1680      file.lpos += strlen(buffer);
1681      compile_error_skip(-/*Unknown command “%s”*/12, buffer);
[3aafcee]1682      return;
[932f7e9]1683   }
1684
1685   switch (cmdtok) {
[3aafcee]1686    case CMD_EXPORT:
1687      if (!f_export_ok)
[0804fbe]1688         compile_error(/**EXPORT must immediately follow “*BEGIN <SURVEY>”*/57);
[3aafcee]1689      break;
1690    case CMD_COPYRIGHT:
1691    case CMD_DATE:
1692    case CMD_INSTRUMENT:
1693    case CMD_TEAM:
1694    case CMD_TITLE:
[4dcd3af]1695      /* These can occur between *begin and *export */
[421b7d2]1696      break;
[a420b49]1697    default:
[4dcd3af]1698      /* NB: additional handling for "*begin <survey>" in cmd_begin */
[3aafcee]1699      f_export_ok = fFalse;
1700      break;
[647407d]1701   }
[421b7d2]1702
[3aafcee]1703   cmd_funcs[cmdtok]();
[5f1e194]1704}
Note: See TracBrowser for help on using the repository browser.