2 * Reads in survey files, dealing with special characters, keywords & data
3 * Copyright (C) 1991-2024 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
42 #if PROJ_VERSION_MAJOR < 8 || \
43 (PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR < 2)
44 /* Needed for proj_factors workaround */
45 # include <proj_experimental.h>
48 #define EPSILON (REAL_EPSILON * 1000)
50 #define var(I) (pcs->Var[(I)])
52 /* true if x is not-a-number value in Compass (999.0 or -999.0) */
53 /* Compass uses -999.0 but understands Karst data which used 999.0
54 * (information from Larry Fish via Simeon Warner). */
55 #define is_compass_NaN(x) ( fabs(fabs(x)-999.0) < EPSILON )
57 #define COMPASS_DATUM_WGS84 1
62 CTYPE_OMIT
, CTYPE_READING
, CTYPE_PLUMB
, CTYPE_INFERPLUMB
, CTYPE_HORIZ
65 /* Don't explicitly initialise as we can't set the jmp_buf - this has
66 * static scope so will be initialised like this anyway */
67 parse file
/* = { NULL, NULL, 0, false, NULL } */ ;
71 static real value
[Fr
- 1];
72 #define VAL(N) value[(N)-1]
73 static real variance
[Fr
- 1];
74 #define VAR(N) variance[(N)-1]
75 static long location
[Fr
- 1];
76 #define LOC(N) location[(N)-1]
77 static int location_width
[Fr
- 1];
78 #define WID(N) location_width[(N)-1]
81 static void data_normal(void);
82 static void data_cartesian(void);
83 static void data_passage(void);
84 static void data_nosurvey(void);
85 static void data_ignore(void);
91 fp
->offset
= ftell(file
.fh
);
93 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
97 set_pos(const filepos
*fp
)
100 if (fseek(file
.fh
, fp
->offset
, SEEK_SET
) == -1)
101 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
105 report_parent(parse
* p
) {
107 report_parent(p
->parent
);
108 /* Force re-report of include tree for further errors in
110 p
->reported_where
= false;
111 /* TRANSLATORS: %s is replaced by the filename of the parent file, and %u
112 * by the line number in that file. Your translation should also contain
113 * %s:%u so that automatic parsing of error messages to determine the file
114 * and line number still works. */
115 fprintf(STDERR
, msg(/*In file included from %s:%u:\n*/5), p
->filename
, p
->line
);
119 error_list_parent_files(void)
121 if (!file
.reported_where
&& file
.parent
) {
122 report_parent(file
.parent
);
123 /* Suppress reporting of full include tree for further errors
125 file
.reported_where
= true;
130 show_line(int col
, int width
)
132 /* Rewind to beginning of line. */
133 long cur_pos
= ftell(file
.fh
);
135 if (cur_pos
< 0 || fseek(file
.fh
, file
.lpos
, SEEK_SET
) == -1)
136 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
138 /* Read the whole line and write it out. */
141 int c
= GETC(file
.fh
);
142 /* Note: isEol() is true for EOF */
144 if (c
== '\t') ++tabs
;
149 /* If we have a location in the line for the error, indicate it. */
153 while (--col
) PUTC(' ', STDERR
);
155 /* Copy tabs from line, replacing other characters with spaces - this
156 * means that the caret should line up correctly. */
157 if (fseek(file
.fh
, file
.lpos
, SEEK_SET
) == -1)
158 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
160 int c
= GETC(file
.fh
);
161 if (c
!= '\t') c
= ' ';
173 /* Revert to where we were. */
174 if (fseek(file
.fh
, cur_pos
, SEEK_SET
) == -1)
175 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
181 /* Rewind to beginning of line. */
182 long cur_pos
= ftell(file
.fh
);
185 if (cur_pos
< 0 || fseek(file
.fh
, file
.lpos
, SEEK_SET
) == -1)
186 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
188 /* Read the whole line into a string. */
190 int c
= GETC(file
.fh
);
191 /* Note: isEol() is true for EOF */
193 s_catchar(&p
, &len
, (char)c
);
196 /* Revert to where we were. */
197 if (fseek(file
.fh
, cur_pos
, SEEK_SET
) == -1) {
199 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
205 static int caret_width
= 0;
208 compile_v_report_fpos(int severity
, long fpos
, int en
, va_list ap
)
211 error_list_parent_files();
212 if (fpos
>= file
.lpos
)
213 col
= fpos
- file
.lpos
- caret_width
;
214 v_report(severity
, file
.filename
, file
.line
, col
, en
, ap
);
215 if (file
.fh
) show_line(col
, caret_width
);
219 compile_v_report(int diag_flags
, int en
, va_list ap
)
221 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
222 if (diag_flags
& (DIAG_COL
|DIAG_BUF
)) {
224 if (diag_flags
& DIAG_BUF
) caret_width
= strlen(buffer
);
225 compile_v_report_fpos(severity
, ftell(file
.fh
), en
, ap
);
226 if (diag_flags
& DIAG_BUF
) caret_width
= 0;
227 if (diag_flags
& DIAG_SKIP
) skipline();
231 error_list_parent_files();
232 v_report(severity
, file
.filename
, file
.line
, 0, en
, ap
);
234 if (diag_flags
& DIAG_BUF
) {
235 show_line(0, strlen(buffer
));
237 show_line(0, caret_width
);
240 if (diag_flags
& DIAG_SKIP
) skipline();
244 compile_diagnostic(int diag_flags
, int en
, ...)
248 if (diag_flags
& (DIAG_TOKEN
|DIAG_UINT
|DIAG_DATE
|DIAG_NUM
)) {
252 if (diag_flags
& DIAG_TOKEN
) {
253 while (!isBlank(ch
) && !isEol(ch
)) {
254 s_catchar(&p
, &len
, (char)ch
);
257 } else if (diag_flags
& DIAG_UINT
) {
258 while (isdigit(ch
)) {
259 s_catchar(&p
, &len
, (char)ch
);
262 } else if (diag_flags
& DIAG_DATE
) {
263 while (isdigit(ch
) || ch
== '.') {
264 s_catchar(&p
, &len
, (char)ch
);
268 if (isMinus(ch
) || isPlus(ch
)) {
269 s_catchar(&p
, &len
, (char)ch
);
272 while (isdigit(ch
)) {
273 s_catchar(&p
, &len
, (char)ch
);
277 s_catchar(&p
, &len
, (char)ch
);
280 while (isdigit(ch
)) {
281 s_catchar(&p
, &len
, (char)ch
);
286 caret_width
= strlen(p
);
289 compile_v_report(diag_flags
|DIAG_COL
, en
, ap
);
291 } else if (diag_flags
& DIAG_STRING
) {
295 caret_width
= ftell(file
.fh
);
296 read_string(&p
, &alloced
);
298 /* We want to include any quotes, so can't use strlen(p). */
299 caret_width
= ftell(file
.fh
) - caret_width
;
300 compile_v_report(diag_flags
|DIAG_COL
, en
, ap
);
303 compile_v_report(diag_flags
, en
, ap
);
309 compile_diagnostic_reading(int diag_flags
, reading r
, int en
, ...)
312 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
314 caret_width
= WID(r
);
315 compile_v_report_fpos(severity
, LOC(r
) + caret_width
, en
, ap
);
321 compile_error_reading_skip(reading r
, int en
, ...)
325 caret_width
= WID(r
);
326 compile_v_report_fpos(DIAG_ERR
, LOC(r
) + caret_width
, en
, ap
);
333 compile_diagnostic_at(int diag_flags
, const char * filename
, unsigned line
, int en
, ...)
336 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
338 v_report(severity
, filename
, line
, 0, en
, ap
);
343 compile_diagnostic_pfx(int diag_flags
, const prefix
* pfx
, int en
, ...)
346 int severity
= (diag_flags
& DIAG_SEVERITY_MASK
);
348 v_report(severity
, pfx
->filename
, pfx
->line
, 0, en
, ap
);
353 compile_diagnostic_token_show(int diag_flags
, int en
)
358 while (!isBlank(ch
) && !isEol(ch
)) {
359 s_catchar(&p
, &len
, (char)ch
);
363 caret_width
= strlen(p
);
364 compile_diagnostic(diag_flags
|DIAG_COL
, en
, p
);
368 compile_diagnostic(DIAG_ERR
|DIAG_COL
, en
, "");
373 compile_error_string(const char * s
, int en
, ...)
377 caret_width
= strlen(s
);
378 compile_v_report(DIAG_ERR
|DIAG_COL
, en
, ap
);
383 /* This function makes a note where to put output files */
385 using_data_file(const char *fnm
)
387 if (!fnm_output_base
) {
388 /* was: fnm_output_base = base_from_fnm(fnm); */
389 fnm_output_base
= baseleaf_from_fnm(fnm
);
390 } else if (fnm_output_base_is_dir
) {
391 /* --output pointed to directory so use the leaf basename in that dir */
393 lf
= baseleaf_from_fnm(fnm
);
394 p
= use_path(fnm_output_base
, lf
);
396 osfree(fnm_output_base
);
398 fnm_output_base_is_dir
= 0;
405 while (!isBlank(ch
) && !isEol(ch
)) nextch();
411 while (isBlank(ch
)) nextch();
417 while (!isEol(ch
)) nextch();
429 compile_diagnostic(DIAG_ERR
|DIAG_COL
, /*End of line not blank*/15);
435 /* skip any different eol characters so we get line counts correct on
436 * DOS text files and similar, but don't count several adjacent blank
440 if (ch
== eolchar
|| !isEol(ch
)) {
443 if (ch
== '\n') eolchar
= ch
;
445 file
.lpos
= ftell(file
.fh
) - 1;
449 process_non_data_line(void)
453 if (isData(ch
)) return false;
466 read_reading(reading r
, bool f_optional
)
471 case Tape
: q
= Q_LENGTH
; break;
472 case BackTape
: q
= Q_BACKLENGTH
; break;
473 case Comp
: q
= Q_BEARING
; break;
474 case BackComp
: q
= Q_BACKBEARING
; break;
475 case Clino
: q
= Q_GRADIENT
; break;
476 case BackClino
: q
= Q_BACKGRADIENT
; break;
477 case FrDepth
: case ToDepth
: q
= Q_DEPTH
; break;
478 case Dx
: q
= Q_DX
; break;
479 case Dy
: q
= Q_DY
; break;
480 case Dz
: q
= Q_DZ
; break;
481 case FrCount
: case ToCount
: q
= Q_COUNT
; break;
482 case Left
: q
= Q_LEFT
; break;
483 case Right
: q
= Q_RIGHT
; break;
484 case Up
: q
= Q_UP
; break;
485 case Down
: q
= Q_DOWN
; break;
487 q
= Q_NULL
; /* Suppress compiler warning */;
488 BUG("Unexpected case");
490 LOC(r
) = ftell(file
.fh
);
491 /* since we don't handle bearings in read_readings, it's never quadrant */
492 VAL(r
) = read_numeric_multi(f_optional
, false, &n_readings
);
493 WID(r
) = ftell(file
.fh
) - LOC(r
);
495 if (n_readings
> 1) VAR(r
) /= sqrt(n_readings
);
499 read_bearing_or_omit(reading r
)
502 bool quadrants
= false;
503 q_quantity q
= Q_NULL
;
507 if (pcs
->f_bearing_quadrants
)
512 if (pcs
->f_backbearing_quadrants
)
516 q
= Q_NULL
; /* Suppress compiler warning */;
517 BUG("Unexpected case");
519 LOC(r
) = ftell(file
.fh
);
520 VAL(r
) = read_bearing_multi_or_omit(quadrants
, &n_readings
);
521 WID(r
) = ftell(file
.fh
) - LOC(r
);
523 if (n_readings
> 1) VAR(r
) /= sqrt(n_readings
);
526 /* For reading Compass MAK files which have a freeform syntax */
528 nextch_handling_eol(void)
531 while (ch
!= EOF
&& isEol(ch
)) {
536 #define LITLEN(S) (sizeof(S"") - 1)
537 #define has_ext(F,L,E) ((L) > LITLEN(E) + 1 &&\
538 (F)[(L) - LITLEN(E) - 1] == FNM_SEP_EXT &&\
539 strcasecmp((F) + (L) - LITLEN(E), E) == 0)
541 data_file(const char *pth
, const char *fnm
)
543 int begin_lineno_store
;
545 volatile enum {FMT_SVX
, FMT_DAT
, FMT_MAK
} fmt
= FMT_SVX
;
553 /* file specified on command line - don't do special translation */
554 fh
= fopenWithPthAndExt(pth
, fnm
, EXT_SVX_DATA
, "rb", &filename
);
556 fh
= fopen_portable(pth
, fnm
, EXT_SVX_DATA
, "rb", &filename
);
560 compile_error_string(fnm
, /*Couldnāt open file ā%sā*/24, fnm
);
564 len
= strlen(filename
);
565 if (has_ext(filename
, len
, "dat")) {
567 } else if (has_ext(filename
, len
, "mak")) {
572 if (file
.fh
) file
.parent
= &file_store
;
574 file
.filename
= filename
;
577 file
.reported_where
= false;
579 if (fmt
== FMT_SVX
&& ch
== 0xef) {
580 /* Maybe a UTF-8 "BOM" - skip if so. */
581 if (nextch() == 0xbb && nextch() == 0xbf) {
591 using_data_file(file
.filename
);
593 begin_lineno_store
= pcs
->begin_lineno
;
594 pcs
->begin_lineno
= 0;
596 if (fmt
== FMT_DAT
) {
601 pcsNew
= osnew(settings
);
602 *pcsNew
= *pcs
; /* copy contents */
603 pcsNew
->begin_lineno
= 0;
609 pcs
->recorded_style
= pcs
->style
= STYLE_NORMAL
;
610 pcs
->units
[Q_LENGTH
] = METRES_PER_FOOT
;
611 t
= ((short*)osmalloc(ossizeof(short) * 257)) + 1;
613 t
[EOF
] = SPECIAL_EOL
;
614 memset(t
, 0, sizeof(short) * 33);
615 for (i
= 33; i
< 127; i
++) t
[i
] = SPECIAL_NAMES
;
617 for (i
= 128; i
< 256; i
++) t
[i
] = SPECIAL_NAMES
;
618 t
['\t'] |= SPECIAL_BLANK
;
619 t
[' '] |= SPECIAL_BLANK
;
620 t
['\032'] |= SPECIAL_EOL
; /* Ctrl-Z, so olde DOS text files are handled ok */
621 t
['\n'] |= SPECIAL_EOL
;
622 t
['\r'] |= SPECIAL_EOL
;
623 t
['.'] |= SPECIAL_DECIMAL
;
624 t
['-'] |= SPECIAL_MINUS
;
625 t
['+'] |= SPECIAL_PLUS
;
628 pcs
->Truncate
= INT_MAX
;
629 pcs
->infer
= BIT(INFER_EQUATES
)|
630 BIT(INFER_EQUATES_SELF_OK
)|
633 } else if (fmt
== FMT_MAK
) {
638 pcsNew
= osnew(settings
);
639 *pcsNew
= *pcs
; /* copy contents */
640 pcsNew
->begin_lineno
= 0;
644 t
= ((short*)osmalloc(ossizeof(short) * 257)) + 1;
646 t
[EOF
] = SPECIAL_EOL
;
647 memset(t
, 0, sizeof(short) * 33);
648 for (i
= 33; i
< 127; i
++) t
[i
] = SPECIAL_NAMES
;
650 for (i
= 128; i
< 256; i
++) t
[i
] = SPECIAL_NAMES
;
651 t
['['] = t
[','] = t
[';'] = 0;
652 t
['\t'] |= SPECIAL_BLANK
;
653 t
[' '] |= SPECIAL_BLANK
;
654 t
['\032'] |= SPECIAL_EOL
; /* Ctrl-Z, so olde DOS text files are handled ok */
655 t
['\n'] |= SPECIAL_EOL
;
656 t
['\r'] |= SPECIAL_EOL
;
657 t
['.'] |= SPECIAL_DECIMAL
;
658 t
['-'] |= SPECIAL_MINUS
;
659 t
['+'] |= SPECIAL_PLUS
;
662 pcs
->Truncate
= INT_MAX
;
666 /* errors in nested functions can longjmp here */
667 if (setjmp(file
.jbSkipLine
)) {
673 if (fmt
== FMT_DAT
) {
674 while (ch
!= EOF
&& !ferror(file
.fh
)) {
675 static const reading compass_order
[] = {
676 Fr
, To
, Tape
, CompassDATComp
, CompassDATClino
,
677 CompassDATLeft
, CompassDATUp
, CompassDATDown
, CompassDATRight
,
678 CompassDATFlags
, IgnoreAll
680 static const reading compass_order_backsights
[] = {
681 Fr
, To
, Tape
, CompassDATComp
, CompassDATClino
,
682 CompassDATLeft
, CompassDATUp
, CompassDATDown
, CompassDATRight
,
683 CompassDATBackComp
, CompassDATBackClino
,
684 CompassDATFlags
, IgnoreAll
689 /* SURVEY NAME: <Short name> */
692 /* if (ch != ':') ... */
697 /* SURVEY DATE: 7 10 79 COMMENT:<Long name> */
700 copy_on_write_meta(pcs
);
702 int year
, month
, day
;
706 /* NB order is *month* *day* year */
710 /* Note: Larry says a 2 digit year is always 19XX */
711 if (year
< 100) year
+= 1900;
713 /* Compass uses 1901-01-01 when no date was specified. */
714 if (year
== 1901 && day
== 1 && month
== 1) goto compass_dat_no_date
;
715 pcs
->meta
->days1
= pcs
->meta
->days2
= days_since_1900(year
, month
, day
);
718 pcs
->meta
->days1
= pcs
->meta
->days2
= -1;
720 pcs
->declination
= HUGE_REAL
;
731 /* DECLINATION: 1.00 FORMAT: DDDDLUDRADLN CORRECTIONS: 2.00 3.00 4.00 */
735 pcs
->z
[Q_DECLINATION
] = -read_numeric(false);
736 pcs
->z
[Q_DECLINATION
] *= pcs
->units
[Q_DECLINATION
];
738 pcs
->ordering
= compass_order
;
739 if (strcmp(buffer
, "FORMAT") == 0) {
740 /* This documents the format in the original survey notebook - we
741 * don't need to fully parse it to be able to parse the survey data
742 * in the file, which gets converted to a fixed order and units.
747 buffer_len
= strlen(buffer
);
748 if (buffer_len
>= 4 && buffer
[3] == 'W') {
749 /* Original "Inclination Units" were "Depth Gauge". */
750 pcs
->recorded_style
= STYLE_DIVING
;
752 if (buffer_len
>= 12 && buffer
[buffer_len
>= 15 ? 13 : 11] == 'B') {
753 /* We have backsights for compass and clino */
754 pcs
->ordering
= compass_order_backsights
;
758 if (strcmp(buffer
, "CORRECTIONS") == 0) {
760 pcs
->z
[Q_BEARING
] = -rad(read_numeric(false));
761 pcs
->z
[Q_GRADIENT
] = -rad(read_numeric(false));
762 pcs
->z
[Q_LENGTH
] = -METRES_PER_FOOT
* read_numeric(false);
764 /* get_token() only reads alphas so we must check for '2' here. */
766 if (strcmp(buffer
, "CORRECTIONS") == 0 && ch
== '2') {
769 pcs
->z
[Q_BACKBEARING
] = -rad(read_numeric(false));
770 pcs
->z
[Q_BACKGRADIENT
] = -rad(read_numeric(false));
794 pcs
->ordering
= NULL
; /* Avoid free() of static array. */
796 } else if (fmt
== FMT_MAK
) {
799 char *path
= path_from_fnm(file
.filename
);
800 int path_len
= strlen(path
);
802 struct mak_folder
*next
;
804 } *folder_stack
= NULL
;
806 while (ch
!= EOF
&& !ferror(file
.fh
)) {
811 char *dat_fnm
= NULL
;
813 nextch_handling_eol();
814 while (ch
!= ',' && ch
!= ';' && ch
!= EOF
) {
815 while (isEol(ch
)) process_eol();
816 s_catchar(&dat_fnm
, &dat_fnm_len
, (char)ch
);
817 nextch_handling_eol();
821 data_file(path
, dat_fnm
);
825 while (ch
!= ';' && ch
!= EOF
) {
827 nextch_handling_eol();
828 name
= read_prefix(PFX_STATION
|PFX_OPT
);
835 bool in_feet
= false;
836 name
->sflags
|= BIT(SFLAGS_FIXED
);
837 nextch_handling_eol();
838 if (ch
== 'F' || ch
== 'f') {
840 nextch_handling_eol();
841 } else if (ch
== 'M' || ch
== 'm') {
842 nextch_handling_eol();
844 compile_diagnostic(DIAG_ERR
, /*Expecting āFā or āMā*/103);
846 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
847 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
848 nextch_handling_eol();
850 x
= read_numeric(false);
851 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
852 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
853 nextch_handling_eol();
855 y
= read_numeric(false);
856 while (!isdigit(ch
) && ch
!= '+' && ch
!= '-' &&
857 ch
!= '.' && ch
!= ']' && ch
!= EOF
) {
858 nextch_handling_eol();
860 z
= read_numeric(false);
862 x
*= METRES_PER_FOOT
;
863 y
*= METRES_PER_FOOT
;
864 z
*= METRES_PER_FOOT
;
866 stn
= StnFromPfx(name
);
873 if (x
!= POS(stn
, 0) || y
!= POS(stn
, 1) ||
875 compile_diagnostic(DIAG_ERR
, /*Station already fixed or equated to a fixed point*/46);
877 compile_diagnostic(DIAG_WARN
, /*Station already fixed at the same coordinates*/55);
880 while (ch
!= ']' && ch
!= EOF
) nextch_handling_eol();
882 nextch_handling_eol();
886 /* FIXME: link station - ignore for now */
887 /* FIXME: perhaps issue warning? Other station names can be "reused", which is problematic... */
889 while (ch
!= ',' && ch
!= ';' && ch
!= EOF
)
890 nextch_handling_eol();
899 utm_zone
= read_int(-60, 60);
901 if (ch
== ';') nextch();
904 if (!pcs
->next
|| pcs
->proj_str
!= pcs
->next
->proj_str
)
905 osfree(pcs
->proj_str
);
906 pcs
->proj_str
= NULL
;
907 if (datum
&& utm_zone
&& abs(utm_zone
) <= 60) {
908 /* Set up coordinate system. */
909 pcs
->proj_str
= osmalloc(32);
911 sprintf(pcs
->proj_str
, "EPSG:%d", 32600 + utm_zone
);
913 sprintf(pcs
->proj_str
, "EPSG:%d", 32700 - utm_zone
);
916 proj_str_out
= osstrdup(pcs
->proj_str
);
919 invalidate_pj_cached();
929 while (ch
!= ';' && !isEol(ch
)) {
930 s_catchar(&p
, &len
, (char)ch
);
932 /* Ignore trailing blanks. */
933 if (!isBlank(ch
)) datum_len
= c
;
936 if (ch
== ';') nextch();
937 /* FIXME: Handle other datums */
938 /* Also seen: North American 1927 */
939 /* Other valid values from docs:
940 * North American 1983
941 * An old changelog entry suggests at least 24 datums are
944 #define EQ(S) datum_len == LITLEN(S) && memcmp(p, S, LITLEN(S)) == 0
945 if (EQ("WGS 1984")) {
946 datum
= COMPASS_DATUM_WGS84
;
951 goto update_proj_str
;
954 // Enter subdirectory.
955 struct mak_folder
*p
= folder_stack
;
956 folder_stack
= osnew(struct mak_folder
);
957 folder_stack
->next
= p
;
958 folder_stack
->len
= strlen(path
);
960 s_catchar(&path
, &path_len
, FNM_SEP_LEV
);
962 while (ch
!= ';' && !isEol(ch
)) {
966 s_catchar(&path
, &path_len
, (char)ch
);
969 if (ch
== ';') nextch();
973 // Leave subdirectory.
974 struct mak_folder
*p
= folder_stack
;
975 if (folder_stack
== NULL
) {
979 path
[folder_stack
->len
] = '\0';
980 folder_stack
= folder_stack
->next
;
984 if (ch
== ';') nextch();
988 nextch_handling_eol();
995 while (ch
!= EOF
&& !ferror(file
.fh
)) {
996 if (!process_non_data_line()) {
998 switch (pcs
->style
) {
1001 case STYLE_CYLPOLAR
:
1004 case STYLE_CARTESIAN
:
1010 case STYLE_NOSURVEY
:
1024 /* don't allow *BEGIN at the end of a file, then *EXPORT in the
1026 f_export_ok
= false;
1028 if (pcs
->begin_lineno
) {
1029 error_in_file(file
.filename
, pcs
->begin_lineno
,
1030 /*BEGIN with no matching END in this file*/23);
1031 /* Implicitly close any unclosed BEGINs from this file */
1034 } while (pcs
->begin_lineno
);
1037 pcs
->begin_lineno
= begin_lineno_store
;
1039 if (ferror(file
.fh
))
1040 fatalerror_in_file(file
.filename
, 0, /*Error reading file*/18);
1042 (void)fclose(file
.fh
);
1046 /* don't free this - it may be pointed to by prefix.file */
1047 /* osfree(file.filename); */
1053 return a
- floor(a
/ (2 * M_PI
)) * (2 * M_PI
);
1057 handle_plumb(clino_type
*p_ctype
)
1060 CLINO_NULL
=-1, CLINO_UP
, CLINO_DOWN
, CLINO_LEVEL
1062 static const sztok clino_tab
[] = {
1064 {"DOWN", CLINO_DOWN
},
1066 {"LEVEL", CLINO_LEVEL
},
1071 static const real clinos
[] = {(real
)M_PI_2
, (real
)(-M_PI_2
), (real
)0.0};
1079 tok
= match_tok(clino_tab
, TABSIZE(clino_tab
));
1080 if (tok
!= CLINO_NULL
) {
1081 *p_ctype
= (tok
== CLINO_LEVEL
? CTYPE_HORIZ
: CTYPE_PLUMB
);
1085 } else if (isSign(ch
)) {
1088 if (toupper(ch
) == 'V') {
1090 *p_ctype
= CTYPE_PLUMB
;
1091 return (!isMinus(chOld
) ? M_PI_2
: -M_PI_2
);
1094 if (isOmit(chOld
)) {
1095 *p_ctype
= CTYPE_OMIT
;
1096 /* no clino reading, so assume 0 with large sd */
1099 } else if (isOmit(ch
)) {
1100 /* OMIT char may not be a SIGN char too so we need to check here as
1101 * well as above... */
1103 *p_ctype
= CTYPE_OMIT
;
1104 /* no clino reading, so assume 0 with large sd */
1111 warn_readings_differ(int msgno
, real diff
, int units
)
1115 diff
/= get_units_factor(units
);
1116 sprintf(buf
, "%.2f", fabs(diff
));
1117 for (p
= buf
; *p
; ++p
) {
1121 if (*p
!= '0') z
= p
+ 1;
1127 strcpy(p
, get_units_string(units
));
1128 compile_diagnostic(DIAG_WARN
, msgno
, buf
);
1132 handle_comp_units(void)
1134 bool fNoComp
= true;
1135 if (VAL(Comp
) != HUGE_REAL
) {
1137 VAL(Comp
) *= pcs
->units
[Q_BEARING
];
1138 if (VAL(Comp
) < (real
)0.0 || VAL(Comp
) - M_PI
* 2.0 > EPSILON
) {
1139 /* TRANSLATORS: Suspicious means something like 410 degrees or -20
1141 compile_diagnostic_reading(DIAG_WARN
, Comp
, /*Suspicious compass reading*/59);
1142 VAL(Comp
) = mod2pi(VAL(Comp
));
1145 if (VAL(BackComp
) != HUGE_REAL
) {
1147 VAL(BackComp
) *= pcs
->units
[Q_BACKBEARING
];
1148 if (VAL(BackComp
) < (real
)0.0 || VAL(BackComp
) - M_PI
* 2.0 > EPSILON
) {
1149 /* FIXME: different message for BackComp? */
1150 compile_diagnostic_reading(DIAG_WARN
, BackComp
, /*Suspicious compass reading*/59);
1151 VAL(BackComp
) = mod2pi(VAL(BackComp
));
1157 static real
compute_convergence(real lon
, real lat
) {
1158 // PROJ < 8.1.0 dereferences the context without a NULL check inside
1159 // proj_create_ellipsoidal_2D_cs() but PJ_DEFAULT_CTX is really just
1160 // NULL so for affected PROJ versions we create a context temporarily to
1161 // avoid a segmentation fault.
1162 PJ_CONTEXT
* ctx
= PJ_DEFAULT_CTX
;
1163 #if PROJ_VERSION_MAJOR < 8 || \
1164 (PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR < 1)
1165 ctx
= proj_context_create();
1168 if (!proj_str_out
) {
1169 compile_diagnostic(DIAG_ERR
, /*Output coordinate system not set*/488);
1172 PJ
* pj
= proj_create(ctx
, proj_str_out
);
1176 #if PROJ_VERSION_MAJOR < 8 || \
1177 (PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR < 2)
1178 /* Code adapted from fix in PROJ 8.2.0 to make proj_factors() work in
1179 * cases we need (e.g. a CRS specified as "EPSG:<number>").
1181 switch (proj_get_type(pj
)) {
1182 case PJ_TYPE_PROJECTED_CRS
: {
1183 /* If it is a projected CRS, then compute the factors on the conversion
1184 * associated to it. We need to start from a temporary geographic CRS
1185 * using the same datum as the one of the projected CRS, and with
1186 * input coordinates being in longitude, latitude order in radian,
1187 * to be consistent with the expectations of the lp input parameter.
1190 PJ
* geodetic_crs
= proj_get_source_crs(ctx
, pj
);
1193 PJ
* datum
= proj_crs_get_datum(ctx
, geodetic_crs
);
1194 #if PROJ_VERSION_MAJOR == 8 || \
1195 (PROJ_VERSION_MAJOR == 7 && PROJ_VERSION_MINOR >= 2)
1196 /* PROJ 7.2.0 upgraded to EPSG 10.x which added the concept
1197 * of a datum ensemble, and this version of PROJ also added
1198 * an API to deal with these.
1200 * If we're using PROJ < 7.2.0 then its EPSG database won't
1201 * have datum ensembles, so we don't need any code to handle
1205 datum
= proj_crs_get_datum_ensemble(ctx
, geodetic_crs
);
1208 PJ
* cs
= proj_create_ellipsoidal_2D_cs(
1209 ctx
, PJ_ELLPS2D_LONGITUDE_LATITUDE
, "Radian", 1.0);
1210 PJ
* temp
= proj_create_geographic_crs_from_datum(
1211 ctx
, "unnamed crs", datum
, cs
);
1212 proj_destroy(datum
);
1214 proj_destroy(geodetic_crs
);
1215 PJ
* newOp
= proj_create_crs_to_crs_from_pj(ctx
, temp
, pj
, NULL
, NULL
);
1227 #if PROJ_VERSION_MAJOR < 9 || \
1228 (PROJ_VERSION_MAJOR == 9 && PROJ_VERSION_MINOR < 3)
1230 /* In PROJ < 9.3.0 proj_factors() returns a grid convergence which is
1231 * off by 90Ā° for a projected coordinate system with northing/easting
1232 * axis order. We can't copy over the fix for this in PROJ 9.3.0's
1233 * proj_factors() since it uses non-public PROJ functions, but
1234 * normalising the output order here works too.
1236 PJ
* pj_norm
= proj_normalize_for_visualization(PJ_DEFAULT_CTX
, pj
);
1241 PJ_FACTORS factors
= proj_factors(pj
, lp
);
1243 #if PROJ_VERSION_MAJOR < 8 || \
1244 (PROJ_VERSION_MAJOR == 8 && PROJ_VERSION_MINOR < 1)
1245 proj_context_destroy(ctx
);
1247 return factors
.meridian_convergence
;
1251 handle_compass(real
*p_var
)
1253 real compvar
= VAR(Comp
);
1254 real comp
= VAL(Comp
);
1255 real backcomp
= VAL(BackComp
);
1257 if (pcs
->z
[Q_DECLINATION
] != HUGE_REAL
) {
1258 declination
= -pcs
->z
[Q_DECLINATION
];
1259 } else if (pcs
->declination
!= HUGE_REAL
) {
1260 /* Cached value calculated for a previous compass reading taken on the
1261 * same date (by the 'else' just below).
1263 declination
= pcs
->declination
;
1265 if (!pcs
->meta
|| pcs
->meta
->days1
== -1) {
1266 compile_diagnostic(DIAG_WARN
, /*No survey date specified - using 0 for magnetic declination*/304);
1269 int avg_days
= (pcs
->meta
->days1
+ pcs
->meta
->days2
) / 2;
1270 double dat
= julian_date_from_days_since_1900(avg_days
);
1271 /* thgeomag() takes (lat, lon, h, dat) - i.e. (y, x, z, date). */
1272 declination
= thgeomag(pcs
->dec_lat
, pcs
->dec_lon
, pcs
->dec_alt
, dat
);
1273 if (declination
< pcs
->min_declination
) {
1274 pcs
->min_declination
= declination
;
1275 pcs
->min_declination_days
= avg_days
;
1277 if (declination
> pcs
->max_declination
) {
1278 pcs
->max_declination
= declination
;
1279 pcs
->max_declination_days
= avg_days
;
1282 if (pcs
->convergence
== HUGE_REAL
) {
1283 /* Compute the convergence lazily. It only depends on the output
1284 * coordinate system so we can cache it for reuse to apply to
1285 * a declination value for a different date.
1287 pcs
->convergence
= compute_convergence(pcs
->dec_lon
, pcs
->dec_lat
);
1289 declination
-= pcs
->convergence
;
1290 /* We cache the calculated declination as the calculation is relatively
1291 * expensive. We also cache an "assumed 0" answer so that we only
1292 * warn once per such survey rather than for every line with a compass
1294 pcs
->declination
= declination
;
1296 if (comp
!= HUGE_REAL
) {
1297 comp
= (comp
- pcs
->z
[Q_BEARING
]) * pcs
->sc
[Q_BEARING
];
1298 comp
+= declination
;
1300 if (backcomp
!= HUGE_REAL
) {
1301 backcomp
= (backcomp
- pcs
->z
[Q_BACKBEARING
])
1302 * pcs
->sc
[Q_BACKBEARING
];
1303 backcomp
+= declination
;
1305 if (comp
!= HUGE_REAL
) {
1306 real diff
= comp
- backcomp
;
1307 real adj
= fabs(diff
) > M_PI
? M_PI
: 0;
1308 diff
-= floor((diff
+ M_PI
) / (2 * M_PI
)) * 2 * M_PI
;
1309 if (sqrd(diff
/ 3.0) > compvar
+ VAR(BackComp
)) {
1310 /* fore and back readings differ by more than 3 sds */
1311 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1312 * by, e.g. "2.5Ā°" or "3įµ". */
1313 warn_readings_differ(/*COMPASS reading and BACKCOMPASS reading disagree by %s*/98,
1314 diff
, get_angle_units(Q_BEARING
));
1316 comp
= (comp
/ compvar
+ backcomp
/ VAR(BackComp
));
1317 compvar
= (compvar
+ VAR(BackComp
)) / 4;
1322 compvar
= VAR(BackComp
);
1330 handle_clino(q_quantity q
, reading r
, real val
, bool percent
, clino_type
*p_ctype
)
1334 real diff_from_abs90
;
1335 val
*= pcs
->units
[q
];
1336 /* percentage scale */
1337 if (percent
) val
= atan(val
);
1338 /* We want to warn if there's a reading which it would be impossible
1339 * to have read from the instrument (e.g. on a -90 to 90 degree scale
1340 * you can't read "96" (it's probably a typo for "69"). However, the
1341 * gradient reading from a topofil is typically in the range 0 to 180,
1342 * with 90 being horizontal.
1344 * Really we should allow the valid range to be specified, but for now
1345 * we infer it from the zero error - if this is within 45 degrees of
1346 * 90 then we assume the range is 0 to 180.
1349 range_0_180
= (z
> M_PI_4
&& z
< 3*M_PI_4
);
1350 diff_from_abs90
= fabs(val
) - M_PI_2
;
1351 if (diff_from_abs90
> EPSILON
) {
1353 int clino_units
= get_angle_units(q
);
1354 const char * units
= get_units_string(clino_units
);
1355 real right_angle
= M_PI_2
/ get_units_factor(clino_units
);
1356 /* FIXME: different message for BackClino? */
1357 /* TRANSLATORS: %.f%s will be replaced with a right angle in the
1358 * units currently in use, e.g. "90Ā°" or "100įµ". And "absolute
1359 * value" means the reading ignoring the sign (so it might be
1360 * < -90Ā° or > 90Ā°. */
1361 compile_diagnostic_reading(DIAG_WARN
, r
, /*Clino reading over %.f%s (absolute value)*/51,
1362 right_angle
, units
);
1364 } else if (TSTBIT(pcs
->infer
, INFER_PLUMBS
) &&
1365 diff_from_abs90
>= -EPSILON
) {
1366 *p_ctype
= CTYPE_INFERPLUMB
;
1368 if (range_0_180
&& *p_ctype
!= CTYPE_INFERPLUMB
) {
1369 /* FIXME: Warning message not ideal... */
1370 if (val
< 0.0 || val
- M_PI
> EPSILON
) {
1371 int clino_units
= get_angle_units(q
);
1372 const char * units
= get_units_string(clino_units
);
1373 real right_angle
= M_PI_2
/ get_units_factor(clino_units
);
1374 compile_diagnostic_reading(DIAG_WARN
, r
, /*Clino reading over %.f%s (absolute value)*/51,
1375 right_angle
, units
);
1382 process_normal(prefix
*fr
, prefix
*to
, bool fToFirst
,
1383 clino_type ctype
, clino_type backctype
)
1385 real tape
= VAL(Tape
);
1386 real clin
= VAL(Clino
);
1387 real backclin
= VAL(BackClino
);
1391 #ifndef NO_COVARIANCES
1397 /* adjusted tape is negative -- probably the calibration is wrong */
1398 if (tape
< (real
)0.0) {
1399 /* TRANSLATE different message for topofil? */
1400 compile_diagnostic_reading(DIAG_WARN
, Tape
, /*Negative adjusted tape reading*/79);
1403 fNoComp
= handle_comp_units();
1405 if (ctype
== CTYPE_READING
) {
1406 clin
= handle_clino(Q_GRADIENT
, Clino
, clin
,
1407 pcs
->f_clino_percent
, &ctype
);
1410 if (backctype
== CTYPE_READING
) {
1411 backclin
= handle_clino(Q_BACKGRADIENT
, BackClino
, backclin
,
1412 pcs
->f_backclino_percent
, &backctype
);
1415 /* un-infer the plumb if the backsight was just a reading */
1416 if (ctype
== CTYPE_INFERPLUMB
&& backctype
== CTYPE_READING
) {
1417 ctype
= CTYPE_READING
;
1420 if (ctype
!= CTYPE_OMIT
&& backctype
!= CTYPE_OMIT
&& ctype
!= backctype
) {
1421 /* TRANSLATORS: In data with backsights, the user has tried to give a
1422 * plumb for the foresight and a clino reading for the backsight, or
1423 * something similar. */
1424 compile_error_reading_skip(Clino
, /*CLINO and BACKCLINO readings must be of the same type*/84);
1428 if (ctype
== CTYPE_PLUMB
|| ctype
== CTYPE_INFERPLUMB
||
1429 backctype
== CTYPE_PLUMB
|| backctype
== CTYPE_INFERPLUMB
) {
1432 if (ctype
== CTYPE_PLUMB
||
1433 (ctype
== CTYPE_INFERPLUMB
&& VAL(Comp
) != 0.0) ||
1434 backctype
== CTYPE_PLUMB
||
1435 (backctype
== CTYPE_INFERPLUMB
&& VAL(BackComp
) != 0.0)) {
1436 /* FIXME: Different message for BackComp? */
1437 /* TRANSLATORS: A "plumbed leg" is one measured using a plumbline
1438 * (a weight on a string). So the problem here is that the leg is
1439 * vertical, so a compass reading has no meaning! */
1440 compile_diagnostic(DIAG_WARN
, /*Compass reading given on plumbed leg*/21);
1444 dx
= dy
= (real
)0.0;
1445 if (ctype
!= CTYPE_OMIT
) {
1446 if (backctype
!= CTYPE_OMIT
&& (clin
> 0) == (backclin
> 0)) {
1447 /* TRANSLATORS: We've been told the foresight and backsight are
1448 * both "UP", or that they're both "DOWN". */
1449 compile_error_reading_skip(Clino
, /*Plumbed CLINO and BACKCLINO readings can't be in the same direction*/92);
1452 dz
= (clin
> (real
)0.0) ? tape
: -tape
;
1454 dz
= (backclin
< (real
)0.0) ? tape
: -tape
;
1456 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1457 vz
= var(Q_POS
) / 3.0 + VAR(Tape
);
1458 #ifndef NO_COVARIANCES
1459 /* Correct values - no covariances in this case! */
1460 cxy
= cyz
= czx
= (real
)0.0;
1463 /* Each of ctype and backctype are either CTYPE_READING/CTYPE_HORIZ
1466 real L2
, cosG
, LcosG
, cosG2
, sinB
, cosB
, dx2
, dy2
, dz2
, v
, V
;
1468 /* TRANSLATORS: Here "legs" are survey legs, i.e. measurements between
1469 * survey stations. */
1470 compile_error_reading_skip(Comp
, /*Compass reading may not be omitted except on plumbed legs*/14);
1473 if (tape
== (real
)0.0) {
1474 dx
= dy
= dz
= (real
)0.0;
1475 vx
= vy
= vz
= (real
)(var(Q_POS
) / 3.0); /* Position error only */
1476 #ifndef NO_COVARIANCES
1477 cxy
= cyz
= czx
= (real
)0.0;
1480 printf("Zero length leg: vx = %f, vy = %f, vz = %f\n", vx
, vy
, vz
);
1484 /* take into account variance in LEVEL case */
1485 real var_clin
= var(Q_LEVEL
);
1487 real comp
= handle_compass(&var_comp
);
1488 /* ctype != CTYPE_READING is LEVEL case */
1489 if (ctype
== CTYPE_READING
) {
1490 clin
= (clin
- pcs
->z
[Q_GRADIENT
]) * pcs
->sc
[Q_GRADIENT
];
1491 var_clin
= VAR(Clino
);
1493 if (backctype
== CTYPE_READING
) {
1494 backclin
= (backclin
- pcs
->z
[Q_BACKGRADIENT
])
1495 * pcs
->sc
[Q_BACKGRADIENT
];
1496 if (ctype
== CTYPE_READING
) {
1497 if (sqrd((clin
+ backclin
) / 3.0) > var_clin
+ VAR(BackClino
)) {
1498 /* fore and back readings differ by more than 3 sds */
1499 /* TRANSLATORS: %s is replaced by the amount the readings disagree
1500 * by, e.g. "2.5Ā°" or "3įµ". */
1501 warn_readings_differ(/*CLINO reading and BACKCLINO reading disagree by %s*/99,
1502 clin
+ backclin
, get_angle_units(Q_GRADIENT
));
1504 clin
= (clin
/ var_clin
- backclin
/ VAR(BackClino
));
1505 var_clin
= (var_clin
+ VAR(BackClino
)) / 4;
1509 var_clin
= VAR(BackClino
);
1514 printf(" %4.2f %4.2f %4.2f\n", tape
, comp
, clin
);
1517 LcosG
= tape
* cosG
;
1521 printf("sinB = %f, cosG = %f, LcosG = %f\n", sinB
, cosG
, LcosG
);
1525 dz
= tape
* sin(clin
);
1526 /* printf("%.2f\n",clin); */
1528 printf("dx = %f\ndy = %f\ndz = %f\n", dx
, dy
, dz
);
1534 cosG2
= cosG
* cosG
;
1535 sinGcosG
= sin(clin
) * cosG
;
1538 #ifdef NO_COVARIANCES
1539 vx
= (var(Q_POS
) / 3.0 + dx2
* V
+ dy2
* var_comp
+
1540 (.5 + sinB
* sinB
* cosG2
) * v
);
1541 vy
= (var(Q_POS
) / 3.0 + dy2
* V
+ dx2
* var_comp
+
1542 (.5 + cosB
* cosB
* cosG2
) * v
);
1543 if (ctype
== CTYPE_OMIT
&& backctype
== CTYPE_OMIT
) {
1544 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1545 vz
= var(Q_POS
) / 3.0 + L2
* (real
)0.1;
1547 vz
= var(Q_POS
) / 3.0 + dz2
* V
+ L2
* cosG2
* var_clin
;
1549 /* for Surveyor87 errors: vx=vy=vz=var(Q_POS)/3.0; */
1551 vx
= var(Q_POS
) / 3.0 + dx2
* V
+ dy2
* var_comp
+
1553 vy
= var(Q_POS
) / 3.0 + dy2
* V
+ dx2
* var_comp
+
1555 if (ctype
== CTYPE_OMIT
&& backctype
== CTYPE_OMIT
) {
1556 /* if no clino, assume sd=tape/sqrt(10) so 3sds = .95*tape */
1557 vz
= var(Q_POS
) / 3.0 + L2
* (real
)0.1;
1559 vz
= var(Q_POS
) / 3.0 + dz2
* V
+ L2
* cosG2
* var_clin
;
1561 /* usual covariance formulae are fine in no clino case since
1562 * dz = 0 so value of var_clin is ignored */
1563 cxy
= sinB
* cosB
* (VAR(Tape
) * cosG2
+ var_clin
* dz2
)
1564 - var_comp
* dx
* dy
;
1565 czx
= VAR(Tape
) * sinB
* sinGcosG
- var_clin
* dx
* dz
;
1566 cyz
= VAR(Tape
) * cosB
* sinGcosG
- var_clin
* dy
* dz
;
1568 printf("vx = %6.3f, vy = %6.3f, vz = %6.3f\n", vx
, vy
, vz
);
1569 printf("cxy = %6.3f, cyz = %6.3f, czx = %6.3f\n", cxy
, cyz
, czx
);
1573 printf("In DATAIN.C, vx = %f, vy = %f, vz = %f\n", vx
, vy
, vz
);
1578 printf("Just before addleg, vx = %f\n", vx
);
1580 /*printf("dx,dy,dz = %.2f %.2f %.2f\n\n", dx, dy, dz);*/
1581 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1582 #ifndef NO_COVARIANCES
1590 process_diving(prefix
*fr
, prefix
*to
, bool fToFirst
, bool fDepthChange
)
1592 real tape
= VAL(Tape
);
1596 #ifndef NO_COVARIANCES
1597 real cxy
= 0, cyz
= 0, czx
= 0;
1600 handle_comp_units();
1602 /* depth gauge readings increase upwards with default calibration */
1604 SVX_ASSERT(VAL(FrDepth
) == 0.0);
1605 dz
= VAL(ToDepth
) * pcs
->units
[Q_DEPTH
] - pcs
->z
[Q_DEPTH
];
1606 dz
*= pcs
->sc
[Q_DEPTH
];
1608 dz
= VAL(ToDepth
) - VAL(FrDepth
);
1609 dz
*= pcs
->units
[Q_DEPTH
] * pcs
->sc
[Q_DEPTH
];
1612 /* adjusted tape is negative -- probably the calibration is wrong */
1613 if (tape
< (real
)0.0) {
1614 compile_diagnostic(DIAG_WARN
, /*Negative adjusted tape reading*/79);
1617 /* check if tape is less than depth change */
1618 if (tape
< fabs(dz
)) {
1619 /* FIXME: allow margin of error based on variances? */
1620 /* TRANSLATORS: This means that the data fed in said this.
1622 * It could be a gross error (e.g. the decimal point is missing from the
1623 * depth gauge reading) or it could just be due to random error on a near
1625 compile_diagnostic(DIAG_WARN
, /*Tape reading is less than change in depth*/62);
1628 if (tape
== (real
)0.0 && dz
== 0.0) {
1629 dx
= dy
= dz
= (real
)0.0;
1630 vx
= vy
= vz
= (real
)(var(Q_POS
) / 3.0); /* Position error only */
1631 } else if (VAL(Comp
) == HUGE_REAL
&&
1632 VAL(BackComp
) == HUGE_REAL
) {
1634 dx
= dy
= (real
)0.0;
1635 if (dz
< 0) tape
= -tape
;
1636 /* FIXME: Should use FrDepth sometimes... */
1637 dz
= (dz
* VAR(Tape
) + tape
* 2 * VAR(ToDepth
))
1638 / (VAR(Tape
) * 2 * VAR(ToDepth
));
1639 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1640 /* FIXME: Should use FrDepth sometimes... */
1641 vz
= var(Q_POS
) / 3.0 + VAR(Tape
) * 2 * VAR(ToDepth
)
1642 / (VAR(Tape
) + VAR(ToDepth
));
1644 real L2
, sinB
, cosB
, dz2
, D2
;
1646 real comp
= handle_compass(&var_comp
);
1652 if (D2
<= (real
)0.0) {
1653 /* FIXME: Should use FrDepth sometimes... */
1654 real vsum
= VAR(Tape
) + 2 * VAR(ToDepth
);
1655 dx
= dy
= (real
)0.0;
1656 vx
= vy
= var(Q_POS
) / 3.0;
1657 /* FIXME: Should use FrDepth sometimes... */
1658 vz
= var(Q_POS
) / 3.0 + VAR(Tape
) * 2 * VAR(ToDepth
) / vsum
;
1660 /* FIXME: Should use FrDepth sometimes... */
1661 dz
= (dz
* VAR(Tape
) + tape
* 2 * VAR(ToDepth
)) / vsum
;
1663 dz
= (dz
* VAR(Tape
) - tape
* 2 * VAR(ToDepth
)) / vsum
;
1667 /* FIXME: Should use FrDepth sometimes... */
1668 real F
= VAR(Tape
) * L2
+ 2 * VAR(ToDepth
) * D2
;
1672 vx
= var(Q_POS
) / 3.0 +
1673 sinB
* sinB
* F
/ D2
+ var_comp
* dy
* dy
;
1674 vy
= var(Q_POS
) / 3.0 +
1675 cosB
* cosB
* F
/ D2
+ var_comp
* dx
* dx
;
1676 /* FIXME: Should use FrDepth sometimes... */
1677 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1679 #ifndef NO_COVARIANCES
1680 cxy
= sinB
* cosB
* (F
/ D2
+ var_comp
* D2
);
1681 /* FIXME: Should use FrDepth sometimes... */
1682 cyz
= -2 * VAR(ToDepth
) * dy
/ D
;
1683 czx
= -2 * VAR(ToDepth
) * dx
/ D
;
1686 /* FIXME: If there's a clino reading, check it against the depth reading,
1688 * if (VAL(Clino) != HUGE_REAL || VAL(BackClino) != HUGE_REAL) { ... }
1691 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1692 #ifndef NO_COVARIANCES
1700 process_cartesian(prefix
*fr
, prefix
*to
, bool fToFirst
)
1702 real dx
= (VAL(Dx
) * pcs
->units
[Q_DX
] - pcs
->z
[Q_DX
]) * pcs
->sc
[Q_DX
];
1703 real dy
= (VAL(Dy
) * pcs
->units
[Q_DY
] - pcs
->z
[Q_DY
]) * pcs
->sc
[Q_DY
];
1704 real dz
= (VAL(Dz
) * pcs
->units
[Q_DZ
] - pcs
->z
[Q_DZ
]) * pcs
->sc
[Q_DZ
];
1706 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, VAR(Dx
), VAR(Dy
), VAR(Dz
)
1707 #ifndef NO_COVARIANCES
1715 data_cartesian(void)
1717 prefix
*fr
= NULL
, *to
= NULL
;
1719 bool fMulti
= false;
1721 reading first_stn
= End
;
1723 const reading
*ordering
;
1727 for (ordering
= pcs
->ordering
; ; ordering
++) {
1729 switch (*ordering
) {
1731 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
1732 if (first_stn
== End
) first_stn
= Fr
;
1735 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
1736 if (first_stn
== End
) first_stn
= To
;
1740 to
= read_prefix(PFX_STATION
);
1743 case Dx
: case Dy
: case Dz
:
1744 read_reading(*ordering
, false);
1748 case IgnoreAllAndNewLine
:
1753 if (!process_cartesian(fr
, to
, first_stn
== To
))
1760 if (isData(ch
)) break;
1771 process_cartesian(fr
, to
, first_stn
== To
);
1778 } while (isComm(ch
));
1780 default: BUG("Unknown reading in ordering");
1786 process_cylpolar(prefix
*fr
, prefix
*to
, bool fToFirst
, bool fDepthChange
)
1788 real tape
= VAL(Tape
);
1792 #ifndef NO_COVARIANCES
1796 handle_comp_units();
1798 /* depth gauge readings increase upwards with default calibration */
1800 SVX_ASSERT(VAL(FrDepth
) == 0.0);
1801 dz
= VAL(ToDepth
) * pcs
->units
[Q_DEPTH
] - pcs
->z
[Q_DEPTH
];
1802 dz
*= pcs
->sc
[Q_DEPTH
];
1804 dz
= VAL(ToDepth
) - VAL(FrDepth
);
1805 dz
*= pcs
->units
[Q_DEPTH
] * pcs
->sc
[Q_DEPTH
];
1808 /* adjusted tape is negative -- probably the calibration is wrong */
1809 if (tape
< (real
)0.0) {
1810 compile_diagnostic(DIAG_WARN
, /*Negative adjusted tape reading*/79);
1813 if (VAL(Comp
) == HUGE_REAL
&& VAL(BackComp
) == HUGE_REAL
) {
1815 dx
= dy
= (real
)0.0;
1816 vx
= vy
= var(Q_POS
) / 3.0 + dz
* dz
* var(Q_PLUMB
);
1817 /* FIXME: Should use FrDepth sometimes... */
1818 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1822 real comp
= handle_compass(&var_comp
);
1829 vx
= var(Q_POS
) / 3.0 +
1830 VAR(Tape
) * sinB
* sinB
+ var_comp
* dy
* dy
;
1831 vy
= var(Q_POS
) / 3.0 +
1832 VAR(Tape
) * cosB
* cosB
+ var_comp
* dx
* dx
;
1833 /* FIXME: Should use FrDepth sometimes... */
1834 vz
= var(Q_POS
) / 3.0 + 2 * VAR(ToDepth
);
1836 #ifndef NO_COVARIANCES
1837 cxy
= (VAR(Tape
) - var_comp
* tape
* tape
) * sinB
* cosB
;
1840 addlegbyname(fr
, to
, fToFirst
, dx
, dy
, dz
, vx
, vy
, vz
1841 #ifndef NO_COVARIANCES
1848 /* Process tape/compass/clino, diving, and cylpolar styles of survey data
1849 * Also handles topofil (fromcount/tocount or count) in place of tape */
1853 prefix
*fr
= NULL
, *to
= NULL
;
1854 reading first_stn
= End
;
1856 bool fTopofil
= false, fMulti
= false;
1858 clino_type ctype
, backctype
;
1860 unsigned long compass_dat_flags
= 0;
1862 const reading
*ordering
;
1864 VAL(Tape
) = VAL(BackTape
) = HUGE_REAL
;
1865 VAL(Comp
) = VAL(BackComp
) = HUGE_REAL
;
1866 VAL(FrCount
) = VAL(ToCount
) = 0;
1867 VAL(FrDepth
) = VAL(ToDepth
) = 0;
1868 VAL(Left
) = VAL(Right
) = VAL(Up
) = VAL(Down
) = HUGE_REAL
;
1871 ctype
= backctype
= CTYPE_OMIT
;
1872 fDepthChange
= false;
1874 /* ordering may omit clino reading, so set up default here */
1875 /* this is also used if clino reading is the omit character */
1876 VAL(Clino
) = VAL(BackClino
) = 0;
1880 /* We clear these flags in the normal course of events, but if there's an
1881 * error in a reading, we might not, so make sure it has been cleared here.
1883 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
1884 for (ordering
= pcs
->ordering
; ; ordering
++) {
1886 switch (*ordering
) {
1888 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
|PFX_ANON
);
1889 if (first_stn
== End
) first_stn
= Fr
;
1892 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
|PFX_ANON
);
1893 if (first_stn
== End
) first_stn
= To
;
1897 to
= read_prefix(PFX_STATION
);
1902 DIR_NULL
=-1, DIR_FORE
, DIR_BACK
1904 static const sztok dir_tab
[] = {
1910 tok
= match_tok(dir_tab
, TABSIZE(dir_tab
));
1918 compile_diagnostic(DIAG_ERR
|DIAG_BUF
|DIAG_SKIP
, /*Found ā%sā, expecting āFā or āBā*/131, buffer
);
1924 case Tape
: case BackTape
: {
1925 reading r
= *ordering
;
1926 read_reading(r
, true);
1927 if (VAL(r
) == HUGE_REAL
) {
1929 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
1930 /* Avoid also warning about omitted tape reading. */
1935 } else if (VAL(r
) < (real
)0.0) {
1936 compile_diagnostic_reading(DIAG_WARN
, r
, /*Negative tape reading*/60);
1941 VAL(FrCount
) = VAL(ToCount
);
1942 LOC(FrCount
) = LOC(ToCount
);
1943 WID(FrCount
) = WID(ToCount
);
1944 read_reading(ToCount
, false);
1948 read_reading(FrCount
, false);
1951 read_reading(ToCount
, false);
1954 case Comp
: case BackComp
:
1955 read_bearing_or_omit(*ordering
);
1957 case Clino
: case BackClino
: {
1958 reading r
= *ordering
;
1959 clino_type
* p_ctype
= (r
== Clino
? &ctype
: &backctype
);
1960 read_reading(r
, true);
1961 if (VAL(r
) == HUGE_REAL
) {
1962 VAL(r
) = handle_plumb(p_ctype
);
1963 if (VAL(r
) != HUGE_REAL
) break;
1964 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
1969 *p_ctype
= CTYPE_READING
;
1972 case FrDepth
: case ToDepth
:
1973 read_reading(*ordering
, false);
1976 VAL(FrDepth
) = VAL(ToDepth
);
1977 LOC(FrDepth
) = LOC(ToDepth
);
1978 WID(FrDepth
) = WID(ToDepth
);
1979 read_reading(ToDepth
, false);
1982 fDepthChange
= true;
1984 read_reading(ToDepth
, false);
1986 case CompassDATComp
:
1987 read_bearing_or_omit(Comp
);
1988 if (is_compass_NaN(VAL(Comp
))) VAL(Comp
) = HUGE_REAL
;
1990 case CompassDATBackComp
:
1991 read_bearing_or_omit(BackComp
);
1992 if (is_compass_NaN(VAL(BackComp
))) VAL(BackComp
) = HUGE_REAL
;
1994 case CompassDATClino
: case CompassDATBackClino
: {
1996 clino_type
* p_ctype
;
1997 if (*ordering
== CompassDATClino
) {
2002 p_ctype
= &backctype
;
2004 read_reading(r
, false);
2005 if (is_compass_NaN(VAL(r
))) {
2007 *p_ctype
= CTYPE_OMIT
;
2009 *p_ctype
= CTYPE_READING
;
2013 case CompassDATLeft
: case CompassDATRight
:
2014 case CompassDATUp
: case CompassDATDown
: {
2015 /* FIXME: need to actually make use of these entries! */
2016 reading actual
= Left
+ (*ordering
- CompassDATLeft
);
2017 read_reading(actual
, false);
2018 if (VAL(actual
) < 0) VAL(actual
) = HUGE_REAL
;
2021 case CompassDATFlags
:
2028 while (ch
>= 'A' && ch
<= 'Z') {
2029 compass_dat_flags
|= BIT(ch
- 'A');
2031 * L (exclude from length)
2033 * P (no plot) (mapped to FLAG_SURFACE)
2035 * FIXME: Defined flags we currently ignore:
2036 * C (no adjustment) (set all (co)variances to 0? Then
2037 * we need to handle a loop of such legs or a traverse
2038 * of such legs between two fixed points...)
2045 compass_dat_flags
= 0;
2055 case IgnoreAllAndNewLine
:
2064 VAL(Tape
) = VAL(ToCount
) - VAL(FrCount
);
2065 LOC(Tape
) = LOC(ToCount
);
2066 WID(Tape
) = WID(ToCount
);
2068 /* Note: frdepth == todepth test works regardless of fDepthChange
2069 * (frdepth always zero, todepth is change of depth) and also
2070 * works for STYLE_NORMAL (both remain 0) */
2071 if (TSTBIT(pcs
->infer
, INFER_EQUATES
) &&
2072 (VAL(Tape
) == (real
)0.0 || VAL(Tape
) == HUGE_REAL
) &&
2073 (VAL(BackTape
) == (real
)0.0 || VAL(BackTape
) == HUGE_REAL
) &&
2074 VAL(FrDepth
) == VAL(ToDepth
)) {
2075 if (!TSTBIT(pcs
->infer
, INFER_EQUATES_SELF_OK
) || fr
!= to
)
2076 process_equate(fr
, to
);
2077 goto inferred_equate
;
2085 VAL(Tape
) *= pcs
->units
[Q_COUNT
] * pcs
->sc
[Q_COUNT
];
2086 } else if (VAL(Tape
) != HUGE_REAL
) {
2087 VAL(Tape
) *= pcs
->units
[Q_LENGTH
];
2088 VAL(Tape
) -= pcs
->z
[Q_LENGTH
];
2089 VAL(Tape
) *= pcs
->sc
[Q_LENGTH
];
2091 if (VAL(BackTape
) != HUGE_REAL
) {
2092 VAL(BackTape
) *= pcs
->units
[Q_BACKLENGTH
];
2093 VAL(BackTape
) -= pcs
->z
[Q_BACKLENGTH
];
2094 VAL(BackTape
) *= pcs
->sc
[Q_BACKLENGTH
];
2095 if (VAL(Tape
) != HUGE_REAL
) {
2096 real diff
= VAL(Tape
) - VAL(BackTape
);
2097 if (sqrd(diff
/ 3.0) > VAR(Tape
) + VAR(BackTape
)) {
2098 /* fore and back readings differ by more than 3 sds */
2099 /* TRANSLATORS: %s is replaced by the amount the readings disagree
2100 * by, e.g. "0.12m" or "0.2ft". */
2101 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
2102 diff
, get_length_units(Q_LENGTH
));
2104 VAL(Tape
) = VAL(Tape
) / VAR(Tape
) + VAL(BackTape
) / VAR(BackTape
);
2105 VAR(Tape
) = (VAR(Tape
) + VAR(BackTape
)) / 4;
2106 VAL(Tape
) *= VAR(Tape
);
2108 VAL(Tape
) = VAL(BackTape
);
2109 VAR(Tape
) = VAR(BackTape
);
2111 } else if (VAL(Tape
) == HUGE_REAL
) {
2112 compile_diagnostic_reading(DIAG_ERR
, Tape
, /*Tape reading may not be omitted*/94);
2113 goto inferred_equate
;
2115 implicit_splay
= TSTBIT(pcs
->flags
, FLAGS_IMPLICIT_SPLAY
);
2116 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
2117 save_flags
= pcs
->flags
;
2118 if (implicit_splay
) {
2119 pcs
->flags
|= BIT(FLAGS_SPLAY
);
2121 switch (pcs
->style
) {
2123 r
= process_normal(fr
, to
, (first_stn
== To
) ^ fRev
,
2127 /* FIXME: Handle any clino readings */
2128 r
= process_diving(fr
, to
, (first_stn
== To
) ^ fRev
,
2131 case STYLE_CYLPOLAR
:
2132 r
= process_cylpolar(fr
, to
, (first_stn
== To
) ^ fRev
,
2136 r
= 0; /* avoid warning */
2139 pcs
->flags
= save_flags
;
2142 /* Swap fr and to back to how they were for next line */
2151 ctype
= backctype
= CTYPE_OMIT
;
2152 fDepthChange
= false;
2154 /* ordering may omit clino reading, so set up default here */
2155 /* this is also used if clino reading is the omit character */
2156 VAL(Clino
) = VAL(BackClino
) = 0;
2157 LOC(Clino
) = LOC(BackClino
) = -1;
2158 WID(Clino
) = WID(BackClino
) = 0;
2166 if (isData(ch
)) break;
2179 /* Compass ignore flag is 'X' */
2180 if ((compass_dat_flags
& BIT('X' - 'A'))) {
2190 VAL(Tape
) = VAL(ToCount
) - VAL(FrCount
);
2191 LOC(Tape
) = LOC(ToCount
);
2192 WID(Tape
) = WID(ToCount
);
2194 /* Note: frdepth == todepth test works regardless of fDepthChange
2195 * (frdepth always zero, todepth is change of depth) and also
2196 * works for STYLE_NORMAL (both remain 0) */
2197 if (TSTBIT(pcs
->infer
, INFER_EQUATES
) &&
2198 (VAL(Tape
) == (real
)0.0 || VAL(Tape
) == HUGE_REAL
) &&
2199 (VAL(BackTape
) == (real
)0.0 || VAL(BackTape
) == HUGE_REAL
) &&
2200 VAL(FrDepth
) == VAL(ToDepth
)) {
2201 if (!TSTBIT(pcs
->infer
, INFER_EQUATES_SELF_OK
) || fr
!= to
)
2202 process_equate(fr
, to
);
2207 VAL(Tape
) *= pcs
->units
[Q_COUNT
] * pcs
->sc
[Q_COUNT
];
2208 } else if (VAL(Tape
) != HUGE_REAL
) {
2209 VAL(Tape
) *= pcs
->units
[Q_LENGTH
];
2210 VAL(Tape
) -= pcs
->z
[Q_LENGTH
];
2211 VAL(Tape
) *= pcs
->sc
[Q_LENGTH
];
2213 if (VAL(BackTape
) != HUGE_REAL
) {
2214 VAL(BackTape
) *= pcs
->units
[Q_BACKLENGTH
];
2215 VAL(BackTape
) -= pcs
->z
[Q_BACKLENGTH
];
2216 VAL(BackTape
) *= pcs
->sc
[Q_BACKLENGTH
];
2217 if (VAL(Tape
) != HUGE_REAL
) {
2218 real diff
= VAL(Tape
) - VAL(BackTape
);
2219 if (sqrd(diff
/ 3.0) > VAR(Tape
) + VAR(BackTape
)) {
2220 /* fore and back readings differ by more than 3 sds */
2221 /* TRANSLATORS: %s is replaced by the amount the readings disagree
2222 * by, e.g. "0.12m" or "0.2ft". */
2223 warn_readings_differ(/*TAPE reading and BACKTAPE reading disagree by %s*/97,
2224 diff
, get_length_units(Q_LENGTH
));
2226 VAL(Tape
) = VAL(Tape
) / VAR(Tape
) + VAL(BackTape
) / VAR(BackTape
);
2227 VAR(Tape
) = (VAR(Tape
) + VAR(BackTape
)) / 4;
2228 VAL(Tape
) *= VAR(Tape
);
2230 VAL(Tape
) = VAL(BackTape
);
2231 VAR(Tape
) = VAR(BackTape
);
2233 } else if (VAL(Tape
) == HUGE_REAL
) {
2234 compile_diagnostic_reading(DIAG_ERR
, Tape
, /*Tape reading may not be omitted*/94);
2238 implicit_splay
= TSTBIT(pcs
->flags
, FLAGS_IMPLICIT_SPLAY
);
2239 pcs
->flags
&= ~(BIT(FLAGS_ANON_ONE_END
) | BIT(FLAGS_IMPLICIT_SPLAY
));
2240 save_flags
= pcs
->flags
;
2241 if (implicit_splay
) {
2242 pcs
->flags
|= BIT(FLAGS_SPLAY
);
2244 if ((compass_dat_flags
& BIT('S' - 'A'))) {
2245 /* 'S' means "splay". It's currently only documented as part
2246 * of the PLT file format, but the flags are the same and so
2247 * it seems it must be supported in DAT files too.
2249 pcs
->flags
|= BIT(FLAGS_SPLAY
);
2251 if ((compass_dat_flags
& BIT('P' - 'A'))) {
2252 /* 'P' means "Exclude this shot from plotting", but the use
2253 * suggested in the Compass docs is for surface data, and legs
2254 * with this flag "[do] not support passage modeling".
2256 * Even if it's actually being used for a different
2257 * purpose, Survex programs don't show surface legs
2258 * by default so FLAGS_SURFACE matches fairly well.
2260 pcs
->flags
|= BIT(FLAGS_SURFACE
);
2262 if ((compass_dat_flags
& BIT('L' - 'A'))) {
2263 /* 'L' means "exclude from length" - map this to Survex's
2264 * FLAGS_DUPLICATE. */
2265 pcs
->flags
|= BIT(FLAGS_DUPLICATE
);
2267 switch (pcs
->style
) {
2269 process_normal(fr
, to
, (first_stn
== To
) ^ fRev
,
2273 /* FIXME: Handle any clino readings */
2274 process_diving(fr
, to
, (first_stn
== To
) ^ fRev
,
2277 case STYLE_CYLPOLAR
:
2278 process_cylpolar(fr
, to
, (first_stn
== To
) ^ fRev
,
2284 pcs
->flags
= save_flags
;
2292 } while (isComm(ch
));
2295 BUG("Unknown reading in ordering");
2301 process_lrud(prefix
*stn
)
2303 SVX_ASSERT(next_lrud
);
2304 lrud
* xsect
= osnew(lrud
);
2306 xsect
->l
= (VAL(Left
) * pcs
->units
[Q_LEFT
] - pcs
->z
[Q_LEFT
]) * pcs
->sc
[Q_LEFT
];
2307 xsect
->r
= (VAL(Right
) * pcs
->units
[Q_RIGHT
] - pcs
->z
[Q_RIGHT
]) * pcs
->sc
[Q_RIGHT
];
2308 xsect
->u
= (VAL(Up
) * pcs
->units
[Q_UP
] - pcs
->z
[Q_UP
]) * pcs
->sc
[Q_UP
];
2309 xsect
->d
= (VAL(Down
) * pcs
->units
[Q_DOWN
] - pcs
->z
[Q_DOWN
]) * pcs
->sc
[Q_DOWN
];
2310 xsect
->meta
= pcs
->meta
;
2311 if (pcs
->meta
) ++pcs
->meta
->ref_count
;
2314 next_lrud
= &(xsect
->next
);
2323 const reading
*ordering
;
2325 for (ordering
= pcs
->ordering
; ; ordering
++) {
2327 switch (*ordering
) {
2329 stn
= read_prefix(PFX_STATION
);
2331 case Left
: case Right
: case Up
: case Down
: {
2332 reading r
= *ordering
;
2333 read_reading(r
, true);
2334 if (VAL(r
) == HUGE_REAL
) {
2336 compile_diagnostic_token_show(DIAG_ERR
, /*Expecting numeric field, found ā%sā*/9);
2354 default: BUG("Unknown reading in ordering");
2360 process_nosurvey(prefix
*fr
, prefix
*to
, bool fToFirst
)
2364 /* Suppress "unused fixed point" warnings for these stations */
2365 fr
->sflags
|= BIT(SFLAGS_USED
);
2366 to
->sflags
|= BIT(SFLAGS_USED
);
2368 /* add to linked list which is dealt with after network is solved */
2369 link
= osnew(nosurveylink
);
2371 link
->to
= StnFromPfx(to
);
2372 link
->fr
= StnFromPfx(fr
);
2374 link
->fr
= StnFromPfx(fr
);
2375 link
->to
= StnFromPfx(to
);
2377 link
->flags
= pcs
->flags
| (STYLE_NOSURVEY
<< FLAGS_STYLE_BIT0
);
2378 link
->meta
= pcs
->meta
;
2379 if (pcs
->meta
) ++pcs
->meta
->ref_count
;
2380 link
->next
= nosurveyhead
;
2381 nosurveyhead
= link
;
2388 prefix
*fr
= NULL
, *to
= NULL
;
2390 bool fMulti
= false;
2392 reading first_stn
= End
;
2394 const reading
*ordering
;
2398 for (ordering
= pcs
->ordering
; ; ordering
++) {
2400 switch (*ordering
) {
2402 fr
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
2403 if (first_stn
== End
) first_stn
= Fr
;
2406 to
= read_prefix(PFX_STATION
|PFX_ALLOW_ROOT
);
2407 if (first_stn
== End
) first_stn
= To
;
2411 to
= read_prefix(PFX_STATION
);
2416 case IgnoreAllAndNewLine
:
2421 if (!process_nosurvey(fr
, to
, first_stn
== To
))
2424 if (ordering
[1] == End
) {
2428 } while (isComm(ch
));
2438 if (isData(ch
)) break;
2449 (void)process_nosurvey(fr
, to
, first_stn
== To
);
2456 } while (isComm(ch
));
2458 default: BUG("Unknown reading in ordering");
2463 /* totally ignore a line of survey data */