[ff6cfe1] | 1 | /* commands.c |
---|
[d1b1380] | 2 | * Code for directives |
---|
[0f8216c] | 3 | * Copyright (C) 1991-2025 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 | #include <config.h> |
---|
[d1b1380] | 21 | |
---|
[a420b49] | 22 | #include <limits.h> |
---|
[be97baf] | 23 | #include <stddef.h> /* for offsetof */ |
---|
[aeeb3de] | 24 | #include <string.h> |
---|
[a420b49] | 25 | |
---|
[b39e24a] | 26 | #include <proj.h> |
---|
[d9d8f21] | 27 | #if PROJ_VERSION_MAJOR < 8 |
---|
| 28 | # define proj_context_errno_string(CTX, ERR) proj_errno_string(ERR) |
---|
| 29 | #endif |
---|
[c092d72] | 30 | |
---|
[a420b49] | 31 | #include "cavern.h" |
---|
[d1b1380] | 32 | #include "commands.h" |
---|
| 33 | #include "datain.h" |
---|
[1ee204e] | 34 | #include "date.h" |
---|
[d1b1380] | 35 | #include "debug.h" |
---|
[5853657] | 36 | #include "filename.h" |
---|
| 37 | #include "message.h" |
---|
| 38 | #include "netbits.h" |
---|
| 39 | #include "netskel.h" |
---|
[a49a80c0] | 40 | #include "osalloc.h" |
---|
[5f1e194] | 41 | #include "out.h" |
---|
[5853657] | 42 | #include "readval.h" |
---|
[69c920d] | 43 | #include "str.h" |
---|
[a420b49] | 44 | |
---|
[bf9faf6] | 45 | static void |
---|
| 46 | move_to_fixedlist(node *stn, int ignore_dirn) |
---|
| 47 | { |
---|
| 48 | remove_stn_from_list(&stnlist, stn); |
---|
| 49 | add_stn_to_list(&fixedlist, stn); |
---|
| 50 | pos *p = stn->name->pos; |
---|
| 51 | for (int d = 0; d < 3; d++) { |
---|
| 52 | if (d == ignore_dirn) continue; |
---|
| 53 | linkfor *leg = stn->leg[d]; |
---|
| 54 | if (!leg) break; |
---|
| 55 | node *to = leg->l.to; |
---|
| 56 | if (to->name->pos == p) { |
---|
| 57 | move_to_fixedlist(to, reverse_leg_dirn(leg)); |
---|
| 58 | } |
---|
| 59 | } |
---|
| 60 | } |
---|
| 61 | |
---|
[98b705d] | 62 | int fix_station(prefix *fix_name, const double* coords, long offset) { |
---|
[e315359] | 63 | bool new_stn = (fix_name->stn == NULL && |
---|
| 64 | !TSTBIT(fix_name->sflags, SFLAGS_SOLVED)); |
---|
[725d3b1] | 65 | fix_name->sflags |= BIT(SFLAGS_FIXED); |
---|
[e315359] | 66 | if (new_stn) fix_name->sflags |= BIT(SFLAGS_UNUSED_FIXED_POINT); |
---|
[725d3b1] | 67 | node *stn = StnFromPfx(fix_name); |
---|
| 68 | if (fixed(stn)) { |
---|
| 69 | if (coords[0] != POS(stn, 0) || |
---|
| 70 | coords[1] != POS(stn, 1) || |
---|
| 71 | coords[2] != POS(stn, 2)) { |
---|
| 72 | return -1; |
---|
| 73 | } |
---|
| 74 | return 1; |
---|
| 75 | } |
---|
| 76 | |
---|
| 77 | POS(stn, 0) = coords[0]; |
---|
| 78 | POS(stn, 1) = coords[1]; |
---|
| 79 | POS(stn, 2) = coords[2]; |
---|
| 80 | |
---|
[bf9faf6] | 81 | if (new_stn) { |
---|
| 82 | remove_stn_from_list(&stnlist, stn); |
---|
| 83 | add_stn_to_list(&fixedlist, stn); |
---|
| 84 | } else { |
---|
| 85 | move_to_fixedlist(stn, -1); |
---|
| 86 | } |
---|
| 87 | |
---|
[725d3b1] | 88 | // Make the station's file:line location reflect where it was fixed. |
---|
| 89 | fix_name->filename = file.filename; |
---|
| 90 | fix_name->line = file.line; |
---|
[98b705d] | 91 | fix_name->column = offset >= 0 ? offset - file.lpos : 0; |
---|
[725d3b1] | 92 | return 0; |
---|
| 93 | } |
---|
| 94 | |
---|
[05b93bc0] | 95 | void fix_station_with_variance(prefix *fix_name, const double* coords, |
---|
[725d3b1] | 96 | real var_x, real var_y, real var_z, |
---|
| 97 | #ifndef NO_COVARIANCES |
---|
| 98 | real cxy, real cyz, real czx |
---|
| 99 | #endif |
---|
| 100 | ) |
---|
| 101 | { |
---|
[e315359] | 102 | bool new_stn = (fix_name->stn == NULL && |
---|
| 103 | !TSTBIT(fix_name->sflags, SFLAGS_SOLVED)); |
---|
| 104 | if (new_stn) fix_name->sflags |= BIT(SFLAGS_UNUSED_FIXED_POINT); |
---|
| 105 | |
---|
[725d3b1] | 106 | node *stn = StnFromPfx(fix_name); |
---|
| 107 | if (!fixed(stn)) { |
---|
| 108 | node *fixpt = osnew(node); |
---|
| 109 | prefix *name; |
---|
| 110 | name = osnew(prefix); |
---|
| 111 | name->pos = osnew(pos); |
---|
[ba84079] | 112 | name->ident.p = NULL; |
---|
[725d3b1] | 113 | fixpt->name = name; |
---|
| 114 | name->stn = fixpt; |
---|
| 115 | name->up = NULL; |
---|
| 116 | if (TSTBIT(pcs->infer, INFER_EXPORTS)) { |
---|
| 117 | name->min_export = USHRT_MAX; |
---|
| 118 | } else { |
---|
| 119 | name->min_export = 0; |
---|
| 120 | } |
---|
| 121 | name->max_export = 0; |
---|
| 122 | name->sflags = 0; |
---|
[bf9faf6] | 123 | add_stn_to_list(&fixedlist, fixpt); |
---|
[725d3b1] | 124 | POS(fixpt, 0) = coords[0]; |
---|
| 125 | POS(fixpt, 1) = coords[1]; |
---|
| 126 | POS(fixpt, 2) = coords[2]; |
---|
| 127 | fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL; |
---|
| 128 | addfakeleg(fixpt, stn, 0, 0, 0, |
---|
| 129 | var_x, var_y, var_z |
---|
| 130 | #ifndef NO_COVARIANCES |
---|
| 131 | , cxy, cyz, czx |
---|
| 132 | #endif |
---|
| 133 | ); |
---|
| 134 | } |
---|
| 135 | } |
---|
| 136 | |
---|
[a420b49] | 137 | static void |
---|
| 138 | default_grade(settings *s) |
---|
| 139 | { |
---|
[770157e] | 140 | /* Values correspond to those in bcra5.svx */ |
---|
| 141 | s->Var[Q_POS] = (real)sqrd(0.05); |
---|
| 142 | s->Var[Q_LENGTH] = (real)sqrd(0.05); |
---|
[4f38f94] | 143 | s->Var[Q_BACKLENGTH] = (real)sqrd(0.05); |
---|
[770157e] | 144 | s->Var[Q_COUNT] = (real)sqrd(0.05); |
---|
| 145 | s->Var[Q_DX] = s->Var[Q_DY] = s->Var[Q_DZ] = (real)sqrd(0.05); |
---|
| 146 | s->Var[Q_BEARING] = (real)sqrd(rad(0.5)); |
---|
| 147 | s->Var[Q_GRADIENT] = (real)sqrd(rad(0.5)); |
---|
| 148 | s->Var[Q_BACKBEARING] = (real)sqrd(rad(0.5)); |
---|
| 149 | s->Var[Q_BACKGRADIENT] = (real)sqrd(rad(0.5)); |
---|
[a420b49] | 150 | /* SD of plumbed legs (0.25 degrees?) */ |
---|
| 151 | s->Var[Q_PLUMB] = (real)sqrd(rad(0.25)); |
---|
[6b7079f] | 152 | /* SD of level legs (0.25 degrees?) */ |
---|
| 153 | s->Var[Q_LEVEL] = (real)sqrd(rad(0.25)); |
---|
[770157e] | 154 | s->Var[Q_DEPTH] = (real)sqrd(0.05); |
---|
[a420b49] | 155 | } |
---|
| 156 | |
---|
| 157 | static void |
---|
| 158 | default_truncate(settings *s) |
---|
| 159 | { |
---|
| 160 | s->Truncate = INT_MAX; |
---|
| 161 | } |
---|
| 162 | |
---|
| 163 | static void |
---|
| 164 | default_case(settings *s) |
---|
| 165 | { |
---|
| 166 | s->Case = LOWER; |
---|
| 167 | } |
---|
| 168 | |
---|
[27b8b59] | 169 | static reading default_order[] = { Fr, To, Tape, Comp, Clino, End }; |
---|
[a420b49] | 170 | |
---|
| 171 | static void |
---|
| 172 | default_style(settings *s) |
---|
| 173 | { |
---|
[fdffa7d] | 174 | s->recorded_style = s->style = STYLE_NORMAL; |
---|
[a420b49] | 175 | s->ordering = default_order; |
---|
[63d4f07] | 176 | s->dash_for_anon_wall_station = false; |
---|
[a420b49] | 177 | } |
---|
| 178 | |
---|
| 179 | static void |
---|
| 180 | default_prefix(settings *s) |
---|
| 181 | { |
---|
| 182 | s->Prefix = root; |
---|
| 183 | } |
---|
| 184 | |
---|
| 185 | static void |
---|
[5d59477] | 186 | init_default_translate_map(short * t) |
---|
[a420b49] | 187 | { |
---|
| 188 | int i; |
---|
[5d59477] | 189 | for (i = '0'; i <= '9'; i++) t[i] |= SPECIAL_NAMES; |
---|
| 190 | for (i = 'A'; i <= 'Z'; i++) t[i] |= SPECIAL_NAMES; |
---|
| 191 | for (i = 'a'; i <= 'z'; i++) t[i] |= SPECIAL_NAMES; |
---|
[a420b49] | 192 | |
---|
| 193 | t['\t'] |= SPECIAL_BLANK; |
---|
| 194 | t[' '] |= SPECIAL_BLANK; |
---|
| 195 | t[','] |= SPECIAL_BLANK; |
---|
| 196 | t[';'] |= SPECIAL_COMMENT; |
---|
| 197 | t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */ |
---|
| 198 | t['\n'] |= SPECIAL_EOL; |
---|
| 199 | t['\r'] |= SPECIAL_EOL; |
---|
| 200 | t['*'] |= SPECIAL_KEYWORD; |
---|
| 201 | t['-'] |= SPECIAL_OMIT; |
---|
| 202 | t['\\'] |= SPECIAL_ROOT; |
---|
| 203 | t['.'] |= SPECIAL_SEPARATOR; |
---|
| 204 | t['_'] |= SPECIAL_NAMES; |
---|
[f3ac7d4] | 205 | t['-'] |= SPECIAL_NAMES; /* Added in 0.97 prerelease 4 */ |
---|
[a420b49] | 206 | t['.'] |= SPECIAL_DECIMAL; |
---|
| 207 | t['-'] |= SPECIAL_MINUS; |
---|
| 208 | t['+'] |= SPECIAL_PLUS; |
---|
[3593388] | 209 | #if 0 /* FIXME */ |
---|
[7d40549] | 210 | t['{'] |= SPECIAL_OPEN; |
---|
| 211 | t['}'] |= SPECIAL_CLOSE; |
---|
[3593388] | 212 | #endif |
---|
[a420b49] | 213 | } |
---|
| 214 | |
---|
[5d59477] | 215 | static void |
---|
| 216 | default_translate(settings *s) |
---|
| 217 | { |
---|
| 218 | if (s->next && s->next->Translate == s->Translate) { |
---|
| 219 | /* We're currently using the same character translation map as our parent |
---|
| 220 | * scope so allocate a new one before we modify it. |
---|
| 221 | */ |
---|
[ae917b96] | 222 | s->Translate = ((short*)osmalloc(sizeof(short) * 257)) + 1; |
---|
[5d59477] | 223 | } else { |
---|
| 224 | /* SVX_ASSERT(EOF==-1);*/ /* important, since we rely on this */ |
---|
| 225 | } |
---|
| 226 | s->Translate[EOF] = SPECIAL_EOL; |
---|
| 227 | memset(s->Translate, 0, sizeof(short) * 256); |
---|
| 228 | init_default_translate_map(s->Translate); |
---|
| 229 | } |
---|
| 230 | |
---|
| 231 | /* Flag anything used in SPECIAL_* cumulatively to help us pick a suitable |
---|
| 232 | * separator to use in the .3d file. */ |
---|
| 233 | static short separator_map[256]; |
---|
| 234 | |
---|
| 235 | void |
---|
| 236 | scan_compass_station_name(prefix *stn) |
---|
| 237 | { |
---|
| 238 | /* We only need to scan the leaf station name - any survey hierarchy above |
---|
| 239 | * that must have been set up in .svx files for which we update |
---|
| 240 | * separator_map via cmd_set() plus adding the defaults in |
---|
| 241 | * find_output_separator(). |
---|
| 242 | */ |
---|
[ba84079] | 243 | for (const char *p = prefix_ident(stn); *p; ++p) { |
---|
[5d59477] | 244 | separator_map[(unsigned char)*p] |= SPECIAL_NAMES; |
---|
| 245 | } |
---|
| 246 | } |
---|
| 247 | |
---|
| 248 | static char |
---|
| 249 | find_output_separator(void) |
---|
| 250 | { |
---|
| 251 | // Fast path to handle most common cases where we'd pick '.'. |
---|
| 252 | if ((separator_map['.'] & SPECIAL_NAMES) == 0) { |
---|
| 253 | return '.'; |
---|
| 254 | } |
---|
| 255 | |
---|
| 256 | static bool added_defaults = false; |
---|
| 257 | if (!added_defaults) { |
---|
| 258 | /* Add the default settings to separator_map. */ |
---|
| 259 | init_default_translate_map(separator_map); |
---|
| 260 | added_defaults = true; |
---|
| 261 | } |
---|
| 262 | |
---|
| 263 | /* 30 punctuation characters plus space to try arranged in a sensible order |
---|
| 264 | * of decreasing preference (these are all the ASCII punctuation characters |
---|
| 265 | * excluding '_' and '-' since those are allowed in names by default so are |
---|
| 266 | * poor choices for the separator). |
---|
| 267 | */ |
---|
| 268 | int best = -1; |
---|
| 269 | for (const char *p = "./:;,!|\\ ~+*^='`\"#$%&?@<>()[]{}"; *p; ++p) { |
---|
| 270 | unsigned char candidate = *p; |
---|
| 271 | int mask = separator_map[candidate]; |
---|
| 272 | switch (mask & (SPECIAL_SEPARATOR|SPECIAL_NAMES)) { |
---|
| 273 | case SPECIAL_SEPARATOR: |
---|
| 274 | /* A character which is set as a separator character at some |
---|
| 275 | * point but never set as a name character is perfect. |
---|
| 276 | */ |
---|
| 277 | return candidate; |
---|
| 278 | case 0: |
---|
| 279 | /* A character which is never set as either a separator |
---|
| 280 | * character or a name character is a reasonable option. |
---|
| 281 | */ |
---|
| 282 | if (best < 0) best = candidate; |
---|
| 283 | break; |
---|
| 284 | } |
---|
| 285 | } |
---|
| 286 | if (best < 0) { |
---|
| 287 | /* Argh, no plausible choice! Just return the default for now. */ |
---|
| 288 | return '.'; |
---|
| 289 | } |
---|
| 290 | return best; |
---|
| 291 | } |
---|
| 292 | |
---|
[be97baf] | 293 | void |
---|
[a420b49] | 294 | default_units(settings *s) |
---|
| 295 | { |
---|
| 296 | int quantity; |
---|
| 297 | for (quantity = 0; quantity < Q_MAC; quantity++) { |
---|
[7f08c83] | 298 | if (TSTBIT(ANG_QMASK, quantity)) |
---|
[bca0071] | 299 | s->units[quantity] = (real)(M_PI / 180.0); /* degrees */ |
---|
[a420b49] | 300 | else |
---|
| 301 | s->units[quantity] = (real)1.0; /* metres */ |
---|
| 302 | } |
---|
[63d4f07] | 303 | s->f_clino_percent = s->f_backclino_percent = false; |
---|
| 304 | s->f_bearing_quadrants = s->f_backbearing_quadrants = false; |
---|
[a420b49] | 305 | } |
---|
| 306 | |
---|
[be97baf] | 307 | void |
---|
[a420b49] | 308 | default_calib(settings *s) |
---|
| 309 | { |
---|
| 310 | int quantity; |
---|
| 311 | for (quantity = 0; quantity < Q_MAC; quantity++) { |
---|
| 312 | s->z[quantity] = (real)0.0; |
---|
| 313 | s->sc[quantity] = (real)1.0; |
---|
| 314 | } |
---|
| 315 | } |
---|
| 316 | |
---|
[5c3c61a] | 317 | static void |
---|
| 318 | default_flags(settings *s) |
---|
| 319 | { |
---|
| 320 | s->flags = 0; |
---|
| 321 | } |
---|
| 322 | |
---|
[a420b49] | 323 | extern void |
---|
| 324 | default_all(settings *s) |
---|
| 325 | { |
---|
| 326 | default_truncate(s); |
---|
[27b8b59] | 327 | s->infer = 0; |
---|
[a420b49] | 328 | default_case(s); |
---|
| 329 | default_style(s); |
---|
| 330 | default_prefix(s); |
---|
| 331 | default_translate(s); |
---|
| 332 | default_grade(s); |
---|
| 333 | default_units(s); |
---|
| 334 | default_calib(s); |
---|
[5c3c61a] | 335 | default_flags(s); |
---|
[a420b49] | 336 | } |
---|
| 337 | |
---|
[0532954] | 338 | string token = S_INIT; |
---|
[d1b1380] | 339 | |
---|
[725d3b1] | 340 | string uctoken = S_INIT; |
---|
[5f1e194] | 341 | |
---|
[a420b49] | 342 | extern void |
---|
[e1cbc0d] | 343 | get_token_legacy(void) |
---|
[f6bdb01] | 344 | { |
---|
| 345 | skipblanks(); |
---|
[e1cbc0d] | 346 | get_token_legacy_no_blanks(); |
---|
[f6bdb01] | 347 | } |
---|
| 348 | |
---|
| 349 | extern void |
---|
[e1cbc0d] | 350 | get_token_legacy_no_blanks(void) |
---|
[a420b49] | 351 | { |
---|
[0532954] | 352 | s_clear(&token); |
---|
| 353 | s_clear(&uctoken); |
---|
[5f1e194] | 354 | while (isalpha(ch)) { |
---|
[94d9f64] | 355 | s_appendch(&token, ch); |
---|
| 356 | s_appendch(&uctoken, toupper(ch)); |
---|
[5f1e194] | 357 | nextch(); |
---|
| 358 | } |
---|
[cfe093e] | 359 | |
---|
| 360 | #if 0 |
---|
[e1cbc0d] | 361 | printf("get_token_legacy_no_blanks() got “%s”\n", s_str(&token)); |
---|
[cfe093e] | 362 | #endif |
---|
[d1b1380] | 363 | } |
---|
| 364 | |
---|
[05b9de76] | 365 | void |
---|
| 366 | do_legacy_token_warning(void) |
---|
| 367 | { |
---|
| 368 | if (!s_empty(&token)) { |
---|
| 369 | if (!isBlank(ch) && !isComm(ch) && !isEol(ch)) { |
---|
| 370 | compile_diagnostic(DIAG_WARN|DIAG_COL, /*No blank after token*/74); |
---|
| 371 | } |
---|
| 372 | } |
---|
| 373 | } |
---|
| 374 | |
---|
[725d3b1] | 375 | extern void |
---|
[e1cbc0d] | 376 | get_token(void) |
---|
[725d3b1] | 377 | { |
---|
[e1cbc0d] | 378 | skipblanks(); |
---|
| 379 | get_token_no_blanks(); |
---|
| 380 | } |
---|
| 381 | |
---|
| 382 | extern void |
---|
| 383 | get_token_no_blanks(void) |
---|
| 384 | { |
---|
| 385 | s_clear(&token); |
---|
| 386 | s_clear(&uctoken); |
---|
| 387 | if (isalpha(ch)) { |
---|
| 388 | do { |
---|
[94d9f64] | 389 | s_appendch(&token, ch); |
---|
| 390 | s_appendch(&uctoken, toupper(ch)); |
---|
[e1cbc0d] | 391 | nextch(); |
---|
| 392 | } while (isalnum(ch)); |
---|
| 393 | } |
---|
[725d3b1] | 394 | } |
---|
| 395 | |
---|
[dcbcae0] | 396 | /* read word */ |
---|
[725d3b1] | 397 | void |
---|
[dcbcae0] | 398 | get_word(void) |
---|
| 399 | { |
---|
[2f246b0] | 400 | s_clear(&token); |
---|
[dcbcae0] | 401 | skipblanks(); |
---|
[2aa37a8] | 402 | while (!isBlank(ch) && !isComm(ch) && !isEol(ch)) { |
---|
[94d9f64] | 403 | s_appendch(&token, ch); |
---|
[dcbcae0] | 404 | nextch(); |
---|
| 405 | } |
---|
| 406 | #if 0 |
---|
[2f246b0] | 407 | printf("get_word() got “%s”\n", s_str(&token)); |
---|
[dcbcae0] | 408 | #endif |
---|
| 409 | } |
---|
| 410 | |
---|
[d1b1380] | 411 | /* match_tok() now uses binary chop |
---|
| 412 | * tab argument should be alphabetically sorted (ascending) |
---|
| 413 | */ |
---|
[a420b49] | 414 | extern int |
---|
| 415 | match_tok(const sztok *tab, int tab_size) |
---|
| 416 | { |
---|
[5f1e194] | 417 | int a = 0, b = tab_size - 1, c; |
---|
| 418 | int r; |
---|
[0532954] | 419 | const char* tok = s_str(&uctoken); |
---|
[cf0560b] | 420 | SVX_ASSERT(tab_size > 0); /* catch empty table */ |
---|
[d1b1380] | 421 | /* printf("[%d,%d]",a,b); */ |
---|
[5f1e194] | 422 | while (a <= b) { |
---|
| 423 | c = (unsigned)(a + b) / 2; |
---|
[d1b1380] | 424 | /* printf(" %d",c); */ |
---|
[0532954] | 425 | r = strcmp(tab[c].sz, tok); |
---|
[5f1e194] | 426 | if (r == 0) return tab[c].tok; /* match */ |
---|
| 427 | if (r < 0) |
---|
| 428 | a = c + 1; |
---|
| 429 | else |
---|
| 430 | b = c - 1; |
---|
| 431 | } |
---|
| 432 | return tab[tab_size].tok; /* no match */ |
---|
[d1b1380] | 433 | } |
---|
| 434 | |
---|
[fb2e93c] | 435 | typedef enum { |
---|
[abe7192] | 436 | CMD_NULL = -1, CMD_ALIAS, CMD_BEGIN, CMD_CALIBRATE, CMD_CARTESIAN, CMD_CASE, |
---|
| 437 | CMD_COPYRIGHT, CMD_CS, CMD_DATA, CMD_DATE, CMD_DECLINATION, CMD_DEFAULT, |
---|
| 438 | CMD_END, CMD_ENTRANCE, CMD_EQUATE, CMD_EXPORT, CMD_FIX, CMD_FLAGS, |
---|
| 439 | CMD_INCLUDE, CMD_INFER, CMD_INSTRUMENT, CMD_PREFIX, CMD_REF, CMD_REQUIRE, |
---|
| 440 | CMD_SD, CMD_SET, CMD_SOLVE, CMD_TEAM, CMD_TITLE, CMD_TRUNCATE, CMD_UNITS |
---|
[5f1e194] | 441 | } cmds; |
---|
[cb3d1e2] | 442 | |
---|
[82919e07] | 443 | static const sztok cmd_tab[] = { |
---|
[dcbcae0] | 444 | {"ALIAS", CMD_ALIAS}, |
---|
[5f1e194] | 445 | {"BEGIN", CMD_BEGIN}, |
---|
| 446 | {"CALIBRATE", CMD_CALIBRATE}, |
---|
[abe7192] | 447 | {"CARTESIAN", CMD_CARTESIAN}, |
---|
[a420b49] | 448 | {"CASE", CMD_CASE}, |
---|
[13a48f6] | 449 | {"COPYRIGHT", CMD_COPYRIGHT}, |
---|
[abd0310] | 450 | {"CS", CMD_CS}, |
---|
[5f1e194] | 451 | {"DATA", CMD_DATA}, |
---|
[13a48f6] | 452 | {"DATE", CMD_DATE}, |
---|
[58c7b459] | 453 | {"DECLINATION", CMD_DECLINATION}, |
---|
[a7d5f1c] | 454 | #ifndef NO_DEPRECATED |
---|
[5f1e194] | 455 | {"DEFAULT", CMD_DEFAULT}, |
---|
[a7d5f1c] | 456 | #endif |
---|
[5f1e194] | 457 | {"END", CMD_END}, |
---|
[dfb4240] | 458 | {"ENTRANCE", CMD_ENTRANCE}, |
---|
[5f1e194] | 459 | {"EQUATE", CMD_EQUATE}, |
---|
[fb2e93c] | 460 | {"EXPORT", CMD_EXPORT}, |
---|
[5f1e194] | 461 | {"FIX", CMD_FIX}, |
---|
[5c3c61a] | 462 | {"FLAGS", CMD_FLAGS}, |
---|
[5f1e194] | 463 | {"INCLUDE", CMD_INCLUDE}, |
---|
[a420b49] | 464 | {"INFER", CMD_INFER}, |
---|
[ec6a4b3] | 465 | {"INSTRUMENT",CMD_INSTRUMENT}, |
---|
[a7d5f1c] | 466 | #ifndef NO_DEPRECATED |
---|
[5f1e194] | 467 | {"PREFIX", CMD_PREFIX}, |
---|
[a7d5f1c] | 468 | #endif |
---|
[ce15637] | 469 | {"REF", CMD_REF}, |
---|
[647407d] | 470 | {"REQUIRE", CMD_REQUIRE}, |
---|
[a4ae909] | 471 | {"SD", CMD_SD}, |
---|
[5f1e194] | 472 | {"SET", CMD_SET}, |
---|
| 473 | {"SOLVE", CMD_SOLVE}, |
---|
[13a48f6] | 474 | {"TEAM", CMD_TEAM}, |
---|
[a420b49] | 475 | {"TITLE", CMD_TITLE}, |
---|
| 476 | {"TRUNCATE", CMD_TRUNCATE}, |
---|
[5f1e194] | 477 | {"UNITS", CMD_UNITS}, |
---|
[a4ae909] | 478 | {NULL, CMD_NULL} |
---|
[5f1e194] | 479 | }; |
---|
| 480 | |
---|
[fa42426] | 481 | /* masks for units which are length and angles respectively */ |
---|
| 482 | #define LEN_UMASK (BIT(UNITS_METRES) | BIT(UNITS_FEET) | BIT(UNITS_YARDS)) |
---|
| 483 | #define ANG_UMASK (BIT(UNITS_DEGS) | BIT(UNITS_GRADS) | BIT(UNITS_MINUTES)) |
---|
| 484 | |
---|
| 485 | /* ordering must be the same as the units enum */ |
---|
[85c0078] | 486 | const real factor_tab[] = { |
---|
[fa42426] | 487 | 1.0, METRES_PER_FOOT, (METRES_PER_FOOT*3.0), |
---|
[00b10c1] | 488 | (M_PI/180.0), (M_PI/180.0), (M_PI/200.0), 0.01, (M_PI/180.0/60.0) |
---|
[fa42426] | 489 | }; |
---|
| 490 | |
---|
[85c0078] | 491 | const int units_to_msgno[] = { |
---|
| 492 | /*m*/424, |
---|
[f516c1e] | 493 | /*′*/428, |
---|
[85c0078] | 494 | -1, /* yards */ |
---|
[e343cfc0] | 495 | /*°*/344, /* quadrants */ |
---|
[85c0078] | 496 | /*°*/344, |
---|
[85dcdcd] | 497 | /*ᵍ*/345, |
---|
[85c0078] | 498 | /*%*/96, |
---|
| 499 | -1 /* minutes */ |
---|
| 500 | }; |
---|
| 501 | |
---|
| 502 | int get_length_units(int quantity) { |
---|
| 503 | double factor = pcs->units[quantity]; |
---|
| 504 | if (fabs(factor - METRES_PER_FOOT) <= REAL_EPSILON || |
---|
| 505 | fabs(factor - METRES_PER_FOOT * 3.0) <= REAL_EPSILON) { |
---|
| 506 | return UNITS_FEET; |
---|
| 507 | } |
---|
| 508 | return UNITS_METRES; |
---|
| 509 | } |
---|
| 510 | |
---|
| 511 | int get_angle_units(int quantity) { |
---|
| 512 | double factor = pcs->units[quantity]; |
---|
| 513 | if (fabs(factor - M_PI / 200.0) <= REAL_EPSILON) { |
---|
| 514 | return UNITS_GRADS; |
---|
| 515 | } |
---|
| 516 | return UNITS_DEGS; |
---|
| 517 | } |
---|
| 518 | |
---|
[a420b49] | 519 | static int |
---|
[fa42426] | 520 | get_units(unsigned long qmask, bool percent_ok) |
---|
[a420b49] | 521 | { |
---|
[82919e07] | 522 | static const sztok utab[] = { |
---|
[5f1e194] | 523 | {"DEGREES", UNITS_DEGS }, |
---|
[a4ae909] | 524 | {"DEGS", UNITS_DEGS }, |
---|
| 525 | {"FEET", UNITS_FEET }, |
---|
| 526 | {"GRADS", UNITS_GRADS }, |
---|
| 527 | {"METERS", UNITS_METRES }, |
---|
| 528 | {"METRES", UNITS_METRES }, |
---|
| 529 | {"METRIC", UNITS_METRES }, |
---|
[70fa970] | 530 | {"MILS", UNITS_DEPRECATED_ALIAS_FOR_GRADS }, |
---|
[a4ae909] | 531 | {"MINUTES", UNITS_MINUTES }, |
---|
| 532 | {"PERCENT", UNITS_PERCENT }, |
---|
[5f1e194] | 533 | {"PERCENTAGE", UNITS_PERCENT }, |
---|
[00b10c1] | 534 | {"QUADRANTS", UNITS_QUADRANTS }, |
---|
[51951b9] | 535 | {"QUADS", UNITS_QUADRANTS }, |
---|
| 536 | {"YARDS", UNITS_YARDS }, |
---|
[a4ae909] | 537 | {NULL, UNITS_NULL } |
---|
[5f1e194] | 538 | }; |
---|
[3a33d12] | 539 | get_token(); |
---|
[e1cbc0d] | 540 | int units = match_tok(utab, TABSIZE(utab)); |
---|
[647407d] | 541 | if (units == UNITS_NULL) { |
---|
[caae6cd] | 542 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown units “%s”*/35, |
---|
[0532954] | 543 | s_str(&token)); |
---|
[fa42426] | 544 | return UNITS_NULL; |
---|
| 545 | } |
---|
[70fa970] | 546 | /* Survex has long misdefined "mils" as an alias for "grads", of which |
---|
| 547 | * there are 400 in a circle. There are several definitions of "mils" |
---|
| 548 | * with a circle containing 2000π SI milliradians, 6400 NATO mils, 6000 |
---|
| 549 | * Warsaw Pact mils, and 6300 Swedish streck, and they aren't in common |
---|
| 550 | * use by cave surveyors, so we now just warn if mils are used. |
---|
| 551 | */ |
---|
| 552 | if (units == UNITS_DEPRECATED_ALIAS_FOR_GRADS) { |
---|
[caae6cd] | 553 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN|DIAG_SKIP, |
---|
[70fa970] | 554 | /*Units “%s” are deprecated, assuming “grads” - see manual for details*/479, |
---|
[0532954] | 555 | s_str(&token)); |
---|
[70fa970] | 556 | units = UNITS_GRADS; |
---|
| 557 | } |
---|
[fa42426] | 558 | if (units == UNITS_PERCENT && percent_ok && |
---|
| 559 | !(qmask & ~(BIT(Q_GRADIENT)|BIT(Q_BACKGRADIENT)))) { |
---|
| 560 | return units; |
---|
| 561 | } |
---|
[00b10c1] | 562 | if (units == UNITS_QUADRANTS && |
---|
| 563 | !(qmask & ~(BIT(Q_BEARING)|BIT(Q_BACKBEARING)))) { |
---|
| 564 | return units; |
---|
| 565 | } |
---|
[fa42426] | 566 | if (((qmask & LEN_QMASK) && !TSTBIT(LEN_UMASK, units)) || |
---|
| 567 | ((qmask & ANG_QMASK) && !TSTBIT(ANG_UMASK, units))) { |
---|
[736f7df] | 568 | /* TRANSLATORS: Note: In English you talk about the *units* of a single |
---|
| 569 | * measurement, but the correct term in other languages may be singular. |
---|
| 570 | */ |
---|
[caae6cd] | 571 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Invalid units “%s” for quantity*/37, s_str(&token)); |
---|
[fa42426] | 572 | return UNITS_NULL; |
---|
[647407d] | 573 | } |
---|
[5f1e194] | 574 | return units; |
---|
[d1b1380] | 575 | } |
---|
| 576 | |
---|
| 577 | /* returns mask with bit x set to indicate quantity x specified */ |
---|
[67508f0] | 578 | static unsigned long |
---|
[46cb98f] | 579 | get_qlist(unsigned long mask_bad) |
---|
[a420b49] | 580 | { |
---|
[82919e07] | 581 | static const sztok qtab[] = { |
---|
[9b5d785] | 582 | {"ALTITUDE", Q_DZ }, |
---|
[b14f44f] | 583 | {"BACKBEARING", Q_BACKBEARING }, |
---|
| 584 | {"BACKCLINO", Q_BACKGRADIENT }, /* alternative name */ |
---|
| 585 | {"BACKCOMPASS", Q_BACKBEARING }, /* alternative name */ |
---|
| 586 | {"BACKGRADIENT", Q_BACKGRADIENT }, |
---|
[4f38f94] | 587 | {"BACKLENGTH", Q_BACKLENGTH }, |
---|
| 588 | {"BACKTAPE", Q_BACKLENGTH }, /* alternative name */ |
---|
[5f1e194] | 589 | {"BEARING", Q_BEARING }, |
---|
[ee05463] | 590 | {"CEILING", Q_UP }, /* alternative name */ |
---|
[a4ae909] | 591 | {"CLINO", Q_GRADIENT }, /* alternative name */ |
---|
[5f1e194] | 592 | {"COMPASS", Q_BEARING }, /* alternative name */ |
---|
[a4ae909] | 593 | {"COUNT", Q_COUNT }, |
---|
[5f1e194] | 594 | {"COUNTER", Q_COUNT }, /* alternative name */ |
---|
| 595 | {"DECLINATION", Q_DECLINATION }, |
---|
[a420b49] | 596 | {"DEFAULT", Q_DEFAULT }, /* not a real quantity... */ |
---|
[a4ae909] | 597 | {"DEPTH", Q_DEPTH }, |
---|
[ee05463] | 598 | {"DOWN", Q_DOWN }, |
---|
[a4ae909] | 599 | {"DX", Q_DX }, /* alternative name */ |
---|
| 600 | {"DY", Q_DY }, /* alternative name */ |
---|
| 601 | {"DZ", Q_DZ }, /* alternative name */ |
---|
| 602 | {"EASTING", Q_DX }, |
---|
[ee05463] | 603 | {"FLOOR", Q_DOWN }, /* alternative name */ |
---|
[5f1e194] | 604 | {"GRADIENT", Q_GRADIENT }, |
---|
[ee05463] | 605 | {"LEFT", Q_LEFT }, |
---|
[5f1e194] | 606 | {"LENGTH", Q_LENGTH }, |
---|
[a4ae909] | 607 | {"LEVEL", Q_LEVEL}, |
---|
[9b5d785] | 608 | {"NORTHING", Q_DY }, |
---|
[a4ae909] | 609 | {"PLUMB", Q_PLUMB}, |
---|
[5f1e194] | 610 | {"POSITION", Q_POS }, |
---|
[ee05463] | 611 | {"RIGHT", Q_RIGHT }, |
---|
[a4ae909] | 612 | {"TAPE", Q_LENGTH }, /* alternative name */ |
---|
[ee05463] | 613 | {"UP", Q_UP }, |
---|
[a4ae909] | 614 | {NULL, Q_NULL } |
---|
[5f1e194] | 615 | }; |
---|
[67508f0] | 616 | unsigned long qmask = 0; |
---|
[5f1e194] | 617 | int tok; |
---|
[3a33d12] | 618 | filepos fp; |
---|
| 619 | |
---|
[a420b49] | 620 | while (1) { |
---|
[3a33d12] | 621 | get_pos(&fp); |
---|
[e1cbc0d] | 622 | get_token_legacy(); |
---|
[5f1e194] | 623 | tok = match_tok(qtab, TABSIZE(qtab)); |
---|
[da96015] | 624 | if (tok == Q_DEFAULT && !(mask_bad & BIT(Q_DEFAULT))) { |
---|
| 625 | /* Only recognise DEFAULT if it is the first quantity, and then don't |
---|
| 626 | * look for any more. */ |
---|
| 627 | if (qmask == 0) |
---|
| 628 | return BIT(Q_DEFAULT); |
---|
| 629 | break; |
---|
| 630 | } |
---|
[5f1e194] | 631 | /* bail out if we reach the table end with no match */ |
---|
| 632 | if (tok == Q_NULL) break; |
---|
| 633 | qmask |= BIT(tok); |
---|
[da96015] | 634 | if (qmask & mask_bad) { |
---|
[caae6cd] | 635 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown instrument “%s”*/39, s_str(&token)); |
---|
[46cb98f] | 636 | return 0; |
---|
| 637 | } |
---|
[5f1e194] | 638 | } |
---|
[3a33d12] | 639 | |
---|
[647407d] | 640 | if (qmask == 0) { |
---|
[36efb03] | 641 | /* TRANSLATORS: A "quantity" is something measured like "LENGTH", |
---|
| 642 | * "BEARING", "ALTITUDE", etc. */ |
---|
[caae6cd] | 643 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown quantity “%s”*/34, s_str(&token)); |
---|
[3a33d12] | 644 | } else { |
---|
| 645 | set_pos(&fp); |
---|
[647407d] | 646 | } |
---|
[3a33d12] | 647 | |
---|
[5f1e194] | 648 | return qmask; |
---|
[d1b1380] | 649 | } |
---|
| 650 | |
---|
| 651 | #define SPECIAL_UNKNOWN 0 |
---|
[a420b49] | 652 | static void |
---|
[eb18f4d] | 653 | cmd_set(void) |
---|
[a420b49] | 654 | { |
---|
[82919e07] | 655 | static const sztok chartab[] = { |
---|
[5f1e194] | 656 | {"BLANK", SPECIAL_BLANK }, |
---|
[3593388] | 657 | /*FIXME {"CLOSE", SPECIAL_CLOSE }, */ |
---|
[5f1e194] | 658 | {"COMMENT", SPECIAL_COMMENT }, |
---|
| 659 | {"DECIMAL", SPECIAL_DECIMAL }, |
---|
| 660 | {"EOL", SPECIAL_EOL }, /* EOL won't work well */ |
---|
| 661 | {"KEYWORD", SPECIAL_KEYWORD }, |
---|
| 662 | {"MINUS", SPECIAL_MINUS }, |
---|
| 663 | {"NAMES", SPECIAL_NAMES }, |
---|
| 664 | {"OMIT", SPECIAL_OMIT }, |
---|
[3593388] | 665 | /*FIXME {"OPEN", SPECIAL_OPEN }, */ |
---|
[5f1e194] | 666 | {"PLUS", SPECIAL_PLUS }, |
---|
[7f1ab95] | 667 | #ifndef NO_DEPRECATED |
---|
[5f1e194] | 668 | {"ROOT", SPECIAL_ROOT }, |
---|
[7f1ab95] | 669 | #endif |
---|
[5f1e194] | 670 | {"SEPARATOR", SPECIAL_SEPARATOR }, |
---|
[a4ae909] | 671 | {NULL, SPECIAL_UNKNOWN } |
---|
[5f1e194] | 672 | }; |
---|
| 673 | int i; |
---|
[b15eeda] | 674 | |
---|
[a420b49] | 675 | get_token(); |
---|
[e1cbc0d] | 676 | int mask = match_tok(chartab, TABSIZE(chartab)); |
---|
[b15eeda] | 677 | |
---|
[f74d0cb] | 678 | if (mask == SPECIAL_UNKNOWN) { |
---|
[caae6cd] | 679 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown character class “%s”*/42, |
---|
[0532954] | 680 | s_str(&token)); |
---|
[5f1e194] | 681 | return; |
---|
| 682 | } |
---|
[b15eeda] | 683 | |
---|
[7f1ab95] | 684 | #ifndef NO_DEPRECATED |
---|
[c86cc71] | 685 | if (mask == SPECIAL_ROOT) { |
---|
| 686 | if (root_depr_count < 5) { |
---|
[736f7df] | 687 | /* TRANSLATORS: Use of the ROOT character (which is "\" by default) is |
---|
| 688 | * deprecated, so this error would be generated by: |
---|
[b49ac56] | 689 | * |
---|
[736f7df] | 690 | * *equate \foo.7 1 |
---|
[b49ac56] | 691 | * |
---|
[736f7df] | 692 | * If you're unsure what "deprecated" means, see: |
---|
[2c1c52e] | 693 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
[caae6cd] | 694 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN, /*ROOT is deprecated*/25); |
---|
[c86cc71] | 695 | if (++root_depr_count == 5) |
---|
[736f7df] | 696 | /* TRANSLATORS: If you're unsure what "deprecated" means, see: |
---|
[2c1c52e] | 697 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
[64544daf] | 698 | compile_diagnostic(DIAG_INFO, /*Further uses of this deprecated feature will not be reported*/95); |
---|
[c86cc71] | 699 | } |
---|
| 700 | } |
---|
[7f1ab95] | 701 | #endif |
---|
[b15eeda] | 702 | |
---|
[5f1e194] | 703 | /* if we're currently using an inherited translation table, allocate a new |
---|
| 704 | * table, and copy old one into it */ |
---|
| 705 | if (pcs->next && pcs->next->Translate == pcs->Translate) { |
---|
| 706 | short *p; |
---|
[ae917b96] | 707 | p = ((short*)osmalloc(sizeof(short) * 257)) + 1; |
---|
[5f1e194] | 708 | memcpy(p - 1, pcs->Translate - 1, sizeof(short) * 257); |
---|
| 709 | pcs->Translate = p; |
---|
| 710 | } |
---|
[11f9067] | 711 | |
---|
| 712 | skipblanks(); |
---|
| 713 | |
---|
[5f1e194] | 714 | /* clear this flag for all non-alphanums */ |
---|
[a420b49] | 715 | for (i = 0; i < 256; i++) |
---|
| 716 | if (!isalnum(i)) pcs->Translate[i] &= ~mask; |
---|
[11f9067] | 717 | |
---|
[5f1e194] | 718 | /* now set this flag for all specified chars */ |
---|
| 719 | while (!isEol(ch)) { |
---|
[5d59477] | 720 | int char_to_set; |
---|
[11f9067] | 721 | if (!isalnum(ch)) { |
---|
[5d59477] | 722 | char_to_set = ch; |
---|
[11f9067] | 723 | } else if (tolower(ch) == 'x') { |
---|
| 724 | int hex; |
---|
| 725 | filepos fp; |
---|
| 726 | get_pos(&fp); |
---|
| 727 | nextch(); |
---|
| 728 | if (!isxdigit(ch)) { |
---|
| 729 | set_pos(&fp); |
---|
| 730 | break; |
---|
| 731 | } |
---|
| 732 | hex = isdigit(ch) ? ch - '0' : tolower(ch) - 'a'; |
---|
| 733 | nextch(); |
---|
| 734 | if (!isxdigit(ch)) { |
---|
| 735 | set_pos(&fp); |
---|
| 736 | break; |
---|
| 737 | } |
---|
| 738 | hex = hex << 4 | (isdigit(ch) ? ch - '0' : tolower(ch) - 'a'); |
---|
[5d59477] | 739 | char_to_set = hex; |
---|
[11f9067] | 740 | } else { |
---|
| 741 | break; |
---|
| 742 | } |
---|
[5d59477] | 743 | pcs->Translate[char_to_set] |= mask; |
---|
| 744 | separator_map[char_to_set] |= mask; |
---|
[5f1e194] | 745 | nextch(); |
---|
| 746 | } |
---|
[5d59477] | 747 | |
---|
| 748 | output_separator = find_output_separator(); |
---|
| 749 | } |
---|
| 750 | |
---|
| 751 | void |
---|
| 752 | update_output_separator(void) |
---|
| 753 | { |
---|
| 754 | output_separator = find_output_separator(); |
---|
[d1b1380] | 755 | } |
---|
| 756 | |
---|
[4d9eecd] | 757 | static void |
---|
[23e64c14] | 758 | check_reentry(prefix *survey, const filepos* fpos_ptr) |
---|
[4d9eecd] | 759 | { |
---|
[91912b4] | 760 | /* Don't try to check "*prefix \" or "*begin \" */ |
---|
[613028c] | 761 | if (!survey->up) return; |
---|
| 762 | if (TSTBIT(survey->sflags, SFLAGS_PREFIX_ENTERED)) { |
---|
[15696f3] | 763 | static int reenter_depr_count = 0; |
---|
[23e64c14] | 764 | filepos fp_tmp; |
---|
[c86cc71] | 765 | |
---|
[e1a66da] | 766 | if (reenter_depr_count >= 5) |
---|
| 767 | return; |
---|
| 768 | |
---|
[23e64c14] | 769 | get_pos(&fp_tmp); |
---|
| 770 | set_pos(fpos_ptr); |
---|
[1c507cf] | 771 | /* TRANSLATORS: The first of two warnings given when a survey which has |
---|
| 772 | * already been completed is reentered. This example file crawl.svx: |
---|
[e1a66da] | 773 | * |
---|
[5a9e47c] | 774 | * *begin crawl ; <- second warning here |
---|
| 775 | * 1 2 9.45 234 -01 |
---|
[e1a66da] | 776 | * *end crawl |
---|
[5a9e47c] | 777 | * *begin crawl ; <- first warning here |
---|
[e1a66da] | 778 | * 2 3 7.67 223 -03 |
---|
| 779 | * *end crawl |
---|
[1c507cf] | 780 | * |
---|
| 781 | * Would lead to: |
---|
| 782 | * |
---|
[b0a2ddb] | 783 | * crawl.svx:4:8: warning: Reentering an existing survey is deprecated |
---|
| 784 | * crawl.svx:1: info: Originally entered here |
---|
[1c507cf] | 785 | * |
---|
[e1a66da] | 786 | * If you're unsure what "deprecated" means, see: |
---|
[2c1c52e] | 787 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
[d0be687d] | 788 | compile_diagnostic(DIAG_WARN|DIAG_WORD, /*Reentering an existing survey is deprecated*/29); |
---|
[23e64c14] | 789 | set_pos(&fp_tmp); |
---|
[1c507cf] | 790 | /* TRANSLATORS: The second of two warnings given when a survey which has |
---|
| 791 | * already been completed is reentered. This example file crawl.svx: |
---|
| 792 | * |
---|
[9c25fac] | 793 | * *begin crawl ; <- second warning here |
---|
| 794 | * 1 2 9.45 234 -01 |
---|
[1c507cf] | 795 | * *end crawl |
---|
[9c25fac] | 796 | * *begin crawl ; <- first warning here |
---|
[1c507cf] | 797 | * 2 3 7.67 223 -03 |
---|
| 798 | * *end crawl |
---|
| 799 | * |
---|
| 800 | * Would lead to: |
---|
| 801 | * |
---|
[b0a2ddb] | 802 | * crawl.svx:4:8: warning: Reentering an existing survey is deprecated |
---|
| 803 | * crawl.svx:1: info: Originally entered here |
---|
[1c507cf] | 804 | * |
---|
| 805 | * If you're unsure what "deprecated" means, see: |
---|
[2c1c52e] | 806 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
[b0a2ddb] | 807 | compile_diagnostic_pfx(DIAG_INFO, survey, /*Originally entered here*/30); |
---|
[1c507cf] | 808 | if (++reenter_depr_count == 5) { |
---|
| 809 | /* After we've warned about 5 uses of the same deprecated feature, we |
---|
| 810 | * give up for the rest of the current processing run. |
---|
| 811 | * |
---|
| 812 | * If you're unsure what "deprecated" means, see: |
---|
[2c1c52e] | 813 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
[64544daf] | 814 | compile_diagnostic(DIAG_INFO, /*Further uses of this deprecated feature will not be reported*/95); |
---|
[1c507cf] | 815 | } |
---|
[4d9eecd] | 816 | } else { |
---|
[613028c] | 817 | survey->sflags |= BIT(SFLAGS_PREFIX_ENTERED); |
---|
| 818 | survey->filename = file.filename; |
---|
| 819 | survey->line = file.line; |
---|
[98b705d] | 820 | survey->column = fpos_ptr->offset - file.lpos; |
---|
[4d9eecd] | 821 | } |
---|
| 822 | } |
---|
| 823 | |
---|
[7f1ab95] | 824 | #ifndef NO_DEPRECATED |
---|
[a420b49] | 825 | static void |
---|
[eb18f4d] | 826 | cmd_prefix(void) |
---|
[a420b49] | 827 | { |
---|
[23e64c14] | 828 | filepos fp; |
---|
| 829 | get_pos(&fp); |
---|
[98b705d] | 830 | prefix *survey = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT); |
---|
[613028c] | 831 | pcs->Prefix = survey; |
---|
[23e64c14] | 832 | check_reentry(survey, &fp); |
---|
[d1b1380] | 833 | } |
---|
[7f1ab95] | 834 | #endif |
---|
[d1b1380] | 835 | |
---|
[dcbcae0] | 836 | static void |
---|
| 837 | cmd_alias(void) |
---|
| 838 | { |
---|
[45dcea2] | 839 | /* Currently only two forms are supported: |
---|
[dcbcae0] | 840 | * *alias station - .. |
---|
[45dcea2] | 841 | * *alias station - |
---|
[dcbcae0] | 842 | */ |
---|
| 843 | get_token(); |
---|
[4772e46] | 844 | if (!S_EQ(&uctoken, "STATION")) { |
---|
| 845 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_TOKEN, /*Bad *alias command*/397); |
---|
| 846 | return; |
---|
| 847 | } |
---|
[dcbcae0] | 848 | get_word(); |
---|
[2f246b0] | 849 | if (!S_EQ(&token, "-")) |
---|
[4772e46] | 850 | goto bad_word; |
---|
[dcbcae0] | 851 | get_word(); |
---|
[2f246b0] | 852 | if (!s_empty(&token) && !S_EQ(&token, "..")) |
---|
[4772e46] | 853 | goto bad_word; |
---|
[2f246b0] | 854 | pcs->dash_for_anon_wall_station = !s_empty(&token); |
---|
[dcbcae0] | 855 | return; |
---|
[4772e46] | 856 | bad_word: |
---|
[2aa37a8] | 857 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_TOKEN, /*Bad *alias command*/397); |
---|
[dcbcae0] | 858 | } |
---|
| 859 | |
---|
[a420b49] | 860 | static void |
---|
[eb18f4d] | 861 | cmd_begin(void) |
---|
[a420b49] | 862 | { |
---|
[5f1e194] | 863 | settings *pcsNew; |
---|
[4be360f] | 864 | |
---|
[5f1e194] | 865 | pcsNew = osnew(settings); |
---|
| 866 | *pcsNew = *pcs; /* copy contents */ |
---|
[47c7a94] | 867 | pcsNew->begin_lineno = file.line; |
---|
[94aeeaf] | 868 | pcsNew->begin_lpos = file.lpos; |
---|
[5f1e194] | 869 | pcsNew->next = pcs; |
---|
| 870 | pcs = pcsNew; |
---|
[4be360f] | 871 | |
---|
[3be21a9] | 872 | pcs->begin_survey = NULL; |
---|
[94aeeaf] | 873 | pcs->begin_col = 0; |
---|
[3be21a9] | 874 | if (!isEol(ch) && !isComm(ch)) { |
---|
[23e64c14] | 875 | filepos fp; |
---|
| 876 | prefix *survey; |
---|
| 877 | get_pos(&fp); |
---|
[94aeeaf] | 878 | int begin_col = fp.offset - file.lpos; |
---|
[23e64c14] | 879 | survey = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT|PFX_WARN_SEPARATOR); |
---|
[94aeeaf] | 880 | // read_prefix() might fail and longjmp() so only set begin_col if |
---|
| 881 | // it succeeds. |
---|
| 882 | pcs->begin_col = begin_col; |
---|
[c230d677] | 883 | pcs->begin_survey = survey; |
---|
[613028c] | 884 | pcs->Prefix = survey; |
---|
[23e64c14] | 885 | check_reentry(survey, &fp); |
---|
[63d4f07] | 886 | f_export_ok = true; |
---|
[d53b0f5] | 887 | } |
---|
[647407d] | 888 | } |
---|
| 889 | |
---|
[d624d86] | 890 | void |
---|
[da9163b] | 891 | invalidate_pj_cached(void) |
---|
| 892 | { |
---|
| 893 | /* Invalidate the cached PJ. */ |
---|
| 894 | if (pj_cached) { |
---|
| 895 | proj_destroy(pj_cached); |
---|
| 896 | pj_cached = NULL; |
---|
| 897 | } |
---|
| 898 | } |
---|
| 899 | |
---|
[37d6b84] | 900 | void |
---|
| 901 | report_declination(settings *p) |
---|
[da9163b] | 902 | { |
---|
[37d6b84] | 903 | if (p->min_declination <= p->max_declination) { |
---|
| 904 | int y, m, d; |
---|
| 905 | char range[128]; |
---|
| 906 | const char* deg_sign = msg(/*°*/344); |
---|
| 907 | ymd_from_days_since_1900(p->min_declination_days, &y, &m, &d); |
---|
| 908 | snprintf(range, sizeof(range), |
---|
| 909 | "%.1f%s @ %04d-%02d-%02d", |
---|
| 910 | deg(p->min_declination), deg_sign, y, m, d); |
---|
| 911 | if (p->min_declination_days != p->max_declination_days) { |
---|
| 912 | size_t len = strlen(range); |
---|
| 913 | ymd_from_days_since_1900(p->max_declination_days, &y, &m, &d); |
---|
| 914 | snprintf(range + len, sizeof(range) - len, |
---|
| 915 | " / %.1f%s @ %04d-%02d-%02d", |
---|
| 916 | deg(p->max_declination), deg_sign, y, m, d); |
---|
| 917 | } |
---|
| 918 | /* TRANSLATORS: This message gives information about the range of |
---|
| 919 | * declination values and the grid convergence value calculated for |
---|
| 920 | * each "*declination auto ..." command. |
---|
| 921 | * |
---|
| 922 | * The first %s will be replaced by the declination range (or single |
---|
| 923 | * value), and %.1f%s by the grid convergence angle. |
---|
| 924 | */ |
---|
[501dd27] | 925 | compile_diagnostic_at(DIAG_INFO, p->dec_filename, p->dec_line, |
---|
[37d6b84] | 926 | /*Declination: %s, grid convergence: %.1f%s*/484, |
---|
| 927 | range, |
---|
| 928 | deg(p->convergence), deg_sign); |
---|
| 929 | PUTC(' ', STDERR); |
---|
| 930 | fputs(p->dec_context, STDERR); |
---|
| 931 | fputnl(STDERR); |
---|
[725d3b1] | 932 | if (p->next && p->dec_context != p->next->dec_context) |
---|
| 933 | free(p->dec_context); |
---|
[37d6b84] | 934 | p->dec_context = NULL; |
---|
[c1fe79a] | 935 | p->min_declination = HUGE_VAL; |
---|
| 936 | p->max_declination = -HUGE_VAL; |
---|
[37d6b84] | 937 | } |
---|
| 938 | } |
---|
[da9163b] | 939 | |
---|
[37d6b84] | 940 | void |
---|
| 941 | pop_settings(void) |
---|
| 942 | { |
---|
| 943 | settings * p = pcs; |
---|
| 944 | pcs = pcs->next; |
---|
| 945 | |
---|
| 946 | SVX_ASSERT(pcs); |
---|
| 947 | |
---|
| 948 | if (pcs->dec_lat != p->dec_lat || |
---|
| 949 | pcs->dec_lon != p->dec_lon || |
---|
| 950 | pcs->dec_alt != p->dec_alt) { |
---|
| 951 | report_declination(p); |
---|
| 952 | } else { |
---|
| 953 | pcs->min_declination_days = p->min_declination_days; |
---|
| 954 | pcs->max_declination_days = p->max_declination_days; |
---|
| 955 | pcs->min_declination = p->min_declination; |
---|
| 956 | pcs->max_declination = p->max_declination; |
---|
[4bea0f8] | 957 | pcs->convergence = p->convergence; |
---|
[37d6b84] | 958 | } |
---|
| 959 | |
---|
| 960 | if (p->proj_str != pcs->proj_str) { |
---|
| 961 | if (!p->proj_str || !pcs->proj_str || |
---|
| 962 | strcmp(p->proj_str, pcs->proj_str) != 0) { |
---|
| 963 | invalidate_pj_cached(); |
---|
| 964 | } |
---|
| 965 | /* free proj_str if not used by parent */ |
---|
[ae917b96] | 966 | free(p->proj_str); |
---|
[37d6b84] | 967 | } |
---|
[cb3d1e2] | 968 | |
---|
[37d6b84] | 969 | /* don't free default ordering or ordering used by parent */ |
---|
| 970 | if (p->ordering != default_order && p->ordering != pcs->ordering) |
---|
[ae917b96] | 971 | free((reading*)p->ordering); |
---|
[647407d] | 972 | |
---|
[37d6b84] | 973 | /* free Translate if not used by parent */ |
---|
| 974 | if (p->Translate != pcs->Translate) |
---|
[ae917b96] | 975 | free(p->Translate - 1); |
---|
[b5a3219] | 976 | |
---|
[37d6b84] | 977 | /* free meta if not used by parent, or in this block */ |
---|
| 978 | if (p->meta && p->meta != pcs->meta && p->meta->ref_count == 0) |
---|
[ae917b96] | 979 | free(p->meta); |
---|
[37d6b84] | 980 | |
---|
[ae917b96] | 981 | free(p); |
---|
[d1b1380] | 982 | } |
---|
| 983 | |
---|
[4be360f] | 984 | static void |
---|
[eb18f4d] | 985 | cmd_end(void) |
---|
[a420b49] | 986 | { |
---|
[9f55538] | 987 | filepos fp; |
---|
[4be360f] | 988 | |
---|
[94aeeaf] | 989 | int begin_lineno = pcs->begin_lineno; |
---|
| 990 | if (begin_lineno == 0) { |
---|
[da9163b] | 991 | if (pcs->next == NULL) { |
---|
[4be360f] | 992 | /* more ENDs than BEGINs */ |
---|
[725d3b1] | 993 | /* TRANSLATORS: %s is replaced with e.g. BEGIN or .BOOK or #[ */ |
---|
| 994 | compile_diagnostic(DIAG_ERR|DIAG_SKIP, /*No matching %s*/192, "BEGIN"); |
---|
[4be360f] | 995 | } else { |
---|
[944153c] | 996 | /* TRANSLATORS: %s and %s are replaced with e.g. BEGIN and END |
---|
| 997 | * or END and BEGIN or #[ and #] */ |
---|
| 998 | compile_diagnostic(DIAG_ERR|DIAG_SKIP, |
---|
| 999 | /*%s with no matching %s in this file*/23, "END", "BEGIN"); |
---|
[4be360f] | 1000 | } |
---|
| 1001 | return; |
---|
| 1002 | } |
---|
| 1003 | |
---|
[94aeeaf] | 1004 | prefix *begin_survey = pcs->begin_survey; |
---|
| 1005 | long begin_lpos = pcs->begin_lpos; |
---|
| 1006 | int begin_col = pcs->begin_col; |
---|
[647407d] | 1007 | |
---|
[da9163b] | 1008 | pop_settings(); |
---|
[d1b1380] | 1009 | |
---|
[84c60fc] | 1010 | /* note need to read using root *before* BEGIN */ |
---|
[94aeeaf] | 1011 | prefix *survey = NULL; |
---|
| 1012 | if (!isEol(ch) && !isComm(ch)) { |
---|
[9f55538] | 1013 | get_pos(&fp); |
---|
[3916384] | 1014 | survey = read_prefix(PFX_SURVEY|PFX_ALLOW_ROOT); |
---|
| 1015 | } |
---|
| 1016 | |
---|
[613028c] | 1017 | if (survey != begin_survey) { |
---|
[94aeeaf] | 1018 | filepos fp_save; |
---|
| 1019 | get_pos(&fp_save); |
---|
[613028c] | 1020 | if (survey) { |
---|
[9f55538] | 1021 | set_pos(&fp); |
---|
[613028c] | 1022 | if (!begin_survey) { |
---|
| 1023 | /* TRANSLATORS: Used when a BEGIN command has no survey, but the |
---|
| 1024 | * END command does, e.g.: |
---|
[736f7df] | 1025 | * |
---|
| 1026 | * *begin |
---|
| 1027 | * 1 2 10.00 178 -01 |
---|
| 1028 | * *end entrance <--[Message given here] */ |
---|
[d0be687d] | 1029 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Matching BEGIN command has no survey name*/36); |
---|
[647407d] | 1030 | } else { |
---|
[613028c] | 1031 | /* TRANSLATORS: *BEGIN <survey> and *END <survey> should have the |
---|
| 1032 | * same <survey> if it’s given at all */ |
---|
[d0be687d] | 1033 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Survey name doesn’t match BEGIN*/193); |
---|
[647407d] | 1034 | } |
---|
[a420b49] | 1035 | } else { |
---|
[613028c] | 1036 | /* TRANSLATORS: Used when a BEGIN command has a survey name, but the |
---|
| 1037 | * END command omits it, e.g.: |
---|
| 1038 | * |
---|
| 1039 | * *begin entrance |
---|
| 1040 | * 1 2 10.00 178 -01 |
---|
| 1041 | * *end <--[Message given here] */ |
---|
[cab0f26] | 1042 | compile_diagnostic(DIAG_WARN|DIAG_COL, /*Survey name omitted from END*/194); |
---|
[a420b49] | 1043 | } |
---|
[94aeeaf] | 1044 | parse file_save = file; |
---|
| 1045 | file.line = begin_lineno; |
---|
| 1046 | file.lpos = begin_lpos; |
---|
| 1047 | int word_flag = 0; |
---|
| 1048 | if (begin_col) { |
---|
| 1049 | word_flag = DIAG_WORD; |
---|
| 1050 | fseek(file.fh, begin_lpos + begin_col - 1, SEEK_SET); |
---|
| 1051 | nextch(); |
---|
| 1052 | } |
---|
| 1053 | compile_diagnostic(DIAG_INFO|word_flag, /*Corresponding %s was here*/22, "BEGIN"); |
---|
| 1054 | file = file_save; |
---|
| 1055 | set_pos(&fp_save); |
---|
[5f1e194] | 1056 | } |
---|
| 1057 | } |
---|
[d1b1380] | 1058 | |
---|
[dfb4240] | 1059 | static void |
---|
| 1060 | cmd_entrance(void) |
---|
| 1061 | { |
---|
[c458cf7] | 1062 | prefix *pfx = read_prefix(PFX_STATION); |
---|
[e315359] | 1063 | pfx->sflags |= BIT(SFLAGS_ENTRANCE); |
---|
| 1064 | pfx->sflags &= ~BIT(SFLAGS_UNUSED_FIXED_POINT); |
---|
[dfb4240] | 1065 | } |
---|
| 1066 | |
---|
[56db37f] | 1067 | static const prefix * first_fix_name = NULL; |
---|
| 1068 | static const char * first_fix_filename; |
---|
| 1069 | static unsigned first_fix_line; |
---|
[216ada0] | 1070 | |
---|
[a420b49] | 1071 | static void |
---|
[eb18f4d] | 1072 | cmd_fix(void) |
---|
[a420b49] | 1073 | { |
---|
[216ada0] | 1074 | static prefix *name_omit_already = NULL; |
---|
[31699b54] | 1075 | static const char * name_omit_already_filename = NULL; |
---|
| 1076 | static unsigned int name_omit_already_line; |
---|
[725d3b1] | 1077 | PJ_COORD coord; |
---|
[58edecc] | 1078 | filepos fp_stn, fp; |
---|
[5f1e194] | 1079 | |
---|
[58edecc] | 1080 | get_pos(&fp_stn); |
---|
[725d3b1] | 1081 | prefix *fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT); |
---|
[5f1e194] | 1082 | |
---|
[c80bd34] | 1083 | get_pos(&fp); |
---|
[e1cbc0d] | 1084 | get_token_legacy(); |
---|
[72f617b] | 1085 | bool reference = S_EQ(&uctoken, "REFERENCE"); |
---|
| 1086 | if (reference) { |
---|
[05b9de76] | 1087 | do_legacy_token_warning(); |
---|
[c80bd34] | 1088 | } else { |
---|
[0532954] | 1089 | if (!s_empty(&uctoken)) set_pos(&fp); |
---|
[647407d] | 1090 | } |
---|
[c80bd34] | 1091 | |
---|
[1650ba1] | 1092 | skipblanks(); |
---|
| 1093 | get_pos(&fp); |
---|
| 1094 | |
---|
[72f617b] | 1095 | // If `REFERENCE` is specified the coordinates can't be omitted. |
---|
| 1096 | coord.v[0] = read_numeric(!reference); |
---|
[725d3b1] | 1097 | if (coord.v[0] == HUGE_REAL) { |
---|
[2aa2f3f] | 1098 | /* If the end of the line isn't blank, read a number after all to |
---|
| 1099 | * get a more helpful error message */ |
---|
[725d3b1] | 1100 | if (!isEol(ch) && !isComm(ch)) coord.v[0] = read_numeric(false); |
---|
[2aa2f3f] | 1101 | } |
---|
[725d3b1] | 1102 | if (coord.v[0] == HUGE_REAL) { |
---|
[b39e24a] | 1103 | if (pcs->proj_str || proj_str_out) { |
---|
[301a7d4] | 1104 | compile_diagnostic(DIAG_ERR|DIAG_COL|DIAG_SKIP, /*Coordinates can't be omitted when coordinate system has been specified*/439); |
---|
[a4f1d96] | 1105 | return; |
---|
| 1106 | } |
---|
| 1107 | |
---|
[6727d64] | 1108 | if (fix_name == name_omit_already) { |
---|
[301a7d4] | 1109 | compile_diagnostic(DIAG_WARN|DIAG_COL, /*Same station fixed twice with no coordinates*/61); |
---|
[5f1e194] | 1110 | return; |
---|
| 1111 | } |
---|
[6727d64] | 1112 | |
---|
| 1113 | if (name_omit_already) { |
---|
[0ef9ce4] | 1114 | /* TRANSLATORS: Emitted after second and subsequent "FIX" command |
---|
| 1115 | * with no coordinates. |
---|
[6727d64] | 1116 | */ |
---|
[501dd27] | 1117 | compile_diagnostic_at(DIAG_ERR, |
---|
[cab0f26] | 1118 | name_omit_already_filename, |
---|
| 1119 | name_omit_already_line, |
---|
| 1120 | /*Already had FIX command with no coordinates for station “%s”*/441, |
---|
| 1121 | sprint_prefix(name_omit_already)); |
---|
[6727d64] | 1122 | } else { |
---|
[0ef9ce4] | 1123 | /* TRANSLATORS: " *fix a " gives this message: */ |
---|
| 1124 | compile_diagnostic(DIAG_INFO|DIAG_COL, /*FIX command with no coordinates - fixing at (0,0,0)*/54); |
---|
| 1125 | |
---|
[6727d64] | 1126 | name_omit_already = fix_name; |
---|
| 1127 | name_omit_already_filename = file.filename; |
---|
| 1128 | name_omit_already_line = file.line; |
---|
| 1129 | } |
---|
| 1130 | |
---|
[725d3b1] | 1131 | coord.v[0] = coord.v[1] = coord.v[2] = (real)0.0; |
---|
[5f1e194] | 1132 | } else { |
---|
[725d3b1] | 1133 | coord.v[1] = read_numeric(false); |
---|
| 1134 | coord.v[2] = read_numeric(false); |
---|
[702be52] | 1135 | |
---|
[b39e24a] | 1136 | if (pcs->proj_str && proj_str_out) { |
---|
[da9163b] | 1137 | PJ *transform = pj_cached; |
---|
| 1138 | if (!transform) { |
---|
| 1139 | transform = proj_create_crs_to_crs(PJ_DEFAULT_CTX, |
---|
[b39e24a] | 1140 | pcs->proj_str, |
---|
| 1141 | proj_str_out, |
---|
| 1142 | NULL); |
---|
[da9163b] | 1143 | if (transform) { |
---|
[998388e] | 1144 | /* Normalise the output order so x is longitude and y latitude - by |
---|
| 1145 | * default new PROJ has them switched for EPSG:4326 which just seems |
---|
| 1146 | * confusing. |
---|
| 1147 | */ |
---|
[da9163b] | 1148 | PJ* pj_norm = proj_normalize_for_visualization(PJ_DEFAULT_CTX, |
---|
| 1149 | transform); |
---|
| 1150 | proj_destroy(transform); |
---|
| 1151 | transform = pj_norm; |
---|
| 1152 | } |
---|
| 1153 | |
---|
| 1154 | pj_cached = transform; |
---|
[b39e24a] | 1155 | } |
---|
| 1156 | |
---|
| 1157 | if (proj_angular_input(transform, PJ_FWD)) { |
---|
| 1158 | /* Input coordinate system expects radians. */ |
---|
[725d3b1] | 1159 | coord.v[0] = rad(coord.v[0]); |
---|
| 1160 | coord.v[1] = rad(coord.v[1]); |
---|
[702be52] | 1161 | } |
---|
[b39e24a] | 1162 | |
---|
[1a6fddc] | 1163 | coord.v[3] = HUGE_VAL; |
---|
[b39e24a] | 1164 | coord = proj_trans(transform, PJ_FWD, coord); |
---|
| 1165 | |
---|
[725d3b1] | 1166 | if (coord.v[0] == HUGE_VAL || |
---|
| 1167 | coord.v[1] == HUGE_VAL || |
---|
| 1168 | coord.v[2] == HUGE_VAL) { |
---|
[1650ba1] | 1169 | compile_diagnostic(DIAG_ERR|DIAG_FROM(fp), |
---|
| 1170 | /*Failed to convert coordinates: %s*/436, |
---|
[d9d8f21] | 1171 | proj_context_errno_string(PJ_DEFAULT_CTX, |
---|
| 1172 | proj_errno(transform))); |
---|
[998388e] | 1173 | /* Set dummy values which are finite. */ |
---|
[725d3b1] | 1174 | coord.v[0] = coord.v[1] = coord.v[2] = 0; |
---|
[702be52] | 1175 | } |
---|
[b39e24a] | 1176 | } else if (pcs->proj_str) { |
---|
[cab0f26] | 1177 | compile_diagnostic(DIAG_ERR, /*The input projection is set but the output projection isn't*/437); |
---|
[b39e24a] | 1178 | } else if (proj_str_out) { |
---|
[cab0f26] | 1179 | compile_diagnostic(DIAG_ERR, /*The output projection is set but the input projection isn't*/438); |
---|
[702be52] | 1180 | } |
---|
| 1181 | |
---|
[c270761] | 1182 | get_pos(&fp); |
---|
[725d3b1] | 1183 | real sdx = read_numeric(true); |
---|
[2cfcb32] | 1184 | if (sdx <= 0) { |
---|
[c270761] | 1185 | set_pos(&fp); |
---|
| 1186 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_NUM, /*Standard deviation must be positive*/48); |
---|
[2cfcb32] | 1187 | return; |
---|
| 1188 | } |
---|
[647407d] | 1189 | if (sdx != HUGE_REAL) { |
---|
| 1190 | real sdy, sdz; |
---|
[c80bd34] | 1191 | real cxy = 0, cyz = 0, czx = 0; |
---|
[c270761] | 1192 | get_pos(&fp); |
---|
[63d4f07] | 1193 | sdy = read_numeric(true); |
---|
[647407d] | 1194 | if (sdy == HUGE_REAL) { |
---|
| 1195 | /* only one variance given */ |
---|
| 1196 | sdy = sdz = sdx; |
---|
| 1197 | } else { |
---|
[2cfcb32] | 1198 | if (sdy <= 0) { |
---|
[c270761] | 1199 | set_pos(&fp); |
---|
| 1200 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_NUM, /*Standard deviation must be positive*/48); |
---|
[2cfcb32] | 1201 | return; |
---|
| 1202 | } |
---|
[c270761] | 1203 | get_pos(&fp); |
---|
[63d4f07] | 1204 | sdz = read_numeric(true); |
---|
[647407d] | 1205 | if (sdz == HUGE_REAL) { |
---|
| 1206 | /* two variances given - horizontal & vertical */ |
---|
| 1207 | sdz = sdy; |
---|
| 1208 | sdy = sdx; |
---|
[c80bd34] | 1209 | } else { |
---|
[2cfcb32] | 1210 | if (sdz <= 0) { |
---|
[c270761] | 1211 | set_pos(&fp); |
---|
| 1212 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_NUM, /*Standard deviation must be positive*/48); |
---|
[2cfcb32] | 1213 | return; |
---|
| 1214 | } |
---|
[63d4f07] | 1215 | cxy = read_numeric(true); |
---|
[c80bd34] | 1216 | if (cxy != HUGE_REAL) { |
---|
| 1217 | /* covariances given */ |
---|
[63d4f07] | 1218 | cyz = read_numeric(false); |
---|
| 1219 | czx = read_numeric(false); |
---|
[c2211a5] | 1220 | } else { |
---|
| 1221 | cxy = 0; |
---|
[c80bd34] | 1222 | } |
---|
[647407d] | 1223 | } |
---|
| 1224 | } |
---|
[725d3b1] | 1225 | fix_station_with_variance(fix_name, coord.v, |
---|
| 1226 | sdx * sdx, sdy * sdy, sdz * sdz |
---|
[647407d] | 1227 | #ifndef NO_COVARIANCES |
---|
[725d3b1] | 1228 | , cxy, cyz, czx |
---|
[647407d] | 1229 | #endif |
---|
[725d3b1] | 1230 | ); |
---|
[a9c640c] | 1231 | |
---|
[e315359] | 1232 | if (reference) { |
---|
| 1233 | // `*fix reference` so suppress "unused fixed point" warning. |
---|
| 1234 | fix_name->sflags &= ~BIT(SFLAGS_UNUSED_FIXED_POINT); |
---|
| 1235 | } |
---|
[a9c640c] | 1236 | if (!first_fix_name) { |
---|
| 1237 | /* We track if we've fixed a station yet, and if so what the name |
---|
| 1238 | * of the first fix was, so that we can issue an error if the |
---|
| 1239 | * output coordinate system is set after fixing a station. */ |
---|
| 1240 | first_fix_name = fix_name; |
---|
| 1241 | first_fix_filename = file.filename; |
---|
| 1242 | first_fix_line = file.line; |
---|
| 1243 | } |
---|
| 1244 | |
---|
[cb3d1e2] | 1245 | return; |
---|
[647407d] | 1246 | } |
---|
[5f1e194] | 1247 | } |
---|
| 1248 | |
---|
[56db37f] | 1249 | if (!first_fix_name) { |
---|
| 1250 | /* We track if we've fixed a station yet, and if so what the name of the |
---|
| 1251 | * first fix was, so that we can issue an error if the output coordinate |
---|
| 1252 | * system is set after fixing a station. */ |
---|
| 1253 | first_fix_name = fix_name; |
---|
| 1254 | first_fix_filename = file.filename; |
---|
| 1255 | first_fix_line = file.line; |
---|
| 1256 | } |
---|
| 1257 | |
---|
[98b705d] | 1258 | int fix_result = fix_station(fix_name, coord.v, fp_stn.offset); |
---|
[e315359] | 1259 | if (reference) { |
---|
| 1260 | // `*fix reference` so suppress "unused fixed point" warning. |
---|
| 1261 | fix_name->sflags &= ~BIT(SFLAGS_UNUSED_FIXED_POINT); |
---|
| 1262 | } |
---|
[725d3b1] | 1263 | if (fix_result == 0) { |
---|
[5f1e194] | 1264 | return; |
---|
| 1265 | } |
---|
[d1b1380] | 1266 | |
---|
[58edecc] | 1267 | get_pos(&fp); |
---|
| 1268 | set_pos(&fp_stn); |
---|
[725d3b1] | 1269 | if (fix_result < 0) { |
---|
[58edecc] | 1270 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Station already fixed or equated to a fixed point*/46); |
---|
| 1271 | } else { |
---|
| 1272 | /* TRANSLATORS: *fix a 1 2 3 / *fix a 1 2 3 */ |
---|
| 1273 | compile_diagnostic(DIAG_WARN|DIAG_WORD, /*Station already fixed at the same coordinates*/55); |
---|
[5f1e194] | 1274 | } |
---|
[bf669f6] | 1275 | compile_diagnostic_pfx(DIAG_INFO, fix_name, /*Previously fixed or equated here*/493); |
---|
[58edecc] | 1276 | set_pos(&fp); |
---|
[d1b1380] | 1277 | } |
---|
| 1278 | |
---|
[5c3c61a] | 1279 | static void |
---|
| 1280 | cmd_flags(void) |
---|
| 1281 | { |
---|
[82919e07] | 1282 | static const sztok flagtab[] = { |
---|
[5c3c61a] | 1283 | {"DUPLICATE", FLAGS_DUPLICATE }, |
---|
| 1284 | {"NOT", FLAGS_NOT }, |
---|
[95c3272] | 1285 | {"SPLAY", FLAGS_SPLAY }, |
---|
[5c3c61a] | 1286 | {"SURFACE", FLAGS_SURFACE }, |
---|
[a4ae909] | 1287 | {NULL, FLAGS_UNKNOWN } |
---|
[5c3c61a] | 1288 | }; |
---|
[63d4f07] | 1289 | bool fNot = false; |
---|
| 1290 | bool fEmpty = true; |
---|
[5c3c61a] | 1291 | while (1) { |
---|
| 1292 | int flag; |
---|
| 1293 | get_token(); |
---|
[0532954] | 1294 | /* If token is empty, it could mean end of line, or maybe |
---|
[e1cbc0d] | 1295 | * some non-alphanumeric junk which is better reported later */ |
---|
[0532954] | 1296 | if (s_empty(&token)) break; |
---|
[62bb4d3] | 1297 | |
---|
[63d4f07] | 1298 | fEmpty = false; |
---|
[5c3c61a] | 1299 | flag = match_tok(flagtab, TABSIZE(flagtab)); |
---|
| 1300 | /* treat the second NOT in "NOT NOT" as an unknown flag */ |
---|
| 1301 | if (flag == FLAGS_UNKNOWN || (fNot && flag == FLAGS_NOT)) { |
---|
[caae6cd] | 1302 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*FLAG “%s” unknown*/68, |
---|
[0532954] | 1303 | s_str(&token)); |
---|
[0804fbe] | 1304 | /* Recover from “*FLAGS NOT BOGUS SURFACE” by ignoring "NOT BOGUS" */ |
---|
[63d4f07] | 1305 | fNot = false; |
---|
[62bb4d3] | 1306 | } else if (flag == FLAGS_NOT) { |
---|
[63d4f07] | 1307 | fNot = true; |
---|
[5c3c61a] | 1308 | } else if (fNot) { |
---|
[421b7d2] | 1309 | pcs->flags &= ~BIT(flag); |
---|
[63d4f07] | 1310 | fNot = false; |
---|
[5c3c61a] | 1311 | } else { |
---|
[421b7d2] | 1312 | pcs->flags |= BIT(flag); |
---|
[5c3c61a] | 1313 | } |
---|
| 1314 | } |
---|
[9881759] | 1315 | |
---|
| 1316 | if (fNot) { |
---|
[725d3b1] | 1317 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN, |
---|
| 1318 | /*Expecting “%s”, “%s”, or “%s”*/188, |
---|
| 1319 | "DUPLICATE", "SPLAY", "SURFACE"); |
---|
[9881759] | 1320 | } else if (fEmpty) { |
---|
[725d3b1] | 1321 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN, |
---|
| 1322 | /*Expecting “%s”, “%s”, “%s”, or “%s”*/189, |
---|
| 1323 | "NOT", "DUPLICATE", "SPLAY", "SURFACE"); |
---|
[9881759] | 1324 | } |
---|
[5c3c61a] | 1325 | } |
---|
| 1326 | |
---|
[a420b49] | 1327 | static void |
---|
[eb18f4d] | 1328 | cmd_equate(void) |
---|
[a420b49] | 1329 | { |
---|
[c270761] | 1330 | filepos fp; |
---|
| 1331 | get_pos(&fp); |
---|
[bf669f6] | 1332 | prefix *prev_name = NULL; |
---|
| 1333 | prefix *name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO); |
---|
[63d4f07] | 1334 | while (true) { |
---|
[bf669f6] | 1335 | if (!name->stn || !fixed(name->stn)) { |
---|
| 1336 | // If the station isn't already fixed, make its file:line location |
---|
| 1337 | // reflect this *equate. |
---|
| 1338 | name->filename = file.filename; |
---|
| 1339 | name->line = file.line; |
---|
[98b705d] | 1340 | name->column = fp.offset - file.lpos; |
---|
[bf669f6] | 1341 | } |
---|
[b9c82c2] | 1342 | skipblanks(); |
---|
| 1343 | if (isEol(ch) || isComm(ch)) { |
---|
[bf669f6] | 1344 | if (prev_name == NULL) { |
---|
| 1345 | /* E.g. *equate entrance.6 */ |
---|
[c270761] | 1346 | set_pos(&fp); |
---|
[736f7df] | 1347 | /* TRANSLATORS: EQUATE is a command name, so shouldn’t be |
---|
[0b8c321] | 1348 | * translated. |
---|
| 1349 | * |
---|
| 1350 | * Here "station" is a survey station, not a train station. |
---|
| 1351 | */ |
---|
[d0be687d] | 1352 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_WORD, /*Only one station in EQUATE command*/33); |
---|
[11f9067] | 1353 | } |
---|
[5f1e194] | 1354 | return; |
---|
[d1b1380] | 1355 | } |
---|
[cb3d1e2] | 1356 | |
---|
[bf669f6] | 1357 | prev_name = name; |
---|
| 1358 | name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_SUSPECT_TYPO); |
---|
[dad5d599] | 1359 | process_equate(prev_name, name); |
---|
[5f1e194] | 1360 | } |
---|
[d1b1380] | 1361 | } |
---|
| 1362 | |
---|
[84c60fc] | 1363 | static void |
---|
| 1364 | report_missing_export(prefix *pfx, int depth) |
---|
| 1365 | { |
---|
| 1366 | char *s; |
---|
[93e3492] | 1367 | const char *p; |
---|
| 1368 | prefix *survey = pfx; |
---|
[84c60fc] | 1369 | int i; |
---|
| 1370 | for (i = depth + 1; i; i--) { |
---|
| 1371 | survey = survey->up; |
---|
[4c07c51] | 1372 | SVX_ASSERT(survey); |
---|
[84c60fc] | 1373 | } |
---|
| 1374 | s = osstrdup(sprint_prefix(survey)); |
---|
[93e3492] | 1375 | p = sprint_prefix(pfx); |
---|
[84c60fc] | 1376 | if (survey->filename) { |
---|
[93e3492] | 1377 | /* TRANSLATORS: A station must be exported out of each level it is in, so |
---|
| 1378 | * this would give "Station “\outer.inner.1” not exported from survey |
---|
| 1379 | * “\outer”)": |
---|
| 1380 | * |
---|
| 1381 | * *equate entrance outer.inner.1 |
---|
| 1382 | * *begin outer |
---|
| 1383 | * *begin inner |
---|
| 1384 | * *export 1 |
---|
| 1385 | * 1 2 1.23 045 -6 |
---|
| 1386 | * *end inner |
---|
[0b8c321] | 1387 | * *end outer |
---|
| 1388 | * |
---|
| 1389 | * Here "survey" is a "cave map" rather than list of questions - it should be |
---|
| 1390 | * translated to the terminology that cavers using the language would use. |
---|
| 1391 | */ |
---|
[cab0f26] | 1392 | compile_diagnostic_pfx(DIAG_ERR, survey, |
---|
| 1393 | /*Station “%s” not exported from survey “%s”*/26, p, s); |
---|
[93e3492] | 1394 | } else { |
---|
[cab0f26] | 1395 | compile_diagnostic(DIAG_ERR, /*Station “%s” not exported from survey “%s”*/26, p, s); |
---|
[84c60fc] | 1396 | } |
---|
[ae917b96] | 1397 | free(s); |
---|
[84c60fc] | 1398 | } |
---|
| 1399 | |
---|
[fb2e93c] | 1400 | static void |
---|
[d1878c51] | 1401 | cmd_export(void) |
---|
[fb2e93c] | 1402 | { |
---|
[d1878c51] | 1403 | prefix *pfx; |
---|
| 1404 | |
---|
[63d4f07] | 1405 | fExportUsed = true; |
---|
[932f7e9] | 1406 | do { |
---|
[fb2e93c] | 1407 | int depth = 0; |
---|
[6327dcf] | 1408 | pfx = read_prefix(PFX_STATION); |
---|
| 1409 | { |
---|
[421b7d2] | 1410 | prefix *p = pfx; |
---|
[fb2e93c] | 1411 | while (p != NULL && p != pcs->Prefix) { |
---|
| 1412 | depth++; |
---|
| 1413 | p = p->up; |
---|
| 1414 | } |
---|
[84c60fc] | 1415 | /* Something like: *export \foo, but we've excluded use of root */ |
---|
[4c07c51] | 1416 | SVX_ASSERT(p); |
---|
[fb2e93c] | 1417 | } |
---|
[84c60fc] | 1418 | /* *export \ or similar bogus stuff */ |
---|
[4c07c51] | 1419 | SVX_ASSERT(depth); |
---|
[932f7e9] | 1420 | #if 0 |
---|
| 1421 | printf("C min %d max %d depth %d pfx %s\n", |
---|
| 1422 | pfx->min_export, pfx->max_export, depth, sprint_prefix(pfx)); |
---|
| 1423 | #endif |
---|
| 1424 | if (pfx->min_export == 0) { |
---|
[421b7d2] | 1425 | /* not encountered *export for this name before */ |
---|
| 1426 | if (pfx->max_export > depth) report_missing_export(pfx, depth); |
---|
| 1427 | pfx->min_export = pfx->max_export = depth; |
---|
[c00c74a9] | 1428 | } else if (pfx->min_export != USHRT_MAX) { |
---|
| 1429 | /* FIXME: what to do if a station is marked for inferred exports |
---|
| 1430 | * but is then explicitly exported? Currently we just ignore the |
---|
| 1431 | * explicit export... */ |
---|
[421b7d2] | 1432 | if (pfx->min_export - 1 > depth) { |
---|
[84c60fc] | 1433 | report_missing_export(pfx, depth); |
---|
[421b7d2] | 1434 | } else if (pfx->min_export - 1 < depth) { |
---|
[736f7df] | 1435 | /* TRANSLATORS: Here "station" is a survey station, not a train station. |
---|
[b49ac56] | 1436 | * |
---|
[736f7df] | 1437 | * Exporting a station twice gives this error: |
---|
| 1438 | * |
---|
| 1439 | * *begin example |
---|
| 1440 | * *export 1 |
---|
| 1441 | * *export 1 |
---|
| 1442 | * 1 2 1.24 045 -6 |
---|
| 1443 | * *end example */ |
---|
[cab0f26] | 1444 | compile_diagnostic(DIAG_ERR, /*Station “%s” already exported*/66, |
---|
| 1445 | sprint_prefix(pfx)); |
---|
[421b7d2] | 1446 | } |
---|
| 1447 | pfx->min_export = depth; |
---|
[fb2e93c] | 1448 | } |
---|
[b9c82c2] | 1449 | skipblanks(); |
---|
| 1450 | } while (!isEol(ch) && !isComm(ch)); |
---|
[fb2e93c] | 1451 | } |
---|
| 1452 | |
---|
[a420b49] | 1453 | static void |
---|
[eb18f4d] | 1454 | cmd_data(void) |
---|
[a420b49] | 1455 | { |
---|
[82919e07] | 1456 | static const sztok dtab[] = { |
---|
[9b5d785] | 1457 | {"ALTITUDE", Dz }, |
---|
[5b7c1b7] | 1458 | {"BACKBEARING", BackComp }, |
---|
| 1459 | {"BACKCLINO", BackClino }, /* alternative name */ |
---|
| 1460 | {"BACKCOMPASS", BackComp }, /* alternative name */ |
---|
| 1461 | {"BACKGRADIENT", BackClino }, |
---|
[4f38f94] | 1462 | {"BACKLENGTH", BackTape }, |
---|
| 1463 | {"BACKTAPE", BackTape }, /* alternative name */ |
---|
[5f1e194] | 1464 | {"BEARING", Comp }, |
---|
[ee05463] | 1465 | {"CEILING", Up }, /* alternative name */ |
---|
[a4ae909] | 1466 | {"CLINO", Clino }, /* alternative name */ |
---|
[a420b49] | 1467 | {"COMPASS", Comp }, /* alternative name */ |
---|
[a4ae909] | 1468 | {"COUNT", Count }, /* FrCount&ToCount in multiline */ |
---|
| 1469 | {"DEPTH", Depth }, /* FrDepth&ToDepth in multiline */ |
---|
[6114207] | 1470 | {"DEPTHCHANGE", DepthChange }, |
---|
[421b7d2] | 1471 | {"DIRECTION", Dir }, |
---|
[ee05463] | 1472 | {"DOWN", Down }, |
---|
[647407d] | 1473 | {"DX", Dx }, |
---|
| 1474 | {"DY", Dy }, |
---|
| 1475 | {"DZ", Dz }, |
---|
[9b5d785] | 1476 | {"EASTING", Dx }, |
---|
[ee05463] | 1477 | {"FLOOR", Down }, /* alternative name */ |
---|
[a4ae909] | 1478 | {"FROM", Fr }, |
---|
[647407d] | 1479 | {"FROMCOUNT", FrCount }, |
---|
[5f1e194] | 1480 | {"FROMDEPTH", FrDepth }, |
---|
| 1481 | {"GRADIENT", Clino }, |
---|
| 1482 | {"IGNORE", Ignore }, |
---|
| 1483 | {"IGNOREALL", IgnoreAll }, |
---|
[ee05463] | 1484 | {"LEFT", Left }, |
---|
[5f1e194] | 1485 | {"LENGTH", Tape }, |
---|
[a0027a2] | 1486 | {"NEWLINE", Newline }, |
---|
[9b5d785] | 1487 | {"NORTHING", Dy }, |
---|
[ee05463] | 1488 | {"RIGHT", Right }, |
---|
[421b7d2] | 1489 | {"STATION", Station }, /* Fr&To in multiline */ |
---|
[a4ae909] | 1490 | {"TAPE", Tape }, /* alternative name */ |
---|
| 1491 | {"TO", To }, |
---|
[647407d] | 1492 | {"TOCOUNT", ToCount }, |
---|
[5f1e194] | 1493 | {"TODEPTH", ToDepth }, |
---|
[ee05463] | 1494 | {"UP", Up }, |
---|
[a4ae909] | 1495 | {NULL, End } |
---|
[5f1e194] | 1496 | }; |
---|
| 1497 | |
---|
[107b8bd] | 1498 | #define MASK_stns BIT(Fr) | BIT(To) | BIT(Station) |
---|
[4f38f94] | 1499 | #define MASK_tape BIT(Tape) | BIT(BackTape) | BIT(FrCount) | BIT(ToCount) | BIT(Count) |
---|
[107b8bd] | 1500 | #define MASK_dpth BIT(FrDepth) | BIT(ToDepth) | BIT(Depth) | BIT(DepthChange) |
---|
[5b7c1b7] | 1501 | #define MASK_comp BIT(Comp) | BIT(BackComp) |
---|
| 1502 | #define MASK_clin BIT(Clino) | BIT(BackClino) |
---|
[5f1e194] | 1503 | |
---|
[5b7c1b7] | 1504 | #define MASK_NORMAL MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_clin |
---|
[bd263b36] | 1505 | #define MASK_DIVING MASK_NORMAL | MASK_dpth |
---|
[107b8bd] | 1506 | #define MASK_CARTESIAN MASK_stns | BIT(Dx) | BIT(Dy) | BIT(Dz) |
---|
[5b7c1b7] | 1507 | #define MASK_CYLPOLAR MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_dpth |
---|
[107b8bd] | 1508 | #define MASK_NOSURVEY MASK_stns |
---|
[19bb4772] | 1509 | #define MASK_PASSAGE BIT(Station) | BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down) |
---|
[63ae487] | 1510 | #define MASK_IGNORE 0 // No readings in this style. |
---|
[421b7d2] | 1511 | |
---|
[63ae487] | 1512 | // readings which may be given for each style (index is STYLE_*) |
---|
[6114207] | 1513 | static const unsigned long mask[] = { |
---|
[200a12c] | 1514 | MASK_NORMAL, MASK_DIVING, MASK_CARTESIAN, MASK_CYLPOLAR, MASK_NOSURVEY, |
---|
[63ae487] | 1515 | MASK_PASSAGE, MASK_IGNORE |
---|
[5f1e194] | 1516 | }; |
---|
| 1517 | |
---|
[63ae487] | 1518 | // readings which may be omitted for each style (index is STYLE_*) |
---|
[6114207] | 1519 | static const unsigned long mask_optional[] = { |
---|
[5b7c1b7] | 1520 | BIT(Dir) | BIT(Clino) | BIT(BackClino), |
---|
[bd263b36] | 1521 | BIT(Dir) | BIT(Clino) | BIT(BackClino), |
---|
[86f26e2] | 1522 | 0, |
---|
[54c4612] | 1523 | BIT(Dir), |
---|
[200a12c] | 1524 | 0, |
---|
[63ae487] | 1525 | 0, /* BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down), */ |
---|
| 1526 | 0 |
---|
[5f1e194] | 1527 | }; |
---|
| 1528 | |
---|
[6114207] | 1529 | /* all valid readings */ |
---|
| 1530 | static const unsigned long mask_all[] = { |
---|
| 1531 | MASK_NORMAL | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
| 1532 | MASK_DIVING | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
| 1533 | MASK_CARTESIAN | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
| 1534 | MASK_CYLPOLAR | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
[200a12c] | 1535 | MASK_NOSURVEY | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
[63ae487] | 1536 | MASK_PASSAGE | BIT(Ignore) | BIT(IgnoreAll) | BIT(End), |
---|
| 1537 | MASK_IGNORE |
---|
[6114207] | 1538 | }; |
---|
[54c4612] | 1539 | #define STYLE_DEFAULT -2 |
---|
| 1540 | #define STYLE_UNKNOWN -1 |
---|
| 1541 | |
---|
[82919e07] | 1542 | static const sztok styletab[] = { |
---|
[647407d] | 1543 | {"CARTESIAN", STYLE_CARTESIAN }, |
---|
[54c4612] | 1544 | {"CYLPOLAR", STYLE_CYLPOLAR }, |
---|
[a420b49] | 1545 | {"DEFAULT", STYLE_DEFAULT }, |
---|
[5f1e194] | 1546 | {"DIVING", STYLE_DIVING }, |
---|
[63ae487] | 1547 | {"IGNORE", STYLE_IGNORE }, |
---|
[5f1e194] | 1548 | {"NORMAL", STYLE_NORMAL }, |
---|
[647407d] | 1549 | {"NOSURVEY", STYLE_NOSURVEY }, |
---|
[ee05463] | 1550 | {"PASSAGE", STYLE_PASSAGE }, |
---|
[107b8bd] | 1551 | {"TOPOFIL", STYLE_NORMAL }, |
---|
[a4ae909] | 1552 | {NULL, STYLE_UNKNOWN } |
---|
[5f1e194] | 1553 | }; |
---|
| 1554 | |
---|
[ee3a4ed] | 1555 | #define m_multi (BIT(Station) | BIT(Count) | BIT(Depth)) |
---|
| 1556 | |
---|
[dbe783b] | 1557 | int style, k = 0; |
---|
| 1558 | reading d; |
---|
[6114207] | 1559 | unsigned long mUsed = 0; |
---|
[667e803c] | 1560 | int old_style = pcs->style; |
---|
[5f1e194] | 1561 | |
---|
[50f6901] | 1562 | /* after a bad *data command ignore survey data until the next |
---|
| 1563 | * *data command to avoid an avalanche of errors */ |
---|
[fdffa7d] | 1564 | pcs->recorded_style = pcs->style = STYLE_IGNORE; |
---|
[289b7a8] | 1565 | |
---|
[a420b49] | 1566 | get_token(); |
---|
[5f1e194] | 1567 | style = match_tok(styletab, TABSIZE(styletab)); |
---|
| 1568 | |
---|
[a420b49] | 1569 | if (style == STYLE_DEFAULT) { |
---|
| 1570 | default_style(pcs); |
---|
| 1571 | return; |
---|
| 1572 | } |
---|
| 1573 | |
---|
[63ae487] | 1574 | if (style == STYLE_IGNORE) { |
---|
| 1575 | return; |
---|
| 1576 | } |
---|
| 1577 | |
---|
[5f1e194] | 1578 | if (style == STYLE_UNKNOWN) { |
---|
[0532954] | 1579 | if (s_empty(&token)) { |
---|
[b9122e1] | 1580 | /* "*data" without arguments reinitialises the current style - useful |
---|
| 1581 | * when using *data passage as it provides a way to break the passage |
---|
| 1582 | * tube without having to repeat the full *data passage command. |
---|
[667e803c] | 1583 | */ |
---|
[fdffa7d] | 1584 | pcs->recorded_style = pcs->style = style = old_style; |
---|
[667e803c] | 1585 | goto reinit_style; |
---|
| 1586 | } |
---|
[736f7df] | 1587 | /* TRANSLATORS: e.g. trying to refer to an invalid FNORD data style */ |
---|
[caae6cd] | 1588 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Data style “%s” unknown*/65, s_str(&token)); |
---|
[5f1e194] | 1589 | return; |
---|
| 1590 | } |
---|
[a420b49] | 1591 | |
---|
[5f1e194] | 1592 | skipblanks(); |
---|
[d6d3576] | 1593 | #ifndef NO_DEPRECATED |
---|
| 1594 | /* Olde syntax had optional field for survey grade, so allow an omit |
---|
| 1595 | * but issue a warning about it */ |
---|
| 1596 | if (isOmit(ch)) { |
---|
| 1597 | static int data_depr_count = 0; |
---|
| 1598 | if (data_depr_count < 5) { |
---|
[caae6cd] | 1599 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN, /*“*data %s %c …” is deprecated - use “*data %s …” instead*/104, |
---|
[0532954] | 1600 | s_str(&token), ch, s_str(&token)); |
---|
[d6d3576] | 1601 | if (++data_depr_count == 5) |
---|
[64544daf] | 1602 | compile_diagnostic(DIAG_INFO, /*Further uses of this deprecated feature will not be reported*/95); |
---|
[d6d3576] | 1603 | } |
---|
| 1604 | nextch(); |
---|
| 1605 | } |
---|
| 1606 | #endif |
---|
[d1b1380] | 1607 | |
---|
[dbe783b] | 1608 | int kMac = 6; /* minimum for NORMAL style */ |
---|
| 1609 | reading *new_order = osmalloc(kMac * sizeof(reading)); |
---|
[0532954] | 1610 | char *style_name = s_steal(&token); |
---|
[421b7d2] | 1611 | do { |
---|
[c80bd34] | 1612 | filepos fp; |
---|
| 1613 | get_pos(&fp); |
---|
[a420b49] | 1614 | get_token(); |
---|
[5f1e194] | 1615 | d = match_tok(dtab, TABSIZE(dtab)); |
---|
[30c81bb] | 1616 | if (d == End && !s_empty(&token)) { |
---|
| 1617 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, |
---|
| 1618 | /*Reading “%s” not allowed in data style “%s”*/63, |
---|
| 1619 | s_str(&token), style_name); |
---|
[ae917b96] | 1620 | free(style_name); |
---|
| 1621 | free(new_order); |
---|
[30c81bb] | 1622 | return; |
---|
| 1623 | } |
---|
| 1624 | |
---|
[90bb053f] | 1625 | /* only token allowed after IGNOREALL is NEWLINE */ |
---|
| 1626 | if (k && new_order[k - 1] == IgnoreAll && d != Newline) { |
---|
[c80bd34] | 1627 | set_pos(&fp); |
---|
[90bb053f] | 1628 | break; |
---|
| 1629 | } |
---|
[0395657] | 1630 | /* Note: an unknown token is reported as trailing garbage */ |
---|
[6114207] | 1631 | if (!TSTBIT(mask_all[style], d)) { |
---|
[736f7df] | 1632 | /* TRANSLATORS: a data "style" is something like NORMAL, DIVING, etc. |
---|
| 1633 | * a "reading" is one of FROM, TO, TAPE, COMPASS, CLINO for NORMAL |
---|
[88f302c] | 1634 | * style. Neither "style" nor "reading" is a keyword in the program. |
---|
| 1635 | * |
---|
| 1636 | * This error complains about a "DEPTH" gauge reading in "NORMAL" |
---|
| 1637 | * style, for example. |
---|
[736f7df] | 1638 | */ |
---|
[caae6cd] | 1639 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, |
---|
[cab0f26] | 1640 | /*Reading “%s” not allowed in data style “%s”*/63, |
---|
[0532954] | 1641 | s_str(&token), style_name); |
---|
[ae917b96] | 1642 | free(style_name); |
---|
| 1643 | free(new_order); |
---|
[ee3a4ed] | 1644 | return; |
---|
| 1645 | } |
---|
[6114207] | 1646 | if (TSTBIT(mUsed, Newline) && TSTBIT(m_multi, d)) { |
---|
[736f7df] | 1647 | /* TRANSLATORS: caused by e.g. |
---|
| 1648 | * |
---|
| 1649 | * *data diving station newline depth tape compass |
---|
| 1650 | * |
---|
| 1651 | * ("depth" needs to occur before "newline"). */ |
---|
[caae6cd] | 1652 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, |
---|
[0532954] | 1653 | /*Reading “%s” must occur before NEWLINE*/225, s_str(&token)); |
---|
[ae917b96] | 1654 | free(style_name); |
---|
| 1655 | free(new_order); |
---|
[5f1e194] | 1656 | return; |
---|
| 1657 | } |
---|
[0395657] | 1658 | /* Check for duplicates unless it's a special reading: |
---|
[ee3a4ed] | 1659 | * IGNOREALL,IGNORE (duplicates allowed) ; END (not possible) |
---|
[5f1e194] | 1660 | */ |
---|
[ee3a4ed] | 1661 | if (!((BIT(Ignore) | BIT(End) | BIT(IgnoreAll)) & BIT(d))) { |
---|
[95c3272] | 1662 | if (TSTBIT(mUsed, d)) { |
---|
[736f7df] | 1663 | /* TRANSLATORS: complains about a situation like trying to define |
---|
| 1664 | * two from stations per leg */ |
---|
[caae6cd] | 1665 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Duplicate reading “%s”*/67, s_str(&token)); |
---|
[ae917b96] | 1666 | free(style_name); |
---|
| 1667 | free(new_order); |
---|
[90bb053f] | 1668 | return; |
---|
[62bb4d3] | 1669 | } else { |
---|
[5b7c1b7] | 1670 | /* Check for previously listed readings which are incompatible |
---|
| 1671 | * with this one - e.g. Count vs FrCount */ |
---|
[63d4f07] | 1672 | bool fBad = false; |
---|
[90bb053f] | 1673 | switch (d) { |
---|
| 1674 | case Station: |
---|
[63d4f07] | 1675 | if (mUsed & (BIT(Fr) | BIT(To))) fBad = true; |
---|
[90bb053f] | 1676 | break; |
---|
| 1677 | case Fr: case To: |
---|
[63d4f07] | 1678 | if (TSTBIT(mUsed, Station)) fBad = true; |
---|
[90bb053f] | 1679 | break; |
---|
| 1680 | case Count: |
---|
[107b8bd] | 1681 | if (mUsed & (BIT(FrCount) | BIT(ToCount) | BIT(Tape))) |
---|
[63d4f07] | 1682 | fBad = true; |
---|
[90bb053f] | 1683 | break; |
---|
| 1684 | case FrCount: case ToCount: |
---|
[107b8bd] | 1685 | if (mUsed & (BIT(Count) | BIT(Tape))) |
---|
[63d4f07] | 1686 | fBad = true; |
---|
[90bb053f] | 1687 | break; |
---|
| 1688 | case Depth: |
---|
[6114207] | 1689 | if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(DepthChange))) |
---|
[63d4f07] | 1690 | fBad = true; |
---|
[90bb053f] | 1691 | break; |
---|
| 1692 | case FrDepth: case ToDepth: |
---|
[63d4f07] | 1693 | if (mUsed & (BIT(Depth) | BIT(DepthChange))) fBad = true; |
---|
[a186573] | 1694 | break; |
---|
[6114207] | 1695 | case DepthChange: |
---|
[a186573] | 1696 | if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(Depth))) |
---|
[63d4f07] | 1697 | fBad = true; |
---|
[90bb053f] | 1698 | break; |
---|
[ee3a4ed] | 1699 | case Newline: |
---|
| 1700 | if (mUsed & ~m_multi) { |
---|
[736f7df] | 1701 | /* TRANSLATORS: e.g. |
---|
| 1702 | * |
---|
| 1703 | * *data normal from to tape newline compass clino */ |
---|
[caae6cd] | 1704 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*NEWLINE can only be preceded by STATION, DEPTH, and COUNT*/226); |
---|
[ae917b96] | 1705 | free(style_name); |
---|
| 1706 | free(new_order); |
---|
[ee3a4ed] | 1707 | return; |
---|
| 1708 | } |
---|
[6114207] | 1709 | if (k == 0) { |
---|
[736f7df] | 1710 | /* TRANSLATORS: error from: |
---|
| 1711 | * |
---|
| 1712 | * *data normal newline from to tape compass clino */ |
---|
[caae6cd] | 1713 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*NEWLINE can’t be the first reading*/222); |
---|
[ae917b96] | 1714 | free(style_name); |
---|
| 1715 | free(new_order); |
---|
[6114207] | 1716 | return; |
---|
| 1717 | } |
---|
[ee3a4ed] | 1718 | break; |
---|
[90bb053f] | 1719 | default: /* avoid compiler warnings about unhandled enums */ |
---|
| 1720 | break; |
---|
[421b7d2] | 1721 | } |
---|
[90bb053f] | 1722 | if (fBad) { |
---|
[46cb98f] | 1723 | /* Not entirely happy with phrasing this... */ |
---|
[36efb03] | 1724 | /* TRANSLATORS: This is an error from the *DATA command. It |
---|
| 1725 | * means that a reading (which will appear where %s is isn't |
---|
| 1726 | * valid as the list of readings has already included the same |
---|
| 1727 | * reading, or an equivalent one (e.g. you can't have both |
---|
| 1728 | * DEPTH and DEPTHCHANGE together). */ |
---|
[caae6cd] | 1729 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Reading “%s” duplicates previous reading(s)*/77, |
---|
[0532954] | 1730 | s_str(&token)); |
---|
[ae917b96] | 1731 | free(style_name); |
---|
| 1732 | free(new_order); |
---|
[90bb053f] | 1733 | return; |
---|
| 1734 | } |
---|
[62bb4d3] | 1735 | mUsed |= BIT(d); /* used to catch duplicates */ |
---|
[a420b49] | 1736 | } |
---|
[d1b1380] | 1737 | } |
---|
[90bb053f] | 1738 | if (k && new_order[k - 1] == IgnoreAll) { |
---|
[4c07c51] | 1739 | SVX_ASSERT(d == Newline); |
---|
[90bb053f] | 1740 | k--; |
---|
| 1741 | d = IgnoreAllAndNewLine; |
---|
| 1742 | } |
---|
[a420b49] | 1743 | if (k >= kMac) { |
---|
| 1744 | kMac = kMac * 2; |
---|
[0395657] | 1745 | new_order = osrealloc(new_order, kMac * sizeof(reading)); |
---|
[a420b49] | 1746 | } |
---|
| 1747 | new_order[k++] = d; |
---|
[90bb053f] | 1748 | } while (d != End); |
---|
| 1749 | |
---|
[6114207] | 1750 | if (k >= 2 && new_order[k - 2] == Newline) { |
---|
[736f7df] | 1751 | /* TRANSLATORS: error from: |
---|
| 1752 | * |
---|
| 1753 | * *data normal from to tape compass clino newline */ |
---|
[caae6cd] | 1754 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*NEWLINE can’t be the last reading*/223); |
---|
[ae917b96] | 1755 | free(style_name); |
---|
| 1756 | free(new_order); |
---|
[6114207] | 1757 | return; |
---|
| 1758 | } |
---|
[421b7d2] | 1759 | |
---|
[6114207] | 1760 | if (style == STYLE_NOSURVEY) { |
---|
| 1761 | if (TSTBIT(mUsed, Station)) { |
---|
| 1762 | if (k >= kMac) { |
---|
| 1763 | kMac = kMac * 2; |
---|
| 1764 | new_order = osrealloc(new_order, kMac * sizeof(reading)); |
---|
| 1765 | } |
---|
| 1766 | new_order[k - 1] = Newline; |
---|
| 1767 | new_order[k++] = End; |
---|
| 1768 | } |
---|
[ee05463] | 1769 | } else if (style == STYLE_PASSAGE) { |
---|
| 1770 | /* Station doesn't mean "multiline" for STYLE_PASSAGE. */ |
---|
[6114207] | 1771 | } else if (!TSTBIT(mUsed, Newline) && (m_multi & mUsed)) { |
---|
[736f7df] | 1772 | /* TRANSLATORS: Error given by something like: |
---|
| 1773 | * |
---|
[6114207] | 1774 | * *data normal station tape compass clino |
---|
[736f7df] | 1775 | * |
---|
| 1776 | * ("station" signifies interleaved data). */ |
---|
[cab0f26] | 1777 | compile_diagnostic(DIAG_ERR|DIAG_SKIP, /*Interleaved readings, but no NEWLINE*/224); |
---|
[ae917b96] | 1778 | free(style_name); |
---|
| 1779 | free(new_order); |
---|
[6114207] | 1780 | return; |
---|
| 1781 | } |
---|
| 1782 | |
---|
[a6d094f] | 1783 | #if 0 |
---|
| 1784 | printf("mUsed = 0x%x\n", mUsed); |
---|
| 1785 | #endif |
---|
[90bb053f] | 1786 | |
---|
[5b7c1b7] | 1787 | /* Check the supplied readings form a sufficient set. */ |
---|
[ee05463] | 1788 | if (style != STYLE_PASSAGE) { |
---|
[4f38f94] | 1789 | if ((mUsed & (BIT(Fr) | BIT(To))) == (BIT(Fr) | BIT(To))) |
---|
[ee05463] | 1790 | mUsed |= BIT(Station); |
---|
| 1791 | else if (TSTBIT(mUsed, Station)) |
---|
| 1792 | mUsed |= BIT(Fr) | BIT(To); |
---|
| 1793 | } |
---|
[a186573] | 1794 | |
---|
[5b7c1b7] | 1795 | if (mUsed & (BIT(Comp) | BIT(BackComp))) |
---|
| 1796 | mUsed |= BIT(Comp) | BIT(BackComp); |
---|
| 1797 | |
---|
| 1798 | if (mUsed & (BIT(Clino) | BIT(BackClino))) |
---|
| 1799 | mUsed |= BIT(Clino) | BIT(BackClino); |
---|
| 1800 | |
---|
[4f38f94] | 1801 | if ((mUsed & (BIT(FrDepth) | BIT(ToDepth))) == (BIT(FrDepth) | BIT(ToDepth))) |
---|
[6114207] | 1802 | mUsed |= BIT(Depth) | BIT(DepthChange); |
---|
[4f38f94] | 1803 | else if (mUsed & (BIT(Depth) | BIT(DepthChange))) |
---|
| 1804 | mUsed |= BIT(FrDepth) | BIT(ToDepth) | BIT(Depth) | BIT(DepthChange); |
---|
| 1805 | |
---|
| 1806 | if ((mUsed & (BIT(FrCount) | BIT(ToCount))) == (BIT(FrCount) | BIT(ToCount))) |
---|
| 1807 | mUsed |= BIT(Count) | BIT(Tape) | BIT(BackTape); |
---|
| 1808 | else if (mUsed & (BIT(Count) | BIT(Tape) | BIT(BackTape))) |
---|
| 1809 | mUsed |= BIT(FrCount) | BIT(ToCount) | BIT(Count) | BIT(Tape) | BIT(BackTape); |
---|
[90bb053f] | 1810 | |
---|
[a6d094f] | 1811 | #if 0 |
---|
| 1812 | printf("mUsed = 0x%x, opt = 0x%x, mask = 0x%x\n", mUsed, |
---|
| 1813 | mask_optional[style], mask[style]); |
---|
| 1814 | #endif |
---|
[cb3d1e2] | 1815 | |
---|
[6114207] | 1816 | if (((mUsed &~ BIT(Newline)) | mask_optional[style]) != mask[style]) { |
---|
| 1817 | /* Test should only fail with too few bits set, not too many */ |
---|
[4c07c51] | 1818 | SVX_ASSERT((((mUsed &~ BIT(Newline)) | mask_optional[style]) |
---|
[6114207] | 1819 | &~ mask[style]) == 0); |
---|
[736f7df] | 1820 | /* TRANSLATORS: i.e. not enough readings for the style. */ |
---|
[cab0f26] | 1821 | compile_diagnostic(DIAG_ERR|DIAG_SKIP, /*Too few readings for data style “%s”*/64, style_name); |
---|
[ae917b96] | 1822 | free(style_name); |
---|
| 1823 | free(new_order); |
---|
[a420b49] | 1824 | return; |
---|
| 1825 | } |
---|
[d1b1380] | 1826 | |
---|
[a420b49] | 1827 | /* don't free default ordering or ordering used by parent */ |
---|
| 1828 | if (pcs->ordering != default_order && |
---|
| 1829 | !(pcs->next && pcs->next->ordering == pcs->ordering)) |
---|
[ae917b96] | 1830 | free((reading*)pcs->ordering); |
---|
[cb3d1e2] | 1831 | |
---|
[fdffa7d] | 1832 | pcs->recorded_style = pcs->style = style; |
---|
[a420b49] | 1833 | pcs->ordering = new_order; |
---|
[1b34062] | 1834 | |
---|
[ae917b96] | 1835 | free(style_name); |
---|
[ee05463] | 1836 | |
---|
[667e803c] | 1837 | reinit_style: |
---|
[ee05463] | 1838 | if (style == STYLE_PASSAGE) { |
---|
| 1839 | lrudlist * new_psg = osnew(lrudlist); |
---|
| 1840 | new_psg->tube = NULL; |
---|
| 1841 | new_psg->next = model; |
---|
| 1842 | model = new_psg; |
---|
| 1843 | next_lrud = &(new_psg->tube); |
---|
| 1844 | } |
---|
[d1b1380] | 1845 | } |
---|
| 1846 | |
---|
[a420b49] | 1847 | static void |
---|
[eb18f4d] | 1848 | cmd_units(void) |
---|
[a420b49] | 1849 | { |
---|
[5f1e194] | 1850 | int units, quantity; |
---|
[6114207] | 1851 | unsigned long qmask; |
---|
| 1852 | unsigned long m; /* mask with bit x set to indicate quantity x specified */ |
---|
[5f1e194] | 1853 | real factor; |
---|
[9f55538] | 1854 | filepos fp; |
---|
[a420b49] | 1855 | |
---|
[699bf50] | 1856 | qmask = get_qlist(BIT(Q_POS)|BIT(Q_PLUMB)|BIT(Q_LEVEL)); |
---|
| 1857 | |
---|
[647407d] | 1858 | if (!qmask) return; |
---|
[a420b49] | 1859 | if (qmask == BIT(Q_DEFAULT)) { |
---|
| 1860 | default_units(pcs); |
---|
[5f1e194] | 1861 | return; |
---|
| 1862 | } |
---|
[a420b49] | 1863 | |
---|
[9f55538] | 1864 | get_pos(&fp); |
---|
[63d4f07] | 1865 | factor = read_numeric(true); |
---|
[fa42426] | 1866 | if (factor == 0.0) { |
---|
[9f55538] | 1867 | set_pos(&fp); |
---|
[736f7df] | 1868 | /* TRANSLATORS: error message given by "*units tape 0 feet" - it’s |
---|
| 1869 | * meaningless to say your tape is marked in "0 feet" (but you might |
---|
| 1870 | * measure distance by counting knots on a diving line, and tie them |
---|
| 1871 | * every "2 feet"). */ |
---|
[d0be687d] | 1872 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /**UNITS factor must be non-zero*/200); |
---|
[9f55538] | 1873 | skipline(); |
---|
[fa42426] | 1874 | return; |
---|
| 1875 | } |
---|
[a420b49] | 1876 | |
---|
[63d4f07] | 1877 | units = get_units(qmask, true); |
---|
[647407d] | 1878 | if (units == UNITS_NULL) return; |
---|
[fa42426] | 1879 | if (TSTBIT(qmask, Q_GRADIENT)) |
---|
| 1880 | pcs->f_clino_percent = (units == UNITS_PERCENT); |
---|
| 1881 | if (TSTBIT(qmask, Q_BACKGRADIENT)) |
---|
| 1882 | pcs->f_backclino_percent = (units == UNITS_PERCENT); |
---|
| 1883 | |
---|
[00b10c1] | 1884 | if (TSTBIT(qmask, Q_BEARING)) { |
---|
| 1885 | pcs->f_bearing_quadrants = (units == UNITS_QUADRANTS); |
---|
| 1886 | } |
---|
| 1887 | if (TSTBIT(qmask, Q_BACKBEARING)) { |
---|
| 1888 | pcs->f_backbearing_quadrants = (units == UNITS_QUADRANTS); |
---|
| 1889 | } |
---|
| 1890 | |
---|
[6eb50ab] | 1891 | if (factor == HUGE_REAL) { |
---|
| 1892 | factor = factor_tab[units]; |
---|
| 1893 | } else { |
---|
| 1894 | factor *= factor_tab[units]; |
---|
| 1895 | } |
---|
[5f1e194] | 1896 | |
---|
| 1897 | for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1) |
---|
| 1898 | if (qmask & m) pcs->units[quantity] = factor; |
---|
[d1b1380] | 1899 | } |
---|
| 1900 | |
---|
[a420b49] | 1901 | static void |
---|
[eb18f4d] | 1902 | cmd_calibrate(void) |
---|
[a420b49] | 1903 | { |
---|
[d6d3576] | 1904 | real sc, z; |
---|
[67508f0] | 1905 | unsigned long qmask, m; |
---|
[a420b49] | 1906 | int quantity; |
---|
[9f55538] | 1907 | filepos fp; |
---|
[46cb98f] | 1908 | |
---|
[da96015] | 1909 | qmask = get_qlist(BIT(Q_POS)|BIT(Q_PLUMB)|BIT(Q_LEVEL)); |
---|
[46cb98f] | 1910 | if (!qmask) return; /* error already reported */ |
---|
| 1911 | |
---|
[a420b49] | 1912 | if (qmask == BIT(Q_DEFAULT)) { |
---|
| 1913 | default_calib(pcs); |
---|
| 1914 | return; |
---|
| 1915 | } |
---|
[46cb98f] | 1916 | |
---|
[a420b49] | 1917 | if (((qmask & LEN_QMASK)) && ((qmask & ANG_QMASK))) { |
---|
[0b8c321] | 1918 | /* TRANSLATORS: e.g. |
---|
| 1919 | * |
---|
| 1920 | * *calibrate tape compass 1 1 |
---|
| 1921 | */ |
---|
[cab0f26] | 1922 | compile_diagnostic(DIAG_ERR|DIAG_SKIP, /*Can’t calibrate angular and length quantities together*/227); |
---|
[647407d] | 1923 | return; |
---|
[a420b49] | 1924 | } |
---|
[46cb98f] | 1925 | |
---|
[63d4f07] | 1926 | z = read_numeric(false); |
---|
[9f55538] | 1927 | get_pos(&fp); |
---|
[63d4f07] | 1928 | sc = read_numeric(true); |
---|
[88569fe] | 1929 | if (sc == HUGE_REAL) { |
---|
| 1930 | if (isalpha(ch)) { |
---|
[63d4f07] | 1931 | int units = get_units(qmask, false); |
---|
[88569fe] | 1932 | if (units == UNITS_NULL) { |
---|
| 1933 | return; |
---|
| 1934 | } |
---|
| 1935 | z *= factor_tab[units]; |
---|
[63d4f07] | 1936 | sc = read_numeric(true); |
---|
[88569fe] | 1937 | if (sc == HUGE_REAL) { |
---|
| 1938 | sc = (real)1.0; |
---|
| 1939 | } else { |
---|
| 1940 | /* Adjustment applied is: (reading - z) * sc |
---|
| 1941 | * We want: reading * sc - z |
---|
| 1942 | * So divide z by sc so the applied adjustment does what we want. |
---|
| 1943 | */ |
---|
| 1944 | z /= sc; |
---|
| 1945 | } |
---|
| 1946 | } else { |
---|
| 1947 | sc = (real)1.0; |
---|
| 1948 | } |
---|
| 1949 | } |
---|
| 1950 | |
---|
[a420b49] | 1951 | if (sc == HUGE_REAL) sc = (real)1.0; |
---|
[647407d] | 1952 | /* check for declination scale */ |
---|
[95c3272] | 1953 | if (TSTBIT(qmask, Q_DECLINATION) && sc != 1.0) { |
---|
[9f55538] | 1954 | set_pos(&fp); |
---|
[736f7df] | 1955 | /* TRANSLATORS: DECLINATION is a built-in keyword, so best not to |
---|
| 1956 | * translate */ |
---|
[d0be687d] | 1957 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Scale factor must be 1.0 for DECLINATION*/40); |
---|
[9f55538] | 1958 | skipline(); |
---|
[647407d] | 1959 | return; |
---|
| 1960 | } |
---|
[4b14118] | 1961 | if (sc == 0.0) { |
---|
[9f55538] | 1962 | set_pos(&fp); |
---|
[736f7df] | 1963 | /* TRANSLATORS: If the scale factor for an instrument is zero, then any |
---|
| 1964 | * reading would be mapped to zero, which doesn't make sense. */ |
---|
[d0be687d] | 1965 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Scale factor must be non-zero*/391); |
---|
[9f55538] | 1966 | skipline(); |
---|
[4b14118] | 1967 | return; |
---|
| 1968 | } |
---|
[647407d] | 1969 | for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1) { |
---|
[a420b49] | 1970 | if (qmask & m) { |
---|
[647407d] | 1971 | pcs->z[quantity] = pcs->units[quantity] * z; |
---|
[a420b49] | 1972 | pcs->sc[quantity] = sc; |
---|
| 1973 | } |
---|
[647407d] | 1974 | } |
---|
[d1b1380] | 1975 | } |
---|
| 1976 | |
---|
[abe7192] | 1977 | static const sztok north_tab[] = { |
---|
| 1978 | { "GRID", GRID_NORTH }, |
---|
| 1979 | { "MAGNETIC", MAGNETIC_NORTH }, |
---|
| 1980 | { "TRUE", TRUE_NORTH }, |
---|
| 1981 | { NULL, -1 } |
---|
| 1982 | }; |
---|
| 1983 | |
---|
| 1984 | static void |
---|
| 1985 | cmd_cartesian(void) |
---|
| 1986 | { |
---|
| 1987 | get_token(); |
---|
| 1988 | int north = match_tok(north_tab, TABSIZE(north_tab)); |
---|
| 1989 | if (north < 0) { |
---|
| 1990 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, |
---|
| 1991 | /*Expecting “%s”, “%s”, or “%s”*/188, |
---|
| 1992 | "GRID", "MAGNETIC", "TRUE"); |
---|
| 1993 | return; |
---|
| 1994 | } |
---|
| 1995 | pcs->cartesian_north = north; |
---|
| 1996 | pcs->cartesian_rotation = 0.0; |
---|
| 1997 | |
---|
| 1998 | skipblanks(); |
---|
| 1999 | if (!isEol(ch) && !isComm(ch)) { |
---|
| 2000 | real rotation = read_numeric(false); |
---|
| 2001 | // Accept the same units as *declination does. |
---|
| 2002 | int units = get_units(BIT(Q_DECLINATION), false); |
---|
| 2003 | if (units == UNITS_NULL) { |
---|
| 2004 | return; |
---|
| 2005 | } |
---|
| 2006 | pcs->cartesian_rotation = rotation * factor_tab[units]; |
---|
| 2007 | } |
---|
| 2008 | } |
---|
| 2009 | |
---|
[58c7b459] | 2010 | static void |
---|
| 2011 | cmd_declination(void) |
---|
| 2012 | { |
---|
[63d4f07] | 2013 | real v = read_numeric(true); |
---|
[58c7b459] | 2014 | if (v == HUGE_REAL) { |
---|
[e1cbc0d] | 2015 | get_token_legacy_no_blanks(); |
---|
[0532954] | 2016 | if (!S_EQ(&uctoken, "AUTO")) { |
---|
[d72396e] | 2017 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_COL, /*Expected number or “AUTO”*/309); |
---|
[58c7b459] | 2018 | return; |
---|
| 2019 | } |
---|
[d655496] | 2020 | do_legacy_token_warning(); |
---|
[b39e24a] | 2021 | if (!pcs->proj_str) { |
---|
[abe7192] | 2022 | // TRANSLATORS: %s is replaced by the command that requires it, e.g. |
---|
| 2023 | // *DECLINATION AUTO |
---|
[d655496] | 2024 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_TOKEN, |
---|
| 2025 | /*Input coordinate system must be specified for “%s”*/301, |
---|
[abe7192] | 2026 | "*DECLINATION AUTO"); |
---|
[58c7b459] | 2027 | return; |
---|
| 2028 | } |
---|
[d655496] | 2029 | |
---|
| 2030 | /* *declination auto X Y Z */ |
---|
[1650ba1] | 2031 | filepos fp; |
---|
| 2032 | get_pos(&fp); |
---|
[d655496] | 2033 | real x = read_numeric(false); |
---|
| 2034 | real y = read_numeric(false); |
---|
| 2035 | real z = read_numeric(false); |
---|
[1650ba1] | 2036 | set_declination_location(x, y, z, pcs->proj_str, &fp); |
---|
[58c7b459] | 2037 | } else { |
---|
| 2038 | /* *declination D UNITS */ |
---|
[63d4f07] | 2039 | int units = get_units(BIT(Q_DECLINATION), false); |
---|
[58c7b459] | 2040 | if (units == UNITS_NULL) { |
---|
| 2041 | return; |
---|
| 2042 | } |
---|
[85d8e0c] | 2043 | pcs->z[Q_DECLINATION] = -v * factor_tab[units]; |
---|
[2c17123e] | 2044 | pcs->convergence = 0; |
---|
[58c7b459] | 2045 | } |
---|
| 2046 | } |
---|
| 2047 | |
---|
[7f1ab95] | 2048 | #ifndef NO_DEPRECATED |
---|
[a420b49] | 2049 | static void |
---|
[eb18f4d] | 2050 | cmd_default(void) |
---|
[a420b49] | 2051 | { |
---|
[82919e07] | 2052 | static const sztok defaulttab[] = { |
---|
[c0563da] | 2053 | { "CALIBRATE", CMD_CALIBRATE }, |
---|
| 2054 | { "DATA", CMD_DATA }, |
---|
| 2055 | { "UNITS", CMD_UNITS }, |
---|
[a4ae909] | 2056 | { NULL, CMD_NULL } |
---|
[c0563da] | 2057 | }; |
---|
[c86cc71] | 2058 | |
---|
[cb3d1e2] | 2059 | get_token(); |
---|
[c0563da] | 2060 | switch (match_tok(defaulttab, TABSIZE(defaulttab))) { |
---|
| 2061 | case CMD_CALIBRATE: |
---|
[5f1e194] | 2062 | default_calib(pcs); |
---|
[c0563da] | 2063 | break; |
---|
| 2064 | case CMD_DATA: |
---|
[5f1e194] | 2065 | default_style(pcs); |
---|
| 2066 | default_grade(pcs); |
---|
[abe7192] | 2067 | pcs->cartesian_north = TRUE_NORTH; |
---|
| 2068 | pcs->cartesian_rotation = 0.0; |
---|
[c0563da] | 2069 | break; |
---|
| 2070 | case CMD_UNITS: |
---|
[5f1e194] | 2071 | default_units(pcs); |
---|
[c0563da] | 2072 | break; |
---|
| 2073 | default: |
---|
[caae6cd] | 2074 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown setting “%s”*/41, |
---|
[0532954] | 2075 | s_str(&token)); |
---|
[5f1e194] | 2076 | } |
---|
[d1b1380] | 2077 | } |
---|
[7f1ab95] | 2078 | #endif |
---|
[d1b1380] | 2079 | |
---|
[a420b49] | 2080 | static void |
---|
[eb18f4d] | 2081 | cmd_include(void) |
---|
[a420b49] | 2082 | { |
---|
[0532954] | 2083 | char *pth = NULL; |
---|
| 2084 | string fnm = S_INIT; |
---|
[a882316] | 2085 | #ifndef NO_DEPRECATED |
---|
[5f1e194] | 2086 | prefix *root_store; |
---|
[a882316] | 2087 | #endif |
---|
[5f1e194] | 2088 | int ch_store; |
---|
| 2089 | |
---|
[f97076a] | 2090 | pth = path_from_fnm(file.filename); |
---|
| 2091 | |
---|
[0532954] | 2092 | read_string(&fnm); |
---|
[d1b1380] | 2093 | |
---|
[a882316] | 2094 | #ifndef NO_DEPRECATED |
---|
| 2095 | /* Since *begin / *end nesting cannot cross file boundaries we only |
---|
| 2096 | * need to preserve the prefix if the deprecated *prefix command |
---|
| 2097 | * can be used */ |
---|
[5f1e194] | 2098 | root_store = root; |
---|
| 2099 | root = pcs->Prefix; /* Root for include file is current prefix */ |
---|
[a882316] | 2100 | #endif |
---|
[5f1e194] | 2101 | ch_store = ch; |
---|
[cb3d1e2] | 2102 | |
---|
[0532954] | 2103 | data_file(pth, s_str(&fnm)); |
---|
[a420b49] | 2104 | |
---|
[a882316] | 2105 | #ifndef NO_DEPRECATED |
---|
[5f1e194] | 2106 | root = root_store; /* and restore root */ |
---|
[647407d] | 2107 | #endif |
---|
[5f1e194] | 2108 | ch = ch_store; |
---|
[d1b1380] | 2109 | |
---|
[a420b49] | 2110 | s_free(&fnm); |
---|
[ae917b96] | 2111 | free(pth); |
---|
[d1b1380] | 2112 | } |
---|
| 2113 | |
---|
[a420b49] | 2114 | static void |
---|
[eb18f4d] | 2115 | cmd_sd(void) |
---|
[a420b49] | 2116 | { |
---|
[5f1e194] | 2117 | real sd, variance; |
---|
| 2118 | int units; |
---|
[67508f0] | 2119 | unsigned long qmask, m; |
---|
[5f1e194] | 2120 | int quantity; |
---|
[b14f44f] | 2121 | qmask = get_qlist(BIT(Q_DECLINATION)); |
---|
[46cb98f] | 2122 | if (!qmask) return; /* no quantities found - error already reported */ |
---|
| 2123 | |
---|
[a420b49] | 2124 | if (qmask == BIT(Q_DEFAULT)) { |
---|
| 2125 | default_grade(pcs); |
---|
[5f1e194] | 2126 | return; |
---|
| 2127 | } |
---|
[63d4f07] | 2128 | sd = read_numeric(false); |
---|
[d6d3576] | 2129 | if (sd <= (real)0.0) { |
---|
[cab0f26] | 2130 | compile_diagnostic(DIAG_ERR|DIAG_SKIP|DIAG_COL, /*Standard deviation must be positive*/48); |
---|
[d6d3576] | 2131 | return; |
---|
[5f1e194] | 2132 | } |
---|
[63d4f07] | 2133 | units = get_units(qmask, false); |
---|
[647407d] | 2134 | if (units == UNITS_NULL) return; |
---|
[5f1e194] | 2135 | |
---|
| 2136 | sd *= factor_tab[units]; |
---|
| 2137 | variance = sqrd(sd); |
---|
| 2138 | |
---|
| 2139 | for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1) |
---|
| 2140 | if (qmask & m) pcs->Var[quantity] = variance; |
---|
[d1b1380] | 2141 | } |
---|
[5f1e194] | 2142 | |
---|
[0f8216c] | 2143 | enum { |
---|
| 2144 | ROLE_BACKTAPE, |
---|
| 2145 | ROLE_BACKCOMPASS, |
---|
| 2146 | ROLE_BACKCLINO, |
---|
| 2147 | ROLE_TAPE, |
---|
| 2148 | ROLE_COMPASS, |
---|
| 2149 | ROLE_CLINO, |
---|
| 2150 | ROLE_COUNTER, |
---|
| 2151 | ROLE_DEPTH, |
---|
| 2152 | ROLE_STATION, |
---|
| 2153 | ROLE_POSITION, |
---|
| 2154 | ROLE_NOTES, |
---|
| 2155 | ROLE_PICTURES, |
---|
| 2156 | ROLE_INSTRUMENTS, |
---|
| 2157 | ROLE_ASSISTANT, |
---|
| 2158 | ROLE_ALTITUDE, |
---|
| 2159 | ROLE_DIMENSIONS, |
---|
| 2160 | ROLE_LEFT, |
---|
| 2161 | ROLE_RIGHT, |
---|
| 2162 | ROLE_UP, |
---|
| 2163 | ROLE_DOWN, |
---|
| 2164 | ROLE_EXPLORER |
---|
| 2165 | }; |
---|
| 2166 | |
---|
| 2167 | static const sztok role_tab[] = { |
---|
| 2168 | {"ALTITUDE", ROLE_ALTITUDE}, |
---|
| 2169 | {"ASSISTANT", ROLE_ASSISTANT}, |
---|
| 2170 | {"BACKBEARING", ROLE_BACKCOMPASS}, |
---|
| 2171 | {"BACKCLINO", ROLE_BACKCLINO}, |
---|
| 2172 | {"BACKCOMPASS", ROLE_BACKCOMPASS}, |
---|
| 2173 | {"BACKGRADIENT", ROLE_BACKCLINO}, |
---|
| 2174 | {"BACKLENGTH", ROLE_BACKTAPE}, |
---|
| 2175 | {"BACKTAPE", ROLE_BACKTAPE}, |
---|
| 2176 | {"BEARING", ROLE_COMPASS}, |
---|
| 2177 | {"CEILING", ROLE_UP}, |
---|
| 2178 | {"CLINO", ROLE_CLINO}, |
---|
| 2179 | {"COMPASS", ROLE_COMPASS}, |
---|
| 2180 | {"COUNT", ROLE_COUNTER}, |
---|
| 2181 | {"COUNTER", ROLE_COUNTER}, |
---|
| 2182 | {"DEPTH", ROLE_DEPTH}, |
---|
| 2183 | {"DIMENSIONS", ROLE_DIMENSIONS}, |
---|
| 2184 | {"DOG", ROLE_ASSISTANT}, |
---|
| 2185 | {"DOWN", ROLE_DOWN}, |
---|
| 2186 | {"DZ", ROLE_ALTITUDE}, |
---|
| 2187 | {"EXPLORER", ROLE_EXPLORER}, |
---|
| 2188 | {"FLOOR", ROLE_DOWN}, |
---|
| 2189 | {"GRADIENT", ROLE_CLINO}, |
---|
| 2190 | {"INSTRUMENTS", ROLE_INSTRUMENTS}, |
---|
| 2191 | {"INSTS", ROLE_INSTRUMENTS}, |
---|
| 2192 | {"LEFT", ROLE_LEFT}, |
---|
| 2193 | {"LENGTH", ROLE_TAPE}, |
---|
| 2194 | {"NOTEBOOK", ROLE_NOTES}, |
---|
| 2195 | {"NOTES", ROLE_NOTES}, |
---|
| 2196 | {"PICS", ROLE_PICTURES}, |
---|
| 2197 | {"PICTURES", ROLE_PICTURES}, |
---|
| 2198 | {"POSITION", ROLE_POSITION}, |
---|
| 2199 | {"RIGHT", ROLE_RIGHT}, |
---|
| 2200 | {"STATION", ROLE_STATION}, |
---|
| 2201 | {"TAPE", ROLE_TAPE}, |
---|
| 2202 | {"UP", ROLE_UP}, |
---|
| 2203 | {NULL, -1} |
---|
| 2204 | }; |
---|
| 2205 | |
---|
| 2206 | static void |
---|
| 2207 | cmd_team(void) |
---|
| 2208 | { |
---|
| 2209 | string name = S_INIT; |
---|
[62be3ee] | 2210 | if (!read_string_warning(&name)) { |
---|
| 2211 | skipline(); |
---|
| 2212 | return; |
---|
| 2213 | } |
---|
[0f8216c] | 2214 | s_free(&name); |
---|
| 2215 | |
---|
| 2216 | while (true) { |
---|
| 2217 | skipblanks(); |
---|
| 2218 | if (isComm(ch) || isEol(ch)) return; |
---|
| 2219 | get_token(); |
---|
| 2220 | int role = match_tok(role_tab, TABSIZE(role_tab)); |
---|
| 2221 | if (role < 0) { |
---|
| 2222 | // Skip after a bad role to avoid triggering multiple warnings for |
---|
| 2223 | // one *team command in existing data from before this check was |
---|
| 2224 | // implemented. |
---|
| 2225 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN|DIAG_SKIP, /*Unknown team role “%s”*/532, |
---|
| 2226 | s_str(&token)); |
---|
[6b4d2e9] | 2227 | return; |
---|
[0f8216c] | 2228 | } |
---|
| 2229 | } |
---|
| 2230 | } |
---|
| 2231 | |
---|
[a420b49] | 2232 | static void |
---|
[eb18f4d] | 2233 | cmd_title(void) |
---|
[a420b49] | 2234 | { |
---|
[1925d66] | 2235 | if (!fExplicitTitle && pcs->Prefix == root) { |
---|
| 2236 | /* If we don't have an explicit title yet, and we're currently in the |
---|
| 2237 | * root prefix, use this title explicitly. */ |
---|
[63d4f07] | 2238 | fExplicitTitle = true; |
---|
[0532954] | 2239 | read_string(&survey_title); |
---|
[a420b49] | 2240 | } else { |
---|
| 2241 | /* parse and throw away this title (but still check rest of line) */ |
---|
[0532954] | 2242 | string s = S_INIT; |
---|
| 2243 | read_string(&s); |
---|
[a420b49] | 2244 | s_free(&s); |
---|
| 2245 | } |
---|
| 2246 | } |
---|
| 2247 | |
---|
[82919e07] | 2248 | static const sztok case_tab[] = { |
---|
[a420b49] | 2249 | {"PRESERVE", OFF}, |
---|
[c57e9da] | 2250 | {"TOLOWER", LOWER}, |
---|
| 2251 | {"TOUPPER", UPPER}, |
---|
[a420b49] | 2252 | {NULL, -1} |
---|
| 2253 | }; |
---|
[cb3d1e2] | 2254 | |
---|
[a420b49] | 2255 | static void |
---|
[eb18f4d] | 2256 | cmd_case(void) |
---|
[a420b49] | 2257 | { |
---|
| 2258 | int setting; |
---|
| 2259 | get_token(); |
---|
| 2260 | setting = match_tok(case_tab, TABSIZE(case_tab)); |
---|
| 2261 | if (setting != -1) { |
---|
| 2262 | pcs->Case = setting; |
---|
| 2263 | } else { |
---|
[caae6cd] | 2264 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Found “%s”, expecting “PRESERVE”, “TOUPPER”, or “TOLOWER”*/10, s_str(&token)); |
---|
[a420b49] | 2265 | } |
---|
| 2266 | } |
---|
| 2267 | |
---|
[f15c53d9] | 2268 | static void |
---|
| 2269 | cmd_copyright(void) |
---|
| 2270 | { |
---|
| 2271 | filepos fp; |
---|
| 2272 | get_pos(&fp); |
---|
| 2273 | unsigned y1 = read_uint_raw(DIAG_WARN|DIAG_UINT, /*Invalid year*/534, NULL); |
---|
| 2274 | if (y1 < 1000) { |
---|
| 2275 | set_pos(&fp); |
---|
| 2276 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid year*/534, y1); |
---|
[cac5622] | 2277 | } else if (y1 > current_year) { |
---|
| 2278 | set_pos(&fp); |
---|
| 2279 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Date is in the future!*/80); |
---|
[f15c53d9] | 2280 | } |
---|
| 2281 | if (ch == '-') { |
---|
| 2282 | nextch(); |
---|
| 2283 | get_pos(&fp); |
---|
| 2284 | unsigned y2 = read_uint_raw(DIAG_WARN|DIAG_UINT, /*Invalid year*/534, NULL); |
---|
| 2285 | if (y2 < 1000) { |
---|
| 2286 | set_pos(&fp); |
---|
| 2287 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid year*/534, y2); |
---|
| 2288 | } else if (y2 < y1) { |
---|
| 2289 | set_pos(&fp); |
---|
| 2290 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*End of date range is before the start*/81); |
---|
[cac5622] | 2291 | } else if (y2 > current_year) { |
---|
| 2292 | set_pos(&fp); |
---|
| 2293 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Date is in the future!*/80); |
---|
[f15c53d9] | 2294 | } |
---|
| 2295 | } |
---|
| 2296 | |
---|
| 2297 | string text = S_INIT; |
---|
| 2298 | if (!read_string_warning(&text)) { |
---|
| 2299 | skipline(); |
---|
| 2300 | return; |
---|
| 2301 | } |
---|
| 2302 | s_free(&text); |
---|
| 2303 | |
---|
| 2304 | skipblanks(); |
---|
| 2305 | if (!isComm(ch) && !isEol(ch)) |
---|
| 2306 | compile_diagnostic(DIAG_WARN|DIAG_TAIL, /*End of line not blank*/15); |
---|
| 2307 | } |
---|
| 2308 | |
---|
[abd0310] | 2309 | typedef enum { |
---|
| 2310 | CS_NONE = -1, |
---|
| 2311 | CS_CUSTOM, |
---|
| 2312 | CS_EPSG, |
---|
| 2313 | CS_ESRI, |
---|
[b8fb5ac] | 2314 | CS_EUR79Z30, |
---|
[abd0310] | 2315 | CS_IJTSK, |
---|
[b8fb5ac] | 2316 | CS_IJTSK03, |
---|
[abd0310] | 2317 | CS_JTSK, |
---|
[b8fb5ac] | 2318 | CS_JTSK03, |
---|
[abd0310] | 2319 | CS_LAT, |
---|
| 2320 | CS_LOCAL, |
---|
| 2321 | CS_LONG, |
---|
| 2322 | CS_OSGB, |
---|
| 2323 | CS_S_MERC, |
---|
| 2324 | CS_UTM |
---|
| 2325 | } cs_class; |
---|
| 2326 | |
---|
[82919e07] | 2327 | static const sztok cs_tab[] = { |
---|
[b8fb5ac] | 2328 | {"CUSTOM", CS_CUSTOM}, |
---|
| 2329 | {"EPSG", CS_EPSG}, /* EPSG:<number> */ |
---|
| 2330 | {"ESRI", CS_ESRI}, /* ESRI:<number> */ |
---|
| 2331 | {"EUR79Z30", CS_EUR79Z30}, |
---|
| 2332 | {"IJTSK", CS_IJTSK}, |
---|
| 2333 | {"IJTSK03", CS_IJTSK03}, |
---|
| 2334 | {"JTSK", CS_JTSK}, |
---|
| 2335 | {"JTSK03", CS_JTSK03}, |
---|
| 2336 | {"LAT", CS_LAT}, /* LAT-LONG */ |
---|
| 2337 | {"LOCAL", CS_LOCAL}, |
---|
| 2338 | {"LONG", CS_LONG}, /* LONG-LAT */ |
---|
| 2339 | {"OSGB", CS_OSGB}, /* OSGB:<H, N, O, S or T><A-Z except I> */ |
---|
| 2340 | {"S", CS_S_MERC}, /* S-MERC */ |
---|
| 2341 | // UTM<zone><N or S or nothing> is handled separately to avoid needing 180 |
---|
| 2342 | // entries in this lookup table. |
---|
| 2343 | {NULL, CS_NONE} |
---|
[abd0310] | 2344 | }; |
---|
| 2345 | |
---|
| 2346 | static void |
---|
| 2347 | cmd_cs(void) |
---|
| 2348 | { |
---|
[0532954] | 2349 | char *proj_str = NULL; |
---|
[abd0310] | 2350 | cs_class cs; |
---|
| 2351 | int cs_sub = INT_MIN; |
---|
| 2352 | filepos fp; |
---|
[63d4f07] | 2353 | bool output = false; |
---|
[c092d72] | 2354 | enum { YES, NO, MAYBE } ok_for_output = YES; |
---|
[63d4f07] | 2355 | static bool had_cs = false; |
---|
[56db37f] | 2356 | |
---|
| 2357 | if (!had_cs) { |
---|
[63d4f07] | 2358 | had_cs = true; |
---|
[56db37f] | 2359 | if (first_fix_name) { |
---|
[cab0f26] | 2360 | compile_diagnostic_at(DIAG_ERR, |
---|
| 2361 | first_fix_filename, first_fix_line, |
---|
| 2362 | /*Station “%s” fixed before CS command first used*/442, |
---|
| 2363 | sprint_prefix(first_fix_name)); |
---|
[56db37f] | 2364 | } |
---|
| 2365 | } |
---|
[abd0310] | 2366 | |
---|
[b8fb5ac] | 2367 | skipblanks(); |
---|
[abd0310] | 2368 | get_pos(&fp); |
---|
[b8fb5ac] | 2369 | get_token_no_blanks(); |
---|
[0532954] | 2370 | if (S_EQ(&uctoken, "OUT")) { |
---|
[63d4f07] | 2371 | output = true; |
---|
[b8fb5ac] | 2372 | skipblanks(); |
---|
[9f55538] | 2373 | get_pos(&fp); |
---|
[b8fb5ac] | 2374 | get_token_no_blanks(); |
---|
| 2375 | } |
---|
| 2376 | |
---|
| 2377 | if (s_len(&uctoken) > 3 && |
---|
| 2378 | memcmp(s_str(&uctoken), "UTM", 3) == 0 && |
---|
| 2379 | isdigit((unsigned char)s_str(&uctoken)[3])) { |
---|
| 2380 | // The token starts "UTM" followed by a digit so handle that separately |
---|
| 2381 | // to avoid needing 180 entries for UTM zones in the cs_tab lookup |
---|
| 2382 | // table. |
---|
| 2383 | cs = CS_UTM; |
---|
| 2384 | // Reposition on the digit after "UTM". |
---|
| 2385 | set_pos(&fp); |
---|
| 2386 | nextch(); |
---|
| 2387 | nextch(); |
---|
| 2388 | nextch(); |
---|
| 2389 | unsigned n = read_uint(); |
---|
| 2390 | if (n >= 1 && n <= 60) { |
---|
| 2391 | int uch = toupper(ch); |
---|
| 2392 | cs_sub = (int)n; |
---|
| 2393 | if (uch == 'S') { |
---|
[abd0310] | 2394 | nextch(); |
---|
[b8fb5ac] | 2395 | cs_sub = -cs_sub; |
---|
| 2396 | } else if (uch == 'N') { |
---|
| 2397 | nextch(); |
---|
| 2398 | } |
---|
| 2399 | } |
---|
| 2400 | } else { |
---|
| 2401 | cs = match_tok(cs_tab, TABSIZE(cs_tab)); |
---|
| 2402 | switch (cs) { |
---|
| 2403 | case CS_NONE: |
---|
| 2404 | break; |
---|
| 2405 | case CS_CUSTOM: |
---|
| 2406 | ok_for_output = MAYBE; |
---|
| 2407 | get_pos(&fp); |
---|
| 2408 | string str = S_INIT; |
---|
| 2409 | read_string(&str); |
---|
| 2410 | proj_str = s_steal(&str); |
---|
| 2411 | cs_sub = 0; |
---|
| 2412 | break; |
---|
| 2413 | case CS_EPSG: case CS_ESRI: |
---|
| 2414 | ok_for_output = MAYBE; |
---|
| 2415 | if (ch == ':' && isdigit(nextch())) { |
---|
| 2416 | unsigned n = read_uint(); |
---|
| 2417 | if (n < 1000000) { |
---|
| 2418 | cs_sub = (int)n; |
---|
[abd0310] | 2419 | } |
---|
[b8fb5ac] | 2420 | } |
---|
| 2421 | break; |
---|
| 2422 | case CS_EUR79Z30: |
---|
| 2423 | cs_sub = 0; |
---|
| 2424 | break; |
---|
| 2425 | case CS_JTSK: |
---|
| 2426 | case CS_JTSK03: |
---|
| 2427 | ok_for_output = NO; |
---|
| 2428 | cs_sub = 0; |
---|
| 2429 | break; |
---|
| 2430 | case CS_IJTSK: |
---|
| 2431 | case CS_IJTSK03: |
---|
| 2432 | cs_sub = 0; |
---|
| 2433 | break; |
---|
| 2434 | case CS_LAT: case CS_LONG: |
---|
| 2435 | ok_for_output = NO; |
---|
| 2436 | if (ch == '-') { |
---|
| 2437 | nextch(); |
---|
| 2438 | get_token_no_blanks(); |
---|
| 2439 | cs_class cs2 = match_tok(cs_tab, TABSIZE(cs_tab)); |
---|
| 2440 | if ((cs ^ cs2) == (CS_LAT ^ CS_LONG)) { |
---|
| 2441 | cs_sub = 0; |
---|
[abd0310] | 2442 | } |
---|
[b8fb5ac] | 2443 | } |
---|
| 2444 | break; |
---|
| 2445 | case CS_LOCAL: |
---|
| 2446 | cs_sub = 0; |
---|
| 2447 | break; |
---|
| 2448 | case CS_OSGB: |
---|
| 2449 | if (ch == ':') { |
---|
| 2450 | int uch1 = toupper(nextch()); |
---|
| 2451 | if (strchr("HNOST", uch1)) { |
---|
| 2452 | int uch2 = toupper(nextch()); |
---|
| 2453 | if (uch2 >= 'A' && uch2 <= 'Z' && uch2 != 'I') { |
---|
| 2454 | int x, y; |
---|
| 2455 | nextch(); |
---|
| 2456 | if (uch1 > 'I') --uch1; |
---|
| 2457 | uch1 -= 'A'; |
---|
| 2458 | if (uch2 > 'I') --uch2; |
---|
| 2459 | uch2 -= 'A'; |
---|
| 2460 | x = uch1 % 5; |
---|
| 2461 | y = uch1 / 5; |
---|
| 2462 | x = (x * 5) + uch2 % 5; |
---|
| 2463 | y = (y * 5) + uch2 / 5; |
---|
| 2464 | cs_sub = y * 25 + x; |
---|
| 2465 | } |
---|
| 2466 | } |
---|
| 2467 | } |
---|
| 2468 | break; |
---|
| 2469 | case CS_S_MERC: |
---|
| 2470 | if (ch == '-') { |
---|
| 2471 | nextch(); |
---|
| 2472 | get_token_no_blanks(); |
---|
| 2473 | if (S_EQ(&uctoken, "MERC")) { |
---|
| 2474 | cs_sub = 0; |
---|
| 2475 | } |
---|
| 2476 | } |
---|
| 2477 | break; |
---|
| 2478 | case CS_UTM: |
---|
| 2479 | // Handled outside of this switch, but avoid compiler warning about |
---|
| 2480 | // unhandled enumeration value. |
---|
| 2481 | break; |
---|
| 2482 | } |
---|
[abd0310] | 2483 | } |
---|
| 2484 | if (cs_sub == INT_MIN || isalnum(ch)) { |
---|
| 2485 | set_pos(&fp); |
---|
[b8fb5ac] | 2486 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*Unknown coordinate system*/434); |
---|
[9f55538] | 2487 | skipline(); |
---|
[c092d72] | 2488 | return; |
---|
[abd0310] | 2489 | } |
---|
| 2490 | /* Actually handle the cs */ |
---|
[c092d72] | 2491 | switch (cs) { |
---|
[5d36f97] | 2492 | case CS_NONE: |
---|
| 2493 | break; |
---|
| 2494 | case CS_CUSTOM: |
---|
| 2495 | /* proj_str already set */ |
---|
| 2496 | break; |
---|
[ddd24f28] | 2497 | case CS_EPSG: |
---|
| 2498 | proj_str = osmalloc(32); |
---|
[657fcee] | 2499 | snprintf(proj_str, 32, "EPSG:%d", cs_sub); |
---|
[ddd24f28] | 2500 | break; |
---|
| 2501 | case CS_ESRI: |
---|
| 2502 | proj_str = osmalloc(32); |
---|
[657fcee] | 2503 | snprintf(proj_str, 32, "ESRI:%d", cs_sub); |
---|
[ddd24f28] | 2504 | break; |
---|
[b8fb5ac] | 2505 | case CS_EUR79Z30: |
---|
[ddd24f28] | 2506 | proj_str = osstrdup("+proj=utm +zone=30 +ellps=intl +towgs84=-86,-98,-119,0,0,0,0 +no_defs"); |
---|
| 2507 | break; |
---|
[5598e2c] | 2508 | case CS_IJTSK: |
---|
[b8fb5ac] | 2509 | proj_str = osstrdup("+proj=krovak +ellps=bessel +towgs84=570.8285,85.6769,462.842,4.9984,1.5867,5.2611,3.5623 +no_defs"); |
---|
| 2510 | break; |
---|
| 2511 | case CS_IJTSK03: |
---|
| 2512 | proj_str = osstrdup("+proj=krovak +ellps=bessel +towgs84=485.021,169.465,483.839,7.786342,4.397554,4.102655,0 +no_defs"); |
---|
[5598e2c] | 2513 | break; |
---|
[10af28e] | 2514 | case CS_JTSK: |
---|
[b8fb5ac] | 2515 | proj_str = osstrdup("+proj=krovak +czech +ellps=bessel +towgs84=570.8285,85.6769,462.842,4.9984,1.5867,5.2611,3.5623 +no_defs"); |
---|
| 2516 | break; |
---|
| 2517 | case CS_JTSK03: |
---|
| 2518 | proj_str = osstrdup("+proj=krovak +czech +ellps=bessel +towgs84=485.021,169.465,483.839,7.786342,4.397554,4.102655,0 +no_defs"); |
---|
[10af28e] | 2519 | break; |
---|
[16734b2] | 2520 | case CS_LAT: |
---|
| 2521 | /* FIXME: Requires PROJ >= 4.8.0 for +axis, and the SDs will be |
---|
[10af28e] | 2522 | * misapplied, so we may want to swap ourselves. Also, while |
---|
| 2523 | * therion supports lat-long, I'm not totally convinced that it is |
---|
| 2524 | * sensible to do so - people often say "lat-long", but probably |
---|
| 2525 | * don't think that that's actually "Northing, Easting". This |
---|
| 2526 | * seems like it'll result in people accidentally getting X and Y |
---|
| 2527 | * swapped in their fixed points... |
---|
| 2528 | */ |
---|
[5d36f97] | 2529 | #if 0 |
---|
[cb0a137] | 2530 | proj_str = osstrdup("+proj=longlat +ellps=WGS84 +datum=WGS84 +axis=neu +no_defs"); |
---|
[5d36f97] | 2531 | #endif |
---|
[16734b2] | 2532 | break; |
---|
[10af28e] | 2533 | case CS_LOCAL: |
---|
| 2534 | /* FIXME: Is it useful to be able to explicitly specify this? */ |
---|
| 2535 | break; |
---|
[16734b2] | 2536 | case CS_LONG: |
---|
[b39e24a] | 2537 | proj_str = osstrdup("EPSG:4326"); |
---|
[16734b2] | 2538 | break; |
---|
[a4cd4eea] | 2539 | case CS_OSGB: { |
---|
| 2540 | int x = 14 - (cs_sub % 25); |
---|
| 2541 | int y = (cs_sub / 25) - 20; |
---|
| 2542 | proj_str = osmalloc(160); |
---|
[657fcee] | 2543 | snprintf(proj_str, 160, |
---|
| 2544 | "+proj=tmerc +lat_0=49 +lon_0=-2 +k=0.9996012717 " |
---|
| 2545 | "+x_0=%d +y_0=%d +ellps=airy +datum=OSGB36 +units=m +no_defs", |
---|
| 2546 | x * 100000, y * 100000); |
---|
[a4cd4eea] | 2547 | break; |
---|
| 2548 | } |
---|
[2076d59] | 2549 | case CS_S_MERC: |
---|
[b39e24a] | 2550 | proj_str = osstrdup("EPSG:3857"); |
---|
[2076d59] | 2551 | break; |
---|
[c092d72] | 2552 | case CS_UTM: |
---|
[b39e24a] | 2553 | proj_str = osmalloc(32); |
---|
[c092d72] | 2554 | if (cs_sub > 0) { |
---|
[657fcee] | 2555 | snprintf(proj_str, 32, "EPSG:%d", 32600 + cs_sub); |
---|
[c092d72] | 2556 | } else { |
---|
[657fcee] | 2557 | snprintf(proj_str, 32, "EPSG:%d", 32700 - cs_sub); |
---|
[c092d72] | 2558 | } |
---|
| 2559 | break; |
---|
| 2560 | } |
---|
| 2561 | |
---|
[10af28e] | 2562 | if (!proj_str) { |
---|
| 2563 | /* printf("CS %d:%d\n", (int)cs, cs_sub); */ |
---|
| 2564 | set_pos(&fp); |
---|
[88ba3b1] | 2565 | compile_diagnostic(DIAG_ERR|DIAG_STRING, /*Unknown coordinate system*/434); |
---|
[9f55538] | 2566 | skipline(); |
---|
[10af28e] | 2567 | return; |
---|
| 2568 | } |
---|
| 2569 | |
---|
[c092d72] | 2570 | if (output) { |
---|
| 2571 | if (ok_for_output == NO) { |
---|
| 2572 | set_pos(&fp); |
---|
[88ba3b1] | 2573 | compile_diagnostic(DIAG_ERR|DIAG_STRING, /*Coordinate system unsuitable for output*/435); |
---|
[9f55538] | 2574 | skipline(); |
---|
[c092d72] | 2575 | return; |
---|
| 2576 | } |
---|
| 2577 | |
---|
[da9163b] | 2578 | if (proj_str_out && strcmp(proj_str, proj_str_out) == 0) { |
---|
| 2579 | /* Same as the output cs that's already set, so nothing to do. */ |
---|
[ae917b96] | 2580 | free(proj_str); |
---|
[da9163b] | 2581 | return; |
---|
| 2582 | } |
---|
| 2583 | |
---|
| 2584 | if (ok_for_output == MAYBE) { |
---|
| 2585 | /* We only actually create the transformation from input to output when |
---|
| 2586 | * we need it, but for a custom proj string or EPSG/ESRI code we need |
---|
| 2587 | * to check that the specified coordinate system is valid and also if |
---|
| 2588 | * it's suitable for output so we need to test creating it here. |
---|
| 2589 | */ |
---|
[df1d579] | 2590 | proj_errno_reset(NULL); |
---|
[da9163b] | 2591 | PJ* pj = proj_create(PJ_DEFAULT_CTX, proj_str); |
---|
| 2592 | if (!pj) { |
---|
| 2593 | set_pos(&fp); |
---|
[88ba3b1] | 2594 | compile_diagnostic(DIAG_ERR|DIAG_STRING, /*Invalid coordinate system: %s*/443, |
---|
[d9d8f21] | 2595 | proj_context_errno_string(PJ_DEFAULT_CTX, |
---|
| 2596 | proj_context_errno(PJ_DEFAULT_CTX))); |
---|
[da9163b] | 2597 | skipline(); |
---|
[ae917b96] | 2598 | free(proj_str); |
---|
[da9163b] | 2599 | return; |
---|
| 2600 | } |
---|
| 2601 | int type = proj_get_type(pj); |
---|
| 2602 | if (type == PJ_TYPE_GEOGRAPHIC_2D_CRS || |
---|
| 2603 | type == PJ_TYPE_GEOGRAPHIC_3D_CRS) { |
---|
| 2604 | set_pos(&fp); |
---|
[88ba3b1] | 2605 | compile_diagnostic(DIAG_ERR|DIAG_STRING, /*Coordinate system unsuitable for output*/435); |
---|
[da9163b] | 2606 | skipline(); |
---|
[ae917b96] | 2607 | free(proj_str); |
---|
[da9163b] | 2608 | return; |
---|
| 2609 | } |
---|
| 2610 | } |
---|
| 2611 | |
---|
| 2612 | if (proj_str_out) { |
---|
| 2613 | /* If the output cs is already set, subsequent attempts to set it |
---|
| 2614 | * are silently ignored (so you can combine two datasets and set |
---|
| 2615 | * the output cs to use before you include either). |
---|
| 2616 | */ |
---|
[ae917b96] | 2617 | free(proj_str); |
---|
[da9163b] | 2618 | } else { |
---|
| 2619 | proj_str_out = proj_str; |
---|
[c092d72] | 2620 | } |
---|
| 2621 | } else { |
---|
| 2622 | if (proj_str_out && strcmp(proj_str, proj_str_out) == 0) { |
---|
[da9163b] | 2623 | /* Same as the current output projection, so valid for input. */ |
---|
| 2624 | } else if (pcs->proj_str && strcmp(proj_str, pcs->proj_str) == 0) { |
---|
| 2625 | /* Same as the current input projection, so nothing to do! */ |
---|
| 2626 | return; |
---|
| 2627 | } else if (ok_for_output == MAYBE) { |
---|
| 2628 | /* (ok_for_output == MAYBE) also happens to indicate whether we need |
---|
| 2629 | * to check that the coordinate system is valid for input. |
---|
| 2630 | */ |
---|
[df1d579] | 2631 | proj_errno_reset(NULL); |
---|
[b39e24a] | 2632 | PJ* pj = proj_create(PJ_DEFAULT_CTX, proj_str); |
---|
[c092d72] | 2633 | if (!pj) { |
---|
| 2634 | set_pos(&fp); |
---|
[88ba3b1] | 2635 | compile_diagnostic(DIAG_ERR|DIAG_STRING, /*Invalid coordinate system: %s*/443, |
---|
[d9d8f21] | 2636 | proj_context_errno_string(PJ_DEFAULT_CTX, |
---|
| 2637 | proj_context_errno(PJ_DEFAULT_CTX))); |
---|
[9f55538] | 2638 | skipline(); |
---|
[c092d72] | 2639 | return; |
---|
| 2640 | } |
---|
[b39e24a] | 2641 | proj_destroy(pj); |
---|
[c092d72] | 2642 | } |
---|
| 2643 | |
---|
[da9163b] | 2644 | /* Free current input proj_str if not used by parent. */ |
---|
[c092d72] | 2645 | settings * p = pcs; |
---|
[da9163b] | 2646 | if (!p->next || p->proj_str != p->next->proj_str) |
---|
[ae917b96] | 2647 | free(p->proj_str); |
---|
[b39e24a] | 2648 | p->proj_str = proj_str; |
---|
[abe7192] | 2649 | p->input_convergence = HUGE_REAL; |
---|
[da9163b] | 2650 | invalidate_pj_cached(); |
---|
[c092d72] | 2651 | } |
---|
[abd0310] | 2652 | } |
---|
| 2653 | |
---|
[82919e07] | 2654 | static const sztok infer_tab[] = { |
---|
[27b8b59] | 2655 | { "EQUATES", INFER_EQUATES }, |
---|
| 2656 | { "EXPORTS", INFER_EXPORTS }, |
---|
| 2657 | { "PLUMBS", INFER_PLUMBS }, |
---|
| 2658 | #if 0 /* FIXME */ |
---|
| 2659 | { "SUBSURVEYS", INFER_SUBSURVEYS }, |
---|
| 2660 | #endif |
---|
| 2661 | { NULL, INFER_NULL } |
---|
[a420b49] | 2662 | }; |
---|
[cb3d1e2] | 2663 | |
---|
[82919e07] | 2664 | static const sztok onoff_tab[] = { |
---|
[27b8b59] | 2665 | { "OFF", 0 }, |
---|
| 2666 | { "ON", 1 }, |
---|
| 2667 | { NULL, -1 } |
---|
[a420b49] | 2668 | }; |
---|
[cb3d1e2] | 2669 | |
---|
[a420b49] | 2670 | static void |
---|
[eb18f4d] | 2671 | cmd_infer(void) |
---|
[a420b49] | 2672 | { |
---|
[27b8b59] | 2673 | infer_what setting; |
---|
[a420b49] | 2674 | int on; |
---|
| 2675 | get_token(); |
---|
| 2676 | setting = match_tok(infer_tab, TABSIZE(infer_tab)); |
---|
[27b8b59] | 2677 | if (setting == INFER_NULL) { |
---|
[caae6cd] | 2678 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Found “%s”, expecting “EQUATES”, “EXPORTS”, or “PLUMBS”*/31, s_str(&token)); |
---|
[647407d] | 2679 | return; |
---|
[a420b49] | 2680 | } |
---|
| 2681 | get_token(); |
---|
| 2682 | on = match_tok(onoff_tab, TABSIZE(onoff_tab)); |
---|
| 2683 | if (on == -1) { |
---|
[caae6cd] | 2684 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Found “%s”, expecting “ON” or “OFF”*/32, s_str(&token)); |
---|
[647407d] | 2685 | return; |
---|
[a420b49] | 2686 | } |
---|
[cb3d1e2] | 2687 | |
---|
[27b8b59] | 2688 | if (on) { |
---|
| 2689 | pcs->infer |= BIT(setting); |
---|
[63d4f07] | 2690 | if (setting == INFER_EXPORTS) fExportUsed = true; |
---|
[27b8b59] | 2691 | } else { |
---|
| 2692 | pcs->infer &= ~BIT(setting); |
---|
[a420b49] | 2693 | } |
---|
| 2694 | } |
---|
| 2695 | |
---|
| 2696 | static void |
---|
[eb18f4d] | 2697 | cmd_truncate(void) |
---|
[a420b49] | 2698 | { |
---|
[647407d] | 2699 | unsigned int truncate_at = 0; /* default is no truncation */ |
---|
[c80bd34] | 2700 | filepos fp; |
---|
| 2701 | |
---|
| 2702 | get_pos(&fp); |
---|
| 2703 | |
---|
[647407d] | 2704 | get_token(); |
---|
[0532954] | 2705 | if (!S_EQ(&uctoken, "OFF")) { |
---|
| 2706 | if (!s_empty(&uctoken)) set_pos(&fp); |
---|
[647407d] | 2707 | truncate_at = read_uint(); |
---|
| 2708 | } |
---|
| 2709 | /* for backward compatibility, "*truncate 0" means "*truncate off" */ |
---|
| 2710 | pcs->Truncate = (truncate_at == 0) ? INT_MAX : truncate_at; |
---|
| 2711 | } |
---|
| 2712 | |
---|
[e8452e3] | 2713 | static void |
---|
| 2714 | cmd_ref(void) |
---|
| 2715 | { |
---|
| 2716 | /* Just syntax check for now. */ |
---|
[0532954] | 2717 | string ref = S_INIT; |
---|
| 2718 | read_string(&ref); |
---|
[e8452e3] | 2719 | s_free(&ref); |
---|
| 2720 | } |
---|
| 2721 | |
---|
[647407d] | 2722 | static void |
---|
[eb18f4d] | 2723 | cmd_require(void) |
---|
[647407d] | 2724 | { |
---|
[9af1e2c0] | 2725 | // Add extra 0 so `*require 1.4.10.1` fails with cavern version 1.4.10. |
---|
| 2726 | const unsigned version[] = {COMMAVERSION, 0}; |
---|
[c80bd34] | 2727 | |
---|
[9af1e2c0] | 2728 | filepos fp; |
---|
| 2729 | get_pos(&fp); |
---|
| 2730 | |
---|
| 2731 | // Parse the required version number, storing its components in |
---|
| 2732 | // required_version. We only store at most one more component than |
---|
| 2733 | // COMMAVERSION has since more than that can't affect the comparison. |
---|
| 2734 | size_t i = 0; |
---|
| 2735 | int diff = 0; |
---|
| 2736 | while (1) { |
---|
| 2737 | unsigned component = read_uint(); |
---|
| 2738 | if (diff == 0 && i < sizeof(version) / sizeof(version[0])) { |
---|
| 2739 | if (diff == 0) { |
---|
| 2740 | diff = (int)version[i++] - (int)component; |
---|
| 2741 | } |
---|
| 2742 | } |
---|
| 2743 | if (ch != '.' || isBlank(nextch()) || isComm(ch) || isEol(ch)) |
---|
| 2744 | break; |
---|
| 2745 | } |
---|
| 2746 | |
---|
| 2747 | if (diff < 0) { |
---|
| 2748 | // Requirement not satisfied |
---|
| 2749 | size_t len = (size_t)(ftell(file.fh) - fp.offset); |
---|
| 2750 | char *v = osmalloc(len + 1); |
---|
| 2751 | set_pos(&fp); |
---|
| 2752 | for (size_t j = 0; j < len; j++) { |
---|
| 2753 | v[j] = ch; |
---|
[69c920d] | 2754 | nextch(); |
---|
[9af1e2c0] | 2755 | } |
---|
| 2756 | v[len] = '\0'; |
---|
| 2757 | /* TRANSLATORS: Feel free to translate as "or newer" instead of "or |
---|
| 2758 | * greater" if that gives a more natural translation. It's |
---|
| 2759 | * technically not quite right when there are parallel active release |
---|
| 2760 | * series (e.g. Survex 1.0.40 was released *after* 1.2.0), but this |
---|
| 2761 | * seems unlikely to confuse users. "Survex" is the name of the |
---|
| 2762 | * software, so should not be translated. |
---|
| 2763 | * |
---|
| 2764 | * Here "survey" is a "cave map" rather than list of questions - it should be |
---|
| 2765 | * translated to the terminology that cavers using the language would use. |
---|
| 2766 | */ |
---|
[7962c9d] | 2767 | compile_diagnostic(DIAG_FATAL|DIAG_FROM(fp), /*Survex version %s or greater required to process this survey data.*/38, v); |
---|
[9af1e2c0] | 2768 | // Does not return so no point freeing v here. |
---|
| 2769 | } |
---|
[a420b49] | 2770 | } |
---|
| 2771 | |
---|
[b5a3219] | 2772 | /* allocate new meta_data if need be */ |
---|
| 2773 | void |
---|
| 2774 | copy_on_write_meta(settings *s) |
---|
| 2775 | { |
---|
| 2776 | if (!s->meta || s->meta->ref_count != 0) { |
---|
| 2777 | meta_data * meta_new = osnew(meta_data); |
---|
| 2778 | if (!s->meta) { |
---|
[1ee204e] | 2779 | meta_new->days1 = meta_new->days2 = -1; |
---|
[b5a3219] | 2780 | } else { |
---|
| 2781 | *meta_new = *(s->meta); |
---|
| 2782 | } |
---|
| 2783 | meta_new->ref_count = 0; |
---|
| 2784 | s->meta = meta_new; |
---|
| 2785 | } |
---|
| 2786 | } |
---|
| 2787 | |
---|
[c7c0f93] | 2788 | static int |
---|
| 2789 | read_year(filepos *fp_date_ptr) |
---|
| 2790 | { |
---|
[f15c53d9] | 2791 | int y = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, fp_date_ptr); |
---|
[c7c0f93] | 2792 | if (y < 100) { |
---|
| 2793 | /* Two digit year is 19xx. */ |
---|
| 2794 | y += 1900; |
---|
| 2795 | filepos fp_save; |
---|
| 2796 | get_pos(&fp_save); |
---|
| 2797 | set_pos(fp_date_ptr); |
---|
| 2798 | /* TRANSLATORS: %d will be replaced by the assumed year, e.g. 1918 */ |
---|
| 2799 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Assuming 2 digit year is %d*/76, y); |
---|
| 2800 | set_pos(&fp_save); |
---|
| 2801 | } else if (y < 1900 || y > 2078) { |
---|
| 2802 | set_pos(fp_date_ptr); |
---|
| 2803 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid year (< 1900 or > 2078)*/58); |
---|
| 2804 | longjmp(jbSkipLine, 1); |
---|
| 2805 | } |
---|
| 2806 | return y; |
---|
| 2807 | } |
---|
| 2808 | |
---|
[950a829] | 2809 | static void |
---|
| 2810 | cmd_date(void) |
---|
[421b7d2] | 2811 | { |
---|
[c7c0f93] | 2812 | enum { DATE_SURVEYED = 1, DATE_EXPLORED = 2 }; |
---|
| 2813 | unsigned date_flags = 0; |
---|
| 2814 | while (get_token(), !s_empty(&uctoken)) { |
---|
| 2815 | unsigned new_flag = 0; |
---|
| 2816 | if (S_EQ(&uctoken, "SURVEYED")) { |
---|
| 2817 | new_flag = DATE_SURVEYED; |
---|
| 2818 | } else if (S_EQ(&uctoken, "EXPLORED")) { |
---|
| 2819 | new_flag = DATE_EXPLORED; |
---|
| 2820 | } else { |
---|
| 2821 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN, |
---|
| 2822 | /*Expecting “%s” or “%s”*/103, "SURVEYED", "EXPLORED"); |
---|
| 2823 | continue; |
---|
| 2824 | } |
---|
[e0c7cd1] | 2825 | |
---|
[c7c0f93] | 2826 | if ((date_flags & new_flag)) { |
---|
| 2827 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN, |
---|
[0823cb3] | 2828 | /*Duplicate date type “%s”*/416, s_str(&token)); |
---|
[c7c0f93] | 2829 | } |
---|
| 2830 | date_flags |= new_flag; |
---|
| 2831 | } |
---|
[1ee204e] | 2832 | |
---|
[c7c0f93] | 2833 | int date_sep = '-'; |
---|
| 2834 | if (date_flags == 0) { |
---|
| 2835 | // `*date` without qualification sets the surveyed date. |
---|
| 2836 | date_flags = DATE_SURVEYED; |
---|
| 2837 | // Also allow '.' for compatibility. |
---|
| 2838 | date_sep = 0; |
---|
[e0c7cd1] | 2839 | } |
---|
| 2840 | |
---|
[c7c0f93] | 2841 | filepos fp_date1, fp_date2, fp; |
---|
| 2842 | get_pos(&fp_date1); |
---|
| 2843 | int year = read_year(&fp_date1); |
---|
| 2844 | int month = 0, day = 0, year2 = 0, month2 = 0, day2 = 0; |
---|
| 2845 | |
---|
[e0c7cd1] | 2846 | if (ch == '-') { |
---|
[c7c0f93] | 2847 | // Could be ISO-format date (e.g. 2024-10 or 2024-10-21 or 1912-11), or |
---|
| 2848 | // a range of old-format dates (e.g. 1973-1975 or 1911-12.02.03) or an |
---|
| 2849 | // ambiguous case like 1911-12 which we need to warn about in a `*date` |
---|
| 2850 | // command without `surveyed` or `explored` qualifiers. |
---|
| 2851 | nextch(); |
---|
| 2852 | get_pos(&fp_date2); |
---|
[f15c53d9] | 2853 | int v = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, &fp_date1); |
---|
[c7c0f93] | 2854 | if (date_sep == '-') { |
---|
| 2855 | // We're only accepting ISO dates. |
---|
| 2856 | } else if (ch == '-') { |
---|
| 2857 | // Two `-` so must be an ISO date, e.g. `2024-10-21`. |
---|
| 2858 | } else if (v >= 1 && v <= 12) { |
---|
| 2859 | // Valid month number so assume it's an ISO date. |
---|
| 2860 | if (year < 1900 + v) { |
---|
| 2861 | // Warn about ambiguous cases. |
---|
| 2862 | compile_diagnostic(DIAG_WARN|DIAG_FROM(fp_date1), |
---|
| 2863 | /*Interpreting as an ISO-format date - use “*date surveyed %d-%02d” to suppress this warning, or “*date %d %d” if you wanted a date range*/158, |
---|
| 2864 | year, v, year, 1900 + v); |
---|
| 2865 | } |
---|
| 2866 | } else { |
---|
| 2867 | date_sep = '.'; |
---|
| 2868 | year2 = v; |
---|
| 2869 | if (year2 < 100) { |
---|
| 2870 | /* Two digit year is 19xx. */ |
---|
| 2871 | year2 += 1900; |
---|
| 2872 | /* TRANSLATORS: %d will be replaced by the assumed year, e.g. 1918 */ |
---|
| 2873 | compile_diagnostic(DIAG_WARN|DIAG_FROM(fp_date2), |
---|
| 2874 | /*Assuming 2 digit year is %d*/76, year2); |
---|
| 2875 | } else if (year2 < 1900 || year2 > 2078) { |
---|
| 2876 | compile_diagnostic(DIAG_WARN|DIAG_FROM(fp_date2), |
---|
| 2877 | /*Invalid year (< 1900 or > 2078)*/58); |
---|
| 2878 | longjmp(jbSkipLine, 1); |
---|
| 2879 | } |
---|
| 2880 | goto process_dates; |
---|
| 2881 | } |
---|
| 2882 | |
---|
| 2883 | date_sep = '-'; |
---|
| 2884 | month = v; |
---|
| 2885 | fp = fp_date2; |
---|
| 2886 | } else if (ch == '.') { |
---|
| 2887 | if (date_sep == '-') { |
---|
| 2888 | char date_sep_string[2] = { date_sep, '\0' }; |
---|
| 2889 | compile_diagnostic(DIAG_ERR|DIAG_COL|DIAG_SKIP, |
---|
| 2890 | /*Expecting “%s”*/497, date_sep_string); |
---|
| 2891 | return; |
---|
| 2892 | } |
---|
| 2893 | date_sep = ch; |
---|
[e0c7cd1] | 2894 | nextch(); |
---|
[c7c0f93] | 2895 | get_pos(&fp); |
---|
[f15c53d9] | 2896 | month = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, &fp_date1); |
---|
[e0c7cd1] | 2897 | } else { |
---|
[c7c0f93] | 2898 | // Just a year - might be a ISO date range though. |
---|
| 2899 | date_sep = '-'; |
---|
| 2900 | goto try_date2; |
---|
| 2901 | } |
---|
| 2902 | |
---|
| 2903 | if (month < 1 || month > 12) { |
---|
| 2904 | set_pos(&fp); |
---|
| 2905 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid month*/86); |
---|
| 2906 | longjmp(jbSkipLine, 1); |
---|
| 2907 | } |
---|
| 2908 | |
---|
| 2909 | if (ch == date_sep) { |
---|
| 2910 | nextch(); |
---|
| 2911 | get_pos(&fp); |
---|
[f15c53d9] | 2912 | day = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, &fp_date1); |
---|
[c7c0f93] | 2913 | if (day < 1 || day > last_day(year, month)) { |
---|
| 2914 | set_pos(&fp); |
---|
| 2915 | /* TRANSLATORS: e.g. 31st of April, or 32nd of any month */ |
---|
| 2916 | compile_diagnostic(DIAG_WARN|DIAG_UINT, |
---|
| 2917 | /*Invalid day of the month*/87); |
---|
| 2918 | longjmp(jbSkipLine, 1); |
---|
[1ee204e] | 2919 | } |
---|
| 2920 | } |
---|
| 2921 | |
---|
[c7c0f93] | 2922 | try_date2: |
---|
[2d4ca34] | 2923 | if (date_sep == '-') { |
---|
| 2924 | skipblanks(); |
---|
| 2925 | if (!isdigit(ch)) goto process_dates; |
---|
| 2926 | } else if (ch == '-') { |
---|
[c7c0f93] | 2927 | nextch(); |
---|
[2d4ca34] | 2928 | } else { |
---|
| 2929 | goto process_dates; |
---|
| 2930 | } |
---|
| 2931 | { |
---|
[c7c0f93] | 2932 | get_pos(&fp_date2); |
---|
| 2933 | year2 = read_year(&fp_date2); |
---|
| 2934 | if (ch == date_sep) { |
---|
| 2935 | nextch(); |
---|
| 2936 | get_pos(&fp); |
---|
[f15c53d9] | 2937 | month2 = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, |
---|
[c7c0f93] | 2938 | &fp_date2); |
---|
| 2939 | if (month2 < 1 || month2 > 12) { |
---|
| 2940 | set_pos(&fp); |
---|
| 2941 | compile_diagnostic(DIAG_WARN|DIAG_UINT, /*Invalid month*/86); |
---|
| 2942 | longjmp(jbSkipLine, 1); |
---|
| 2943 | } |
---|
| 2944 | |
---|
| 2945 | if (ch == date_sep) { |
---|
| 2946 | nextch(); |
---|
| 2947 | get_pos(&fp); |
---|
[f15c53d9] | 2948 | day2 = read_uint_raw(DIAG_ERR, /*Expecting date, found “%s”*/198, |
---|
[c7c0f93] | 2949 | &fp_date2); |
---|
| 2950 | if (day2 < 1 || day2 > last_day(year2, month2)) { |
---|
| 2951 | set_pos(&fp); |
---|
| 2952 | /* TRANSLATORS: e.g. 31st of April, or 32nd of any month */ |
---|
| 2953 | compile_diagnostic(DIAG_WARN|DIAG_UINT, |
---|
| 2954 | /*Invalid day of the month*/87); |
---|
| 2955 | longjmp(jbSkipLine, 1); |
---|
| 2956 | } |
---|
| 2957 | } |
---|
| 2958 | } |
---|
| 2959 | } |
---|
[1ee204e] | 2960 | |
---|
[50bfed5] | 2961 | process_dates:; |
---|
[c7c0f93] | 2962 | bool date_range = (year2 != 0); |
---|
| 2963 | if (!date_range) { |
---|
| 2964 | year2 = year; |
---|
| 2965 | month2 = month; |
---|
| 2966 | day2 = day; |
---|
| 2967 | } |
---|
| 2968 | |
---|
| 2969 | int days1 = days_since_1900(year, month ? month : 1, day ? day : 1); |
---|
| 2970 | |
---|
| 2971 | if (days1 > current_days_since_1900) { |
---|
| 2972 | filepos fp_save; |
---|
| 2973 | get_pos(&fp_save); |
---|
| 2974 | set_pos(&fp_date1); |
---|
| 2975 | compile_diagnostic(DIAG_WARN|DIAG_DATE, /*Date is in the future!*/80); |
---|
| 2976 | set_pos(&fp_save); |
---|
| 2977 | } |
---|
| 2978 | |
---|
| 2979 | if (month2 == 0) { |
---|
| 2980 | month2 = 12; |
---|
| 2981 | day2 = 31; |
---|
| 2982 | } else if (day2 == 0) { |
---|
| 2983 | day2 = last_day(year2, month2); |
---|
| 2984 | } |
---|
| 2985 | int days2 = days_since_1900(year2, month2, day2); |
---|
| 2986 | if (date_range && days2 > current_days_since_1900) { |
---|
| 2987 | // If !date_range, either we already emitted this warning when |
---|
| 2988 | // processing the start date, or the date is partial and for the |
---|
| 2989 | // current year or current month, in which case it's not helpful |
---|
| 2990 | // to warn that the end is on the future, but it makes sense to |
---|
| 2991 | // process for the end date so the result doesn't change as time |
---|
| 2992 | // passes. |
---|
| 2993 | filepos fp_save; |
---|
| 2994 | get_pos(&fp_save); |
---|
| 2995 | set_pos(&fp_date2); |
---|
[1d74718] | 2996 | compile_diagnostic(DIAG_WARN|DIAG_DATE, /*Date is in the future!*/80); |
---|
[c7c0f93] | 2997 | set_pos(&fp_save); |
---|
[e0c7cd1] | 2998 | } |
---|
[1ee204e] | 2999 | |
---|
| 3000 | if (days2 < days1) { |
---|
[c7c0f93] | 3001 | filepos fp_save; |
---|
| 3002 | get_pos(&fp_save); |
---|
| 3003 | set_pos(&fp_date1); |
---|
[d0be687d] | 3004 | compile_diagnostic(DIAG_ERR|DIAG_WORD, /*End of date range is before the start*/81); |
---|
[c7c0f93] | 3005 | set_pos(&fp_save); |
---|
| 3006 | // Swap range ends to put us in a consistent state. |
---|
[95b0f1d] | 3007 | int tmp = days1; |
---|
| 3008 | days1 = days2; |
---|
| 3009 | days2 = tmp; |
---|
[1ee204e] | 3010 | } |
---|
[e0c7cd1] | 3011 | |
---|
[c7c0f93] | 3012 | if ((date_flags & DATE_SURVEYED)) { |
---|
| 3013 | if (!pcs->meta || pcs->meta->days1 != days1 || pcs->meta->days2 != days2) { |
---|
| 3014 | copy_on_write_meta(pcs); |
---|
| 3015 | pcs->meta->days1 = days1; |
---|
| 3016 | pcs->meta->days2 = days2; |
---|
| 3017 | /* Invalidate cached declination. */ |
---|
| 3018 | pcs->declination = HUGE_REAL; |
---|
| 3019 | } |
---|
| 3020 | } |
---|
| 3021 | |
---|
| 3022 | if ((date_flags & DATE_EXPLORED)) { |
---|
| 3023 | // FIXME: Need to revise 3d format to allow storing EXPLORED date too. |
---|
[95b0f1d] | 3024 | } |
---|
[950a829] | 3025 | } |
---|
| 3026 | |
---|
[3aafcee] | 3027 | typedef void (*cmd_fn)(void); |
---|
| 3028 | |
---|
[82919e07] | 3029 | static const cmd_fn cmd_funcs[] = { |
---|
[dcbcae0] | 3030 | cmd_alias, |
---|
[3aafcee] | 3031 | cmd_begin, |
---|
| 3032 | cmd_calibrate, |
---|
[abe7192] | 3033 | cmd_cartesian, |
---|
[3aafcee] | 3034 | cmd_case, |
---|
[f15c53d9] | 3035 | cmd_copyright, |
---|
[abd0310] | 3036 | cmd_cs, |
---|
[3aafcee] | 3037 | cmd_data, |
---|
[950a829] | 3038 | cmd_date, |
---|
[58c7b459] | 3039 | cmd_declination, |
---|
[7f1ab95] | 3040 | #ifndef NO_DEPRECATED |
---|
[3aafcee] | 3041 | cmd_default, |
---|
[7f1ab95] | 3042 | #endif |
---|
[3aafcee] | 3043 | cmd_end, |
---|
| 3044 | cmd_entrance, |
---|
| 3045 | cmd_equate, |
---|
| 3046 | cmd_export, |
---|
| 3047 | cmd_fix, |
---|
| 3048 | cmd_flags, |
---|
| 3049 | cmd_include, |
---|
| 3050 | cmd_infer, |
---|
| 3051 | skipline, /*cmd_instrument,*/ |
---|
[7f1ab95] | 3052 | #ifndef NO_DEPRECATED |
---|
[3aafcee] | 3053 | cmd_prefix, |
---|
[7f1ab95] | 3054 | #endif |
---|
[e8452e3] | 3055 | cmd_ref, |
---|
[3aafcee] | 3056 | cmd_require, |
---|
| 3057 | cmd_sd, |
---|
| 3058 | cmd_set, |
---|
| 3059 | solve_network, |
---|
[0f8216c] | 3060 | cmd_team, |
---|
[3aafcee] | 3061 | cmd_title, |
---|
| 3062 | cmd_truncate, |
---|
| 3063 | cmd_units |
---|
| 3064 | }; |
---|
| 3065 | |
---|
[a420b49] | 3066 | extern void |
---|
| 3067 | handle_command(void) |
---|
| 3068 | { |
---|
[05b9de76] | 3069 | filepos fp; |
---|
| 3070 | get_pos(&fp); |
---|
[e1cbc0d] | 3071 | get_token_legacy(); |
---|
[05b9de76] | 3072 | int cmdtok = match_tok(cmd_tab, TABSIZE(cmd_tab)); |
---|
[3aafcee] | 3073 | if (cmdtok < 0 || cmdtok >= (int)(sizeof(cmd_funcs) / sizeof(cmd_fn))) { |
---|
[05b9de76] | 3074 | set_pos(&fp); |
---|
| 3075 | get_token(); |
---|
[caae6cd] | 3076 | compile_diagnostic(DIAG_ERR|DIAG_TOKEN|DIAG_SKIP, /*Unknown command “%s”*/12, s_str(&token)); |
---|
[3aafcee] | 3077 | return; |
---|
[932f7e9] | 3078 | } |
---|
| 3079 | |
---|
[05b9de76] | 3080 | do_legacy_token_warning(); |
---|
| 3081 | |
---|
[932f7e9] | 3082 | switch (cmdtok) { |
---|
[3aafcee] | 3083 | case CMD_EXPORT: |
---|
| 3084 | if (!f_export_ok) |
---|
[736f7df] | 3085 | /* TRANSLATORS: The *EXPORT command is only valid just after *BEGIN |
---|
| 3086 | * <SURVEY>, so this would generate this error: |
---|
| 3087 | * |
---|
| 3088 | * *begin fred |
---|
| 3089 | * 1 2 1.23 045 -6 |
---|
| 3090 | * *export 2 |
---|
| 3091 | * *end fred */ |
---|
[cab0f26] | 3092 | compile_diagnostic(DIAG_ERR, /**EXPORT must immediately follow “*BEGIN <SURVEY>”*/57); |
---|
[3aafcee] | 3093 | break; |
---|
[ce15637] | 3094 | case CMD_ALIAS: |
---|
| 3095 | case CMD_CALIBRATE: |
---|
[abe7192] | 3096 | case CMD_CARTESIAN: |
---|
[ce15637] | 3097 | case CMD_CASE: |
---|
[3aafcee] | 3098 | case CMD_COPYRIGHT: |
---|
[ce15637] | 3099 | case CMD_CS: |
---|
| 3100 | case CMD_DATA: |
---|
[3aafcee] | 3101 | case CMD_DATE: |
---|
[ce15637] | 3102 | case CMD_DECLINATION: |
---|
| 3103 | case CMD_FLAGS: |
---|
| 3104 | case CMD_INFER: |
---|
[3aafcee] | 3105 | case CMD_INSTRUMENT: |
---|
[ce15637] | 3106 | case CMD_REF: |
---|
| 3107 | case CMD_REQUIRE: |
---|
| 3108 | case CMD_SD: |
---|
| 3109 | case CMD_SET: |
---|
[3aafcee] | 3110 | case CMD_TEAM: |
---|
| 3111 | case CMD_TITLE: |
---|
[ce15637] | 3112 | case CMD_TRUNCATE: |
---|
| 3113 | case CMD_UNITS: |
---|
[98b705d] | 3114 | /* These can all occur between *begin and *export */ |
---|
| 3115 | break; |
---|
| 3116 | case CMD_DEFAULT: { |
---|
| 3117 | // Issue warning here before we skipblanks(). |
---|
| 3118 | static int default_depr_count = 0; |
---|
| 3119 | if (default_depr_count < 5) { |
---|
| 3120 | /* TRANSLATORS: If you're unsure what "deprecated" means, see: |
---|
| 3121 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
| 3122 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN, /**DEFAULT is deprecated - use *CALIBRATE/DATA/SD/UNITS with argument DEFAULT instead*/20); |
---|
| 3123 | if (++default_depr_count == 5) |
---|
| 3124 | compile_diagnostic(DIAG_INFO, /*Further uses of this deprecated feature will not be reported*/95); |
---|
| 3125 | } |
---|
| 3126 | /* Can occur between *begin and *export */ |
---|
| 3127 | break; |
---|
| 3128 | } |
---|
| 3129 | case CMD_PREFIX: { |
---|
| 3130 | // Issue warning here before we skipblanks(). |
---|
| 3131 | static int prefix_depr_count = 0; |
---|
| 3132 | if (prefix_depr_count < 5) { |
---|
| 3133 | /* TRANSLATORS: If you're unsure what "deprecated" means, see: |
---|
| 3134 | * https://en.wikipedia.org/wiki/Deprecation */ |
---|
| 3135 | compile_diagnostic(DIAG_WARN|DIAG_TOKEN, /**prefix is deprecated - use *begin and *end instead*/109); |
---|
| 3136 | if (++prefix_depr_count == 5) |
---|
| 3137 | compile_diagnostic(DIAG_INFO, /*Further uses of this deprecated feature will not be reported*/95); |
---|
| 3138 | } |
---|
| 3139 | f_export_ok = false; |
---|
[421b7d2] | 3140 | break; |
---|
[98b705d] | 3141 | } |
---|
[a420b49] | 3142 | default: |
---|
[4dcd3af] | 3143 | /* NB: additional handling for "*begin <survey>" in cmd_begin */ |
---|
[63d4f07] | 3144 | f_export_ok = false; |
---|
[3aafcee] | 3145 | break; |
---|
[647407d] | 3146 | } |
---|
[421b7d2] | 3147 | |
---|
[98b705d] | 3148 | skipblanks(); |
---|
| 3149 | |
---|
[3aafcee] | 3150 | cmd_funcs[cmdtok](); |
---|
[5f1e194] | 3151 | } |
---|