source: git/src/datain.c @ 167626d

RELEASE/1.2debug-cidebug-ci-sanitiserswalls-datawalls-data-hanging-as-warning
Last change on this file since 167626d was 78ed938, checked in by Olly Betts <olly@…>, 7 years ago

Make arrays of fixed data "const"

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