Reliably disable scale bar in perspective view
[survex.git] / src / datain.c
blobd97de7a7b3f2862f83316f0bb654ff0974c44a70
1 /* datain.c
2 * Reads in survey files, dealing with special characters, keywords & data
3 * Copyright (C) 1991-2003,2005,2009,2010,2011,2012,2013,2014,2015,2016,2017 Olly Betts
4 * Copyright (C) 2004 Simeon Warner
6 * This program is free software; you can redistribute it and/or modify
7 * it under the terms of the GNU General Public License as published by
8 * the Free Software Foundation; either version 2 of the License, or
9 * (at your option) any later version.
11 * This program is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14 * GNU General Public License for more details.
16 * You should have received a copy of the GNU General Public License
17 * along with this program; if not, write to the Free Software
18 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
21 #ifdef HAVE_CONFIG_H
22 #include <config.h>
23 #endif
25 #include <limits.h>
26 #include <stdarg.h>
28 #include "debug.h"
29 #include "cavern.h"
30 #include "date.h"
31 #include "filename.h"
32 #include "message.h"
33 #include "filelist.h"
34 #include "netbits.h"
35 #include "netskel.h"
36 #include "readval.h"
37 #include "datain.h"
38 #include "commands.h"
39 #include "out.h"
40 #include "str.h"
41 #include "thgeomag.h"
43 #define EPSILON (REAL_EPSILON * 1000)
45 #define var(I) (pcs->Var[(I)])
47 /* true if x is not-a-number value in Compass (999.0 or -999.0) */
48 /* Compass uses 999.0 but understands Karst data which used -999.0 */
49 #define is_compass_NaN(x) ( fabs(fabs(x)-999.0) < EPSILON )
51 int ch;
53 typedef enum {
54 CTYPE_OMIT, CTYPE_READING, CTYPE_PLUMB, CTYPE_INFERPLUMB, CTYPE_HORIZ
55 } clino_type;
57 /* Don't explicitly initialise as we can't set the jmp_buf - this has
58 * static scope so will be initialised like this anyway */
59 parse file /* = { NULL, NULL, 0, fFalse, NULL } */ ;
61 bool f_export_ok;
63 static real value[Fr - 1];
64 #define VAL(N) value[(N)-1]
65 static real variance[Fr - 1];
66 #define VAR(N) variance[(N)-1]
67 static long location[Fr - 1];
68 #define LOC(N) location[(N)-1]
69 static int location_width[Fr - 1];
70 #define WID(N) location_width[(N)-1]
72 /* style functions */
73 static void data_normal(void);
74 static void data_cartesian(void);
75 static void data_passage(void);
76 static void data_nosurvey(void);
77 static void data_ignore(void);
79 void
80 get_pos(filepos *fp)
82 fp->ch = ch;
83 fp->offset = ftell(file.fh);
84 if (fp->offset == -1)
85 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
88 void
89 set_pos(const filepos *fp)
91 ch = fp->ch;
92 if (fseek(file.fh, fp->offset, SEEK_SET) == -1)
93 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
96 static void
97 report_parent(parse * p) {
98 if (p->parent)
99 report_parent(p->parent);
100 /* Force re-report of include tree for further errors in
101 * parent files */
102 p->reported_where = fFalse;
103 /* TRANSLATORS: %s is replaced by the filename of the parent file, and %u
104 * by the line number in that file. Your translation should also contain
105 * %s:%u so that automatic parsing of error messages to determine the file
106 * and line number still works. */
107 fprintf(STDERR, msg(/*In file included from %s:%u:\n*/5), p->filename, p->line);
110 static void
111 error_list_parent_files(void)
113 if (!file.reported_where && file.parent) {
114 report_parent(file.parent);
115 /* Suppress reporting of full include tree for further errors
116 * in this file */
117 file.reported_where = fTrue;
121 static void
122 show_line(int col, int width)
124 /* Rewind to beginning of line. */
125 long cur_pos = ftell(file.fh);
126 int tabs = 0;
127 if (cur_pos < 0 || fseek(file.fh, file.lpos, SEEK_SET) == -1)
128 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
130 /* Read the whole line and write it out. */
131 PUTC(' ', STDERR);
132 while (1) {
133 int c = GETC(file.fh);
134 /* Note: isEol() is true for EOF */
135 if (isEol(c)) break;
136 if (c == '\t') ++tabs;
137 PUTC(c, STDERR);
139 fputnl(STDERR);
141 /* If we have a location in the line for the error, indicate it. */
142 if (col) {
143 PUTC(' ', STDERR);
144 if (tabs == 0) {
145 while (--col) PUTC(' ', STDERR);
146 } else {
147 /* Copy tabs from line, replacing other characters with spaces - this
148 * means that the caret should line up correctly. */
149 if (fseek(file.fh, file.lpos, SEEK_SET) == -1)
150 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
151 while (--col) {
152 int c = GETC(file.fh);
153 if (c != '\t') c = ' ';
154 PUTC(c, STDERR);
157 PUTC('^', STDERR);
158 while (width > 1) {
159 PUTC('~', STDERR);
160 --width;
162 fputnl(STDERR);
165 /* Revert to where we were. */
166 if (fseek(file.fh, cur_pos, SEEK_SET) == -1)
167 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
170 static int caret_width = 0;
172 static void
173 compile_v_report_fpos(int severity, long fpos, int en, va_list ap)
175 int col = 0;
176 error_list_parent_files();
177 if (fpos >= file.lpos)
178 col = fpos - file.lpos - caret_width;
179 v_report(severity, file.filename, file.line, col, en, ap);
180 if (file.fh) show_line(col, caret_width);
183 static void
184 compile_v_report(int diag_flags, int en, va_list ap)
186 int severity = (diag_flags & DIAG_SEVERITY_MASK);
187 if (diag_flags & (DIAG_COL|DIAG_BUF)) {
188 if (file.fh) {
189 if (diag_flags & DIAG_BUF) caret_width = strlen(buffer);
190 compile_v_report_fpos(severity, ftell(file.fh), en, ap);
191 if (diag_flags & DIAG_BUF) caret_width = 0;
192 if (diag_flags & DIAG_SKIP) skipline();
193 return;
196 error_list_parent_files();
197 v_report(severity, file.filename, file.line, 0, en, ap);
198 if (file.fh) {
199 if (diag_flags & DIAG_BUF) {
200 show_line(0, strlen(buffer));
201 } else {
202 show_line(0, caret_width);
205 if (diag_flags & DIAG_SKIP) skipline();
208 void
209 compile_diagnostic(int diag_flags, int en, ...)
211 va_list ap;
212 va_start(ap, en);
213 if (diag_flags & (DIAG_TOKEN|DIAG_UINT|DIAG_DATE|DIAG_NUM)) {
214 char *p = NULL;
215 int len = 0;
216 skipblanks();
217 if (diag_flags & DIAG_TOKEN) {
218 while (!isBlank(ch) && !isEol(ch)) {
219 s_catchar(&p, &len, (char)ch);
220 nextch();
222 } else if (diag_flags & DIAG_UINT) {
223 while (isdigit(ch)) {
224 s_catchar(&p, &len, (char)ch);
225 nextch();
227 } else if (diag_flags & DIAG_DATE) {
228 while (isdigit(ch) || ch == '.') {
229 s_catchar(&p, &len, (char)ch);
230 nextch();
232 } else {
233 if (isMinus(ch) || isPlus(ch)) {
234 s_catchar(&p, &len, (char)ch);
235 nextch();
237 while (isdigit(ch)) {
238 s_catchar(&p, &len, (char)ch);
239 nextch();
241 if (isDecimal(ch)) {
242 s_catchar(&p, &len, (char)ch);
243 nextch();
245 while (isdigit(ch)) {
246 s_catchar(&p, &len, (char)ch);
247 nextch();
250 if (p) {
251 caret_width = strlen(p);
252 osfree(p);
254 compile_v_report(diag_flags|DIAG_COL, en, ap);
255 caret_width = 0;
256 } else {
257 compile_v_report(diag_flags, en, ap);
259 va_end(ap);
262 static void
263 compile_diagnostic_reading(int diag_flags, reading r, int en, ...)
265 va_list ap;
266 int severity = (diag_flags & DIAG_SEVERITY_MASK);
267 va_start(ap, en);
268 caret_width = WID(r);
269 compile_v_report_fpos(severity, LOC(r) + caret_width, en, ap);
270 caret_width = 0;
271 va_end(ap);
274 static void
275 compile_error_reading_skip(reading r, int en, ...)
277 va_list ap;
278 va_start(ap, en);
279 caret_width = WID(r);
280 compile_v_report_fpos(1, LOC(r) + caret_width, en, ap);
281 caret_width = 0;
282 va_end(ap);
283 skipline();
286 void
287 compile_diagnostic_at(int diag_flags, const char * filename, unsigned line, int en, ...)
289 va_list ap;
290 int severity = (diag_flags & DIAG_SEVERITY_MASK);
291 va_start(ap, en);
292 v_report(severity, filename, line, 0, en, ap);
293 va_end(ap);
296 void
297 compile_diagnostic_pfx(int diag_flags, const prefix * pfx, int en, ...)
299 va_list ap;
300 int severity = (diag_flags & DIAG_SEVERITY_MASK);
301 va_start(ap, en);
302 v_report(severity, pfx->filename, pfx->line, 0, en, ap);
303 va_end(ap);
306 void
307 compile_diagnostic_token_show(int diag_flags, int en)
309 char *p = NULL;
310 int len = 0;
311 skipblanks();
312 while (!isBlank(ch) && !isEol(ch)) {
313 s_catchar(&p, &len, (char)ch);
314 nextch();
316 if (p) {
317 caret_width = strlen(p);
318 compile_diagnostic(diag_flags|DIAG_COL, en, p);
319 caret_width = 0;
320 osfree(p);
321 } else {
322 compile_diagnostic(DIAG_ERR|DIAG_COL, en, "");
326 static void
327 compile_error_string(const char * s, int en, ...)
329 va_list ap;
330 va_start(ap, en);
331 caret_width = strlen(s);
332 compile_v_report(DIAG_ERR|DIAG_COL, en, ap);
333 va_end(ap);
334 caret_width = 0;
337 /* This function makes a note where to put output files */
338 static void
339 using_data_file(const char *fnm)
341 if (!fnm_output_base) {
342 /* was: fnm_output_base = base_from_fnm(fnm); */
343 fnm_output_base = baseleaf_from_fnm(fnm);
344 } else if (fnm_output_base_is_dir) {
345 /* --output pointed to directory so use the leaf basename in that dir */
346 char *lf, *p;
347 lf = baseleaf_from_fnm(fnm);
348 p = use_path(fnm_output_base, lf);
349 osfree(lf);
350 osfree(fnm_output_base);
351 fnm_output_base = p;
352 fnm_output_base_is_dir = 0;
356 static void
357 skipword(void)
359 while (!isBlank(ch) && !isEol(ch)) nextch();
362 extern void
363 skipblanks(void)
365 while (isBlank(ch)) nextch();
368 extern void
369 skipline(void)
371 while (!isEol(ch)) nextch();
374 static void
375 process_eol(void)
377 int eolchar;
379 skipblanks();
381 if (!isEol(ch)) {
382 if (!isComm(ch))
383 compile_diagnostic(DIAG_ERR|DIAG_COL, /*End of line not blank*/15);
384 skipline();
387 eolchar = ch;
388 file.line++;
389 /* skip any different eol characters so we get line counts correct on
390 * DOS text files and similar, but don't count several adjacent blank
391 * lines as one */
392 while (ch != EOF) {
393 nextch();
394 if (ch == eolchar || !isEol(ch)) {
395 break;
397 if (ch == '\n') eolchar = ch;
399 file.lpos = ftell(file.fh) - 1;
402 static bool
403 process_non_data_line(void)
405 skipblanks();
407 if (isData(ch)) return fFalse;
409 if (isKeywd(ch)) {
410 nextch();
411 handle_command();
414 process_eol();
416 return fTrue;
419 static void
420 read_reading(reading r, bool f_optional)
422 int n_readings;
423 q_quantity q;
424 switch (r) {
425 case Tape: q = Q_LENGTH; break;
426 case BackTape: q = Q_BACKLENGTH; break;
427 case Comp: q = Q_BEARING; break;
428 case BackComp: q = Q_BACKBEARING; break;
429 case Clino: q = Q_GRADIENT; break;
430 case BackClino: q = Q_BACKGRADIENT; break;
431 case FrDepth: case ToDepth: q = Q_DEPTH; break;
432 case Dx: q = Q_DX; break;
433 case Dy: q = Q_DY; break;
434 case Dz: q = Q_DZ; break;
435 case FrCount: case ToCount: q = Q_COUNT; break;
436 case Left: q = Q_LEFT; break;
437 case Right: q = Q_RIGHT; break;
438 case Up: q = Q_UP; break;
439 case Down: q = Q_DOWN; break;
440 default:
441 q = Q_NULL; /* Suppress compiler warning */;
442 BUG("Unexpected case");
444 LOC(r) = ftell(file.fh);
445 VAL(r) = read_numeric_multi(f_optional, &n_readings);
446 WID(r) = ftell(file.fh) - LOC(r);
447 VAR(r) = var(q);
448 if (n_readings > 1) VAR(r) /= sqrt(n_readings);
451 static void
452 read_bearing_or_omit(reading r)
454 int n_readings;
455 q_quantity q = Q_NULL;
456 LOC(r) = ftell(file.fh);
457 VAL(r) = read_numeric_multi_or_omit(&n_readings);
458 WID(r) = ftell(file.fh) - LOC(r);
459 switch (r) {
460 case Comp: q = Q_BEARING; break;
461 case BackComp: q = Q_BACKBEARING; break;
462 default:
463 q = Q_NULL; /* Suppress compiler warning */;
464 BUG("Unexpected case");
466 VAR(r) = var(q);
467 if (n_readings > 1) VAR(r) /= sqrt(n_readings);
470 /* For reading Compass MAK files which have a freeform syntax */
471 static void
472 nextch_handling_eol(void)
474 nextch();
475 while (ch != EOF && isEol(ch)) {
476 process_eol();
480 #define LITLEN(S) (sizeof(S"") - 1)
481 #define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
482 (F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
483 strcasecmp((F) + (L) - LITLEN(E), E) == 0)
484 extern void
485 data_file(const char *pth, const char *fnm)
487 int begin_lineno_store;
488 parse file_store;
489 volatile enum {FMT_SVX, FMT_DAT, FMT_MAK} fmt = FMT_SVX;
492 char *filename;
493 FILE *fh;
494 size_t len;
496 if (!pth) {
497 /* file specified on command line - don't do special translation */
498 fh = fopenWithPthAndExt(pth, fnm, EXT_SVX_DATA, "rb", &filename);
499 } else {
500 fh = fopen_portable(pth, fnm, EXT_SVX_DATA, "rb", &filename);
503 if (fh == NULL) {
504 compile_error_string(fnm, /*Couldnā€™t open file ā€œ%sā€*/24, fnm);
505 return;
508 len = strlen(filename);
509 if (has_ext(filename, len, "dat")) {
510 fmt = FMT_DAT;
511 } else if (has_ext(filename, len, "mak")) {
512 fmt = FMT_MAK;
515 file_store = file;
516 if (file.fh) file.parent = &file_store;
517 file.fh = fh;
518 file.filename = filename;
519 file.line = 1;
520 file.lpos = 0;
521 file.reported_where = fFalse;
522 nextch();
523 if (fmt == FMT_SVX && ch == 0xef) {
524 /* Maybe a UTF-8 "BOM" - skip if so. */
525 if (nextch() == 0xbb && nextch() == 0xbf) {
526 nextch();
527 file.lpos = 3;
528 } else {
529 rewind(fh);
530 ch = 0xef;
535 using_data_file(file.filename);
537 begin_lineno_store = pcs->begin_lineno;
538 pcs->begin_lineno = 0;
540 if (fmt == FMT_DAT) {
541 short *t;
542 int i;
543 settings *pcsNew;
545 pcsNew = osnew(settings);
546 *pcsNew = *pcs; /* copy contents */
547 pcsNew->begin_lineno = 0;
548 pcsNew->next = pcs;
549 pcs = pcsNew;
550 default_units(pcs);
551 default_calib(pcs);
553 pcs->style = STYLE_NORMAL;
554 pcs->units[Q_LENGTH] = METRES_PER_FOOT;
555 t = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
557 t[EOF] = SPECIAL_EOL;
558 memset(t, 0, sizeof(short) * 33);
559 for (i = 33; i < 127; i++) t[i] = SPECIAL_NAMES;
560 t[127] = 0;
561 for (i = 128; i < 256; i++) t[i] = SPECIAL_NAMES;
562 t['\t'] |= SPECIAL_BLANK;
563 t[' '] |= SPECIAL_BLANK;
564 t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */
565 t['\n'] |= SPECIAL_EOL;
566 t['\r'] |= SPECIAL_EOL;
567 t['.'] |= SPECIAL_DECIMAL;
568 t['-'] |= SPECIAL_MINUS;
569 t['+'] |= SPECIAL_PLUS;
570 pcs->Translate = t;
571 pcs->Case = OFF;
572 pcs->Truncate = INT_MAX;
573 pcs->infer = BIT(INFER_EQUATES)|BIT(INFER_EXPORTS)|BIT(INFER_PLUMBS);
574 } else if (fmt == FMT_MAK) {
575 short *t;
576 int i;
577 settings *pcsNew;
579 pcsNew = osnew(settings);
580 *pcsNew = *pcs; /* copy contents */
581 pcsNew->begin_lineno = 0;
582 pcsNew->next = pcs;
583 pcs = pcsNew;
585 t = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
587 t[EOF] = SPECIAL_EOL;
588 memset(t, 0, sizeof(short) * 33);
589 for (i = 33; i < 127; i++) t[i] = SPECIAL_NAMES;
590 t[127] = 0;
591 for (i = 128; i < 256; i++) t[i] = SPECIAL_NAMES;
592 t['['] = t[','] = t[';'] = 0;
593 t['\t'] |= SPECIAL_BLANK;
594 t[' '] |= SPECIAL_BLANK;
595 t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */
596 t['\n'] |= SPECIAL_EOL;
597 t['\r'] |= SPECIAL_EOL;
598 t['.'] |= SPECIAL_DECIMAL;
599 t['-'] |= SPECIAL_MINUS;
600 t['+'] |= SPECIAL_PLUS;
601 pcs->Translate = t;
602 pcs->Case = OFF;
603 pcs->Truncate = INT_MAX;
606 #ifdef HAVE_SETJMP_H
607 /* errors in nested functions can longjmp here */
608 if (setjmp(file.jbSkipLine)) {
609 skipline();
610 process_eol();
612 #endif
614 if (fmt == FMT_DAT) {
615 while (ch != EOF && !ferror(file.fh)) {
616 static const reading compass_order[] = {
617 Fr, To, Tape, CompassDATComp, CompassDATClino,
618 CompassDATLeft, CompassDATRight, CompassDATUp, CompassDATDown,
619 CompassDATFlags, IgnoreAll
621 static const reading compass_order_backsights[] = {
622 Fr, To, Tape, CompassDATComp, CompassDATClino,
623 CompassDATLeft, CompassDATRight, CompassDATUp, CompassDATDown,
624 CompassDATBackComp, CompassDATBackClino,
625 CompassDATFlags, IgnoreAll
627 /* <Cave name> */
628 skipline();
629 process_eol();
630 /* SURVEY NAME: <Short name> */
631 get_token();
632 get_token();
633 /* if (ch != ':') ... */
634 nextch();
635 get_token();
636 skipline();
637 process_eol();
638 /* SURVEY DATE: 7 10 79 COMMENT:<Long name> */
639 get_token();
640 get_token();
641 copy_on_write_meta(pcs);
642 if (ch == ':') {
643 int year, month, day;
645 nextch();
647 /* NB order is *month* *day* year */
648 month = read_uint();
649 day = read_uint();
650 year = read_uint();
651 /* Note: Larry says a 2 digit year is always 19XX */
652 if (year < 100) year += 1900;
654 pcs->meta->days1 = pcs->meta->days2 = days_since_1900(year, month, day);
655 } else {
656 pcs->meta->days1 = pcs->meta->days2 = -1;
658 pcs->declination = HUGE_REAL;
659 skipline();
660 process_eol();
661 /* SURVEY TEAM: */
662 get_token();
663 get_token();
664 skipline();
665 process_eol();
666 /* <Survey team> */
667 skipline();
668 process_eol();
669 /* DECLINATION: 1.00 FORMAT: DDDDLUDRADLN CORRECTIONS: 2.00 3.00 4.00 */
670 get_token();
671 nextch(); /* : */
672 skipblanks();
673 pcs->z[Q_DECLINATION] = -read_numeric(fFalse);
674 pcs->z[Q_DECLINATION] *= pcs->units[Q_DECLINATION];
675 get_token();
676 pcs->ordering = compass_order;
677 if (strcmp(buffer, "FORMAT") == 0) {
678 nextch(); /* : */
679 get_token();
680 if (strlen(buffer) >= 12 && buffer[11] == 'B') {
681 /* We have backsights for compass and clino */
682 pcs->ordering = compass_order_backsights;
684 get_token();
686 if (strcmp(buffer, "CORRECTIONS") == 0) {
687 nextch(); /* : */
688 pcs->z[Q_BEARING] = -rad(read_numeric(fFalse));
689 pcs->z[Q_GRADIENT] = -rad(read_numeric(fFalse));
690 pcs->z[Q_LENGTH] = -read_numeric(fFalse);
691 } else {
692 pcs->z[Q_BEARING] = 0;
693 pcs->z[Q_GRADIENT] = 0;
694 pcs->z[Q_LENGTH] = 0;
696 skipline();
697 process_eol();
698 /* BLANK LINE */
699 skipline();
700 process_eol();
701 /* heading line */
702 skipline();
703 process_eol();
704 /* BLANK LINE */
705 skipline();
706 process_eol();
707 while (ch != EOF) {
708 if (ch == '\x0c') {
709 nextch();
710 process_eol();
711 break;
713 data_normal();
715 clear_last_leg();
718 settings *pcsParent = pcs->next;
719 SVX_ASSERT(pcsParent);
720 pcs->ordering = NULL;
721 free_settings(pcs);
722 pcs = pcsParent;
724 } else if (fmt == FMT_MAK) {
725 nextch_handling_eol();
726 while (ch != EOF && !ferror(file.fh)) {
727 if (ch == '#') {
728 /* include a file */
729 int ch_store;
730 char *dat_pth = path_from_fnm(file.filename);
731 char *dat_fnm = NULL;
732 int dat_fnm_len;
733 nextch_handling_eol();
734 while (ch != ',' && ch != ';' && ch != EOF) {
735 while (isEol(ch)) process_eol();
736 s_catchar(&dat_fnm, &dat_fnm_len, (char)ch);
737 nextch_handling_eol();
739 while (ch != ';' && ch != EOF) {
740 prefix *name;
741 nextch_handling_eol();
742 name = read_prefix(PFX_STATION|PFX_OPT);
743 if (name) {
744 skipblanks();
745 if (ch == '[') {
746 /* fixed pt */
747 node *stn;
748 real x, y, z;
749 name->sflags |= BIT(SFLAGS_FIXED);
750 nextch_handling_eol();
751 while (!isdigit(ch) && ch != '+' && ch != '-' &&
752 ch != '.' && ch != ']' && ch != EOF) {
753 nextch_handling_eol();
755 x = read_numeric(fFalse);
756 while (!isdigit(ch) && ch != '+' && ch != '-' &&
757 ch != '.' && ch != ']' && ch != EOF) {
758 nextch_handling_eol();
760 y = read_numeric(fFalse);
761 while (!isdigit(ch) && ch != '+' && ch != '-' &&
762 ch != '.' && ch != ']' && ch != EOF) {
763 nextch_handling_eol();
765 z = read_numeric(fFalse);
766 stn = StnFromPfx(name);
767 if (!fixed(stn)) {
768 POS(stn, 0) = x;
769 POS(stn, 1) = y;
770 POS(stn, 2) = z;
771 fix(stn);
772 } else {
773 if (x != POS(stn, 0) || y != POS(stn, 1) ||
774 z != POS(stn, 2)) {
775 compile_diagnostic(DIAG_ERR, /*Station already fixed or equated to a fixed point*/46);
776 } else {
777 compile_diagnostic(DIAG_WARN, /*Station already fixed at the same coordinates*/55);
780 while (ch != ']' && ch != EOF) nextch_handling_eol();
781 if (ch == ']') {
782 nextch_handling_eol();
783 skipblanks();
785 } else {
786 /* FIXME: link station - ignore for now */
787 /* FIXME: perhaps issue warning? */
789 while (ch != ',' && ch != ';' && ch != EOF)
790 nextch_handling_eol();
793 if (dat_fnm) {
794 ch_store = ch;
795 data_file(dat_pth, dat_fnm);
796 ch = ch_store;
797 osfree(dat_fnm);
799 } else {
800 /* FIXME: also check for % and $ later */
801 nextch_handling_eol();
805 settings *pcsParent = pcs->next;
806 SVX_ASSERT(pcsParent);
807 free_settings(pcs);
808 pcs = pcsParent;
810 } else {
811 while (ch != EOF && !ferror(file.fh)) {
812 if (!process_non_data_line()) {
813 f_export_ok = fFalse;
814 switch (pcs->style) {
815 case STYLE_NORMAL:
816 case STYLE_DIVING:
817 case STYLE_CYLPOLAR:
818 data_normal();
819 break;
820 case STYLE_CARTESIAN:
821 data_cartesian();
822 break;
823 case STYLE_PASSAGE:
824 data_passage();
825 break;
826 case STYLE_NOSURVEY:
827 data_nosurvey();
828 break;
829 case STYLE_IGNORE:
830 data_ignore();
831 break;
832 default:
833 BUG("bad style");
837 clear_last_leg();
840 /* don't allow *BEGIN at the end of a file, then *EXPORT in the
841 * including file */
842 f_export_ok = fFalse;
844 if (pcs->begin_lineno) {
845 error_in_file(file.filename, pcs->begin_lineno,
846 /*BEGIN with no matching END in this file*/23);
847 /* Implicitly close any unclosed BEGINs from this file */
848 do {
849 settings *pcsParent = pcs->next;
850 SVX_ASSERT(pcsParent);
851 free_settings(pcs);
852 pcs = pcsParent;
853 } while (pcs->begin_lineno);
856 pcs->begin_lineno = begin_lineno_store;
858 if (ferror(file.fh))
859 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
861 (void)fclose(file.fh);
863 file = file_store;
865 /* don't free this - it may be pointed to by prefix.file */
866 /* osfree(file.filename); */
869 static real
870 mod2pi(real a)
872 return a - floor(a / (2 * M_PI)) * (2 * M_PI);
875 static real
876 handle_plumb(clino_type *p_ctype)
878 typedef enum {
879 CLINO_NULL=-1, CLINO_UP, CLINO_DOWN, CLINO_LEVEL
880 } clino_tok;
881 static const sztok clino_tab[] = {
882 {"D", CLINO_DOWN},
883 {"DOWN", CLINO_DOWN},
884 {"H", CLINO_LEVEL},
885 {"LEVEL", CLINO_LEVEL},
886 {"U", CLINO_UP},
887 {"UP", CLINO_UP},
888 {NULL, CLINO_NULL}
890 static const real clinos[] = {(real)M_PI_2, (real)(-M_PI_2), (real)0.0};
891 clino_tok tok;
893 skipblanks();
894 if (isalpha(ch)) {
895 filepos fp;
896 get_pos(&fp);
897 get_token();
898 tok = match_tok(clino_tab, TABSIZE(clino_tab));
899 if (tok != CLINO_NULL) {
900 *p_ctype = (tok == CLINO_LEVEL ? CTYPE_HORIZ : CTYPE_PLUMB);
901 return clinos[tok];
903 set_pos(&fp);
904 } else if (isSign(ch)) {
905 int chOld = ch;
906 nextch();
907 if (toupper(ch) == 'V') {
908 nextch();
909 *p_ctype = CTYPE_PLUMB;
910 return (!isMinus(chOld) ? M_PI_2 : -M_PI_2);
913 if (isOmit(chOld)) {
914 *p_ctype = CTYPE_OMIT;
915 /* no clino reading, so assume 0 with large sd */
916 return (real)0.0;
918 } else if (isOmit(ch)) {
919 /* OMIT char may not be a SIGN char too so we need to check here as
920 * well as above... */
921 nextch();
922 *p_ctype = CTYPE_OMIT;
923 /* no clino reading, so assume 0 with large sd */
924 return (real)0.0;
926 return HUGE_REAL;
929 static void
930 warn_readings_differ(int msgno, real diff, int units)
932 char buf[64];
933 char *p;
934 diff /= get_units_factor(units);
935 sprintf(buf, "%.2f", fabs(diff));
936 for (p = buf; *p; ++p) {
937 if (*p == '.') {
938 char *z = p;
939 while (*++p) {
940 if (*p != '0') z = p + 1;
942 p = z;
943 break;
946 strcpy(p, get_units_string(units));
947 compile_diagnostic(DIAG_WARN, msgno, buf);
950 static bool
951 handle_comp_units(void)
953 bool fNoComp = fTrue;
954 if (VAL(Comp) != HUGE_REAL) {
955 fNoComp = fFalse;
956 VAL(Comp) *= pcs->units[Q_BEARING];
957 if (VAL(Comp) < (real)0.0 || VAL(Comp) - M_PI * 2.0 > EPSILON) {
958 /* TRANSLATORS: Suspicious means something like 410 degrees or -20
959 * degrees */
960 compile_diagnostic_reading(DIAG_WARN, Comp, /*Suspicious compass reading*/59);
961 VAL(Comp) = mod2pi(VAL(Comp));
964 if (VAL(BackComp) != HUGE_REAL) {
965 fNoComp = fFalse;
966 VAL(BackComp) *= pcs->units[Q_BACKBEARING];
967 if (VAL(BackComp) < (real)0.0 || VAL(BackComp) - M_PI * 2.0 > EPSILON) {
968 /* FIXME: different message for BackComp? */
969 compile_diagnostic_reading(DIAG_WARN, BackComp, /*Suspicious compass reading*/59);
970 VAL(BackComp) = mod2pi(VAL(BackComp));
973 return fNoComp;
976 static real
977 handle_compass(real *p_var)
979 real compvar = VAR(Comp);
980 real comp = VAL(Comp);
981 real backcomp = VAL(BackComp);
982 real declination;
983 if (pcs->z[Q_DECLINATION] != HUGE_REAL) {
984 declination = -pcs->z[Q_DECLINATION];
985 } else if (pcs->declination != HUGE_REAL) {
986 /* Cached value calculated for a previous compass reading taken on the
987 * same date (by the 'else' just below).
989 declination = pcs->declination;
990 } else {
991 if (!pcs->meta || pcs->meta->days1 == -1) {
992 compile_diagnostic(DIAG_WARN, /*No survey date specified - using 0 for magnetic declination*/304);
993 declination = 0;
994 } else {
995 int avg_days = (pcs->meta->days1 + pcs->meta->days2) / 2;
996 double dat = julian_date_from_days_since_1900(avg_days);
997 /* thgeomag() takes (lat, lon, h, dat) - i.e. (y, x, z, date). */
998 declination = thgeomag(pcs->dec_y, pcs->dec_x, pcs->dec_z, dat);
1000 declination -= pcs->convergence;
1001 /* We cache the calculated declination as the calculation is relatively
1002 * expensive. We also cache an "assumed 0" answer so that we only
1003 * warn once per such survey rather than for every line with a compass
1004 * reading. */
1005 pcs->declination = declination;
1007 if (comp != HUGE_REAL) {
1008 comp = (comp - pcs->z[Q_BEARING]) * pcs->sc[Q_BEARING];
1009 comp += declination;
1011 if (backcomp != HUGE_REAL) {
1012 backcomp = (backcomp - pcs->z[Q_BACKBEARING])
1013 * pcs->sc[Q_BACKBEARING];
1014 backcomp += declination;
1015 backcomp -= M_PI;
1016 if (comp != HUGE_REAL) {
1017 real diff = comp - backcomp;
1018 real adj = fabs(diff) > M_PI ? M_PI : 0;
1019 diff -= floor((diff + M_PI) / (2 * M_PI)) * 2 * M_PI;
1020 if (sqrd(diff / 3.0) > compvar + VAR(BackComp)) {
1021 /* fore and back readings differ by more than 3 sds */
1022 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1023 * by, e.g. "2.5Ā°" or "3įµ". */
1024 warn_readings_differ(/*COMPASS reading and BACKCOMPASS reading disagree by %s*/98,
1025 diff, get_angle_units(Q_BEARING));
1027 comp = (comp / compvar + backcomp / VAR(BackComp));
1028 compvar = (compvar + VAR(BackComp)) / 4;
1029 comp *= compvar;
1030 comp += adj;
1031 } else {
1032 comp = backcomp;
1033 compvar = VAR(BackComp);
1036 *p_var = compvar;
1037 return comp;
1040 static real
1041 handle_clino(q_quantity q, reading r, real val, bool percent, clino_type *p_ctype)
1043 bool range_0_180;
1044 real z;
1045 real diff_from_abs90;
1046 val *= pcs->units[q];
1047 /* percentage scale */
1048 if (percent) val = atan(val);
1049 /* We want to warn if there's a reading which it would be impossible
1050 * to have read from the instrument (e.g. on a -90 to 90 degree scale
1051 * you can't read "96" (it's probably a typo for "69"). However, the
1052 * gradient reading from a topofil is typically in the range 0 to 180,
1053 * with 90 being horizontal.
1055 * Really we should allow the valid range to be specified, but for now
1056 * we infer it from the zero error - if this is within 45 degrees of
1057 * 90 then we assume the range is 0 to 180.
1059 z = pcs->z[q];
1060 range_0_180 = (z > M_PI_4 && z < 3*M_PI_4);
1061 diff_from_abs90 = fabs(val) - M_PI_2;
1062 if (diff_from_abs90 > EPSILON) {
1063 if (!range_0_180) {
1064 int clino_units = get_angle_units(q);
1065 const char * units = get_units_string(clino_units);
1066 real right_angle = M_PI_2 / get_units_factor(clino_units);
1067 /* FIXME: different message for BackClino? */
1068 /* TRANSLATORS: %.f%s will be replaced with a right angle in the
1069 * units currently in use, e.g. "90Ā°" or "100įµ". And "absolute
1070 * value" means the reading ignoring the sign (so it might be
1071 * < -90Ā° or > 90Ā°. */
1072 compile_diagnostic_reading(DIAG_WARN, r, /*Clino reading over %.f%s (absolute value)*/51,
1073 right_angle, units);
1075 } else if (TSTBIT(pcs->infer, INFER_PLUMBS) &&
1076 diff_from_abs90 >= -EPSILON) {
1077 *p_ctype = CTYPE_INFERPLUMB;
1079 if (range_0_180 && *p_ctype != CTYPE_INFERPLUMB) {
1080 /* FIXME: Warning message not ideal... */
1081 if (val < 0.0 || val - M_PI > EPSILON) {
1082 int clino_units = get_angle_units(q);
1083 const char * units = get_units_string(clino_units);
1084 real right_angle = M_PI_2 / get_units_factor(clino_units);
1085 compile_diagnostic_reading(DIAG_WARN, r, /*Clino reading over %.f%s (absolute value)*/51,
1086 right_angle, units);
1089 return val;
1092 static int
1093 process_normal(prefix *fr, prefix *to, bool fToFirst,
1094 clino_type ctype, clino_type backctype)
1096 real tape = VAL(Tape);
1097 real clin = VAL(Clino);
1098 real backclin = VAL(BackClino);
1100 real dx, dy, dz;
1101 real vx, vy, vz;
1102 #ifndef NO_COVARIANCES
1103 real cxy, cyz, czx;
1104 #endif
1106 bool fNoComp;
1108 /* adjusted tape is negative -- probably the calibration is wrong */
1109 if (tape < (real)0.0) {
1110 /* TRANSLATE different message for topofil? */
1111 compile_diagnostic_reading(DIAG_WARN, Tape, /*Negative adjusted tape reading*/79);
1114 fNoComp = handle_comp_units();
1116 if (ctype == CTYPE_READING) {
1117 clin = handle_clino(Q_GRADIENT, Clino, clin,
1118 pcs->f_clino_percent, &ctype);
1121 if (backctype == CTYPE_READING) {
1122 backclin = handle_clino(Q_BACKGRADIENT, BackClino, backclin,
1123 pcs->f_backclino_percent, &backctype);
1126 /* un-infer the plumb if the backsight was just a reading */
1127 if (ctype == CTYPE_INFERPLUMB && backctype == CTYPE_READING) {
1128 ctype = CTYPE_READING;
1131 if (ctype != CTYPE_OMIT && backctype != CTYPE_OMIT && ctype != backctype) {
1132 /* TRANSLATORS: In data with backsights, the user has tried to give a
1133 * plumb for the foresight and a clino reading for the backsight, or
1134 * something similar. */
1135 compile_error_reading_skip(Clino, /*CLINO and BACKCLINO readings must be of the same type*/84);
1136 return 0;
1139 if (ctype == CTYPE_PLUMB || ctype == CTYPE_INFERPLUMB ||
1140 backctype == CTYPE_PLUMB || backctype == CTYPE_INFERPLUMB) {
1141 /* plumbed */
1142 if (!fNoComp) {
1143 if (ctype == CTYPE_PLUMB ||
1144 (ctype == CTYPE_INFERPLUMB && VAL(Comp) != 0.0) ||
1145 backctype == CTYPE_PLUMB ||
1146 (backctype == CTYPE_INFERPLUMB && VAL(BackComp) != 0.0)) {
1147 /* FIXME: Different message for BackComp? */
1148 /* TRANSLATORS: A "plumbed leg" is one measured using a plumbline
1149 * (a weight on a string). So the problem here is that the leg is
1150 * vertical, so a compass reading has no meaning! */
1151 compile_diagnostic(DIAG_WARN, /*Compass reading given on plumbed leg*/21);
1155 dx = dy = (real)0.0;
1156 if (ctype != CTYPE_OMIT) {
1157 if (backctype != CTYPE_OMIT && (clin > 0) == (backclin > 0)) {
1158 /* TRANSLATORS: We've been told the foresight and backsight are
1159 * both "UP", or that they're both "DOWN". */
1160 compile_error_reading_skip(Clino, /*Plumbed CLINO and BACKCLINO readings can't be in the same direction*/92);
1161 return 0;
1163 dz = (clin > (real)0.0) ? tape : -tape;
1164 } else {
1165 dz = (backclin < (real)0.0) ? tape : -tape;
1167 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1168 vz = var(Q_POS) / 3.0 + VAR(Tape);
1169 #ifndef NO_COVARIANCES
1170 /* Correct values - no covariances in this case! */
1171 cxy = cyz = czx = (real)0.0;
1172 #endif
1173 } else {
1174 /* Each of ctype and backctype are either CTYPE_READING/CTYPE_HORIZ
1175 * or CTYPE_OMIT */
1176 /* clino */
1177 real L2, cosG, LcosG, cosG2, sinB, cosB, dx2, dy2, dz2, v, V;
1178 if (fNoComp) {
1179 /* TRANSLATORS: Here "legs" are survey legs, i.e. measurements between
1180 * survey stations. */
1181 compile_error_reading_skip(Comp, /*Compass reading may not be omitted except on plumbed legs*/14);
1182 return 0;
1184 if (tape == (real)0.0) {
1185 dx = dy = dz = (real)0.0;
1186 vx = vy = vz = (real)(var(Q_POS) / 3.0); /* Position error only */
1187 #ifndef NO_COVARIANCES
1188 cxy = cyz = czx = (real)0.0;
1189 #endif
1190 #if DEBUG_DATAIN_1
1191 printf("Zero length leg: vx = %f, vy = %f, vz = %f\n", vx, vy, vz);
1192 #endif
1193 } else {
1194 real sinGcosG;
1195 /* take into account variance in LEVEL case */
1196 real var_clin = var(Q_LEVEL);
1197 real var_comp;
1198 real comp = handle_compass(&var_comp);
1199 /* ctype != CTYPE_READING is LEVEL case */
1200 if (ctype == CTYPE_READING) {
1201 clin = (clin - pcs->z[Q_GRADIENT]) * pcs->sc[Q_GRADIENT];
1202 var_clin = VAR(Clino);
1204 if (backctype == CTYPE_READING) {
1205 backclin = (backclin - pcs->z[Q_BACKGRADIENT])
1206 * pcs->sc[Q_BACKGRADIENT];
1207 if (ctype == CTYPE_READING) {
1208 if (sqrd((clin + backclin) / 3.0) > var_clin + VAR(BackClino)) {
1209 /* fore and back readings differ by more than 3 sds */
1210 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1211 * by, e.g. "2.5Ā°" or "3įµ". */
1212 warn_readings_differ(/*CLINO reading and BACKCLINO reading disagree by %s*/99,
1213 clin + backclin, get_angle_units(Q_GRADIENT));
1215 clin = (clin / var_clin - backclin / VAR(BackClino));
1216 var_clin = (var_clin + VAR(BackClino)) / 4;
1217 clin *= var_clin;
1218 } else {
1219 clin = -backclin;
1220 var_clin = VAR(BackClino);
1224 #if DEBUG_DATAIN
1225 printf(" %4.2f %4.2f %4.2f\n", tape, comp, clin);
1226 #endif
1227 cosG = cos(clin);
1228 LcosG = tape * cosG;
1229 sinB = sin(comp);
1230 cosB = cos(comp);
1231 #if DEBUG_DATAIN_1
1232 printf("sinB = %f, cosG = %f, LcosG = %f\n", sinB, cosG, LcosG);
1233 #endif
1234 dx = LcosG * sinB;
1235 dy = LcosG * cosB;
1236 dz = tape * sin(clin);
1237 /* printf("%.2f\n",clin); */
1238 #if DEBUG_DATAIN_1
1239 printf("dx = %f\ndy = %f\ndz = %f\n", dx, dy, dz);
1240 #endif
1241 dx2 = dx * dx;
1242 L2 = tape * tape;
1243 V = VAR(Tape) / L2;
1244 dy2 = dy * dy;
1245 cosG2 = cosG * cosG;
1246 sinGcosG = sin(clin) * cosG;
1247 dz2 = dz * dz;
1248 v = dz2 * var_clin;
1249 #ifdef NO_COVARIANCES
1250 vx = (var(Q_POS) / 3.0 + dx2 * V + dy2 * var_comp +
1251 (.5 + sinB * sinB * cosG2) * v);
1252 vy = (var(Q_POS) / 3.0 + dy2 * V + dx2 * var_comp +
1253 (.5 + cosB * cosB * cosG2) * v);
1254 if (ctype == CTYPE_OMIT && backctype == CTYPE_OMIT) {
1255 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1256 vz = var(Q_POS) / 3.0 + L2 * (real)0.1;
1257 } else {
1258 vz = var(Q_POS) / 3.0 + dz2 * V + L2 * cosG2 * var_clin;
1260 /* for Surveyor87 errors: vx=vy=vz=var(Q_POS)/3.0; */
1261 #else
1262 vx = var(Q_POS) / 3.0 + dx2 * V + dy2 * var_comp +
1263 (sinB * sinB * v);
1264 vy = var(Q_POS) / 3.0 + dy2 * V + dx2 * var_comp +
1265 (cosB * cosB * v);
1266 if (ctype == CTYPE_OMIT && backctype == CTYPE_OMIT) {
1267 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1268 vz = var(Q_POS) / 3.0 + L2 * (real)0.1;
1269 } else {
1270 vz = var(Q_POS) / 3.0 + dz2 * V + L2 * cosG2 * var_clin;
1272 /* usual covariance formulae are fine in no clino case since
1273 * dz = 0 so value of var_clin is ignored */
1274 cxy = sinB * cosB * (VAR(Tape) * cosG2 + var_clin * dz2)
1275 - var_comp * dx * dy;
1276 czx = VAR(Tape) * sinB * sinGcosG - var_clin * dx * dz;
1277 cyz = VAR(Tape) * cosB * sinGcosG - var_clin * dy * dz;
1278 #if 0
1279 printf("vx = %6.3f, vy = %6.3f, vz = %6.3f\n", vx, vy, vz);
1280 printf("cxy = %6.3f, cyz = %6.3f, czx = %6.3f\n", cxy, cyz, czx);
1281 #endif
1282 #endif
1283 #if DEBUG_DATAIN_1
1284 printf("In DATAIN.C, vx = %f, vy = %f, vz = %f\n", vx, vy, vz);
1285 #endif
1288 #if DEBUG_DATAIN_1
1289 printf("Just before addleg, vx = %f\n", vx);
1290 #endif
1291 /*printf("dx,dy,dz = %.2f %.2f %.2f\n\n", dx, dy, dz);*/
1292 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1293 #ifndef NO_COVARIANCES
1294 , cyz, czx, cxy
1295 #endif
1297 return 1;
1300 static int
1301 process_diving(prefix *fr, prefix *to, bool fToFirst, bool fDepthChange)
1303 real tape = VAL(Tape);
1305 real dx, dy, dz;
1306 real vx, vy, vz;
1307 #ifndef NO_COVARIANCES
1308 real cxy = 0, cyz = 0, czx = 0;
1309 #endif
1311 handle_comp_units();
1313 /* depth gauge readings increase upwards with default calibration */
1314 if (fDepthChange) {
1315 SVX_ASSERT(VAL(FrDepth) == 0.0);
1316 dz = VAL(ToDepth) * pcs->units[Q_DEPTH] - pcs->z[Q_DEPTH];
1317 dz *= pcs->sc[Q_DEPTH];
1318 } else {
1319 dz = VAL(ToDepth) - VAL(FrDepth);
1320 dz *= pcs->units[Q_DEPTH] * pcs->sc[Q_DEPTH];
1323 /* adjusted tape is negative -- probably the calibration is wrong */
1324 if (tape < (real)0.0) {
1325 compile_diagnostic(DIAG_WARN, /*Negative adjusted tape reading*/79);
1328 /* check if tape is less than depth change */
1329 if (tape < fabs(dz)) {
1330 /* FIXME: allow margin of error based on variances? */
1331 /* TRANSLATORS: This means that the data fed in said this.
1333 * It could be a gross error (e.g. the decimal point is missing from the
1334 * depth gauge reading) or it could just be due to random error on a near
1335 * vertical leg */
1336 compile_diagnostic(DIAG_WARN, /*Tape reading is less than change in depth*/62);
1339 if (tape == (real)0.0 && dz == 0.0) {
1340 dx = dy = dz = (real)0.0;
1341 vx = vy = vz = (real)(var(Q_POS) / 3.0); /* Position error only */
1342 } else if (VAL(Comp) == HUGE_REAL &&
1343 VAL(BackComp) == HUGE_REAL) {
1344 /* plumb */
1345 dx = dy = (real)0.0;
1346 if (dz < 0) tape = -tape;
1347 /* FIXME: Should use FrDepth sometimes... */
1348 dz = (dz * VAR(Tape) + tape * 2 * VAR(ToDepth))
1349 / (VAR(Tape) * 2 * VAR(ToDepth));
1350 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1351 /* FIXME: Should use FrDepth sometimes... */
1352 vz = var(Q_POS) / 3.0 + VAR(Tape) * 2 * VAR(ToDepth)
1353 / (VAR(Tape) + VAR(ToDepth));
1354 } else {
1355 real L2, sinB, cosB, dz2, D2;
1356 real var_comp;
1357 real comp = handle_compass(&var_comp);
1358 sinB = sin(comp);
1359 cosB = cos(comp);
1360 L2 = tape * tape;
1361 dz2 = dz * dz;
1362 D2 = L2 - dz2;
1363 if (D2 <= (real)0.0) {
1364 /* FIXME: Should use FrDepth sometimes... */
1365 real vsum = VAR(Tape) + 2 * VAR(ToDepth);
1366 dx = dy = (real)0.0;
1367 vx = vy = var(Q_POS) / 3.0;
1368 /* FIXME: Should use FrDepth sometimes... */
1369 vz = var(Q_POS) / 3.0 + VAR(Tape) * 2 * VAR(ToDepth) / vsum;
1370 if (dz > 0) {
1371 /* FIXME: Should use FrDepth sometimes... */
1372 dz = (dz * VAR(Tape) + tape * 2 * VAR(ToDepth)) / vsum;
1373 } else {
1374 dz = (dz * VAR(Tape) - tape * 2 * VAR(ToDepth)) / vsum;
1376 } else {
1377 real D = sqrt(D2);
1378 /* FIXME: Should use FrDepth sometimes... */
1379 real F = VAR(Tape) * L2 + 2 * VAR(ToDepth) * D2;
1380 dx = D * sinB;
1381 dy = D * cosB;
1383 vx = var(Q_POS) / 3.0 +
1384 sinB * sinB * F / D2 + var_comp * dy * dy;
1385 vy = var(Q_POS) / 3.0 +
1386 cosB * cosB * F / D2 + var_comp * dx * dx;
1387 /* FIXME: Should use FrDepth sometimes... */
1388 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1390 #ifndef NO_COVARIANCES
1391 cxy = sinB * cosB * (F / D2 + var_comp * D2);
1392 /* FIXME: Should use FrDepth sometimes... */
1393 cyz = -2 * VAR(ToDepth) * dy / D;
1394 czx = -2 * VAR(ToDepth) * dx / D;
1395 #endif
1397 /* FIXME: If there's a clino reading, check it against the depth reading,
1398 * and average.
1399 * if (VAL(Clino) != HUGE_REAL || VAL(BackClino) != HUGE_REAL) { ... }
1402 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1403 #ifndef NO_COVARIANCES
1404 , cxy, cyz, czx
1405 #endif
1407 return 1;
1410 static int
1411 process_cartesian(prefix *fr, prefix *to, bool fToFirst)
1413 real dx = (VAL(Dx) * pcs->units[Q_DX] - pcs->z[Q_DX]) * pcs->sc[Q_DX];
1414 real dy = (VAL(Dy) * pcs->units[Q_DY] - pcs->z[Q_DY]) * pcs->sc[Q_DY];
1415 real dz = (VAL(Dz) * pcs->units[Q_DZ] - pcs->z[Q_DZ]) * pcs->sc[Q_DZ];
1417 addlegbyname(fr, to, fToFirst, dx, dy, dz, VAR(Dx), VAR(Dy), VAR(Dz)
1418 #ifndef NO_COVARIANCES
1419 , 0, 0, 0
1420 #endif
1422 return 1;
1425 static void
1426 data_cartesian(void)
1428 prefix *fr = NULL, *to = NULL;
1430 bool fMulti = fFalse;
1432 reading first_stn = End;
1434 const reading *ordering;
1436 again:
1438 for (ordering = pcs->ordering ; ; ordering++) {
1439 skipblanks();
1440 switch (*ordering) {
1441 case Fr:
1442 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
1443 if (first_stn == End) first_stn = Fr;
1444 break;
1445 case To:
1446 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
1447 if (first_stn == End) first_stn = To;
1448 break;
1449 case Station:
1450 fr = to;
1451 to = read_prefix(PFX_STATION);
1452 first_stn = To;
1453 break;
1454 case Dx: case Dy: case Dz:
1455 read_reading(*ordering, fFalse);
1456 break;
1457 case Ignore:
1458 skipword(); break;
1459 case IgnoreAllAndNewLine:
1460 skipline();
1461 /* fall through */
1462 case Newline:
1463 if (fr != NULL) {
1464 if (!process_cartesian(fr, to, first_stn == To))
1465 skipline();
1467 fMulti = fTrue;
1468 while (1) {
1469 process_eol();
1470 skipblanks();
1471 if (isData(ch)) break;
1472 if (!isComm(ch)) {
1473 return;
1476 break;
1477 case IgnoreAll:
1478 skipline();
1479 /* fall through */
1480 case End:
1481 if (!fMulti) {
1482 process_cartesian(fr, to, first_stn == To);
1483 process_eol();
1484 return;
1486 do {
1487 process_eol();
1488 skipblanks();
1489 } while (isComm(ch));
1490 goto again;
1491 default: BUG("Unknown reading in ordering");
1496 static int
1497 process_cylpolar(prefix *fr, prefix *to, bool fToFirst, bool fDepthChange)
1499 real tape = VAL(Tape);
1501 real dx, dy, dz;
1502 real vx, vy, vz;
1503 #ifndef NO_COVARIANCES
1504 real cxy = 0;
1505 #endif
1507 handle_comp_units();
1509 /* depth gauge readings increase upwards with default calibration */
1510 if (fDepthChange) {
1511 SVX_ASSERT(VAL(FrDepth) == 0.0);
1512 dz = VAL(ToDepth) * pcs->units[Q_DEPTH] - pcs->z[Q_DEPTH];
1513 dz *= pcs->sc[Q_DEPTH];
1514 } else {
1515 dz = VAL(ToDepth) - VAL(FrDepth);
1516 dz *= pcs->units[Q_DEPTH] * pcs->sc[Q_DEPTH];
1519 /* adjusted tape is negative -- probably the calibration is wrong */
1520 if (tape < (real)0.0) {
1521 compile_diagnostic(DIAG_WARN, /*Negative adjusted tape reading*/79);
1524 if (VAL(Comp) == HUGE_REAL && VAL(BackComp) == HUGE_REAL) {
1525 /* plumb */
1526 dx = dy = (real)0.0;
1527 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1528 /* FIXME: Should use FrDepth sometimes... */
1529 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1530 } else {
1531 real sinB, cosB;
1532 real var_comp;
1533 real comp = handle_compass(&var_comp);
1534 sinB = sin(comp);
1535 cosB = cos(comp);
1537 dx = tape * sinB;
1538 dy = tape * cosB;
1540 vx = var(Q_POS) / 3.0 +
1541 VAR(Tape) * sinB * sinB + var_comp * dy * dy;
1542 vy = var(Q_POS) / 3.0 +
1543 VAR(Tape) * cosB * cosB + var_comp * dx * dx;
1544 /* FIXME: Should use FrDepth sometimes... */
1545 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1547 #ifndef NO_COVARIANCES
1548 cxy = (VAR(Tape) - var_comp * tape * tape) * sinB * cosB;
1549 #endif
1551 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1552 #ifndef NO_COVARIANCES
1553 , cxy, 0, 0
1554 #endif
1556 return 1;
1559 /* Process tape/compass/clino, diving, and cylpolar styles of survey data
1560 * Also handles topofil (fromcount/tocount or count) in place of tape */
1561 static void
1562 data_normal(void)
1564 prefix *fr = NULL, *to = NULL;
1565 reading first_stn = End;
1567 bool fTopofil = fFalse, fMulti = fFalse;
1568 bool fRev;
1569 clino_type ctype, backctype;
1570 bool fDepthChange;
1571 unsigned long compass_dat_flags = 0;
1573 const reading *ordering;
1575 VAL(Tape) = VAL(BackTape) = HUGE_REAL;
1576 VAL(Comp) = VAL(BackComp) = HUGE_REAL;
1577 VAL(FrCount) = VAL(ToCount) = 0;
1578 VAL(FrDepth) = VAL(ToDepth) = 0;
1579 VAL(Left) = VAL(Right) = VAL(Up) = VAL(Down) = HUGE_REAL;
1581 fRev = fFalse;
1582 ctype = backctype = CTYPE_OMIT;
1583 fDepthChange = fFalse;
1585 /* ordering may omit clino reading, so set up default here */
1586 /* this is also used if clino reading is the omit character */
1587 VAL(Clino) = VAL(BackClino) = 0;
1589 again:
1591 /* We clear these flags in the normal course of events, but if there's an
1592 * error in a reading, we might not, so make sure it has been cleared here.
1594 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1595 for (ordering = pcs->ordering; ; ordering++) {
1596 skipblanks();
1597 switch (*ordering) {
1598 case Fr:
1599 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_ANON);
1600 if (first_stn == End) first_stn = Fr;
1601 break;
1602 case To:
1603 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_ANON);
1604 if (first_stn == End) first_stn = To;
1605 break;
1606 case Station:
1607 fr = to;
1608 to = read_prefix(PFX_STATION);
1609 first_stn = To;
1610 break;
1611 case Dir: {
1612 typedef enum {
1613 DIR_NULL=-1, DIR_FORE, DIR_BACK
1614 } dir_tok;
1615 static const sztok dir_tab[] = {
1616 {"B", DIR_BACK},
1617 {"F", DIR_FORE},
1619 dir_tok tok;
1620 get_token();
1621 tok = match_tok(dir_tab, TABSIZE(dir_tab));
1622 switch (tok) {
1623 case DIR_FORE:
1624 break;
1625 case DIR_BACK:
1626 fRev = fTrue;
1627 break;
1628 default:
1629 compile_diagnostic(DIAG_ERR|DIAG_BUF|DIAG_SKIP, /*Found ā€œ%sā€, expecting ā€œFā€ or ā€œBā€*/131, buffer);
1630 process_eol();
1631 return;
1633 break;
1635 case Tape: case BackTape: {
1636 reading r = *ordering;
1637 read_reading(r, fTrue);
1638 if (VAL(r) == HUGE_REAL) {
1639 if (!isOmit(ch)) {
1640 compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found ā€œ%sā€*/9);
1641 /* Avoid also warning about omitted tape reading. */
1642 VAL(r) = 0;
1643 } else {
1644 nextch();
1646 } else if (VAL(r) < (real)0.0) {
1647 compile_diagnostic_reading(DIAG_WARN, r, /*Negative tape reading*/60);
1649 break;
1651 case Count:
1652 VAL(FrCount) = VAL(ToCount);
1653 LOC(FrCount) = LOC(ToCount);
1654 WID(FrCount) = WID(ToCount);
1655 read_reading(ToCount, fFalse);
1656 fTopofil = fTrue;
1657 break;
1658 case FrCount:
1659 read_reading(FrCount, fFalse);
1660 break;
1661 case ToCount:
1662 read_reading(ToCount, fFalse);
1663 fTopofil = fTrue;
1664 break;
1665 case Comp: case BackComp:
1666 read_bearing_or_omit(*ordering);
1667 break;
1668 case Clino: case BackClino: {
1669 reading r = *ordering;
1670 clino_type * p_ctype = (r == Clino ? &ctype : &backctype);
1671 read_reading(r, fTrue);
1672 if (VAL(r) == HUGE_REAL) {
1673 VAL(r) = handle_plumb(p_ctype);
1674 if (VAL(r) != HUGE_REAL) break;
1675 compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found ā€œ%sā€*/9);
1676 skipline();
1677 process_eol();
1678 return;
1680 *p_ctype = CTYPE_READING;
1681 break;
1683 case FrDepth: case ToDepth:
1684 read_reading(*ordering, fFalse);
1685 break;
1686 case Depth:
1687 VAL(FrDepth) = VAL(ToDepth);
1688 LOC(FrDepth) = LOC(ToDepth);
1689 WID(FrDepth) = WID(ToDepth);
1690 read_reading(ToDepth, fFalse);
1691 break;
1692 case DepthChange:
1693 fDepthChange = fTrue;
1694 VAL(FrDepth) = 0;
1695 read_reading(ToDepth, fFalse);
1696 break;
1697 case CompassDATComp:
1698 read_bearing_or_omit(Comp);
1699 if (is_compass_NaN(VAL(Comp))) VAL(Comp) = HUGE_REAL;
1700 break;
1701 case CompassDATBackComp:
1702 read_bearing_or_omit(BackComp);
1703 if (is_compass_NaN(VAL(BackComp))) VAL(BackComp) = HUGE_REAL;
1704 break;
1705 case CompassDATClino: case CompassDATBackClino: {
1706 reading r;
1707 clino_type * p_ctype;
1708 if (*ordering == CompassDATClino) {
1709 r = Clino;
1710 p_ctype = &ctype;
1711 } else {
1712 r = BackClino;
1713 p_ctype = &backctype;
1715 read_reading(r, fFalse);
1716 if (is_compass_NaN(VAL(r))) {
1717 VAL(r) = HUGE_REAL;
1718 *p_ctype = CTYPE_OMIT;
1719 } else {
1720 *p_ctype = CTYPE_READING;
1722 break;
1724 case CompassDATLeft: case CompassDATRight:
1725 case CompassDATUp: case CompassDATDown: {
1726 /* FIXME: need to actually make use of these entries! */
1727 reading actual = Left + (*ordering - CompassDATLeft);
1728 read_reading(actual, fFalse);
1729 if (VAL(actual) < 0) VAL(actual) = HUGE_REAL;
1730 break;
1732 case CompassDATFlags:
1733 if (ch == '#') {
1734 filepos fp;
1735 get_pos(&fp);
1736 nextch();
1737 if (ch == '|') {
1738 nextch();
1739 while (ch >= 'A' && ch <= 'Z') {
1740 compass_dat_flags |= BIT(ch - 'A');
1741 /* We currently understand:
1742 * L (exclude from length)
1743 * X (exclude data)
1744 * FIXME: but should also handle at least some of:
1745 * C (no adjustment) (set all (co)variances to 0?)
1746 * P (no plot) (new flag in 3d for "hidden by default"?)
1748 nextch();
1750 if (ch == '#') {
1751 nextch();
1752 } else {
1753 compass_dat_flags = 0;
1754 set_pos(&fp);
1756 } else {
1757 set_pos(&fp);
1760 break;
1761 case Ignore:
1762 skipword(); break;
1763 case IgnoreAllAndNewLine:
1764 skipline();
1765 /* fall through */
1766 case Newline:
1767 if (fr != NULL) {
1768 int r;
1769 int save_flags;
1770 int implicit_splay;
1771 if (fTopofil) {
1772 VAL(Tape) = VAL(ToCount) - VAL(FrCount);
1773 LOC(Tape) = LOC(ToCount);
1774 WID(Tape) = WID(ToCount);
1776 /* Note: frdepth == todepth test works regardless of fDepthChange
1777 * (frdepth always zero, todepth is change of depth) and also
1778 * works for STYLE_NORMAL (both remain 0) */
1779 if (TSTBIT(pcs->infer, INFER_EQUATES) &&
1780 (VAL(Tape) == (real)0.0 || VAL(Tape) == HUGE_REAL) &&
1781 (VAL(BackTape) == (real)0.0 || VAL(BackTape) == HUGE_REAL) &&
1782 VAL(FrDepth) == VAL(ToDepth)) {
1783 process_equate(fr, to);
1784 goto inferred_equate;
1786 if (fRev) {
1787 prefix *t = fr;
1788 fr = to;
1789 to = t;
1791 if (fTopofil) {
1792 VAL(Tape) *= pcs->units[Q_COUNT] * pcs->sc[Q_COUNT];
1793 } else if (VAL(Tape) != HUGE_REAL) {
1794 VAL(Tape) *= pcs->units[Q_LENGTH];
1795 VAL(Tape) -= pcs->z[Q_LENGTH];
1796 VAL(Tape) *= pcs->sc[Q_LENGTH];
1798 if (VAL(BackTape) != HUGE_REAL) {
1799 VAL(BackTape) *= pcs->units[Q_BACKLENGTH];
1800 VAL(BackTape) -= pcs->z[Q_BACKLENGTH];
1801 VAL(BackTape) *= pcs->sc[Q_BACKLENGTH];
1802 if (VAL(Tape) != HUGE_REAL) {
1803 real diff = VAL(Tape) - VAL(BackTape);
1804 if (sqrd(diff / 3.0) > VAR(Tape) + VAR(BackTape)) {
1805 /* fore and back readings differ by more than 3 sds */
1806 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1807 * by, e.g. "0.12m" or "0.2ft". */
1808 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1809 diff, get_length_units(Q_LENGTH));
1811 VAL(Tape) = VAL(Tape) / VAR(Tape) + VAL(BackTape) / VAR(BackTape);
1812 VAR(Tape) = (VAR(Tape) + VAR(BackTape)) / 4;
1813 VAL(Tape) *= VAR(Tape);
1814 } else {
1815 VAL(Tape) = VAL(BackTape);
1816 VAR(Tape) = VAR(BackTape);
1818 } else if (VAL(Tape) == HUGE_REAL) {
1819 compile_diagnostic_reading(DIAG_ERR, Tape, /*Tape reading may not be omitted*/94);
1820 goto inferred_equate;
1822 implicit_splay = TSTBIT(pcs->flags, FLAGS_IMPLICIT_SPLAY);
1823 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1824 save_flags = pcs->flags;
1825 if (implicit_splay) {
1826 pcs->flags |= BIT(FLAGS_SPLAY);
1828 switch (pcs->style) {
1829 case STYLE_NORMAL:
1830 r = process_normal(fr, to, (first_stn == To) ^ fRev,
1831 ctype, backctype);
1832 break;
1833 case STYLE_DIVING:
1834 /* FIXME: Handle any clino readings */
1835 r = process_diving(fr, to, (first_stn == To) ^ fRev,
1836 fDepthChange);
1837 break;
1838 case STYLE_CYLPOLAR:
1839 r = process_cylpolar(fr, to, (first_stn == To) ^ fRev,
1840 fDepthChange);
1841 break;
1842 default:
1843 r = 0; /* avoid warning */
1844 BUG("bad style");
1846 pcs->flags = save_flags;
1847 if (!r) skipline();
1849 /* Swap fr and to back to how they were for next line */
1850 if (fRev) {
1851 prefix *t = fr;
1852 fr = to;
1853 to = t;
1857 fRev = fFalse;
1858 ctype = backctype = CTYPE_OMIT;
1859 fDepthChange = fFalse;
1861 /* ordering may omit clino reading, so set up default here */
1862 /* this is also used if clino reading is the omit character */
1863 VAL(Clino) = VAL(BackClino) = 0;
1864 LOC(Clino) = LOC(BackClino) = -1;
1865 WID(Clino) = WID(BackClino) = 0;
1867 inferred_equate:
1869 fMulti = fTrue;
1870 while (1) {
1871 process_eol();
1872 skipblanks();
1873 if (isData(ch)) break;
1874 if (!isComm(ch)) {
1875 return;
1878 break;
1879 case IgnoreAll:
1880 skipline();
1881 /* fall through */
1882 case End:
1883 if (!fMulti) {
1884 int save_flags;
1885 int implicit_splay;
1886 /* Compass ignore flag is 'X' */
1887 if ((compass_dat_flags & BIT('X' - 'A'))) {
1888 process_eol();
1889 return;
1891 if (fRev) {
1892 prefix *t = fr;
1893 fr = to;
1894 to = t;
1896 if (fTopofil) {
1897 VAL(Tape) = VAL(ToCount) - VAL(FrCount);
1898 LOC(Tape) = LOC(ToCount);
1899 WID(Tape) = WID(ToCount);
1901 /* Note: frdepth == todepth test works regardless of fDepthChange
1902 * (frdepth always zero, todepth is change of depth) and also
1903 * works for STYLE_NORMAL (both remain 0) */
1904 if (TSTBIT(pcs->infer, INFER_EQUATES) &&
1905 (VAL(Tape) == (real)0.0 || VAL(Tape) == HUGE_REAL) &&
1906 (VAL(BackTape) == (real)0.0 || VAL(BackTape) == HUGE_REAL) &&
1907 VAL(FrDepth) == VAL(ToDepth)) {
1908 process_equate(fr, to);
1909 process_eol();
1910 return;
1912 if (fTopofil) {
1913 VAL(Tape) *= pcs->units[Q_COUNT] * pcs->sc[Q_COUNT];
1914 } else if (VAL(Tape) != HUGE_REAL) {
1915 VAL(Tape) *= pcs->units[Q_LENGTH];
1916 VAL(Tape) -= pcs->z[Q_LENGTH];
1917 VAL(Tape) *= pcs->sc[Q_LENGTH];
1919 if (VAL(BackTape) != HUGE_REAL) {
1920 VAL(BackTape) *= pcs->units[Q_BACKLENGTH];
1921 VAL(BackTape) -= pcs->z[Q_BACKLENGTH];
1922 VAL(BackTape) *= pcs->sc[Q_BACKLENGTH];
1923 if (VAL(Tape) != HUGE_REAL) {
1924 real diff = VAL(Tape) - VAL(BackTape);
1925 if (sqrd(diff / 3.0) > VAR(Tape) + VAR(BackTape)) {
1926 /* fore and back readings differ by more than 3 sds */
1927 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1928 * by, e.g. "0.12m" or "0.2ft". */
1929 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1930 diff, get_length_units(Q_LENGTH));
1932 VAL(Tape) = VAL(Tape) / VAR(Tape) + VAL(BackTape) / VAR(BackTape);
1933 VAR(Tape) = (VAR(Tape) + VAR(BackTape)) / 4;
1934 VAL(Tape) *= VAR(Tape);
1935 } else {
1936 VAL(Tape) = VAL(BackTape);
1937 VAR(Tape) = VAR(BackTape);
1939 } else if (VAL(Tape) == HUGE_REAL) {
1940 compile_diagnostic_reading(DIAG_ERR, Tape, /*Tape reading may not be omitted*/94);
1941 process_eol();
1942 return;
1944 implicit_splay = TSTBIT(pcs->flags, FLAGS_IMPLICIT_SPLAY);
1945 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1946 save_flags = pcs->flags;
1947 if (implicit_splay) {
1948 pcs->flags |= BIT(FLAGS_SPLAY);
1950 if ((compass_dat_flags & BIT('L' - 'A'))) {
1951 /* 'L' means "exclude from length" - map this to Survex's
1952 * FLAGS_DUPLICATE. */
1953 pcs->flags |= BIT(FLAGS_DUPLICATE);
1955 switch (pcs->style) {
1956 case STYLE_NORMAL:
1957 process_normal(fr, to, (first_stn == To) ^ fRev,
1958 ctype, backctype);
1959 break;
1960 case STYLE_DIVING:
1961 /* FIXME: Handle any clino readings */
1962 process_diving(fr, to, (first_stn == To) ^ fRev,
1963 fDepthChange);
1964 break;
1965 case STYLE_CYLPOLAR:
1966 process_cylpolar(fr, to, (first_stn == To) ^ fRev,
1967 fDepthChange);
1968 break;
1969 default:
1970 BUG("bad style");
1972 pcs->flags = save_flags;
1974 process_eol();
1975 return;
1977 do {
1978 process_eol();
1979 skipblanks();
1980 } while (isComm(ch));
1981 goto again;
1982 default:
1983 BUG("Unknown reading in ordering");
1988 static int
1989 process_lrud(prefix *stn)
1991 SVX_ASSERT(next_lrud);
1992 lrud * xsect = osnew(lrud);
1993 xsect->stn = stn;
1994 xsect->l = (VAL(Left) * pcs->units[Q_LEFT] - pcs->z[Q_LEFT]) * pcs->sc[Q_LEFT];
1995 xsect->r = (VAL(Right) * pcs->units[Q_RIGHT] - pcs->z[Q_RIGHT]) * pcs->sc[Q_RIGHT];
1996 xsect->u = (VAL(Up) * pcs->units[Q_UP] - pcs->z[Q_UP]) * pcs->sc[Q_UP];
1997 xsect->d = (VAL(Down) * pcs->units[Q_DOWN] - pcs->z[Q_DOWN]) * pcs->sc[Q_DOWN];
1998 xsect->meta = pcs->meta;
1999 if (pcs->meta) ++pcs->meta->ref_count;
2000 xsect->next = NULL;
2001 *next_lrud = xsect;
2002 next_lrud = &(xsect->next);
2004 return 1;
2007 static void
2008 data_passage(void)
2010 prefix *stn = NULL;
2011 const reading *ordering;
2013 for (ordering = pcs->ordering ; ; ordering++) {
2014 skipblanks();
2015 switch (*ordering) {
2016 case Station:
2017 stn = read_prefix(PFX_STATION);
2018 break;
2019 case Left: case Right: case Up: case Down: {
2020 reading r = *ordering;
2021 read_reading(r, fTrue);
2022 if (VAL(r) == HUGE_REAL) {
2023 if (!isOmit(ch)) {
2024 compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found ā€œ%sā€*/9);
2025 } else {
2026 nextch();
2028 VAL(r) = -1;
2030 break;
2032 case Ignore:
2033 skipword(); break;
2034 case IgnoreAll:
2035 skipline();
2036 /* fall through */
2037 case End: {
2038 process_lrud(stn);
2039 process_eol();
2040 return;
2042 default: BUG("Unknown reading in ordering");
2047 static int
2048 process_nosurvey(prefix *fr, prefix *to, bool fToFirst)
2050 nosurveylink *link;
2052 /* Suppress "unused fixed point" warnings for these stations */
2053 fr->sflags |= BIT(SFLAGS_USED);
2054 to->sflags |= BIT(SFLAGS_USED);
2056 /* add to linked list which is dealt with after network is solved */
2057 link = osnew(nosurveylink);
2058 if (fToFirst) {
2059 link->to = StnFromPfx(to);
2060 link->fr = StnFromPfx(fr);
2061 } else {
2062 link->fr = StnFromPfx(fr);
2063 link->to = StnFromPfx(to);
2065 link->flags = pcs->flags | (STYLE_NOSURVEY << FLAGS_STYLE_BIT0);
2066 link->meta = pcs->meta;
2067 if (pcs->meta) ++pcs->meta->ref_count;
2068 link->next = nosurveyhead;
2069 nosurveyhead = link;
2070 return 1;
2073 static void
2074 data_nosurvey(void)
2076 prefix *fr = NULL, *to = NULL;
2078 bool fMulti = fFalse;
2080 reading first_stn = End;
2082 const reading *ordering;
2084 again:
2086 for (ordering = pcs->ordering ; ; ordering++) {
2087 skipblanks();
2088 switch (*ordering) {
2089 case Fr:
2090 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
2091 if (first_stn == End) first_stn = Fr;
2092 break;
2093 case To:
2094 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
2095 if (first_stn == End) first_stn = To;
2096 break;
2097 case Station:
2098 fr = to;
2099 to = read_prefix(PFX_STATION);
2100 first_stn = To;
2101 break;
2102 case Ignore:
2103 skipword(); break;
2104 case IgnoreAllAndNewLine:
2105 skipline();
2106 /* fall through */
2107 case Newline:
2108 if (fr != NULL) {
2109 if (!process_nosurvey(fr, to, first_stn == To))
2110 skipline();
2112 if (ordering[1] == End) {
2113 do {
2114 process_eol();
2115 skipblanks();
2116 } while (isComm(ch));
2117 if (!isData(ch)) {
2118 return;
2120 goto again;
2122 fMulti = fTrue;
2123 while (1) {
2124 process_eol();
2125 skipblanks();
2126 if (isData(ch)) break;
2127 if (!isComm(ch)) {
2128 return;
2131 break;
2132 case IgnoreAll:
2133 skipline();
2134 /* fall through */
2135 case End:
2136 if (!fMulti) {
2137 (void)process_nosurvey(fr, to, first_stn == To);
2138 process_eol();
2139 return;
2141 do {
2142 process_eol();
2143 skipblanks();
2144 } while (isComm(ch));
2145 goto again;
2146 default: BUG("Unknown reading in ordering");
2151 /* totally ignore a line of survey data */
2152 static void
2153 data_ignore(void)
2155 skipline();
2156 process_eol();