Пример #1
0
static void
cmd_units(void)
{
   int units, quantity;
   unsigned long qmask;
   unsigned long m; /* mask with bit x set to indicate quantity x specified */
   real factor;

   qmask = get_qlist(0);
   if (!qmask) return;
   if (qmask == BIT(Q_DEFAULT)) {
      default_units(pcs);
      return;
   }

   factor = read_numeric(fTrue, NULL);
   if (factor == 0.0) {
      compile_error_skip(-/**UNITS factor must be non-zero*/200);
      return;
   }
   if (factor == HUGE_REAL) factor = (real)1.0;

   units = get_units(qmask, fTrue);
   if (units == UNITS_NULL) return;
   if (TSTBIT(qmask, Q_GRADIENT))
      pcs->f_clino_percent = (units == UNITS_PERCENT);
   if (TSTBIT(qmask, Q_BACKGRADIENT))
      pcs->f_backclino_percent = (units == UNITS_PERCENT);

   factor *= factor_tab[units];

   for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1)
      if (qmask & m) pcs->units[quantity] = factor;
}
Пример #2
0
static void
check_node(prefix *p)
{
   if (!p->pos) {
      if (!TSTBIT(p->sflags, SFLAGS_SURVEY)) {
	 /* Could do away with the SFLAGS_SURVEY check and check
	  * p->min_export instead of p->max_export I think ... */
	 if (TSTBIT(p->sflags, SFLAGS_ENTRANCE) || p->max_export) {
	     /* p is a station which was referred to in "*entrance" and/or
	      * "*export" but not elsewhere (otherwise it'd have a position).
	      * p could also be a survey (SFLAGS_SURVEY) or be mentioned as
	      * a station, but only in a line of data which was rejected
	      * because of an error.
	      */
	     warning_in_file(p->filename, p->line,
		     /*Station “%s” referred to by *entrance or *export but never used*/190,
		     sprint_prefix(p));
	 }
      }
   } else {
      /* Do we need to worry about export violations in hanging surveys? */
      if (fExportUsed) {
#if 0
	 printf("L min %d max %d pfx %s\n",
		p->min_export, p->max_export, sprint_prefix(p));
#endif
	 if ((p->min_export > 1 && p->min_export != USHRT_MAX) ||
	     (p->min_export == 0 && p->max_export)) {
	    char *s;
	    prefix *where = p->up;
	    int msgno;
	    SVX_ASSERT(where);
	    s = osstrdup(sprint_prefix(where));
	    /* Report better when station called 2.1 for example */
	    while (!where->filename && where->up) where = where->up;

	    if (TSTBIT(where->sflags, SFLAGS_PREFIX_ENTERED)) {
	       msgno = /*Station “%s” not exported from survey “%s”*/26;
	    } else {
		/* TRANSLATORS: This error occurs if there's an attempt to
		 * export a station from a survey which doesn't actually exist.
		 */
	       msgno = /*Reference to station “%s” from non-existent survey “%s”*/286;
	    }
	    compile_error_pfx(where, msgno, sprint_prefix(p), s);
	    osfree(s);
	 }
      }

      if (TSTBIT(p->sflags, SFLAGS_SUSPECTTYPO)) {
	 /* TRANSLATORS: Here "station" is a survey station, not a train station. */
	 warning_in_file(p->filename, p->line,
		 /*Station “%s” referred to just once, with an explicit survey name - typo?*/70,
		 sprint_prefix(p));
      }
   }
}
Пример #3
0
static void
check_reentry(prefix *tag)
{
   /* Don't try to check "*prefix \" or "*begin \" */
   if (!tag->up) return;
   if (TSTBIT(tag->sflags, SFLAGS_PREFIX_ENTERED)) {
      if (tag->line != file.line ||
	  strcmp(tag->filename, file.filename) != 0) {
	 const char *filename_store = file.filename;
	 unsigned int line_store = file.line;
	 static int reenter_depr_count = 0;

	 if (reenter_depr_count < 5) {
	    compile_warning(/*Reentering an existing prefix level is deprecated*/29);
	    if (++reenter_depr_count == 5)
	       compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
	 }

	 file.filename = tag->filename;
	 file.line = tag->line;
	 compile_warning(/*Originally entered here*/30);
	 file.filename = filename_store;
	 file.line = line_store;
      }
   } else {
      tag->sflags |= BIT(SFLAGS_PREFIX_ENTERED);
      tag->filename = file.filename;
      tag->line = file.line;
   }
}
Пример #4
0
void kbPutCh() {

	while ( TSTBIT( p_keyboard->status , KB_GETCH ) ) {
		;
	}
	
	if ( TSTBIT( p_keyboard->status , KB_PUTCH ) == 0 ) {
		SETBIT( p_keyboard->status , KB_PUTCH );
		if ( !( TSTBIT( p_keyboard->status , KB_BUFFER_FULL ) ) ) {
			p_keyboard->Buffer[p_keyboard->BufPos] = getch();
// printf("\n\r kbPutCh: BufPos %d c %02X", p_keyboard->BufPos, p_keyboard->Buffer[p_keyboard->BufPos] );
			kbIncBufPos();
		}
		CLRBIT( p_keyboard->status , KB_PUTCH );
	}
}
Пример #5
0
static void _mem_send_data( dt_8bit dt ) {
	
 	gate_set_val( devMemory->mem_gate[ MEM_Data_00 ], (TSTBIT(dt,0)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_01 ], (TSTBIT(dt,1)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_02 ], (TSTBIT(dt,2)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_03 ], (TSTBIT(dt,3)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_04 ], (TSTBIT(dt,4)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_05 ], (TSTBIT(dt,5)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_06 ], (TSTBIT(dt,6)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );
 	gate_set_val( devMemory->mem_gate[ MEM_Data_07 ], (TSTBIT(dt,7)==STATO_VAL_MIN ? STATO_VAL_MIN : STATO_VAL_MAX) );

}
Пример #6
0
void
default_units(settings *s)
{
   int quantity;
   for (quantity = 0; quantity < Q_MAC; quantity++) {
      if (TSTBIT(ANG_QMASK, quantity))
	 s->units[quantity] = (real)(M_PI / 180.0); /* degrees */
      else
	 s->units[quantity] = (real)1.0; /* metres */
   }
   s->f_clino_percent = s->f_backclino_percent = fFalse;
}
Пример #7
0
uchar kbGetCh() {

	uchar c = '\0';
	uchar i;
	
	while ( TSTBIT( p_keyboard->status , KB_PUTCH ) ) {
		;
	}
	
	SETBIT( p_keyboard->status , KB_GETCH );
	if ( !( TSTBIT( p_keyboard->status , KB_BUFFER_EMPTY ) ) ) {
		c = p_keyboard->Buffer[ KB_BUFFER_MIN_POS ];
		for ( i=KB_BUFFER_MIN_POS ; i < p_keyboard->BufPos ; i++ ) {
			p_keyboard->Buffer[ i ] = p_keyboard->Buffer[ i + 1 ];
// printf("\n\r kbGetCh: i %d BufPos %d c %02X", i, p_keyboard->BufPos, p_keyboard->Buffer[i] );
		}
		p_keyboard->Buffer[ p_keyboard->BufPos ] = '\0';
		kbDecBufPos();
	}
	CLRBIT( p_keyboard->status , KB_GETCH );
	return c;
}
Пример #8
0
static int
get_units(unsigned long qmask, bool percent_ok)
{
   static sztok utab[] = {
	{"DEGREES",       UNITS_DEGS },
	{"DEGS",	  UNITS_DEGS },
	{"FEET",	  UNITS_FEET },
	{"GRADS",	  UNITS_GRADS },
	{"METERS",	  UNITS_METRES },
	{"METRES",	  UNITS_METRES },
	{"METRIC",	  UNITS_METRES },
	{"MILS",	  UNITS_GRADS },
	{"MINUTES",	  UNITS_MINUTES },
	{"PERCENT",	  UNITS_PERCENT },
	{"PERCENTAGE",    UNITS_PERCENT },
	{"YARDS",	  UNITS_YARDS },
	{NULL,		  UNITS_NULL }
   };
   int units;
   get_token();
   units = match_tok(utab, TABSIZE(utab));
   if (units == UNITS_NULL) {
      file.lpos += strlen(buffer);
      compile_error_skip(-/*Unknown units “%s”*/35, buffer);
      return UNITS_NULL;
   }
   if (units == UNITS_PERCENT && percent_ok &&
       !(qmask & ~(BIT(Q_GRADIENT)|BIT(Q_BACKGRADIENT)))) {
      return units;
   }
   if (((qmask & LEN_QMASK) && !TSTBIT(LEN_UMASK, units)) ||
       ((qmask & ANG_QMASK) && !TSTBIT(ANG_UMASK, units))) {
      file.lpos += strlen(buffer);
      compile_error_skip(-/*Invalid units “%s” for quantity*/37, buffer);
      return UNITS_NULL;
   }
   return units;
}
Пример #9
0
/*----------------------------------------------------------------------*/
static int
omatch( const tchar * * strp,
        const pattern * pat,
        const tchar * start )
{
  /*
   * Match one pattern element, pointed at by pat, against the character at
   * **strp. Return 0 on a failure, 1 on success. *strp is advanced to skip
   * over the matched character on a successful match. Closure is handled one
   * level up by patcmp().
   *
   * "start" points at the character at the left edge of the line. This might
   * not be the same thing as *strp if the search is starting in the middle
   * of the string. An end-of- line anchor matches '\n' or '\0'.
   */

  int advance = -1; /* amount to advance *strp, -1 == error  */

  switch (*pat) {
  case M_BOL:           /* First char in string? */
    if (*strp == start)     /* Only one star here.   */
      advance = 0;
    break;

  case M_ANY:           /* . = anything but newline */
    if (**strp != _T('\n'))
      advance = 1;
    break;

  case M_EOL:
    if (**strp == _T('\n') || **strp == _T('\0'))
      advance = 0;
    break;

  case M_CCL:
    if (TSTBIT(**strp, pat + 1))
      advance = 1;
    break;

  default:          /* literal match */
    if (**strp == *pat)
      advance = 1;
    break;
  }

  if (advance > 0)
    *strp += advance;

  return (advance + 1);
}
Пример #10
0
void busShow( t_window* dsp ) {

	p_wlist r;
	p_slist	c;

	dsp->cursor.y = dsp->start.y;
	for ( r = p_all_wires; r != NULL; r=r->w_next ) {
		
		if ( r->Wire->visible == W_VISIBLE ) {
			dsp->cursor.x = dsp->start.x;
			mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "%s: ", r->Wire->nome );
			dsp->cursor.x += 9;
			for ( c = r->Wire->stato->oldest ; c != NULL; c = c->s_next ) {

				if ( TSTBIT( c->flag, STATO_FLAG_LOW ) )
					mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "_" );

				if ( TSTBIT( c->flag, STATO_FLAG_HIGH ) )
					mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "'" );

				if ( TSTBIT( c->flag, STATO_FLAG_RAISE ) )
					mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "/" );

				if ( TSTBIT( c->flag, STATO_FLAG_FALL ) )
					mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "\\" );

				//mvwprintw( dsp->wnd, dsp->cursor.y , dsp->cursor.x, "%d", c->valore );
				dsp->cursor.x += 1;

			}
			dsp->cursor.y++;
		}
	}

	wrefresh( dsp->wnd );
}
Пример #11
0
static void
cmd_calibrate(void)
{
   real sc, z;
   unsigned long qmask, m;
   int quantity;

   qmask = get_qlist(BIT(Q_POS)|BIT(Q_PLUMB)|BIT(Q_LEVEL));
   if (!qmask) return; /* error already reported */

   if (qmask == BIT(Q_DEFAULT)) {
      default_calib(pcs);
      return;
   }

   if (((qmask & LEN_QMASK)) && ((qmask & ANG_QMASK))) {
      compile_error_skip(/*Can’t calibrate angular and length quantities together*/227);
      return;
   }

   z = read_numeric(fFalse, NULL);
   sc = read_numeric(fTrue, NULL);
   if (sc == HUGE_REAL) sc = (real)1.0;
   /* check for declination scale */
   /* perhaps "*calibrate declination XXX" should be "*declination XXX" ? */
   if (TSTBIT(qmask, Q_DECLINATION) && sc != 1.0) {
      compile_error_skip(-/*Scale factor must be 1.0 for DECLINATION*/40);
      return;
   }
   if (sc == 0.0) {
      compile_error_skip(-/*Scale factor must be non-zero*/391);
      return;
   }
   for (quantity = 0, m = BIT(quantity); m <= qmask; quantity++, m <<= 1) {
      if (qmask & m) {
	 pcs->z[quantity] = pcs->units[quantity] * z;
	 pcs->sc[quantity] = sc;
      }
   }
}
Пример #12
0
static prefix *
new_anon_station(void)
{
    prefix *name = osnew(prefix);
    name->pos = NULL;
    name->ident = NULL;
    name->shape = 0;
    name->stn = NULL;
    name->up = pcs->Prefix;
    name->down = NULL;
    name->filename = file.filename;
    name->line = file.line;
    if (TSTBIT(pcs->infer, INFER_EXPORTS)) {
	name->min_export = USHRT_MAX;
    } else {
	name->min_export = 0;
    }
    name->max_export = 0;
    name->sflags = BIT(SFLAGS_ANON);
    /* Keep linked list of anon stations for node stats. */
    name->right = anon_list;
    anon_list = name;
    return name;
}
Пример #13
0
extern void
articulate(void)
{
   node *stn, *stnStart;
   int i;
   long cFixed;

   component_list = NULL;
   articulation_list = NULL;
   artlist = NULL;
   fixedlist = NULL;

   /* find articulation points and components */
   colour = 0;
   stnStart = NULL;
   cMaxVisits = 0;
   FOR_EACH_STN(stn, stnlist) {
      if (fixed(stn)) {
	 remove_stn_from_list(&stnlist, stn);
	 add_stn_to_list(&fixedlist, stn);
	 colour++;
	 stn->colour = -colour;
#ifdef DEBUG_ARTIC
	 printf("Putting stn ");
	 print_prefix(stn->name);
	 printf(" on fixedlist\n");
#endif
      } else {
	 cMaxVisits++;
	 stn->colour = 0;
      }
   }
   dirn_stack = osmalloc(cMaxVisits);
   min_stack = osmalloc(cMaxVisits * sizeof(long));

   /* fixedlist can be NULL here if we've had a *solve followed by survey
    * which is all hanging. */
   cFixed = colour;
   while (fixedlist) {
      int c;
      stnStart = fixedlist;
      stn = stnStart;

      /* see if this is a fresh component - it may not be, we may be
       * processing the other way from a fixed point cut-line */
      if (stn->colour < 0) {
#ifdef DEBUG_ARTIC
	 printf("new component\n");
#endif
	 stn->colour = -stn->colour; /* fixed points are negative until we colour from them */
	 cComponents++;

	 /* FIXME: logic to count components isn't the same as the logic
	  * to start a new one - we should start a new one for a fixed point
	  * cut-line (see below) */
	 if (artlist) {
	     component *comp;
	     articulation *art;

	     art = osnew(articulation);
	     art->stnlist = artlist;
	     art->next = articulation_list;
	     articulation_list = art;
	     artlist = NULL;

	     comp = osnew(component);
	     comp->next = component_list;
	     comp->artic = articulation_list;
	     component_list = comp;
	     articulation_list = NULL;
	 }

#ifdef DEBUG_ARTIC
	 print_prefix(stn->name);
	 printf(" [%p] is root of component %ld\n", stn, cComponents);
	 printf(" and colour = %d/%d\n", stn->colour, cFixed);
#endif
      }

      c = 0;
      for (i = 0; i <= 2 && stn->leg[i]; i++) {
	 node *stn2 = stn->leg[i]->l.to;
	 if (stn2->colour < 0) {
	    stn2->colour = -stn2->colour;
	 } else if (stn2->colour == 0) {
	    /* Special case to check if start station is an articulation point
	     * which it is iff we have to colour from it in more than one dirn
	     *
	     * We're looking for articulation legs - these are those where
	     * colouring from here doesn't reach a fixed point (including
	     * stn - the fixed point we've started from)
	     *
	     * FIXME: this is a "fixed point cut-line" case where we could
	     * start a new component.
	     */
	    long col = visit(stn2, reverse_leg_dirn(stn->leg[i]));
#ifdef DEBUG_ARTIC
	    print_prefix(stn->name);
	    printf(" -> ");
	    print_prefix(stn2->name);
	    printf(" col %d cFixed %d\n", col, cFixed);
#endif
	    if (col > cFixed) {
		/* start new articulation - FIXME - overeager */
		articulation *art = osnew(articulation);
		art->stnlist = artlist;
		art->next = articulation_list;
		articulation_list = art;
		artlist = NULL;
		c |= 1 << i;
	    }
	 }
      }

      switch (c) {
       /* had to colour in 2 or 3 directions from start point */
       case 3: case 5: case 6: case 7:
#ifdef DEBUG_ARTIC
	 print_prefix(stn->name);
	 printf(" is a special case start articulation point [%d]\n", c);
#endif
	 for (i = 0; i <= 2 && stn->leg[i]; i++) {
	    if (TSTBIT(c, i)) {
	       /* flag leg as an articulation for loop error reporting */
	       stn->leg[i]->l.reverse |= FLAG_ARTICULATION;
#ifdef DEBUG_ARTIC
	       print_prefix(stn->leg[i]->l.to->name);
	       putnl();
#endif
	       reverse_leg(stn->leg[i])->l.reverse |= FLAG_ARTICULATION;
	    }
	 }
      }

#ifdef DEBUG_ARTIC
      printf("Putting FIXED stn ");
      print_prefix(stn->name);
      printf(" on artlist\n");
#endif
      remove_stn_from_list(&fixedlist, stn);
      add_stn_to_list(&artlist, stn);

      if (stnStart->colour == 1) {
#ifdef DEBUG_ARTIC
	 printf("%ld components\n",cComponents);
#endif
	 break;
      }
   }

   osfree(dirn_stack);
   dirn_stack = NULL;
   osfree(min_stack);
   min_stack = NULL;

   if (artlist) {
      articulation *art = osnew(articulation);
      art->stnlist = artlist;
      art->next = articulation_list;
      articulation_list = art;
      artlist = NULL;
   }
   if (articulation_list) {
      component *comp = osnew(component);
      comp->next = component_list;
      comp->artic = articulation_list;
      component_list = comp;
      articulation_list = NULL;
   }

   if (stnlist) {
      /* Any stations still in stnlist are unfixed, which is means we have
       * one or more hanging surveys.
       *
       * The cause of the problem is pretty likely to be a typo, so run the
       * checks which report errors and warnings about issues which such a
       * typo is likely to result in.
       */
      check_node_stats();

      /* Actually this error is fatal, but we want to list the survey
       * stations which aren't connected, so we report it as an error
       * and die after listing them...
       */
      bool fNotAttached = fFalse;
      error(/*Survey not all connected to fixed stations*/45);
      FOR_EACH_STN(stn, stnlist) {
	 /* Anonymous stations must be at the end of a trailing traverse (since
	  * the same anonymous station can't be referred to more than once),
	  * and trailing traverses have been removed at this point.
	  */
	 SVX_ASSERT(!TSTBIT(stn->name->sflags, SFLAGS_ANON));
	 if (stn->name->ident) {
	    if (!fNotAttached) {
	       fNotAttached = fTrue;
	       puts(msg(/*The following survey stations are not attached to a fixed point:*/71));
	    }
	    puts(sprint_prefix(stn->name));
	 }
      }
      exit(EXIT_FAILURE);
   }
Пример #14
0
static void
cmd_data(void)
{
   static sztok dtab[] = {
	{"ALTITUDE",	 Dz },
	{"BACKBEARING",  BackComp },
	{"BACKCLINO",    BackClino }, /* alternative name */
	{"BACKCOMPASS",  BackComp }, /* alternative name */
	{"BACKGRADIENT", BackClino },
	{"BEARING",      Comp },
	{"CEILING",      Up }, /* alternative name */
	{"CLINO",	 Clino }, /* alternative name */
	{"COMPASS",      Comp }, /* alternative name */
	{"COUNT",	 Count }, /* FrCount&ToCount in multiline */
	{"DEPTH",	 Depth }, /* FrDepth&ToDepth in multiline */
	{"DEPTHCHANGE",  DepthChange },
	{"DIRECTION",    Dir },
	{"DOWN",         Down },
	{"DX",		 Dx },
	{"DY",		 Dy },
	{"DZ",		 Dz },
	{"EASTING",      Dx },
	{"FLOOR",        Down }, /* alternative name */
	{"FROM",	 Fr },
	{"FROMCOUNT",    FrCount },
	{"FROMDEPTH",    FrDepth },
	{"GRADIENT",     Clino },
	{"IGNORE",       Ignore },
	{"IGNOREALL",    IgnoreAll },
	{"LEFT",         Left },
	{"LENGTH",       Tape },
	{"NEWLINE",      Newline },
	{"NORTHING",     Dy },
	{"RIGHT",        Right },
	{"STATION",      Station }, /* Fr&To in multiline */
	{"TAPE",	 Tape }, /* alternative name */
	{"TO",		 To },
	{"TOCOUNT",      ToCount },
	{"TODEPTH",      ToDepth },
	{"UP",           Up },
	{NULL,		 End }
   };

#define MASK_stns BIT(Fr) | BIT(To) | BIT(Station)
#define MASK_tape BIT(Tape) | BIT(FrCount) | BIT(ToCount) | BIT(Count)
#define MASK_dpth BIT(FrDepth) | BIT(ToDepth) | BIT(Depth) | BIT(DepthChange)
#define MASK_comp BIT(Comp) | BIT(BackComp)
#define MASK_clin BIT(Clino) | BIT(BackClino)

#define MASK_NORMAL MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_clin
#define MASK_DIVING MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_dpth
#define MASK_CARTESIAN MASK_stns | BIT(Dx) | BIT(Dy) | BIT(Dz)
#define MASK_CYLPOLAR  MASK_stns | BIT(Dir) | MASK_tape | MASK_comp | MASK_dpth
#define MASK_PASSAGE BIT(Station) | BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down)
#define MASK_NOSURVEY MASK_stns

   /* readings which may be given for each style */
   static const unsigned long mask[] = {
      MASK_NORMAL, MASK_DIVING, MASK_CARTESIAN, MASK_CYLPOLAR, MASK_NOSURVEY,
      MASK_PASSAGE
   };

   /* readings which may be omitted for each style */
   static const unsigned long mask_optional[] = {
      BIT(Dir) | BIT(Clino) | BIT(BackClino),
      BIT(Dir),
      0,
      BIT(Dir),
      0,
      0 /* BIT(Left) | BIT(Right) | BIT(Up) | BIT(Down), */
   };

   /* all valid readings */
   static const unsigned long mask_all[] = {
      MASK_NORMAL | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
      MASK_DIVING | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
      MASK_CARTESIAN | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
      MASK_CYLPOLAR | BIT(Newline) | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
      MASK_NOSURVEY | BIT(Ignore) | BIT(IgnoreAll) | BIT(End),
      MASK_PASSAGE | BIT(Ignore) | BIT(IgnoreAll) | BIT(End)
   };
#define STYLE_DEFAULT   -2
#define STYLE_UNKNOWN   -1

   static sztok styletab[] = {
	{"CARTESIAN",    STYLE_CARTESIAN },
	{"CYLPOLAR",     STYLE_CYLPOLAR },
	{"DEFAULT",      STYLE_DEFAULT },
	{"DIVING",       STYLE_DIVING },
	{"NORMAL",       STYLE_NORMAL },
	{"NOSURVEY",     STYLE_NOSURVEY },
	{"PASSAGE",      STYLE_PASSAGE },
	{"TOPOFIL",      STYLE_NORMAL },
	{NULL,		 STYLE_UNKNOWN }
   };

#define m_multi (BIT(Station) | BIT(Count) | BIT(Depth))

   int style, k = 0, kMac;
   reading *new_order, d;
   unsigned long mUsed = 0;
   char *style_name;

   /* after a bad *data command ignore survey data until the next
    * *data command to avoid an avalanche of errors */
   pcs->style = STYLE_IGNORE;

   kMac = 6; /* minimum for NORMAL style */
   new_order = osmalloc(kMac * sizeof(reading));

   get_token();
   style = match_tok(styletab, TABSIZE(styletab));

   if (style == STYLE_DEFAULT) {
      default_style(pcs);
      return;
   }

   if (style == STYLE_UNKNOWN) {
      file.lpos += strlen(buffer);
      compile_error_skip(-/*Data style “%s” unknown*/65, buffer);
      return;
   }

   skipblanks();
#ifndef NO_DEPRECATED
   /* Olde syntax had optional field for survey grade, so allow an omit
    * but issue a warning about it */
   if (isOmit(ch)) {
      static int data_depr_count = 0;
      if (data_depr_count < 5) {
	 file.lpos += strlen(buffer);
	 compile_warning(-/*“*data %s %c …” is deprecated - use “*data %s …” instead*/104,
			 buffer, ch, buffer);
	 if (++data_depr_count == 5)
	    compile_warning(/*Further uses of this deprecated feature will not be reported*/95);
      }
      nextch();
   }
#endif

   style_name = osstrdup(buffer);
   do {
      filepos fp;
      get_pos(&fp);
      get_token();
      d = match_tok(dtab, TABSIZE(dtab));
      /* only token allowed after IGNOREALL is NEWLINE */
      if (k && new_order[k - 1] == IgnoreAll && d != Newline) {
	 set_pos(&fp);
	 break;
      }
      /* Note: an unknown token is reported as trailing garbage */
      if (!TSTBIT(mask_all[style], d)) {
	 file.lpos += strlen(buffer);
	 compile_error_skip(-/*Reading “%s” not allowed in data style “%s”*/63,
		       buffer, style_name);
	 osfree(style_name);
	 osfree(new_order);
	 return;
      }
      if (TSTBIT(mUsed, Newline) && TSTBIT(m_multi, d)) {
	 /* e.g. "*data diving station newline tape depth compass" */
	 file.lpos += strlen(buffer);
	 compile_error_skip(-/*Reading “%s” must occur before NEWLINE*/225, buffer);
	 osfree(style_name);
	 osfree(new_order);
	 return;
      }
      /* Check for duplicates unless it's a special reading:
       *   IGNOREALL,IGNORE (duplicates allowed) ; END (not possible)
       */
      if (!((BIT(Ignore) | BIT(End) | BIT(IgnoreAll)) & BIT(d))) {
	 if (TSTBIT(mUsed, d)) {
	    file.lpos += strlen(buffer);
	    compile_error_skip(-/*Duplicate reading “%s”*/67, buffer);
	    osfree(style_name);
	    osfree(new_order);
	    return;
	 } else {
	    /* Check for previously listed readings which are incompatible
	     * with this one - e.g. Count vs FrCount */
	    bool fBad = fFalse;
	    switch (d) {
	     case Station:
	       if (mUsed & (BIT(Fr) | BIT(To))) fBad = fTrue;
	       break;
	     case Fr: case To:
	       if (TSTBIT(mUsed, Station)) fBad = fTrue;
	       break;
	     case Count:
	       if (mUsed & (BIT(FrCount) | BIT(ToCount) | BIT(Tape)))
		  fBad = fTrue;
	       break;
	     case FrCount: case ToCount:
	       if (mUsed & (BIT(Count) | BIT(Tape)))
		  fBad = fTrue;
	       break;
	     case Depth:
	       if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(DepthChange)))
		  fBad = fTrue;
	       break;
	     case FrDepth: case ToDepth:
	       if (mUsed & (BIT(Depth) | BIT(DepthChange))) fBad = fTrue;
	       break;
	     case DepthChange:
	       if (mUsed & (BIT(FrDepth) | BIT(ToDepth) | BIT(Depth)))
		  fBad = fTrue;
	       break;
	     case Newline:
	       if (mUsed & ~m_multi) {
		  /* e.g. "*data normal from to tape newline compass clino" */
		  file.lpos += strlen(buffer);
		  compile_error_skip(-/*NEWLINE can only be preceded by STATION, DEPTH, and COUNT*/226);
		  osfree(style_name);
		  osfree(new_order);
		  return;
	       }
	       if (k == 0) {
		  file.lpos += strlen(buffer);
		  compile_error_skip(-/*NEWLINE can’t be the first reading*/222);
		  osfree(style_name);
		  osfree(new_order);
		  return;
	       }
	       break;
	     default: /* avoid compiler warnings about unhandled enums */
	       break;
	    }
	    if (fBad) {
	       /* Not entirely happy with phrasing this... */
	       file.lpos += strlen(buffer);
	       compile_error_skip(-/*Reading “%s” duplicates previous reading(s)*/77,
			     buffer);
	       osfree(style_name);
	       osfree(new_order);
	       return;
	    }
	    mUsed |= BIT(d); /* used to catch duplicates */
	 }
      }
      if (k && new_order[k - 1] == IgnoreAll) {
	 SVX_ASSERT(d == Newline);
	 k--;
	 d = IgnoreAllAndNewLine;
      }
      if (k >= kMac) {
	 kMac = kMac * 2;
	 new_order = osrealloc(new_order, kMac * sizeof(reading));
      }
      new_order[k++] = d;
   } while (d != End);

   if (k >= 2 && new_order[k - 2] == Newline) {
      file.lpos += strlen(buffer);
      compile_error_skip(-/*NEWLINE can’t be the last reading*/223);
      osfree(style_name);
      osfree(new_order);
      return;
   }

   if (style == STYLE_NOSURVEY) {
      if (TSTBIT(mUsed, Station)) {
	 if (k >= kMac) {
	    kMac = kMac * 2;
	    new_order = osrealloc(new_order, kMac * sizeof(reading));
	 }
	 new_order[k - 1] = Newline;
	 new_order[k++] = End;
      }
   } else if (style == STYLE_PASSAGE) {
      /* Station doesn't mean "multiline" for STYLE_PASSAGE. */
   } else if (!TSTBIT(mUsed, Newline) && (m_multi & mUsed)) {
      /* This is for when they write
       * *data normal station tape compass clino
       * (i.e. no newline, but interleaved readings)
       */
      compile_error_skip(/*Interleaved readings, but no NEWLINE*/224);
      osfree(style_name);
      osfree(new_order);
      return;
   }

#if 0
   printf("mUsed = 0x%x\n", mUsed);
#endif

   /* Check the supplied readings form a sufficient set. */
   if (style != STYLE_PASSAGE) {
       if (mUsed & (BIT(Fr) | BIT(To)))
	   mUsed |= BIT(Station);
       else if (TSTBIT(mUsed, Station))
	   mUsed |= BIT(Fr) | BIT(To);
   }

   if (mUsed & (BIT(Comp) | BIT(BackComp)))
      mUsed |= BIT(Comp) | BIT(BackComp);

   if (mUsed & (BIT(Clino) | BIT(BackClino)))
      mUsed |= BIT(Clino) | BIT(BackClino);

   if (mUsed & (BIT(FrDepth) | BIT(ToDepth)))
      mUsed |= BIT(Depth) | BIT(DepthChange);
   else if (TSTBIT(mUsed, Depth))
      mUsed |= BIT(FrDepth) | BIT(ToDepth) | BIT(DepthChange);
   else if (TSTBIT(mUsed, DepthChange))
      mUsed |= BIT(FrDepth) | BIT(ToDepth) | BIT(Depth);

   if (mUsed & (BIT(FrCount) | BIT(ToCount)))
      mUsed |= BIT(Count) | BIT(Tape);
   else if (TSTBIT(mUsed, Count))
      mUsed |= BIT(FrCount) | BIT(ToCount) | BIT(Tape);
   else if (TSTBIT(mUsed, Tape))
      mUsed |= BIT(FrCount) | BIT(ToCount) | BIT(Count);

#if 0
   printf("mUsed = 0x%x, opt = 0x%x, mask = 0x%x\n", mUsed,
	  mask_optional[style], mask[style]);
#endif

   if (((mUsed &~ BIT(Newline)) | mask_optional[style]) != mask[style]) {
      /* Test should only fail with too few bits set, not too many */
      SVX_ASSERT((((mUsed &~ BIT(Newline)) | mask_optional[style])
	      &~ mask[style]) == 0);
      compile_error_skip(/*Too few readings for data style “%s”*/64, style_name);
      osfree(style_name);
      osfree(new_order);
      return;
   }

   /* don't free default ordering or ordering used by parent */
   if (pcs->ordering != default_order &&
       !(pcs->next && pcs->next->ordering == pcs->ordering))
      osfree(pcs->ordering);

   pcs->style = style;
   pcs->ordering = new_order;

   osfree(style_name);

   if (style == STYLE_PASSAGE) {
      lrudlist * new_psg = osnew(lrudlist);
      new_psg->tube = NULL;
      new_psg->next = model;
      model = new_psg;
      next_lrud = &(new_psg->tube);
   }
}
Пример #15
0
static void
cmd_fix(void)
{
   prefix *fix_name;
   node *stn = NULL;
   static node *stnOmitAlready = NULL;
   real x, y, z;
   int nx, ny, nz;
   filepos fp;

   fix_name = read_prefix(PFX_STATION|PFX_ALLOW_ROOT);
   fix_name->sflags |= BIT(SFLAGS_FIXED);

   get_pos(&fp);
   get_token();
   if (strcmp(ucbuffer, "REFERENCE") == 0) {
      /* suppress "unused fixed point" warnings for this station */
      fix_name->sflags |= BIT(SFLAGS_USED);
   } else {
      if (*ucbuffer) set_pos(&fp);
   }

   x = read_numeric(fTrue, &nx);
   if (x == HUGE_REAL) {
      /* If the end of the line isn't blank, read a number after all to
       * get a more helpful error message */
      if (!isEol(ch) && !isComm(ch)) x = read_numeric(fFalse, &nx);
   }
   if (x == HUGE_REAL) {
      if (stnOmitAlready) {
	 if (fix_name != stnOmitAlready->name) {
	    compile_error_skip(/*More than one FIX command with no coordinates*/56);
	 } else {
	    compile_warning(/*Same station fixed twice with no coordinates*/61);
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
      compile_warning(/*FIX command with no coordinates - fixing at (0,0,0)*/54);
      x = y = z = (real)0.0;
      stnOmitAlready = stn;
   } else {
      real sdx;
      y = read_numeric(fFalse, &ny);
      z = read_numeric(fFalse, &nz);
      sdx = read_numeric(fTrue, NULL);
      if (sdx != HUGE_REAL) {
	 real sdy, sdz;
	 real cxy = 0, cyz = 0, czx = 0;
	 sdy = read_numeric(fTrue, NULL);
	 if (sdy == HUGE_REAL) {
	    /* only one variance given */
	    sdy = sdz = sdx;
	 } else {
	    sdz = read_numeric(fTrue, NULL);
	    if (sdz == HUGE_REAL) {
	       /* two variances given - horizontal & vertical */
	       sdz = sdy;
	       sdy = sdx;
	    } else {
	       cxy = read_numeric(fTrue, NULL);
	       if (cxy != HUGE_REAL) {
		  /* covariances given */
		  cyz = read_numeric(fFalse, NULL);
		  czx = read_numeric(fFalse, NULL);
	       } else {
		  cxy = 0;
	       }
	    }
	 }
	 stn = StnFromPfx(fix_name);
	 if (!fixed(stn)) {
	    node *fixpt = osnew(node);
	    prefix *name;
	    name = osnew(prefix);
	    name->pos = osnew(pos);
	    name->ident = NULL;
	    name->shape = 0;
	    fixpt->name = name;
	    name->stn = fixpt;
	    name->up = NULL;
	    if (TSTBIT(pcs->infer, INFER_EXPORTS)) {
	       name->min_export = USHRT_MAX;
	    } else {
	       name->min_export = 0;
	    }
	    name->max_export = 0;
	    name->sflags = 0;
	    add_stn_to_list(&stnlist, fixpt);
	    POS(fixpt, 0) = x;
	    POS(fixpt, 1) = y;
	    POS(fixpt, 2) = z;
	    fix(fixpt);
	    fixpt->leg[0] = fixpt->leg[1] = fixpt->leg[2] = NULL;
	    addfakeleg(fixpt, stn, 0, 0, 0,
		       sdx * sdx, sdy * sdy, sdz * sdz
#ifndef NO_COVARIANCES
		       , cxy, cyz, czx
#endif
		       );
	 }
	 return;
      }
      stn = StnFromPfx(fix_name);
   }

   if (!fixed(stn)) {
      POS(stn, 0) = x;
      POS(stn, 1) = y;
      POS(stn, 2) = z;
      fix(stn);
      return;
   }

   if (x != POS(stn, 0) || y != POS(stn, 1) || z != POS(stn, 2)) {
      compile_error(/*Station already fixed or equated to a fixed point*/46);
      return;
   }
   compile_warning(/*Station already fixed at the same coordinates*/55);
}
Пример #16
0
void *MemoryTask() {
	p_gate 	pCE1	= NULL;
	p_gate 	pCE2	= NULL;
	p_gate 	pRD	    = NULL;
	p_gate 	pWR	    = NULL;
	p_slist pSCE1	= NULL;
	p_slist pSCE2	= NULL;
	p_slist pSRD	= NULL;
	p_slist pSWR	= NULL;

	dt_16bit 	ma	= 0;
	dt_8bit		dt	= 0;
	
	pCE1  = devMemory->mem_gate[ MEM__CE1 ];
	pCE2  = devMemory->mem_gate[ MEM__CE2 ];
	pRD  = devMemory->mem_gate[ MEM__RD ];
	pWR   = devMemory->mem_gate[ MEM__WR ];

	if ( pCE1->Wire != NULL )
		pSCE1 = pCE1->Wire->stato->att;
	if ( pCE2->Wire != NULL )
		pSCE2 = pCE2->Wire->stato->att;
	if ( pRD->Wire != NULL )
		pSRD = pRD->Wire->stato->att;
	if ( pWR->Wire != NULL )
		pSWR = pWR->Wire->stato->att;

	//	Lettura
	if ( pSCE1 != NULL && pSRD != NULL ) {

		if ( (TSTBIT( pSCE1->flag , STATO_FLAG_FALL ) || TSTBIT( pSCE1->flag , STATO_FLAG_LOW )) && TSTBIT( pSRD->flag , STATO_FLAG_FALL ) ) {

			ma = _mem_read_address();
			dt = devMemory->memory[ ma ];

			gate_set_state( devMemory->mem_gate[ MEM_Data_00 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_01 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_02 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_03 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_04 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_05 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_06 ], GATEMODE_OUTPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_07 ], GATEMODE_OUTPUT );

			_mem_send_data( dt );
			
		}
	
		if ( ( gate_get_state( devMemory->mem_gate[ MEM_Data_00 ] ) == GATEMODE_OUTPUT ) && ( TSTBIT( pSCE1->flag , STATO_FLAG_HIGH ) || TSTBIT( pSCE2->flag , STATO_FLAG_HIGH ) ) ) {

			gate_set_state( devMemory->mem_gate[ MEM_Data_00 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_01 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_02 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_03 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_04 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_05 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_06 ], GATEMODE_INPUT );
			gate_set_state( devMemory->mem_gate[ MEM_Data_07 ], GATEMODE_INPUT );

		}
	
	}

	//	Scrittura
	if ( pSCE1 != NULL && pSWR != NULL ) {

		if ( (TSTBIT( pSCE1->flag , STATO_FLAG_FALL ) || TSTBIT( pSCE1->flag , STATO_FLAG_LOW )) && TSTBIT( pSWR->flag , STATO_FLAG_FALL ) ) {

			ma = _mem_read_address();
			dt = _mem_read_data();

			devMemory->memory[ ma ] = dt;
			
		}
	
	}

	return NULL;
}
Пример #17
0
void scrWrite( unsigned char c ) {
	
	unsigned char d,e;
	
	switch ( c ) {
		case 8:
			scrBackSpace();
			break;
		case 127:
			scrBackSpace();
			break;
		case 10:
			scrReturn();
			scrRepaint();
			break;
		case 13:
			break;
		case 27:
			#ifdef _KEYBOARD
				#ifndef THREAD_KEYBOARD	
					kbPutCh();
				#endif
				switch ( kbGetCh() ) {
			#else
				d = getch();
				switch ( d ) {
			#endif
				case 91:
				#ifdef _KEYBOARD
					#ifndef THREAD_KEYBOARD	
						kbPutCh();
					#endif
					switch ( kbGetCh() ) {
				#else
					e = getch();
					switch ( e ) {
				#endif
						case 65:		//	KEY_UP
							scrDecY();
							break;
						case 66:		//	KEY_DOWN
							scrIncY();
							break;
						case 67:		//	KEY_RIGHT
							scrIncX();
							break;
						case 68:		//	KEY_LEFT
							scrDecX();
							break;
						default:
							break;
					}
					break;
				default:
					break;
			}
			break;
		default:
			if ( p_screen->x_pos < SCR_XMAX_SIZE ) {
				p_screen->Buffer[ p_screen->y_pos*SCR_XMAX_SIZE + p_screen->x_pos ] = c;
				scrIncX();
			}
	}

	SETBIT(p_screen->status,f_srcContentChanged);
}

unsigned char scrRead() {
	return ( p_screen->Buffer[ p_screen->y_pos*SCR_XMAX_SIZE + p_screen->x_pos ] );
}

//----------------------------------------------------

void scrRepaint() {

	curscoord x, y, xs, xe, ys, ye;
	
	if ( TSTBIT(p_screen->status,f_srcRepainting) )
		return;
		
	SETBIT(p_screen->status,f_srcRepainting);
	
	if ( TSTBIT(p_screen->status,f_srcContentChanged) ) {
	
		x  = ( p_screen->x_pos<SCR_POSX_MAX ? p_screen->x_pos : SCR_POSX_MAX );
		y  = ( p_screen->y_pos<SCR_POSY_MAX ? p_screen->y_pos : SCR_POSY_MAX );
		
		xs = ( x < dspXmax( p_display ) ? 0 : x - dspXmax( p_display ) + 1 );
		xe = xs + dspXmax( p_display ) - 1;
		ys = ( y < dspYmax( p_display ) ? 0 : y - dspYmax( p_display ) + 1 );
		ye = ys + dspYmax( p_display ) - 1;

		dspCursorHome( p_display );
		for ( y = ys; y <= ye; y++ ) {
			for ( x = xs; x <= xe; x++ ) {
				if ( x-xs < SCR_XMAX_SIZE && y-ys < SCR_YMAX_SIZE ) {
					dspWrite( p_display, p_screen->Buffer[ y*SCR_XMAX_SIZE + x ] );
				} else {
					dspWrite( p_display, '~' );
				}
			}
		}
		#ifndef THREAD_DISPLAY_REPAINT
		dspRefresh( p_display );
		#endif
	
		CLRBIT(p_screen->status,f_srcContentChanged);
		
	}
	
	CLRBIT(p_screen->status,f_srcRepainting);
	
}
Пример #18
0
/* if prefix is omitted: if PFX_OPT set return NULL, otherwise use longjmp */
extern prefix *
read_prefix(unsigned pfx_flags)
{
   bool f_optional = !!(pfx_flags & PFX_OPT);
   bool fSurvey = !!(pfx_flags & PFX_SURVEY);
   bool fSuspectTypo = !!(pfx_flags & PFX_SUSPECT_TYPO);
   prefix *back_ptr, *ptr;
   char *name;
   size_t name_len = 32;
   size_t i;
   bool fNew;
   bool fImplicitPrefix = fTrue;
   int depth = -1;
   filepos fp_firstsep;

   skipblanks();
#ifndef NO_DEPRECATED
   if (isRoot(ch)) {
      if (!(pfx_flags & PFX_ALLOW_ROOT)) {
	 compile_diagnostic(DIAG_ERR|DIAG_COL, /*ROOT is deprecated*/25);
	 LONGJMP(file.jbSkipLine);
      }
      if (root_depr_count < 5) {
	 compile_diagnostic(DIAG_WARN|DIAG_COL, /*ROOT is deprecated*/25);
	 if (++root_depr_count == 5)
	    compile_diagnostic(DIAG_WARN, /*Further uses of this deprecated feature will not be reported*/95);
      }
      nextch();
      ptr = root;
      if (!isNames(ch)) {
	 if (!isSep(ch)) return ptr;
	 /* Allow optional SEPARATOR after ROOT */
	 get_pos(&fp_firstsep);
	 nextch();
      }
      fImplicitPrefix = fFalse;
#else
   if (0) {
#endif
   } else {
      if ((pfx_flags & PFX_ANON) &&
	  (isSep(ch) || (pcs->dash_for_anon_wall_station && ch == '-'))) {
	 int first_ch = ch;
	 filepos here;
	 get_pos(&here);
	 nextch();
	 if (isBlank(ch) || isEol(ch)) {
	    if (!isSep(first_ch))
	       goto anon_wall_station;
	    /* A single separator alone ('.' by default) is an anonymous
	     * station which is on a point inside the passage and implies
	     * the leg to it is a splay.
	     */
	    if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
	       set_pos(&here);
	       compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
	       LONGJMP(file.jbSkipLine);
	    }
	    pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
	    return new_anon_station();
	 }
	 if (isSep(first_ch) && ch == first_ch) {
	    nextch();
	    if (isBlank(ch) || isEol(ch)) {
	       /* A double separator ('..' by default) is an anonymous station
		* which is on the wall and implies the leg to it is a splay.
		*/
	       prefix * pfx;
anon_wall_station:
	       if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
		  set_pos(&here);
		  compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
		  LONGJMP(file.jbSkipLine);
	       }
	       pcs->flags |= BIT(FLAGS_ANON_ONE_END) | BIT(FLAGS_IMPLICIT_SPLAY);
	       pfx = new_anon_station();
	       pfx->sflags |= BIT(SFLAGS_WALL);
	       return pfx;
	    }
	    if (ch == first_ch) {
	       nextch();
	       if (isBlank(ch) || isEol(ch)) {
		  /* A triple separator ('...' by default) is an anonymous
		   * station, but otherwise not handled specially (e.g. for
		   * a single leg down an unexplored side passage to a station
		   * which isn't refindable).
		   */
		  if (TSTBIT(pcs->flags, FLAGS_ANON_ONE_END)) {
		     set_pos(&here);
		     compile_diagnostic(DIAG_ERR|DIAG_TOKEN, /*Can't have a leg between two anonymous stations*/3);
		     LONGJMP(file.jbSkipLine);
		  }
		  pcs->flags |= BIT(FLAGS_ANON_ONE_END);
		  return new_anon_station();
	       }
	    }
	 }
	 set_pos(&here);
      }
      ptr = pcs->Prefix;
   }

   i = 0;
   name = NULL;
   do {
      fNew = fFalse;
      if (name == NULL) {
	 /* Need a new name buffer */
	 name = osmalloc(name_len);
      }
      /* i==0 iff this is the first pass */
      if (i) {
	 i = 0;
	 nextch();
      }
      while (isNames(ch)) {
	 if (i < pcs->Truncate) {
	    /* truncate name */
	    name[i++] = (pcs->Case == LOWER ? tolower(ch) :
			 (pcs->Case == OFF ? ch : toupper(ch)));
	    if (i >= name_len) {
	       name_len = name_len + name_len;
	       name = osrealloc(name, name_len);
	    }
	 }
	 nextch();
      }
      if (isSep(ch)) {
	 fImplicitPrefix = fFalse;
	 get_pos(&fp_firstsep);
      }
      if (i == 0) {
	 osfree(name);
	 if (!f_optional) {
	    if (isEol(ch)) {
	       if (fSurvey) {
		  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting survey name*/89);
	       } else {
		  compile_diagnostic(DIAG_ERR|DIAG_COL, /*Expecting station name*/28);
	       }
	    } else {
	       /* TRANSLATORS: Here "station" is a survey station, not a train station. */
	       compile_diagnostic(DIAG_ERR|DIAG_COL, /*Character “%c” not allowed in station name (use *SET NAMES to set allowed characters)*/7, ch);
	    }
	    LONGJMP(file.jbSkipLine);
	 }
	 return (prefix *)NULL;
      }

      name[i++] = '\0';

      back_ptr = ptr;
      ptr = ptr->down;
      if (ptr == NULL) {
	 /* Special case first time around at each level */
	 name = osrealloc(name, i);
	 ptr = osnew(prefix);
	 ptr->ident = name;
	 name = NULL;
	 ptr->right = ptr->down = NULL;
	 ptr->pos = NULL;
	 ptr->shape = 0;
	 ptr->stn = NULL;
	 ptr->up = back_ptr;
	 ptr->filename = file.filename;
	 ptr->line = file.line;
	 ptr->min_export = ptr->max_export = 0;
	 ptr->sflags = BIT(SFLAGS_SURVEY);
	 if (fSuspectTypo && !fImplicitPrefix)
	    ptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
	 back_ptr->down = ptr;
	 fNew = fTrue;
      } else {
	 /* Use caching to speed up adding an increasing sequence to a
	  * large survey */
	 static prefix *cached_survey = NULL, *cached_station = NULL;
	 prefix *ptrPrev = NULL;
	 int cmp = 1; /* result of strcmp ( -ve for <, 0 for =, +ve for > ) */
	 if (cached_survey == back_ptr) {
	    cmp = strcmp(cached_station->ident, name);
	    if (cmp <= 0) ptr = cached_station;
	 }
	 while (ptr && (cmp = strcmp(ptr->ident, name))<0) {
	    ptrPrev = ptr;
	    ptr = ptr->right;
	 }
	 if (cmp) {
	    /* ie we got to one that was higher, or the end */
	    prefix *newptr;
	    name = osrealloc(name, i);
	    newptr = osnew(prefix);
	    newptr->ident = name;
	    name = NULL;
	    if (ptrPrev == NULL)
	       back_ptr->down = newptr;
	    else
	       ptrPrev->right = newptr;
	    newptr->right = ptr;
	    newptr->down = NULL;
	    newptr->pos = NULL;
	    newptr->shape = 0;
	    newptr->stn = NULL;
	    newptr->up = back_ptr;
	    newptr->filename = file.filename;
	    newptr->line = file.line;
	    newptr->min_export = newptr->max_export = 0;
	    newptr->sflags = BIT(SFLAGS_SURVEY);
	    if (fSuspectTypo && !fImplicitPrefix)
	       newptr->sflags |= BIT(SFLAGS_SUSPECTTYPO);
	    ptr = newptr;
	    fNew = fTrue;
	 }
	 cached_survey = back_ptr;
	 cached_station = ptr;
      }
      depth++;
      f_optional = fFalse; /* disallow after first level */
      if (isSep(ch)) get_pos(&fp_firstsep);
   } while (isSep(ch));
   if (name) osfree(name);

   /* don't warn about a station that is referred to twice */
   if (!fNew) ptr->sflags &= ~BIT(SFLAGS_SUSPECTTYPO);

   if (fNew) {
      /* fNew means SFLAGS_SURVEY is currently set */
      SVX_ASSERT(TSTBIT(ptr->sflags, SFLAGS_SURVEY));
      if (!fSurvey) {
	 ptr->sflags &= ~BIT(SFLAGS_SURVEY);
	 if (TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
      }
   } else {
      /* check that the same name isn't being used for a survey and station */
      if (fSurvey ^ TSTBIT(ptr->sflags, SFLAGS_SURVEY)) {
	 /* TRANSLATORS: Here "station" is a survey station, not a train station.
	  *
	  * Here "survey" is a "cave map" rather than list of questions - it should be
	  * translated to the terminology that cavers using the language would use.
	  */
	 compile_diagnostic(DIAG_ERR, /*“%s” can’t be both a station and a survey*/27,
			    sprint_prefix(ptr));
      }
      if (!fSurvey && TSTBIT(pcs->infer, INFER_EXPORTS)) ptr->min_export = USHRT_MAX;
   }

   /* check the export level */
#if 0
   printf("R min %d max %d depth %d pfx %s\n",
	  ptr->min_export, ptr->max_export, depth, sprint_prefix(ptr));
#endif
   if (ptr->min_export == 0 || ptr->min_export == USHRT_MAX) {
      if (depth > ptr->max_export) ptr->max_export = depth;
   } else if (ptr->max_export < depth) {
      prefix *survey = ptr;
      char *s;
      const char *p;
      int level;
      for (level = ptr->max_export + 1; level; level--) {
	 survey = survey->up;
	 SVX_ASSERT(survey);
      }
      s = osstrdup(sprint_prefix(survey));
      p = sprint_prefix(ptr);
      if (survey->filename) {
	 compile_diagnostic_pfx(DIAG_ERR, survey,
				/*Station “%s” not exported from survey “%s”*/26,
				p, s);
      } else {
	 compile_diagnostic(DIAG_ERR, /*Station “%s” not exported from survey “%s”*/26, p, s);
      }
      osfree(s);
#if 0
      printf(" *** pfx %s warning not exported enough depth %d "
	     "ptr->max_export %d\n", sprint_prefix(ptr),
	     depth, ptr->max_export);
#endif
   }
   if (!fImplicitPrefix && (pfx_flags & PFX_WARN_SEPARATOR)) {
      filepos fp_tmp;
      get_pos(&fp_tmp);
      set_pos(&fp_firstsep);
      compile_diagnostic(DIAG_WARN|DIAG_COL, /*Separator in survey name*/392);
      set_pos(&fp_tmp);
   }
   return ptr;
}

/* if numeric expr is omitted: if f_optional return HUGE_REAL, else longjmp */
static real
read_number(bool f_optional)
{
   bool fPositive, fDigits = fFalse;
   real n = (real)0.0;
   filepos fp;
   int ch_old;

   get_pos(&fp);
   ch_old = ch;
   fPositive = !isMinus(ch);
   if (isSign(ch)) nextch();

   while (isdigit(ch)) {
      n = n * (real)10.0 + (char)(ch - '0');
      nextch();
      fDigits = fTrue;
   }

   if (isDecimal(ch)) {
      real mult = (real)1.0;
      nextch();
      while (isdigit(ch)) {
	 mult *= (real).1;
	 n += (char)(ch - '0') * mult;
	 fDigits = fTrue;
	 nextch();
      }
   }

   /* !'fRead' => !fDigits so fDigits => 'fRead' */
   if (fDigits) return (fPositive ? n : -n);

   /* didn't read a valid number.  If it's optional, reset filepos & return */
   set_pos(&fp);
   if (f_optional) {
      return HUGE_REAL;
   }

   if (isOmit(ch_old)) {
      compile_diagnostic(DIAG_ERR|DIAG_COL, /*Field may not be omitted*/8);
   } else {
      compile_diagnostic_token_show(DIAG_ERR, /*Expecting numeric field, found “%s”*/9);
   }
   LONGJMP(file.jbSkipLine);
   return 0.0; /* for brain-fried compilers */
}