source: git/src/datain.c @ 98cda63

RELEASE/1.1RELEASE/1.2debug-cidebug-ci-sanitisersfaster-cavernloglog-selectstereostereo-2025walls-datawalls-data-hanging-as-warningwarn-only-for-hanging-survey
Last change on this file since 98cda63 was ee05463, checked in by Olly Betts <olly@…>, 20 years ago

Added support for LRUD data in .svx files, in .3d files, and tweak aven to
load them. The ability to "fake" LRUD data in aven is gone for now...

git-svn-id: file:///home/survex-svn/survex/branches/survex-1_1@2895 4b37db11-9a0c-4f06-9ece-9ab7cdaee568

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