| /* 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); |
| } |
| } |
| } |