Refactor to eliminate repeated code
[survex.git] / src / datain.c
blobb0a6f1e175245fbd72ad0decd0e2cc1d508b12ee
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 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]
70 /* style functions */
71 static void data_normal(void);
72 static void data_cartesian(void);
73 static void data_passage(void);
74 static void data_nosurvey(void);
75 static void data_ignore(void);
77 void
78 get_pos(filepos *fp)
80 fp->ch = ch;
81 fp->offset = ftell(file.fh);
82 if (fp->offset == -1)
83 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
86 void
87 set_pos(const filepos *fp)
89 ch = fp->ch;
90 if (fseek(file.fh, fp->offset, SEEK_SET) == -1)
91 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
94 static void
95 report_parent(parse * p) {
96 if (p->parent)
97 report_parent(p->parent);
98 /* Force re-report of include tree for further errors in
99 * parent files */
100 p->reported_where = fFalse;
101 /* TRANSLATORS: %s is replaced by the filename of the parent file, and %u
102 * by the line number in that file. Your translation should also contain
103 * %s:%u so that automatic parsing of error messages to determine the file
104 * and line number still works. */
105 fprintf(STDERR, msg(/*In file included from %s:%u:\n*/5), p->filename, p->line);
108 static void
109 error_list_parent_files(void)
111 if (!file.reported_where && file.parent) {
112 report_parent(file.parent);
113 /* Suppress reporting of full include tree for further errors
114 * in this file */
115 file.reported_where = fTrue;
119 static void
120 show_line(int col, int width)
122 /* Rewind to beginning of line. */
123 long cur_pos = ftell(file.fh);
124 int tabs = 0;
125 if (cur_pos < 0 || fseek(file.fh, file.lpos, SEEK_SET) == -1)
126 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
128 /* Read the whole line and write it out. */
129 PUTC(' ', STDERR);
130 while (!feof(file.fh)) {
131 int c = GETC(file.fh);
132 if (isEol(c)) break;
133 if (c == '\t') ++tabs;
134 PUTC(c, STDERR);
136 fputnl(STDERR);
138 /* If we have a location in the line for the error, indicate it. */
139 if (col) {
140 PUTC(' ', STDERR);
141 if (tabs == 0) {
142 while (--col) PUTC(' ', STDERR);
143 } else {
144 /* Copy tabs from line, replacing other characters with spaces - this
145 * means that the caret should line up correctly. */
146 if (fseek(file.fh, file.lpos, SEEK_SET) == -1)
147 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
148 while (--col) {
149 int c = GETC(file.fh);
150 if (c != '\t') c = ' ';
151 PUTC(c, STDERR);
154 PUTC('^', STDERR);
155 while (width > 1) {
156 PUTC('~', STDERR);
157 --width;
159 fputnl(STDERR);
162 /* Revert to where we were. */
163 if (fseek(file.fh, cur_pos, SEEK_SET) == -1)
164 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
167 static int caret_width = 0;
169 static void
170 compile_v_report_fpos(int severity, long fpos, int en, va_list ap)
172 int col = 0;
173 error_list_parent_files();
174 if (en < 0) {
175 en = -en;
176 if (fpos >= file.lpos) col = fpos - file.lpos - caret_width;
178 v_report(severity, file.filename, file.line, col, en, ap);
179 if (col)
180 show_line(col, caret_width);
183 static void
184 compile_v_report(int severity, int en, va_list ap)
186 compile_v_report_fpos(severity, file.fh ? ftell(file.fh) : -1, en, ap);
189 void
190 compile_error(int en, ...)
192 va_list ap;
193 va_start(ap, en);
194 compile_v_report(1, en, ap);
195 va_end(ap);
198 void
199 compile_error_skip(int en, ...)
201 va_list ap;
202 va_start(ap, en);
203 compile_v_report(1, en, ap);
204 va_end(ap);
205 skipline();
208 static void
209 compile_error_reading(reading r, int en, ...)
211 va_list ap;
212 va_start(ap, en);
213 compile_v_report_fpos(1, LOC(r), en, ap);
214 va_end(ap);
217 static void
218 compile_error_reading_skip(reading r, int en, ...)
220 va_list ap;
221 compile_v_report_fpos(1, LOC(r), en, ap);
222 va_end(ap);
223 skipline();
226 void
227 compile_error_at(const char * filename, unsigned line, int en, ...)
229 va_list ap;
230 va_start(ap, en);
231 v_report(1, filename, line, 0, en, ap);
232 va_end(ap);
235 void
236 compile_error_pfx(const prefix * pfx, int en, ...)
238 va_list ap;
239 va_start(ap, en);
240 v_report(1, pfx->filename, pfx->line, 0, en, ap);
241 va_end(ap);
244 void
245 compile_error_token(int en)
247 char *p = NULL;
248 int len = 0;
249 skipblanks();
250 while (!isBlank(ch) && !isEol(ch)) {
251 s_catchar(&p, &len, (char)ch);
252 nextch();
254 if (p) {
255 caret_width = strlen(p);
256 compile_error(en, p);
257 caret_width = 0;
258 osfree(p);
259 } else {
260 compile_error(en, "");
264 void
265 compile_error_buffer(int en, ...)
267 va_list ap;
268 va_start(ap, en);
269 caret_width = strlen(buffer);
270 compile_v_report(1, en, ap);
271 va_end(ap);
272 caret_width = 0;
275 void
276 compile_error_buffer_skip(int en, ...)
278 va_list ap;
279 va_start(ap, en);
280 caret_width = strlen(buffer);
281 compile_v_report(1, en, ap);
282 va_end(ap);
283 caret_width = 0;
284 skipline();
287 void
288 compile_warning_buffer(int en, ...)
290 va_list ap;
291 va_start(ap, en);
292 caret_width = strlen(buffer);
293 compile_v_report(0, en, ap);
294 va_end(ap);
295 caret_width = 0;
298 void
299 compile_warning(int en, ...)
301 va_list ap;
302 va_start(ap, en);
303 compile_v_report(0, en, ap);
304 va_end(ap);
307 void
308 compile_warning_at(const char * filename, unsigned line, int en, ...)
310 va_list ap;
311 va_start(ap, en);
312 v_report(0, filename, line, 0, en, ap);
313 va_end(ap);
316 void
317 compile_warning_pfx(const prefix * pfx, int en, ...)
319 va_list ap;
320 va_start(ap, en);
321 v_report(0, pfx->filename, pfx->line, 0, en, ap);
322 va_end(ap);
325 /* This function makes a note where to put output files */
326 static void
327 using_data_file(const char *fnm)
329 if (!fnm_output_base) {
330 /* was: fnm_output_base = base_from_fnm(fnm); */
331 fnm_output_base = baseleaf_from_fnm(fnm);
332 } else if (fnm_output_base_is_dir) {
333 /* --output pointed to directory so use the leaf basename in that dir */
334 char *lf, *p;
335 lf = baseleaf_from_fnm(fnm);
336 p = use_path(fnm_output_base, lf);
337 osfree(lf);
338 osfree(fnm_output_base);
339 fnm_output_base = p;
340 fnm_output_base_is_dir = 0;
344 static void
345 skipword(void)
347 while (!isBlank(ch) && !isEol(ch)) nextch();
350 extern void
351 skipblanks(void)
353 while (isBlank(ch)) nextch();
356 extern void
357 skipline(void)
359 while (!isEol(ch)) nextch();
362 static void
363 process_eol(void)
365 int eolchar;
367 skipblanks();
369 if (!isEol(ch)) {
370 if (!isComm(ch)) compile_error(-/*End of line not blank*/15);
371 skipline();
374 eolchar = ch;
375 file.line++;
376 /* skip any different eol characters so we get line counts correct on
377 * DOS text files and similar, but don't count several adjacent blank
378 * lines as one */
379 while (ch != EOF) {
380 nextch();
381 if (ch == eolchar || !isEol(ch)) {
382 break;
384 if (ch == '\n') eolchar = ch;
386 file.lpos = ftell(file.fh) - 1;
389 static bool
390 process_non_data_line(void)
392 skipblanks();
394 if (isData(ch)) return fFalse;
396 if (isKeywd(ch)) {
397 nextch();
398 handle_command();
401 process_eol();
403 return fTrue;
406 static void
407 read_reading(reading r, bool f_optional)
409 int n_readings;
410 q_quantity q;
411 switch (r) {
412 case Tape: q = Q_LENGTH; break;
413 case BackTape: q = Q_BACKLENGTH; break;
414 case Comp: q = Q_BEARING; break;
415 case BackComp: q = Q_BACKBEARING; break;
416 case Clino: q = Q_GRADIENT; break;
417 case BackClino: q = Q_BACKGRADIENT; break;
418 case FrDepth: case ToDepth: q = Q_DEPTH; break;
419 case Dx: q = Q_DX; break;
420 case Dy: q = Q_DY; break;
421 case Dz: q = Q_DZ; break;
422 case FrCount: case ToCount: q = Q_COUNT; break;
423 case Left: q = Q_LEFT; break;
424 case Right: q = Q_RIGHT; break;
425 case Up: q = Q_UP; break;
426 case Down: q = Q_DOWN; break;
427 default:
428 q = Q_NULL; /* Suppress compiler warning */;
429 BUG("Unexpected case");
431 LOC(r) = ftell(file.fh);
432 VAL(r) = read_numeric_multi(f_optional, &n_readings);
433 VAR(r) = var(q);
434 if (n_readings > 1) VAR(r) /= sqrt(n_readings);
437 static void
438 read_bearing_or_omit(reading r)
440 int n_readings;
441 q_quantity q = Q_NULL;
442 LOC(r) = ftell(file.fh);
443 VAL(r) = read_numeric_multi_or_omit(&n_readings);
444 switch (r) {
445 case Comp: q = Q_BEARING; break;
446 case BackComp: q = Q_BACKBEARING; break;
447 default:
448 q = Q_NULL; /* Suppress compiler warning */;
449 BUG("Unexpected case");
451 VAR(r) = var(q);
452 if (n_readings > 1) VAR(r) /= sqrt(n_readings);
455 /* For reading Compass MAK files which have a freeform syntax */
456 static void
457 nextch_handling_eol(void)
459 nextch();
460 while (ch != EOF && isEol(ch)) {
461 process_eol();
465 #define LITLEN(S) (sizeof(S"") - 1)
466 #define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
467 (F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
468 strcasecmp((F) + (L) - LITLEN(E), E) == 0)
469 extern void
470 data_file(const char *pth, const char *fnm)
472 int begin_lineno_store;
473 parse file_store;
474 volatile enum {FMT_SVX, FMT_DAT, FMT_MAK} fmt = FMT_SVX;
477 char *filename;
478 FILE *fh;
479 size_t len;
481 if (!pth) {
482 /* file specified on command line - don't do special translation */
483 fh = fopenWithPthAndExt(pth, fnm, EXT_SVX_DATA, "rb", &filename);
484 } else {
485 fh = fopen_portable(pth, fnm, EXT_SVX_DATA, "rb", &filename);
488 if (fh == NULL) {
489 compile_error(-/*Couldnā€™t open file ā€œ%sā€*/24, fnm);
490 return;
493 len = strlen(filename);
494 if (has_ext(filename, len, "dat")) {
495 fmt = FMT_DAT;
496 } else if (has_ext(filename, len, "mak")) {
497 fmt = FMT_MAK;
500 file_store = file;
501 if (file.fh) file.parent = &file_store;
502 file.fh = fh;
503 file.filename = filename;
504 file.line = 1;
505 file.lpos = 0;
506 file.reported_where = fFalse;
507 nextch();
510 using_data_file(file.filename);
512 begin_lineno_store = pcs->begin_lineno;
513 pcs->begin_lineno = 0;
515 if (fmt == FMT_DAT) {
516 short *t;
517 int i;
518 settings *pcsNew;
520 pcsNew = osnew(settings);
521 *pcsNew = *pcs; /* copy contents */
522 pcsNew->begin_lineno = 0;
523 pcsNew->next = pcs;
524 pcs = pcsNew;
525 default_units(pcs);
526 default_calib(pcs);
528 pcs->style = STYLE_NORMAL;
529 pcs->units[Q_LENGTH] = METRES_PER_FOOT;
530 t = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
532 t[EOF] = SPECIAL_EOL;
533 memset(t, 0, sizeof(short) * 33);
534 for (i = 33; i < 127; i++) t[i] = SPECIAL_NAMES;
535 t[127] = 0;
536 for (i = 128; i < 256; i++) t[i] = SPECIAL_NAMES;
537 t['\t'] |= SPECIAL_BLANK;
538 t[' '] |= SPECIAL_BLANK;
539 t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */
540 t['\n'] |= SPECIAL_EOL;
541 t['\r'] |= SPECIAL_EOL;
542 t['.'] |= SPECIAL_DECIMAL;
543 t['-'] |= SPECIAL_MINUS;
544 t['+'] |= SPECIAL_PLUS;
545 pcs->Translate = t;
546 pcs->Case = OFF;
547 pcs->Truncate = INT_MAX;
548 pcs->infer = BIT(INFER_EQUATES)|BIT(INFER_EXPORTS)|BIT(INFER_PLUMBS);
549 } else if (fmt == FMT_MAK) {
550 short *t;
551 int i;
552 settings *pcsNew;
554 pcsNew = osnew(settings);
555 *pcsNew = *pcs; /* copy contents */
556 pcsNew->begin_lineno = 0;
557 pcsNew->next = pcs;
558 pcs = pcsNew;
560 t = ((short*)osmalloc(ossizeof(short) * 257)) + 1;
562 t[EOF] = SPECIAL_EOL;
563 memset(t, 0, sizeof(short) * 33);
564 for (i = 33; i < 127; i++) t[i] = SPECIAL_NAMES;
565 t[127] = 0;
566 for (i = 128; i < 256; i++) t[i] = SPECIAL_NAMES;
567 t['['] = t[','] = t[';'] = 0;
568 t['\t'] |= SPECIAL_BLANK;
569 t[' '] |= SPECIAL_BLANK;
570 t['\032'] |= SPECIAL_EOL; /* Ctrl-Z, so olde DOS text files are handled ok */
571 t['\n'] |= SPECIAL_EOL;
572 t['\r'] |= SPECIAL_EOL;
573 t['.'] |= SPECIAL_DECIMAL;
574 t['-'] |= SPECIAL_MINUS;
575 t['+'] |= SPECIAL_PLUS;
576 pcs->Translate = t;
577 pcs->Case = OFF;
578 pcs->Truncate = INT_MAX;
581 #ifdef HAVE_SETJMP_H
582 /* errors in nested functions can longjmp here */
583 if (setjmp(file.jbSkipLine)) {
584 skipline();
585 process_eol();
587 #endif
589 if (fmt == FMT_DAT) {
590 while (!feof(file.fh) && !ferror(file.fh)) {
591 static reading compass_order[] = {
592 Fr, To, Tape, CompassDATComp, CompassDATClino,
593 CompassDATLeft, CompassDATRight, CompassDATUp, CompassDATDown,
594 CompassDATFlags, IgnoreAll
596 static reading compass_order_backsights[] = {
597 Fr, To, Tape, CompassDATComp, CompassDATClino,
598 CompassDATLeft, CompassDATRight, CompassDATUp, CompassDATDown,
599 CompassDATBackComp, CompassDATBackClino,
600 CompassDATFlags, IgnoreAll
602 /* <Cave name> */
603 skipline();
604 process_eol();
605 /* SURVEY NAME: <Short name> */
606 get_token();
607 get_token();
608 /* if (ch != ':') ... */
609 nextch();
610 get_token();
611 skipline();
612 process_eol();
613 /* SURVEY DATE: 7 10 79 COMMENT:<Long name> */
614 get_token();
615 get_token();
616 copy_on_write_meta(pcs);
617 if (ch == ':') {
618 int year, month, day;
620 nextch();
622 /* NB order is *month* *day* year */
623 month = read_uint();
624 day = read_uint();
625 year = read_uint();
626 /* Note: Larry says a 2 digit year is always 19XX */
627 if (year < 100) year += 1900;
629 pcs->meta->days1 = pcs->meta->days2 = days_since_1900(year, month, day);
630 } else {
631 pcs->meta->days1 = pcs->meta->days2 = -1;
633 pcs->declination = HUGE_REAL;
634 skipline();
635 process_eol();
636 /* SURVEY TEAM: */
637 get_token();
638 get_token();
639 skipline();
640 process_eol();
641 /* <Survey team> */
642 nextch();
643 skipline();
644 process_eol();
645 /* DECLINATION: 1.00 FORMAT: DDDDLUDRADLN CORRECTIONS: 2.00 3.00 4.00 */
646 get_token();
647 nextch(); /* : */
648 skipblanks();
649 pcs->z[Q_DECLINATION] = -read_numeric(fFalse);
650 pcs->z[Q_DECLINATION] *= pcs->units[Q_DECLINATION];
651 get_token();
652 pcs->ordering = compass_order;
653 if (strcmp(buffer, "FORMAT") == 0) {
654 nextch(); /* : */
655 get_token();
656 if (strlen(buffer) >= 12 && buffer[11] == 'B') {
657 /* We have backsights for compass and clino */
658 pcs->ordering = compass_order_backsights;
660 get_token();
662 if (strcmp(buffer, "CORRECTIONS") == 0) {
663 nextch(); /* : */
664 pcs->z[Q_BEARING] = -rad(read_numeric(fFalse));
665 pcs->z[Q_GRADIENT] = -rad(read_numeric(fFalse));
666 pcs->z[Q_LENGTH] = -read_numeric(fFalse);
667 } else {
668 pcs->z[Q_BEARING] = 0;
669 pcs->z[Q_GRADIENT] = 0;
670 pcs->z[Q_LENGTH] = 0;
672 skipline();
673 process_eol();
674 /* BLANK LINE */
675 skipline();
676 process_eol();
677 /* heading line */
678 skipline();
679 process_eol();
680 /* BLANK LINE */
681 skipline();
682 process_eol();
683 while (!feof(file.fh)) {
684 if (ch == '\x0c') {
685 nextch();
686 process_eol();
687 break;
689 data_normal();
691 clear_last_leg();
694 settings *pcsParent = pcs->next;
695 SVX_ASSERT(pcsParent);
696 pcs->ordering = NULL;
697 free_settings(pcs);
698 pcs = pcsParent;
700 } else if (fmt == FMT_MAK) {
701 nextch_handling_eol();
702 while (!feof(file.fh) && !ferror(file.fh)) {
703 if (ch == '#') {
704 /* include a file */
705 int ch_store;
706 char *dat_pth = path_from_fnm(file.filename);
707 char *dat_fnm = NULL;
708 int dat_fnm_len;
709 nextch_handling_eol();
710 while (ch != ',' && ch != ';' && ch != EOF) {
711 while (isEol(ch)) process_eol();
712 s_catchar(&dat_fnm, &dat_fnm_len, (char)ch);
713 nextch_handling_eol();
715 while (ch != ';' && ch != EOF) {
716 prefix *name;
717 nextch_handling_eol();
718 name = read_prefix(PFX_STATION|PFX_OPT);
719 if (name) {
720 skipblanks();
721 if (ch == '[') {
722 /* fixed pt */
723 node *stn;
724 real x, y, z;
725 name->sflags |= BIT(SFLAGS_FIXED);
726 nextch_handling_eol();
727 while (!isdigit(ch) && ch != '+' && ch != '-' &&
728 ch != '.' && ch != ']' && ch != EOF) {
729 nextch_handling_eol();
731 x = read_numeric(fFalse);
732 while (!isdigit(ch) && ch != '+' && ch != '-' &&
733 ch != '.' && ch != ']' && ch != EOF) {
734 nextch_handling_eol();
736 y = read_numeric(fFalse);
737 while (!isdigit(ch) && ch != '+' && ch != '-' &&
738 ch != '.' && ch != ']' && ch != EOF) {
739 nextch_handling_eol();
741 z = read_numeric(fFalse);
742 stn = StnFromPfx(name);
743 if (!fixed(stn)) {
744 POS(stn, 0) = x;
745 POS(stn, 1) = y;
746 POS(stn, 2) = z;
747 fix(stn);
748 } else {
749 if (x != POS(stn, 0) || y != POS(stn, 1) ||
750 z != POS(stn, 2)) {
751 compile_error(/*Station already fixed or equated to a fixed point*/46);
752 } else {
753 compile_warning(/*Station already fixed at the same coordinates*/55);
756 while (ch != ']' && ch != EOF) nextch_handling_eol();
757 if (ch == ']') {
758 nextch_handling_eol();
759 skipblanks();
761 } else {
762 /* FIXME: link station - ignore for now */
763 /* FIXME: perhaps issue warning? */
765 while (ch != ',' && ch != ';' && ch != EOF)
766 nextch_handling_eol();
769 if (dat_fnm) {
770 ch_store = ch;
771 data_file(dat_pth, dat_fnm);
772 ch = ch_store;
773 osfree(dat_fnm);
775 } else {
776 /* FIXME: also check for % and $ later */
777 nextch_handling_eol();
781 settings *pcsParent = pcs->next;
782 SVX_ASSERT(pcsParent);
783 free_settings(pcs);
784 pcs = pcsParent;
786 } else {
787 while (!feof(file.fh) && !ferror(file.fh)) {
788 if (!process_non_data_line()) {
789 f_export_ok = fFalse;
790 switch (pcs->style) {
791 case STYLE_NORMAL:
792 case STYLE_DIVING:
793 case STYLE_CYLPOLAR:
794 data_normal();
795 break;
796 case STYLE_CARTESIAN:
797 data_cartesian();
798 break;
799 case STYLE_PASSAGE:
800 data_passage();
801 break;
802 case STYLE_NOSURVEY:
803 data_nosurvey();
804 break;
805 case STYLE_IGNORE:
806 data_ignore();
807 break;
808 default:
809 BUG("bad style");
813 clear_last_leg();
816 /* don't allow *BEGIN at the end of a file, then *EXPORT in the
817 * including file */
818 f_export_ok = fFalse;
820 if (pcs->begin_lineno) {
821 error_in_file(file.filename, pcs->begin_lineno,
822 /*BEGIN with no matching END in this file*/23);
823 /* Implicitly close any unclosed BEGINs from this file */
824 do {
825 settings *pcsParent = pcs->next;
826 SVX_ASSERT(pcsParent);
827 free_settings(pcs);
828 pcs = pcsParent;
829 } while (pcs->begin_lineno);
832 pcs->begin_lineno = begin_lineno_store;
834 if (ferror(file.fh))
835 fatalerror_in_file(file.filename, 0, /*Error reading file*/18);
837 (void)fclose(file.fh);
839 file = file_store;
841 /* don't free this - it may be pointed to by prefix.file */
842 /* osfree(file.filename); */
845 static real
846 mod2pi(real a)
848 return a - floor(a / (2 * M_PI)) * (2 * M_PI);
851 static real
852 handle_plumb(clino_type *p_ctype)
854 typedef enum {
855 CLINO_NULL=-1, CLINO_UP, CLINO_DOWN, CLINO_LEVEL
856 } clino_tok;
857 static sztok clino_tab[] = {
858 {"D", CLINO_DOWN},
859 {"DOWN", CLINO_DOWN},
860 {"H", CLINO_LEVEL},
861 {"LEVEL", CLINO_LEVEL},
862 {"U", CLINO_UP},
863 {"UP", CLINO_UP},
864 {NULL, CLINO_NULL}
866 static real clinos[] = {(real)M_PI_2, (real)(-M_PI_2), (real)0.0};
867 clino_tok tok;
869 skipblanks();
870 if (isalpha(ch)) {
871 filepos fp;
872 get_pos(&fp);
873 get_token();
874 tok = match_tok(clino_tab, TABSIZE(clino_tab));
875 if (tok != CLINO_NULL) {
876 *p_ctype = (tok == CLINO_LEVEL ? CTYPE_HORIZ : CTYPE_PLUMB);
877 return clinos[tok];
879 set_pos(&fp);
880 } else if (isSign(ch)) {
881 int chOld = ch;
882 nextch();
883 if (toupper(ch) == 'V') {
884 nextch();
885 *p_ctype = CTYPE_PLUMB;
886 return (!isMinus(chOld) ? M_PI_2 : -M_PI_2);
889 if (isOmit(chOld)) {
890 *p_ctype = CTYPE_OMIT;
891 /* no clino reading, so assume 0 with large sd */
892 return (real)0.0;
894 } else if (isOmit(ch)) {
895 /* OMIT char may not be a SIGN char too so we need to check here as
896 * well as above... */
897 nextch();
898 *p_ctype = CTYPE_OMIT;
899 /* no clino reading, so assume 0 with large sd */
900 return (real)0.0;
902 return HUGE_REAL;
905 static void
906 warn_readings_differ(int msgno, real diff, int units)
908 char buf[64];
909 char *p;
910 diff /= get_units_factor(units);
911 sprintf(buf, "%.2f", fabs(diff));
912 for (p = buf; *p; ++p) {
913 if (*p == '.') {
914 char *z = p;
915 while (*++p) {
916 if (*p != '0') z = p + 1;
918 p = z;
919 break;
922 strcpy(p, get_units_string(units));
923 compile_warning(msgno, buf);
926 static bool
927 handle_comp_units(void)
929 bool fNoComp = fTrue;
930 if (VAL(Comp) != HUGE_REAL) {
931 fNoComp = fFalse;
932 VAL(Comp) *= pcs->units[Q_BEARING];
933 if (VAL(Comp) < (real)0.0 || VAL(Comp) - M_PI * 2.0 > EPSILON) {
934 /* TRANSLATORS: Suspicious means something like 410 degrees or -20
935 * degrees */
936 compile_warning(/*Suspicious compass reading*/59);
937 VAL(Comp) = mod2pi(VAL(Comp));
940 if (VAL(BackComp) != HUGE_REAL) {
941 fNoComp = fFalse;
942 VAL(BackComp) *= pcs->units[Q_BACKBEARING];
943 if (VAL(BackComp) < (real)0.0 || VAL(BackComp) - M_PI * 2.0 > EPSILON) {
944 /* FIXME: different message for BackComp? */
945 compile_warning(/*Suspicious compass reading*/59);
946 VAL(BackComp) = mod2pi(VAL(BackComp));
949 return fNoComp;
952 static real
953 handle_compass(real *p_var)
955 real compvar = VAR(Comp);
956 real comp = VAL(Comp);
957 real backcomp = VAL(BackComp);
958 real declination;
959 if (pcs->z[Q_DECLINATION] != HUGE_REAL) {
960 declination = -pcs->z[Q_DECLINATION];
961 } else if (pcs->declination != HUGE_REAL) {
962 /* Cached value calculated for a previous compass reading taken on the
963 * same date (by the 'else' just below).
965 declination = pcs->declination;
966 } else {
967 if (!pcs->meta || pcs->meta->days1 == -1) {
968 compile_warning(/*No survey date specified - using 0 for magnetic declination*/304);
969 declination = 0;
970 } else {
971 int avg_days = (pcs->meta->days1 + pcs->meta->days2) / 2;
972 double dat = julian_date_from_days_since_1900(avg_days);
973 /* thgeomag() takes (lat, lon, h, dat) - i.e. (y, x, z, date). */
974 declination = thgeomag(pcs->dec_y, pcs->dec_x, pcs->dec_z, dat);
976 declination -= pcs->convergence;
977 /* We cache the calculated declination as the calculation is relatively
978 * expensive. We also cache an "assumed 0" answer so that we only
979 * warn once per such survey rather than for every line with a compass
980 * reading. */
981 pcs->declination = declination;
983 if (comp != HUGE_REAL) {
984 comp = (comp - pcs->z[Q_BEARING]) * pcs->sc[Q_BEARING];
985 comp += declination;
987 if (backcomp != HUGE_REAL) {
988 backcomp = (backcomp - pcs->z[Q_BACKBEARING])
989 * pcs->sc[Q_BACKBEARING];
990 backcomp += declination;
991 backcomp -= M_PI;
992 if (comp != HUGE_REAL) {
993 real diff = comp - backcomp;
994 real adj = fabs(diff) > M_PI ? M_PI : 0;
995 diff -= floor((diff + M_PI) / (2 * M_PI)) * 2 * M_PI;
996 if (sqrd(diff / 3.0) > compvar + VAR(BackComp)) {
997 /* fore and back readings differ by more than 3 sds */
998 /* TRANSLATORS: %s is replaced by the amount the readings disagree
999 * by, e.g. "2.5Ā°" or "3įµ". */
1000 warn_readings_differ(/*COMPASS reading and BACKCOMPASS reading disagree by %s*/98,
1001 diff, get_angle_units(Q_BEARING));
1003 comp = (comp / compvar + backcomp / VAR(BackComp));
1004 compvar = (compvar + VAR(BackComp)) / 4;
1005 comp *= compvar;
1006 comp += adj;
1007 } else {
1008 comp = backcomp;
1009 compvar = VAR(BackComp);
1012 *p_var = compvar;
1013 return comp;
1016 static int
1017 process_normal(prefix *fr, prefix *to, bool fToFirst,
1018 clino_type ctype, clino_type backctype)
1020 real tape = VAL(Tape);
1021 real clin = VAL(Clino);
1022 real backclin = VAL(BackClino);
1024 real dx, dy, dz;
1025 real vx, vy, vz;
1026 #ifndef NO_COVARIANCES
1027 real cxy, cyz, czx;
1028 #endif
1030 bool fNoComp;
1032 /* adjusted tape is negative -- probably the calibration is wrong */
1033 if (tape < (real)0.0) {
1034 /* TRANSLATE different message for topofil? */
1035 compile_warning(/*Negative adjusted tape reading*/79);
1038 fNoComp = handle_comp_units();
1040 if (ctype == CTYPE_READING) {
1041 bool range_0_180;
1042 real z;
1043 real diff_from_abs90;
1044 clin *= pcs->units[Q_GRADIENT];
1045 /* percentage scale */
1046 if (pcs->f_clino_percent) clin = atan(clin);
1047 /* We want to warn if there's a reading which it would be impossible
1048 * to have read from the instrument (e.g. on a -90 to 90 degree scale
1049 * you can't read "96" (it's probably a typo for "69"). However, the
1050 * gradient reading from a topofil is typically in the range 0 to 180,
1051 * with 90 being horizontal.
1053 * Really we should allow the valid range to be specified, but for now
1054 * we infer it from the zero error - if this is within 45 degrees of
1055 * 90 then we assume the range is 0 to 180.
1057 z = pcs->z[Q_GRADIENT];
1058 range_0_180 = (z > M_PI_4 && z < 3*M_PI_4);
1059 diff_from_abs90 = fabs(clin) - M_PI_2;
1060 if (diff_from_abs90 > EPSILON) {
1061 if (!range_0_180) {
1062 int clino_units = get_angle_units(Q_GRADIENT);
1063 const char * units = get_units_string(clino_units);
1064 real right_angle = M_PI_2 / get_units_factor(clino_units);
1065 /* TRANSLATORS: %.f%s will be replaced with a right angle in the
1066 * units currently in use, e.g. "90Ā°" or "100įµ". And "absolute
1067 * value" means the reading ignoring the sign (so it might be
1068 * < -90Ā° or > 90Ā°. */
1069 compile_warning(/*Clino reading over %.f%s (absolute value)*/51,
1070 right_angle, units);
1072 } else if (TSTBIT(pcs->infer, INFER_PLUMBS) &&
1073 diff_from_abs90 >= -EPSILON) {
1074 ctype = CTYPE_INFERPLUMB;
1076 if (range_0_180 && ctype != CTYPE_INFERPLUMB) {
1077 /* FIXME: Warning message not ideal... */
1078 if (clin < 0.0 || clin - M_PI > EPSILON) {
1079 int clino_units = get_angle_units(Q_GRADIENT);
1080 const char * units = get_units_string(clino_units);
1081 real right_angle = M_PI_2 / get_units_factor(clino_units);
1082 compile_warning(/*Clino reading over %.f%s (absolute value)*/51,
1083 right_angle, units);
1088 if (backctype == CTYPE_READING) {
1089 backclin *= pcs->units[Q_BACKGRADIENT];
1090 /* percentage scale */
1091 if (pcs->f_backclino_percent) backclin = atan(backclin);
1092 /* FIXME: Add range_0_180 handling here too */
1093 if (ctype != CTYPE_READING) {
1094 real diff_from_abs90 = fabs(backclin) - M_PI_2;
1095 if (diff_from_abs90 > EPSILON) {
1096 /* FIXME: different message for BackClino? */
1097 int clino_units = get_angle_units(Q_BACKGRADIENT);
1098 const char * units = get_units_string(clino_units);
1099 real right_angle = M_PI_2 / get_units_factor(clino_units);
1100 compile_warning(/*Clino reading over %.f%s (absolute value)*/51,
1101 right_angle, units);
1102 } else if (TSTBIT(pcs->infer, INFER_PLUMBS) &&
1103 diff_from_abs90 >= -EPSILON) {
1104 backctype = CTYPE_INFERPLUMB;
1109 /* un-infer the plumb if the backsight was just a reading */
1110 if (ctype == CTYPE_INFERPLUMB && backctype == CTYPE_READING) {
1111 ctype = CTYPE_READING;
1114 if (ctype != CTYPE_OMIT && backctype != CTYPE_OMIT && ctype != backctype) {
1115 /* TRANSLATORS: In data with backsights, the user has tried to give a
1116 * plumb for the foresight and a clino reading for the backsight, or
1117 * something similar. */
1118 compile_error_reading_skip(Clino, /*CLINO and BACKCLINO readings must be of the same type*/84);
1119 return 0;
1122 if (ctype == CTYPE_PLUMB || ctype == CTYPE_INFERPLUMB ||
1123 backctype == CTYPE_PLUMB || backctype == CTYPE_INFERPLUMB) {
1124 /* plumbed */
1125 if (!fNoComp) {
1126 if (ctype == CTYPE_PLUMB ||
1127 (ctype == CTYPE_INFERPLUMB && VAL(Comp) != 0.0) ||
1128 backctype == CTYPE_PLUMB ||
1129 (backctype == CTYPE_INFERPLUMB && VAL(BackComp) != 0.0)) {
1130 /* FIXME: Different message for BackComp? */
1131 /* TRANSLATORS: A "plumbed leg" is one measured using a plumbline
1132 * (a weight on a string). So the problem here is that the leg is
1133 * vertical, so a compass reading has no meaning! */
1134 compile_warning(/*Compass reading given on plumbed leg*/21);
1138 dx = dy = (real)0.0;
1139 if (ctype != CTYPE_OMIT) {
1140 if (backctype != CTYPE_OMIT && (clin > 0) == (backclin > 0)) {
1141 /* TRANSLATORS: We've been told the foresight and backsight are
1142 * both "UP", or that they're both "DOWN". */
1143 compile_error_reading_skip(Clino, /*Plumbed CLINO and BACKCLINO readings can't be in the same direction*/92);
1144 return 0;
1146 dz = (clin > (real)0.0) ? tape : -tape;
1147 } else {
1148 dz = (backclin < (real)0.0) ? tape : -tape;
1150 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1151 vz = var(Q_POS) / 3.0 + VAR(Tape);
1152 #ifndef NO_COVARIANCES
1153 /* Correct values - no covariances in this case! */
1154 cxy = cyz = czx = (real)0.0;
1155 #endif
1156 } else {
1157 /* Each of ctype and backctype are either CTYPE_READING/CTYPE_HORIZ
1158 * or CTYPE_OMIT */
1159 /* clino */
1160 real L2, cosG, LcosG, cosG2, sinB, cosB, dx2, dy2, dz2, v, V;
1161 if (fNoComp) {
1162 /* TRANSLATORS: Here "legs" are survey legs, i.e. measurements between
1163 * survey stations. */
1164 compile_error_reading_skip(Comp, /*Compass reading may not be omitted except on plumbed legs*/14);
1165 return 0;
1167 if (tape == (real)0.0) {
1168 dx = dy = dz = (real)0.0;
1169 vx = vy = vz = (real)(var(Q_POS) / 3.0); /* Position error only */
1170 #ifndef NO_COVARIANCES
1171 cxy = cyz = czx = (real)0.0;
1172 #endif
1173 #if DEBUG_DATAIN_1
1174 printf("Zero length leg: vx = %f, vy = %f, vz = %f\n", vx, vy, vz);
1175 #endif
1176 } else {
1177 real sinGcosG;
1178 /* take into account variance in LEVEL case */
1179 real var_clin = var(Q_LEVEL);
1180 real var_comp;
1181 real comp = handle_compass(&var_comp);
1182 /* ctype != CTYPE_READING is LEVEL case */
1183 if (ctype == CTYPE_READING) {
1184 clin = (clin - pcs->z[Q_GRADIENT]) * pcs->sc[Q_GRADIENT];
1185 var_clin = VAR(Clino);
1187 if (backctype == CTYPE_READING) {
1188 backclin = (backclin - pcs->z[Q_BACKGRADIENT])
1189 * pcs->sc[Q_BACKGRADIENT];
1190 if (ctype == CTYPE_READING) {
1191 if (sqrd((clin + backclin) / 3.0) > var_clin + VAR(BackClino)) {
1192 /* fore and back readings differ by more than 3 sds */
1193 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1194 * by, e.g. "2.5Ā°" or "3įµ". */
1195 warn_readings_differ(/*CLINO reading and BACKCLINO reading disagree by %s*/99,
1196 clin + backclin, get_angle_units(Q_GRADIENT));
1198 clin = (clin / var_clin - backclin / VAR(BackClino));
1199 var_clin = (var_clin + VAR(BackClino)) / 4;
1200 clin *= var_clin;
1201 } else {
1202 clin = -backclin;
1203 var_clin = VAR(BackClino);
1207 #if DEBUG_DATAIN
1208 printf(" %4.2f %4.2f %4.2f\n", tape, comp, clin);
1209 #endif
1210 cosG = cos(clin);
1211 LcosG = tape * cosG;
1212 sinB = sin(comp);
1213 cosB = cos(comp);
1214 #if DEBUG_DATAIN_1
1215 printf("sinB = %f, cosG = %f, LcosG = %f\n", sinB, cosG, LcosG);
1216 #endif
1217 dx = LcosG * sinB;
1218 dy = LcosG * cosB;
1219 dz = tape * sin(clin);
1220 /* printf("%.2f\n",clin); */
1221 #if DEBUG_DATAIN_1
1222 printf("dx = %f\ndy = %f\ndz = %f\n", dx, dy, dz);
1223 #endif
1224 dx2 = dx * dx;
1225 L2 = tape * tape;
1226 V = VAR(Tape) / L2;
1227 dy2 = dy * dy;
1228 cosG2 = cosG * cosG;
1229 sinGcosG = sin(clin) * cosG;
1230 dz2 = dz * dz;
1231 v = dz2 * var_clin;
1232 #ifdef NO_COVARIANCES
1233 vx = (var(Q_POS) / 3.0 + dx2 * V + dy2 * var_comp +
1234 (.5 + sinB * sinB * cosG2) * v);
1235 vy = (var(Q_POS) / 3.0 + dy2 * V + dx2 * var_comp +
1236 (.5 + cosB * cosB * cosG2) * v);
1237 if (ctype == CTYPE_OMIT && backctype == CTYPE_OMIT) {
1238 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1239 vz = var(Q_POS) / 3.0 + L2 * (real)0.1;
1240 } else {
1241 vz = var(Q_POS) / 3.0 + dz2 * V + L2 * cosG2 * var_clin;
1243 /* for Surveyor87 errors: vx=vy=vz=var(Q_POS)/3.0; */
1244 #else
1245 vx = var(Q_POS) / 3.0 + dx2 * V + dy2 * var_comp +
1246 (sinB * sinB * v);
1247 vy = var(Q_POS) / 3.0 + dy2 * V + dx2 * var_comp +
1248 (cosB * cosB * v);
1249 if (ctype == CTYPE_OMIT && backctype == CTYPE_OMIT) {
1250 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1251 vz = var(Q_POS) / 3.0 + L2 * (real)0.1;
1252 } else {
1253 vz = var(Q_POS) / 3.0 + dz2 * V + L2 * cosG2 * var_clin;
1255 /* usual covariance formulae are fine in no clino case since
1256 * dz = 0 so value of var_clin is ignored */
1257 cxy = sinB * cosB * (VAR(Tape) * cosG2 + var_clin * dz2)
1258 - var_comp * dx * dy;
1259 czx = VAR(Tape) * sinB * sinGcosG - var_clin * dx * dz;
1260 cyz = VAR(Tape) * cosB * sinGcosG - var_clin * dy * dz;
1261 #if 0
1262 printf("vx = %6.3f, vy = %6.3f, vz = %6.3f\n", vx, vy, vz);
1263 printf("cxy = %6.3f, cyz = %6.3f, czx = %6.3f\n", cxy, cyz, czx);
1264 #endif
1265 #endif
1266 #if DEBUG_DATAIN_1
1267 printf("In DATAIN.C, vx = %f, vy = %f, vz = %f\n", vx, vy, vz);
1268 #endif
1271 #if DEBUG_DATAIN_1
1272 printf("Just before addleg, vx = %f\n", vx);
1273 #endif
1274 /*printf("dx,dy,dz = %.2f %.2f %.2f\n\n", dx, dy, dz);*/
1275 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1276 #ifndef NO_COVARIANCES
1277 , cyz, czx, cxy
1278 #endif
1280 return 1;
1283 static int
1284 process_diving(prefix *fr, prefix *to, bool fToFirst, bool fDepthChange)
1286 real tape = VAL(Tape);
1288 real dx, dy, dz;
1289 real vx, vy, vz;
1290 #ifndef NO_COVARIANCES
1291 real cxy = 0, cyz = 0, czx = 0;
1292 #endif
1294 handle_comp_units();
1296 /* depth gauge readings increase upwards with default calibration */
1297 if (fDepthChange) {
1298 SVX_ASSERT(VAL(FrDepth) == 0.0);
1299 dz = VAL(ToDepth) * pcs->units[Q_DEPTH] - pcs->z[Q_DEPTH];
1300 dz *= pcs->sc[Q_DEPTH];
1301 } else {
1302 dz = VAL(ToDepth) - VAL(FrDepth);
1303 dz *= pcs->units[Q_DEPTH] * pcs->sc[Q_DEPTH];
1306 /* adjusted tape is negative -- probably the calibration is wrong */
1307 if (tape < (real)0.0) {
1308 compile_warning(/*Negative adjusted tape reading*/79);
1311 /* check if tape is less than depth change */
1312 if (tape < fabs(dz)) {
1313 /* FIXME: allow margin of error based on variances? */
1314 /* TRANSLATORS: This means that the data fed in said this.
1316 * It could be a gross error (e.g. the decimal point is missing from the
1317 * depth gauge reading) or it could just be due to random error on a near
1318 * vertical leg */
1319 compile_warning(/*Tape reading is less than change in depth*/62);
1322 if (tape == (real)0.0 && dz == 0.0) {
1323 dx = dy = dz = (real)0.0;
1324 vx = vy = vz = (real)(var(Q_POS) / 3.0); /* Position error only */
1325 } else if (VAL(Comp) == HUGE_REAL &&
1326 VAL(BackComp) == HUGE_REAL) {
1327 /* plumb */
1328 dx = dy = (real)0.0;
1329 if (dz < 0) tape = -tape;
1330 /* FIXME: Should use FrDepth sometimes... */
1331 dz = (dz * VAR(Tape) + tape * 2 * VAR(ToDepth))
1332 / (VAR(Tape) * 2 * VAR(ToDepth));
1333 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1334 /* FIXME: Should use FrDepth sometimes... */
1335 vz = var(Q_POS) / 3.0 + VAR(Tape) * 2 * VAR(ToDepth)
1336 / (VAR(Tape) + VAR(ToDepth));
1337 } else {
1338 real L2, sinB, cosB, dz2, D2;
1339 real var_comp;
1340 real comp = handle_compass(&var_comp);
1341 sinB = sin(comp);
1342 cosB = cos(comp);
1343 L2 = tape * tape;
1344 dz2 = dz * dz;
1345 D2 = L2 - dz2;
1346 if (D2 <= (real)0.0) {
1347 /* FIXME: Should use FrDepth sometimes... */
1348 real vsum = VAR(Tape) + 2 * VAR(ToDepth);
1349 dx = dy = (real)0.0;
1350 vx = vy = var(Q_POS) / 3.0;
1351 /* FIXME: Should use FrDepth sometimes... */
1352 vz = var(Q_POS) / 3.0 + VAR(Tape) * 2 * VAR(ToDepth) / vsum;
1353 if (dz > 0) {
1354 /* FIXME: Should use FrDepth sometimes... */
1355 dz = (dz * VAR(Tape) + tape * 2 * VAR(ToDepth)) / vsum;
1356 } else {
1357 dz = (dz * VAR(Tape) - tape * 2 * VAR(ToDepth)) / vsum;
1359 } else {
1360 real D = sqrt(D2);
1361 /* FIXME: Should use FrDepth sometimes... */
1362 real F = VAR(Tape) * L2 + 2 * VAR(ToDepth) * D2;
1363 dx = D * sinB;
1364 dy = D * cosB;
1366 vx = var(Q_POS) / 3.0 +
1367 sinB * sinB * F / D2 + var_comp * dy * dy;
1368 vy = var(Q_POS) / 3.0 +
1369 cosB * cosB * F / D2 + var_comp * dx * dx;
1370 /* FIXME: Should use FrDepth sometimes... */
1371 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1373 #ifndef NO_COVARIANCES
1374 cxy = sinB * cosB * (F / D2 + var_comp * D2);
1375 /* FIXME: Should use FrDepth sometimes... */
1376 cyz = -2 * VAR(ToDepth) * dy / D;
1377 czx = -2 * VAR(ToDepth) * dx / D;
1378 #endif
1380 /* FIXME: If there's a clino reading, check it against the depth reading,
1381 * and average.
1382 * if (VAL(Clino) != HUGE_REAL || VAL(BackClino) != HUGE_REAL) { ... }
1385 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1386 #ifndef NO_COVARIANCES
1387 , cxy, cyz, czx
1388 #endif
1390 return 1;
1393 static int
1394 process_cartesian(prefix *fr, prefix *to, bool fToFirst)
1396 real dx = (VAL(Dx) * pcs->units[Q_DX] - pcs->z[Q_DX]) * pcs->sc[Q_DX];
1397 real dy = (VAL(Dy) * pcs->units[Q_DY] - pcs->z[Q_DY]) * pcs->sc[Q_DY];
1398 real dz = (VAL(Dz) * pcs->units[Q_DZ] - pcs->z[Q_DZ]) * pcs->sc[Q_DZ];
1400 addlegbyname(fr, to, fToFirst, dx, dy, dz, VAR(Dx), VAR(Dy), VAR(Dz)
1401 #ifndef NO_COVARIANCES
1402 , 0, 0, 0
1403 #endif
1405 return 1;
1408 static void
1409 data_cartesian(void)
1411 prefix *fr = NULL, *to = NULL;
1413 bool fMulti = fFalse;
1415 reading first_stn = End;
1417 reading *ordering;
1419 again:
1421 for (ordering = pcs->ordering ; ; ordering++) {
1422 skipblanks();
1423 switch (*ordering) {
1424 case Fr:
1425 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
1426 if (first_stn == End) first_stn = Fr;
1427 break;
1428 case To:
1429 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
1430 if (first_stn == End) first_stn = To;
1431 break;
1432 case Station:
1433 fr = to;
1434 to = read_prefix(PFX_STATION);
1435 first_stn = To;
1436 break;
1437 case Dx: case Dy: case Dz:
1438 read_reading(*ordering, fFalse);
1439 break;
1440 case Ignore:
1441 skipword(); break;
1442 case IgnoreAllAndNewLine:
1443 skipline();
1444 /* fall through */
1445 case Newline:
1446 if (fr != NULL) {
1447 if (!process_cartesian(fr, to, first_stn == To))
1448 skipline();
1450 fMulti = fTrue;
1451 while (1) {
1452 process_eol();
1453 skipblanks();
1454 if (isData(ch)) break;
1455 if (!isComm(ch)) {
1456 return;
1459 break;
1460 case IgnoreAll:
1461 skipline();
1462 /* fall through */
1463 case End:
1464 if (!fMulti) {
1465 process_cartesian(fr, to, first_stn == To);
1466 process_eol();
1467 return;
1469 do {
1470 process_eol();
1471 skipblanks();
1472 } while (isComm(ch));
1473 goto again;
1474 default: BUG("Unknown reading in ordering");
1479 static int
1480 process_cylpolar(prefix *fr, prefix *to, bool fToFirst, bool fDepthChange)
1482 real tape = VAL(Tape);
1484 real dx, dy, dz;
1485 real vx, vy, vz;
1486 #ifndef NO_COVARIANCES
1487 real cxy = 0;
1488 #endif
1490 handle_comp_units();
1492 /* depth gauge readings increase upwards with default calibration */
1493 if (fDepthChange) {
1494 SVX_ASSERT(VAL(FrDepth) == 0.0);
1495 dz = VAL(ToDepth) * pcs->units[Q_DEPTH] - pcs->z[Q_DEPTH];
1496 dz *= pcs->sc[Q_DEPTH];
1497 } else {
1498 dz = VAL(ToDepth) - VAL(FrDepth);
1499 dz *= pcs->units[Q_DEPTH] * pcs->sc[Q_DEPTH];
1502 /* adjusted tape is negative -- probably the calibration is wrong */
1503 if (tape < (real)0.0) {
1504 compile_warning(/*Negative adjusted tape reading*/79);
1507 if (VAL(Comp) == HUGE_REAL && VAL(BackComp) == HUGE_REAL) {
1508 /* plumb */
1509 dx = dy = (real)0.0;
1510 vx = vy = var(Q_POS) / 3.0 + dz * dz * var(Q_PLUMB);
1511 /* FIXME: Should use FrDepth sometimes... */
1512 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1513 } else {
1514 real sinB, cosB;
1515 real var_comp;
1516 real comp = handle_compass(&var_comp);
1517 sinB = sin(comp);
1518 cosB = cos(comp);
1520 dx = tape * sinB;
1521 dy = tape * cosB;
1523 vx = var(Q_POS) / 3.0 +
1524 VAR(Tape) * sinB * sinB + var_comp * dy * dy;
1525 vy = var(Q_POS) / 3.0 +
1526 VAR(Tape) * cosB * cosB + var_comp * dx * dx;
1527 /* FIXME: Should use FrDepth sometimes... */
1528 vz = var(Q_POS) / 3.0 + 2 * VAR(ToDepth);
1530 #ifndef NO_COVARIANCES
1531 cxy = (VAR(Tape) - var_comp * tape * tape) * sinB * cosB;
1532 #endif
1534 addlegbyname(fr, to, fToFirst, dx, dy, dz, vx, vy, vz
1535 #ifndef NO_COVARIANCES
1536 , cxy, 0, 0
1537 #endif
1539 return 1;
1542 /* Process tape/compass/clino, diving, and cylpolar styles of survey data
1543 * Also handles topofil (fromcount/tocount or count) in place of tape */
1544 static void
1545 data_normal(void)
1547 prefix *fr = NULL, *to = NULL;
1548 reading first_stn = End;
1550 bool fTopofil = fFalse, fMulti = fFalse;
1551 bool fRev;
1552 clino_type ctype, backctype;
1553 bool fDepthChange;
1554 unsigned long compass_dat_flags = 0;
1556 reading *ordering;
1558 VAL(Tape) = VAL(BackTape) = HUGE_REAL;
1559 VAL(Comp) = VAL(BackComp) = HUGE_REAL;
1560 VAL(FrCount) = VAL(ToCount) = 0;
1561 VAL(FrDepth) = VAL(ToDepth) = 0;
1562 VAL(Left) = VAL(Right) = VAL(Up) = VAL(Down) = HUGE_REAL;
1564 fRev = fFalse;
1565 ctype = backctype = CTYPE_OMIT;
1566 fDepthChange = fFalse;
1568 /* ordering may omit clino reading, so set up default here */
1569 /* this is also used if clino reading is the omit character */
1570 VAL(Clino) = VAL(BackClino) = 0;
1572 again:
1574 /* We clear these flags in the normal course of events, but if there's an
1575 * error in a reading, we might not, so make sure it has been cleared here.
1577 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1578 for (ordering = pcs->ordering; ; ordering++) {
1579 skipblanks();
1580 switch (*ordering) {
1581 case Fr:
1582 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_ANON);
1583 if (first_stn == End) first_stn = Fr;
1584 break;
1585 case To:
1586 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT|PFX_ANON);
1587 if (first_stn == End) first_stn = To;
1588 break;
1589 case Station:
1590 fr = to;
1591 to = read_prefix(PFX_STATION);
1592 first_stn = To;
1593 break;
1594 case Dir: {
1595 typedef enum {
1596 DIR_NULL=-1, DIR_FORE, DIR_BACK
1597 } dir_tok;
1598 static sztok dir_tab[] = {
1599 {"B", DIR_BACK},
1600 {"F", DIR_FORE},
1602 dir_tok tok;
1603 get_token();
1604 tok = match_tok(dir_tab, TABSIZE(dir_tab));
1605 switch (tok) {
1606 case DIR_FORE:
1607 break;
1608 case DIR_BACK:
1609 fRev = fTrue;
1610 break;
1611 default:
1612 compile_error_buffer_skip(-/*Found ā€œ%sā€, expecting ā€œFā€ or ā€œBā€*/131, buffer);
1613 process_eol();
1614 return;
1616 break;
1618 case Tape: case BackTape: {
1619 reading r = *ordering;
1620 read_reading(r, fTrue);
1621 if (VAL(r) == HUGE_REAL) {
1622 if (!isOmit(ch)) {
1623 compile_error_token(-/*Expecting numeric field, found ā€œ%sā€*/9);
1624 /* Avoid also warning about omitted tape reading. */
1625 VAL(r) = 0;
1626 } else {
1627 nextch();
1629 } else if (VAL(r) < (real)0.0) {
1630 compile_warning(-/*Negative tape reading*/60);
1632 break;
1634 case Count:
1635 VAL(FrCount) = VAL(ToCount);
1636 LOC(FrCount) = LOC(ToCount);
1637 read_reading(ToCount, fFalse);
1638 fTopofil = fTrue;
1639 break;
1640 case FrCount:
1641 read_reading(FrCount, fFalse);
1642 break;
1643 case ToCount:
1644 read_reading(ToCount, fFalse);
1645 fTopofil = fTrue;
1646 break;
1647 case Comp: case BackComp:
1648 read_bearing_or_omit(*ordering);
1649 break;
1650 case Clino: case BackClino: {
1651 reading r = *ordering;
1652 clino_type * p_ctype = (r == Clino ? &ctype : &backctype);
1653 read_reading(r, fTrue);
1654 if (VAL(r) == HUGE_REAL) {
1655 VAL(r) = handle_plumb(p_ctype);
1656 if (VAL(r) != HUGE_REAL) break;
1657 compile_error_token(-/*Expecting numeric field, found ā€œ%sā€*/9);
1658 skipline();
1659 process_eol();
1660 return;
1662 *p_ctype = CTYPE_READING;
1663 break;
1665 case FrDepth: case ToDepth:
1666 read_reading(*ordering, fFalse);
1667 break;
1668 case Depth:
1669 VAL(FrDepth) = VAL(ToDepth);
1670 LOC(FrDepth) = LOC(ToDepth);
1671 read_reading(ToDepth, fFalse);
1672 break;
1673 case DepthChange:
1674 fDepthChange = fTrue;
1675 VAL(FrDepth) = 0;
1676 read_reading(ToDepth, fFalse);
1677 break;
1678 case CompassDATComp:
1679 read_bearing_or_omit(Comp);
1680 if (is_compass_NaN(VAL(Comp))) VAL(Comp) = HUGE_REAL;
1681 break;
1682 case CompassDATBackComp:
1683 read_bearing_or_omit(BackComp);
1684 if (is_compass_NaN(VAL(BackComp))) VAL(BackComp) = HUGE_REAL;
1685 break;
1686 case CompassDATClino: case CompassDATBackClino: {
1687 reading r;
1688 clino_type * p_ctype;
1689 if (*ordering == CompassDATClino) {
1690 r = Clino;
1691 p_ctype = &ctype;
1692 } else {
1693 r = BackClino;
1694 p_ctype = &backctype;
1696 read_reading(r, fFalse);
1697 if (is_compass_NaN(VAL(r))) {
1698 VAL(r) = HUGE_REAL;
1699 *p_ctype = CTYPE_OMIT;
1700 } else {
1701 *p_ctype = CTYPE_READING;
1703 break;
1705 case CompassDATLeft: case CompassDATRight:
1706 case CompassDATUp: case CompassDATDown: {
1707 /* FIXME: need to actually make use of these entries! */
1708 reading actual = Left + (*ordering - CompassDATLeft);
1709 read_reading(actual, fFalse);
1710 if (VAL(actual) < 0) VAL(actual) = HUGE_REAL;
1711 break;
1713 case CompassDATFlags:
1714 if (ch == '#') {
1715 filepos fp;
1716 get_pos(&fp);
1717 nextch();
1718 if (ch == '|') {
1719 nextch();
1720 while (ch >= 'A' && ch <= 'Z') {
1721 compass_dat_flags |= BIT(ch - 'A');
1722 /* We currently understand:
1723 * L (exclude from length)
1724 * X (exclude data)
1725 * FIXME: but should also handle at least some of:
1726 * C (no adjustment) (set all (co)variances to 0?)
1727 * P (no plot) (new flag in 3d for "hidden by default"?)
1729 nextch();
1731 if (ch == '#') {
1732 nextch();
1733 } else {
1734 compass_dat_flags = 0;
1735 set_pos(&fp);
1737 } else {
1738 set_pos(&fp);
1741 break;
1742 case Ignore:
1743 skipword(); break;
1744 case IgnoreAllAndNewLine:
1745 skipline();
1746 /* fall through */
1747 case Newline:
1748 if (fr != NULL) {
1749 int r;
1750 int save_flags;
1751 int implicit_splay;
1752 if (fTopofil) {
1753 VAL(Tape) = VAL(ToCount) - VAL(FrCount);
1754 LOC(Tape) = LOC(ToCount);
1756 /* Note: frdepth == todepth test works regardless of fDepthChange
1757 * (frdepth always zero, todepth is change of depth) and also
1758 * works for STYLE_NORMAL (both remain 0) */
1759 if (TSTBIT(pcs->infer, INFER_EQUATES) &&
1760 (VAL(Tape) == (real)0.0 || VAL(Tape) == HUGE_REAL) &&
1761 (VAL(BackTape) == (real)0.0 || VAL(BackTape) == HUGE_REAL) &&
1762 VAL(FrDepth) == VAL(ToDepth)) {
1763 process_equate(fr, to);
1764 goto inferred_equate;
1766 if (fRev) {
1767 prefix *t = fr;
1768 fr = to;
1769 to = t;
1771 if (fTopofil) {
1772 VAL(Tape) *= pcs->units[Q_COUNT] * pcs->sc[Q_COUNT];
1773 } else if (VAL(Tape) != HUGE_REAL) {
1774 VAL(Tape) *= pcs->units[Q_LENGTH];
1775 VAL(Tape) -= pcs->z[Q_LENGTH];
1776 VAL(Tape) *= pcs->sc[Q_LENGTH];
1778 if (VAL(BackTape) != HUGE_REAL) {
1779 VAL(BackTape) *= pcs->units[Q_BACKLENGTH];
1780 VAL(BackTape) -= pcs->z[Q_BACKLENGTH];
1781 VAL(BackTape) *= pcs->sc[Q_BACKLENGTH];
1782 if (VAL(Tape) != HUGE_REAL) {
1783 real diff = VAL(Tape) - VAL(BackTape);
1784 if (sqrd(diff / 3.0) > VAR(Tape) + VAR(BackTape)) {
1785 /* fore and back readings differ by more than 3 sds */
1786 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1787 * by, e.g. "0.12m" or "0.2ft". */
1788 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1789 diff, get_length_units(Q_LENGTH));
1791 VAL(Tape) = VAL(Tape) / VAR(Tape) + VAL(BackTape) / VAR(BackTape);
1792 VAR(Tape) = (VAR(Tape) + VAR(BackTape)) / 4;
1793 VAL(Tape) *= VAR(Tape);
1794 } else {
1795 VAL(Tape) = VAL(BackTape);
1796 VAR(Tape) = VAR(BackTape);
1798 } else if (VAL(Tape) == HUGE_REAL) {
1799 compile_error_reading(Tape, /*Tape reading may not be omitted*/94);
1800 goto inferred_equate;
1802 implicit_splay = TSTBIT(pcs->flags, FLAGS_IMPLICIT_SPLAY);
1803 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1804 save_flags = pcs->flags;
1805 if (implicit_splay) {
1806 pcs->flags |= BIT(FLAGS_SPLAY);
1808 switch (pcs->style) {
1809 case STYLE_NORMAL:
1810 r = process_normal(fr, to, (first_stn == To) ^ fRev,
1811 ctype, backctype);
1812 break;
1813 case STYLE_DIVING:
1814 /* FIXME: Handle any clino readings */
1815 r = process_diving(fr, to, (first_stn == To) ^ fRev,
1816 fDepthChange);
1817 break;
1818 case STYLE_CYLPOLAR:
1819 r = process_cylpolar(fr, to, (first_stn == To) ^ fRev,
1820 fDepthChange);
1821 break;
1822 default:
1823 r = 0; /* avoid warning */
1824 BUG("bad style");
1826 pcs->flags = save_flags;
1827 if (!r) skipline();
1829 /* Swap fr and to back to how they were for next line */
1830 if (fRev) {
1831 prefix *t = fr;
1832 fr = to;
1833 to = t;
1837 fRev = fFalse;
1838 ctype = backctype = CTYPE_OMIT;
1839 fDepthChange = fFalse;
1841 /* ordering may omit clino reading, so set up default here */
1842 /* this is also used if clino reading is the omit character */
1843 VAL(Clino) = VAL(BackClino) = 0;
1844 LOC(Clino) = LOC(BackClino) = -1;
1846 inferred_equate:
1848 fMulti = fTrue;
1849 while (1) {
1850 process_eol();
1851 skipblanks();
1852 if (isData(ch)) break;
1853 if (!isComm(ch)) {
1854 return;
1857 break;
1858 case IgnoreAll:
1859 skipline();
1860 /* fall through */
1861 case End:
1862 if (!fMulti) {
1863 int save_flags;
1864 int implicit_splay;
1865 /* Compass ignore flag is 'X' */
1866 if ((compass_dat_flags & BIT('X' - 'A'))) {
1867 process_eol();
1868 return;
1870 if (fRev) {
1871 prefix *t = fr;
1872 fr = to;
1873 to = t;
1875 if (fTopofil) {
1876 VAL(Tape) = VAL(ToCount) - VAL(FrCount);
1877 LOC(Tape) = LOC(ToCount);
1879 /* Note: frdepth == todepth test works regardless of fDepthChange
1880 * (frdepth always zero, todepth is change of depth) and also
1881 * works for STYLE_NORMAL (both remain 0) */
1882 if (TSTBIT(pcs->infer, INFER_EQUATES) &&
1883 (VAL(Tape) == (real)0.0 || VAL(Tape) == HUGE_REAL) &&
1884 (VAL(BackTape) == (real)0.0 || VAL(BackTape) == HUGE_REAL) &&
1885 VAL(FrDepth) == VAL(ToDepth)) {
1886 process_equate(fr, to);
1887 process_eol();
1888 return;
1890 if (fTopofil) {
1891 VAL(Tape) *= pcs->units[Q_COUNT] * pcs->sc[Q_COUNT];
1892 } else if (VAL(Tape) != HUGE_REAL) {
1893 VAL(Tape) *= pcs->units[Q_LENGTH];
1894 VAL(Tape) -= pcs->z[Q_LENGTH];
1895 VAL(Tape) *= pcs->sc[Q_LENGTH];
1897 if (VAL(BackTape) != HUGE_REAL) {
1898 VAL(BackTape) *= pcs->units[Q_BACKLENGTH];
1899 VAL(BackTape) -= pcs->z[Q_BACKLENGTH];
1900 VAL(BackTape) *= pcs->sc[Q_BACKLENGTH];
1901 if (VAL(Tape) != HUGE_REAL) {
1902 real diff = VAL(Tape) - VAL(BackTape);
1903 if (sqrd(diff / 3.0) > VAR(Tape) + VAR(BackTape)) {
1904 /* fore and back readings differ by more than 3 sds */
1905 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1906 * by, e.g. "0.12m" or "0.2ft". */
1907 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
1908 diff, get_length_units(Q_LENGTH));
1910 VAL(Tape) = VAL(Tape) / VAR(Tape) + VAL(BackTape) / VAR(BackTape);
1911 VAR(Tape) = (VAR(Tape) + VAR(BackTape)) / 4;
1912 VAL(Tape) *= VAR(Tape);
1913 } else {
1914 VAL(Tape) = VAL(BackTape);
1915 VAR(Tape) = VAR(BackTape);
1917 } else if (VAL(Tape) == HUGE_REAL) {
1918 compile_error_reading(Tape, /*Tape reading may not be omitted*/94);
1919 process_eol();
1920 return;
1922 implicit_splay = TSTBIT(pcs->flags, FLAGS_IMPLICIT_SPLAY);
1923 pcs->flags &= ~(BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY));
1924 save_flags = pcs->flags;
1925 if (implicit_splay) {
1926 pcs->flags |= BIT(FLAGS_SPLAY);
1928 if ((compass_dat_flags & BIT('L' - 'A'))) {
1929 /* 'L' means "exclude from length" - map this to Survex's
1930 * FLAGS_DUPLICATE. */
1931 pcs->flags |= BIT(FLAGS_DUPLICATE);
1933 switch (pcs->style) {
1934 case STYLE_NORMAL:
1935 process_normal(fr, to, (first_stn == To) ^ fRev,
1936 ctype, backctype);
1937 break;
1938 case STYLE_DIVING:
1939 /* FIXME: Handle any clino readings */
1940 process_diving(fr, to, (first_stn == To) ^ fRev,
1941 fDepthChange);
1942 break;
1943 case STYLE_CYLPOLAR:
1944 process_cylpolar(fr, to, (first_stn == To) ^ fRev,
1945 fDepthChange);
1946 break;
1947 default:
1948 BUG("bad style");
1950 pcs->flags = save_flags;
1952 process_eol();
1953 return;
1955 do {
1956 process_eol();
1957 skipblanks();
1958 } while (isComm(ch));
1959 goto again;
1960 default:
1961 BUG("Unknown reading in ordering");
1966 static int
1967 process_lrud(prefix *stn)
1969 SVX_ASSERT(next_lrud);
1970 lrud * xsect = osnew(lrud);
1971 xsect->stn = stn;
1972 xsect->l = (VAL(Left) * pcs->units[Q_LEFT] - pcs->z[Q_LEFT]) * pcs->sc[Q_LEFT];
1973 xsect->r = (VAL(Right) * pcs->units[Q_RIGHT] - pcs->z[Q_RIGHT]) * pcs->sc[Q_RIGHT];
1974 xsect->u = (VAL(Up) * pcs->units[Q_UP] - pcs->z[Q_UP]) * pcs->sc[Q_UP];
1975 xsect->d = (VAL(Down) * pcs->units[Q_DOWN] - pcs->z[Q_DOWN]) * pcs->sc[Q_DOWN];
1976 xsect->meta = pcs->meta;
1977 if (pcs->meta) ++pcs->meta->ref_count;
1978 xsect->next = NULL;
1979 *next_lrud = xsect;
1980 next_lrud = &(xsect->next);
1982 return 1;
1985 static void
1986 data_passage(void)
1988 prefix *stn = NULL;
1989 reading *ordering;
1991 for (ordering = pcs->ordering ; ; ordering++) {
1992 skipblanks();
1993 switch (*ordering) {
1994 case Station:
1995 stn = read_prefix(PFX_STATION);
1996 break;
1997 case Left: case Right: case Up: case Down: {
1998 reading r = *ordering;
1999 read_reading(r, fTrue);
2000 if (VAL(r) == HUGE_REAL) {
2001 if (!isOmit(ch)) {
2002 compile_error_token(-/*Expecting numeric field, found ā€œ%sā€*/9);
2003 } else {
2004 nextch();
2006 VAL(r) = -1;
2008 break;
2010 case Ignore:
2011 skipword(); break;
2012 case IgnoreAll:
2013 skipline();
2014 /* fall through */
2015 case End: {
2016 process_lrud(stn);
2017 process_eol();
2018 return;
2020 default: BUG("Unknown reading in ordering");
2025 static int
2026 process_nosurvey(prefix *fr, prefix *to, bool fToFirst)
2028 nosurveylink *link;
2030 /* Suppress "unused fixed point" warnings for these stations */
2031 fr->sflags |= BIT(SFLAGS_USED);
2032 to->sflags |= BIT(SFLAGS_USED);
2034 /* add to linked list which is dealt with after network is solved */
2035 link = osnew(nosurveylink);
2036 if (fToFirst) {
2037 link->to = StnFromPfx(to);
2038 link->fr = StnFromPfx(fr);
2039 } else {
2040 link->fr = StnFromPfx(fr);
2041 link->to = StnFromPfx(to);
2043 link->flags = pcs->flags | (STYLE_NOSURVEY << FLAGS_STYLE_BIT0);
2044 link->meta = pcs->meta;
2045 if (pcs->meta) ++pcs->meta->ref_count;
2046 link->next = nosurveyhead;
2047 nosurveyhead = link;
2048 return 1;
2051 static void
2052 data_nosurvey(void)
2054 prefix *fr = NULL, *to = NULL;
2056 bool fMulti = fFalse;
2058 reading first_stn = End;
2060 reading *ordering;
2062 again:
2064 for (ordering = pcs->ordering ; ; ordering++) {
2065 skipblanks();
2066 switch (*ordering) {
2067 case Fr:
2068 fr = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
2069 if (first_stn == End) first_stn = Fr;
2070 break;
2071 case To:
2072 to = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
2073 if (first_stn == End) first_stn = To;
2074 break;
2075 case Station:
2076 fr = to;
2077 to = read_prefix(PFX_STATION);
2078 first_stn = To;
2079 break;
2080 case Ignore:
2081 skipword(); break;
2082 case IgnoreAllAndNewLine:
2083 skipline();
2084 /* fall through */
2085 case Newline:
2086 if (fr != NULL) {
2087 if (!process_nosurvey(fr, to, first_stn == To))
2088 skipline();
2090 if (ordering[1] == End) {
2091 do {
2092 process_eol();
2093 skipblanks();
2094 } while (isComm(ch));
2095 if (!isData(ch)) {
2096 return;
2098 goto again;
2100 fMulti = fTrue;
2101 while (1) {
2102 process_eol();
2103 skipblanks();
2104 if (isData(ch)) break;
2105 if (!isComm(ch)) {
2106 return;
2109 break;
2110 case IgnoreAll:
2111 skipline();
2112 /* fall through */
2113 case End:
2114 if (!fMulti) {
2115 (void)process_nosurvey(fr, to, first_stn == To);
2116 process_eol();
2117 return;
2119 do {
2120 process_eol();
2121 skipblanks();
2122 } while (isComm(ch));
2123 goto again;
2124 default: BUG("Unknown reading in ordering");
2129 /* totally ignore a line of survey data */
2130 static void
2131 data_ignore(void)
2133 skipline();
2134 process_eol();