blob: 7856ed0989adb02ebb2043330c23bb6afe4962f4 [file] [log] [blame]
/* Copyright (c) 1988 Bellcore
** All Rights Reserved
** Permission is granted to copy or use this program, EXCEPT that it
** may not be sold for profit, the copyright notice must be reproduced
** on copies, and credit should be given to Bellcore where it is due.
** BELLCORE MAKES NO WARRANTY AND ACCEPTS NO LIABILITY FOR THIS PROGRAM.
*/
#ifndef lint
static char rcsid[]= "$Header$";
#endif
#include "misc.h"
#include "float.h"
#include "tol.h"
#include "token.h"
/*
** storage for the default tolerances
*/
T_tol _T_gtol = _T_null;
/*
** tolerances that can be set in the command script and attached to floating
** point numbers at parse time
*/
static T_tol _T_tols[_T_TOLMAX];
/*
** initialize the global tolerance
** should be called only once at the beginning of the program
*/
void
T_initdefault()
{
static int called_before = 0;
if (called_before)
{
Z_fatal("T_initdefault called more than once\n");
}
/*
** if the default tolerance was set somewhere else
** don't set it here
*/
if (T_isnull(_T_gtol))
{
T_defatol(_T_ADEF);
T_defrtol(_T_RDEF);
}
called_before = 1;
}
static void
_T_tolclear(addr)
T_tol *addr;
{
*addr = _T_null;
}
/*
** clear the parse time tolerances
*/
void
T_clear_tols()
{
int i;
for(i=0;i<_T_TOLMAX;i++)
{
_T_tolclear(&_T_tols[i]);
}
}
static void
_T_defclear()
{
_T_tolclear(&_T_gtol);
}
/*
** take a series of specifiers and add them to the tolerance
*/
static void
_T_settol(toladdr,str)
T_tol *toladdr;
char *str;
{
char typechar;
while ('\0' != *str)
{
/*
** find the first non-whitespace character
*/
S_skipspace(&str);
/*
** snarf up the type specifier
*/
typechar = *str;
/*
** now skip the first char
*/
str++;
/*
** skip any possibly intervening whitespace
*/
S_skipspace(&str);
switch (typechar)
{
case 'a':
_T_addtol(toladdr,T_ABSOLUTE,str);
break;
case 'r':
_T_addtol(toladdr,T_RELATIVE,str);
break;
case 'i':
_T_addtol(toladdr,T_IGNORE,(char*)0);
break;
case 'd':
_T_appendtols(toladdr,_T_gtol);
break;
default:
(void) sprintf(Z_err_buf,
"don't understand tolerance type '%c'\n",typechar);
Z_fatal(Z_err_buf);
}
/*
** and skip to next tolerance
*/
S_nextword(&str);
}
}
/*
** set the default tolerance
*/
void
T_setdef(str)
char *str;
{
_T_defclear();
_T_settol(&_T_gtol,str);
}
static char*
_T_nextspec(ptr)
char *ptr;
{
/*
** find the end of the current spec
*/
for(;(_T_SEPCHAR != *ptr) && ('\0' != *ptr);ptr++)
{
}
/*
** and step over the seperator if necessary
*/
if (_T_SEPCHAR == *ptr)
ptr++;
return(ptr);
}
/*
** return just the next set of specs
** ie the string up to end of line or
** the first _T_SEPCHAR
** returned string does not include the _T_SEPCHAR
*/
static char *
_T_getspec(from)
char *from;
{
static char retval[Z_LINELEN];
char *ptr = retval;
while((_T_SEPCHAR != *from) && ('\0' != *from))
{
*ptr++ = *from++;
}
*ptr = '\0'; /* terminate the line */
return(retval);
}
/*
** parse a series of _T_SEPCHAR separated tolerance specifications
*/
void
T_tolline(str)
char *str;
{
int nexttol;
T_clear_tols();
for(nexttol=0;'\0' != *str;nexttol++,str = _T_nextspec(str))
{
/*
** make sure we haven't run off the end
*/
if (nexttol >= _T_TOLMAX)
{
Z_fatal("too many tolerances per line");
}
/*
** and set the tolerance
*/
_T_settol(&_T_tols[nexttol],_T_getspec(str));
}
}
int
T_moretols(int next_tol)
{
return((next_tol >= 0) &&
(_T_TOLMAX-1 > next_tol) &&
(!T_isnull( _T_tols[next_tol+1])));
}
T_tol
T_gettol(index)
int index;
{
return(_T_tols[index]);
}
/*
** chose which tolerance to use
** precidence is
** first tolerance
** second tolerance
** default tolerance
*/
T_tol
T_picktol(p1,p2)
T_tol p1, p2;
{
if (!(T_isnull(p1)))
return(p1);
if (!(T_isnull(p2)))
return(p2);
return(_T_gtol);
}
void
_T_appendtols(to,from)
T_tol *to,from;
{
T_tol last;
/*
** are there any elements on the list yet
*/
if (T_isnull(*to))
{
/*
** it's a null list, so allocat space for the
** first element and set pointer to it.
*/
*to = from;
}
else
{
/*
** find the last element on the list
*/
for(last= *to;!T_isnull(T_getnext(last));last = T_getnext(last))
{
}
/*
** add an element on the end
*/
T_setnext(last,from);
}
}
/*
** add a tolerance to a list
*/
void
_T_addtol(listptr,type,str)
T_tol *listptr;
int type;
char *str;
{
T_tol last;
/*
** are there any elements on the list yet
*/
if (T_isnull(*listptr))
{
/*
** it's a null list, so allocat space for the
** first element and set pointer to it.
*/
last = *listptr = Z_ALLOC(1,_T_struct);
}
else
{
/*
** find the last element on the list
*/
for(last= *listptr;!T_isnull(T_getnext(last));last = T_getnext(last))
{
}
/*
** add an element on the end
*/
T_setnext(last,Z_ALLOC(1,_T_struct));
/*
** and point to the new element
*/
last = T_getnext(last);
}
T_settype(last,type);
T_setnext(last,_T_null);
/*
** set the float value only if necessary
*/
if (T_IGNORE == type)
{
T_setfloat(last,F_null);
}
else
{
T_setfloat(last,F_atof(str,NO_USE_ALL));
/*
** test new tolerance for sanity
*/
if (F_getsign(T_getfloat(last)))
{
(void) sprintf(Z_err_buf,
"%s : negative tolerances don't make any sense\n",str);
Z_fatal(Z_err_buf);
}
/*
** check for excessively large relative tolerances
*/
if ((T_RELATIVE == type) &&
(F_floatcmp(T_getfloat(last),
F_atof("2.0",USE_ALL)) > 0))
{
(void) sprintf(Z_err_buf,
"%s : relative tolerances greater than 2 don't make any sense\n",str);
Z_fatal(Z_err_buf);
}
}
}