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