aboutsummaryrefslogtreecommitdiff
path: root/sys/fmtio/ctod.x
diff options
context:
space:
mode:
Diffstat (limited to 'sys/fmtio/ctod.x')
-rw-r--r--sys/fmtio/ctod.x154
1 files changed, 154 insertions, 0 deletions
diff --git a/sys/fmtio/ctod.x b/sys/fmtio/ctod.x
new file mode 100644
index 00000000..06b1d351
--- /dev/null
+++ b/sys/fmtio/ctod.x
@@ -0,0 +1,154 @@
+# Copyright(c) 1986 Association of Universities for Research in Astronomy Inc.
+
+include <mach.h>
+include <ctype.h>
+
+define DECIMAL 10
+
+.help
+.nf _________________________________________________________________________
+Attempt to convert a string to a number: nchar = ctod (str, ip, dval)
+The index IP must be set to the first character to be scanned upon entry
+to CTOD, and will be left pointing at the first untranslated character.
+
+If the string is successfully converted, the number of characters used
+is returned as the function argument. If the string (or the first few
+characters of the string) cannot be interpreted as a number, zero will be
+returned. Note that even if no numeric characters are encountered, the
+index IP may be incremented, if leading whitespace is encountered (but the
+return value N will still be zero).
+
+The upper case string "INDEF" is a legal real number, as is "." (. == 0.0).
+Sexagesimal numbers are permitted. Excess digits of precision are ignored.
+Out of range exponents are detected, and result in the value INDEF being
+returned (this is not considered an ERROR condition). Any number with an
+exponent greater than or equal to MAX_EXPONENT is interpreted as INDEF,
+regardless of the mantissa. The number need not contain a decimal point.
+
+Lexical form of a sexagesimal number:
+
+ D :== [0-9] numeric digit
+ E :== [eEdD] exponent symbol
+
+ ({D}*:)+{D}*(".")?{D}*({E}("+"|"-")?{D}+)?
+
+The format for sexagesimal numbers is fairly permissive. Any number of
+colon fields are permitted, with any number of digits (including zero) in
+each field. An exponent may occur at the end of a sexagesimal number.
+Leading zeros may be omitted in the fields.
+.endhelp ____________________________________________________________________
+
+
+# CTOD -- Convert a string to double precision real.
+
+int procedure ctod (str, ip, dval)
+
+char str[ARB] # string to be converted
+int ip # pointer into str
+double dval # receives binary value
+
+bool neg
+char dig[MAX_DIGITS]
+int j, e, vexp, ip_start
+long expon
+double value, scalar
+int strncmp(), gctol(), stridx()
+
+begin
+ while (IS_WHITE (str[ip])) # skip whitespace
+ ip = ip + 1
+ ip_start = ip
+ dval = INDEFD
+
+ if (strncmp (str[ip], "INDEF", 5) == 0) { # check for "INDEF"
+ for (ip=ip+5; IS_ALPHA (str[ip]) || str[ip] == '_'; ip=ip+1)
+ ;
+ return (ip - ip_start)
+ }
+
+ neg = (str[ip] == '-') # check for sign
+ if (neg || str[ip] == '+')
+ ip = ip + 1
+
+ while (str[ip] == '0') # ignore leading zeros
+ ip = ip + 1
+
+ dval = 0.0
+ scalar = 60.0
+
+ repeat { # accumulate digits
+ for (j=1; j <= MAX_DIGITS && IS_DIGIT(str[ip]); j=j+1) {
+ dig[j] = str[ip]
+ ip = ip + 1
+ }
+
+ for (e=0; IS_DIGIT(str[ip]); e=e+1) # ignore the rest
+ ip = ip + 1
+
+ scalar = scalar / 60.0
+ if (ip > 1 && stridx(str[ip], "'\":dDhHmMsS")>0) { # sexagesimal?
+ ip = ip + 1
+ dig[j] = EOS
+ value = 0.0 # convert digits
+ for (j=1; dig[j] != EOS; j=j+1)
+ value = value * 10.0D0 + TO_INTEG (dig[j])
+ dval = dval + value * scalar * (10.0 ** e)
+
+ while (str[ip] != EOS && # multiple spaces etc
+ stridx(str[ip]," '\":dDhHmMsS")>0)
+ ip = ip + 1
+ } else
+ break
+ }
+
+ if (str[ip] == '.') { # check for a fraction
+ ip = ip + 1
+ if (j == 1) # skip leading zeros
+ while (str[ip] == '0') { # if str = "0.00ddd"
+ ip = ip + 1
+ e = e - 1
+ }
+ for (; j <= MAX_DIGITS && IS_DIGIT(str[ip]); j=j+1) {
+ dig[j] = str[ip]
+ e = e - 1 # adjust scale factor
+ ip = ip + 1
+ } # discard insignificant
+ while (IS_DIGIT (str[ip])) # fractional digits
+ ip = ip + 1
+ }
+
+ dig[j] = EOS # no more digits
+ vexp = e + j - 1 # save for ovfl check
+ if (ip == ip_start) # not a number?
+ return (0)
+
+ value = 0.0 # convert the mantissa
+ for (j=1; dig[j] != EOS; j=j+1)
+ value = value * 10.0D0 + TO_INTEG (dig[j])
+ if (e != 0)
+ value = value * (10.0D0 ** e) # scale by e
+
+
+ # Check for exponent.
+
+ j = ip
+ expon = 0
+ if (stridx (str[ip], "eEdD") > 0) { # exponent?
+ ip = ip + 1
+ if (gctol (str, ip, expon, DECIMAL) <= 0) {
+ ip = j # return chars
+ expon = 0
+ }
+ }
+
+ if (abs(vexp+expon) > MAX_EXPONENTD) # check for overflow
+ return (ip - ip_start)
+
+ dval = dval + value * scalar
+ if (expon != 0)
+ dval = dval * (10.0D0 ** expon) # apply exponent
+
+ if (neg)
+ dval = -dval
+ return (ip - ip_start)
+end