summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorCharles.Forsyth <devnull@localhost>2007-09-06 15:37:43 +0000
committerCharles.Forsyth <devnull@localhost>2007-09-06 15:37:43 +0000
commita584e84874abd077df5ee1f3687f84d9d4fc3bfa (patch)
tree506bd77b52dfb953acf3ac1bf55f77826675085a
parent06965d10d9199bef760049aa302caf8c1c77e96f (diff)
20070906-1636
-rw-r--r--CHANGES2
-rw-r--r--appl/lib/string.b243
-rw-r--r--dis/lib/string.disbin3096 -> 4051 bytes
-rw-r--r--include/version.h2
-rw-r--r--man/2/INDEX1
-rw-r--r--man/2/string18
-rw-r--r--module/string.m1
7 files changed, 178 insertions, 89 deletions
diff --git a/CHANGES b/CHANGES
index 5c1513b5..ddaa09f9 100644
--- a/CHANGES
+++ b/CHANGES
@@ -1,3 +1,5 @@
+20070906
+ add toreal to string(2)
20070905
/appl/cmd/ed.b (caerwyn's fix for g/.../d)
also /appl/lib/ecmascript/builtin.b (toupper fix)
diff --git a/appl/lib/string.b b/appl/lib/string.b
index 16bc1940..fb123f7e 100644
--- a/appl/lib/string.b
+++ b/appl/lib/string.b
@@ -1,4 +1,5 @@
implement String;
+
include "string.m";
splitl(s: string, cl: string): (string, string)
@@ -112,61 +113,56 @@ splitstrr(s: string, t: string): (string, string)
prefix(pre: string, s: string): int
{
- ns := len s;
- n := len pre;
- if(ns < n)
+ if(len s < len pre)
return 0;
- for(k := 0; k < n; k++) {
+ for(k := 0; k < len pre; k++)
if(pre[k] != s[k])
return 0;
- }
return 1;
}
tolower(s: string): string
{
- r := s;
- for(i := 0; i < len r; i++) {
- c := r[i];
- if(c >= int 'A' && c <= int 'Z')
- r[i] = r[i] + (int 'a' - int 'A');
+ for(i := 0; i < len s; i++) {
+ c := s[i];
+ if(c >= 'A' && c <= 'Z')
+ s[i] += 'a' - 'A';
}
- return r;
+ return s;
}
toupper(s: string): string
{
- r := s;
- for(i := 0; i < len r; i++) {
- c := r[i];
- if(c >= int 'a' && c <= int 'z')
- r[i] = r[i] - (int 'a' - int 'A');
+ for(i := 0; i < len s; i++) {
+ c := s[i];
+ if(c >= 'a' && c <= 'z')
+ s[i] += 'A' - 'a';
}
- return r;
+ return s;
}
-tobig(s: string, base: int): (big, string)
+startnum(s: string, base: int): (int, int, int)
{
- if (s == nil || base < 0 || base > 36 || base == 1)
- return (big 0, s);
+ if(s == nil || base != 0 && (base < 2 || base > 36))
+ return (0, 0, 0);
# skip possible leading white space
- c: int;
+ c := ' ';
for (i := 0; i < len s; i++) {
c = s[i];
if(c != ' ' && c != '\t' && c != '\n')
break;
}
- # skip possible sign character
+ # optional sign
neg := 0;
- if (c == '-' || c == '+') {
+ if(c == '-' || c == '+') {
if(c == '-')
neg = 1;
i++;
}
- if (base == 0) {
+ if(base == 0) {
# parse possible leading base designator
start := i;
base = -1;
@@ -183,26 +179,30 @@ tobig(s: string, base: int): (big, string)
i = start;
base = 10;
} else if (base == 0 || base > 36)
- return (big 0, s);
+ return (0, 0, i);
}
+ if(i >= len s)
+ return (0, 0, 0);
+
+ return (base, neg, i);
+}
+
+tobig(s: string, base: int): (big, string)
+{
+ neg, i: int;
+
+ (base, neg, i) = startnum(s, base);
+ if(base == 0)
+ return (big 0, s);
# parse number itself.
- # perhaps this should check for overflow, and max out, as limbo op does?
+ # probably this should check for overflow, and max out, as limbo op does?
start := i;
- dig := '9';
- if (base < 10)
- dig = '0' + base - 1;
n := big 0;
for (; i < len s; i++) {
- c = s[i];
- if ('0' <= c && c <= dig)
- n = (n * big base) + big(c - '0');
- else if ('a' <= c && c < 'a' + base - 10)
- n = (n * big base) + big(c - 'a' + 10);
- else if ('A' <= c && c < 'A' + base - 10)
- n = (n * big base) + big(c - 'A' + 10);
- else
+ if((d := digit(s[i], base)) < 0)
break;
+ n = n*big base + big d;
}
if (i == start)
return (big 0, s);
@@ -213,62 +213,20 @@ tobig(s: string, base: int): (big, string)
toint(s: string, base: int): (int, string)
{
- if (s == nil || base < 0 || base > 36 || base == 1)
- return (0, s);
-
- # skip possible leading white space
- c: int;
- for (i := 0; i < len s; i++) {
- c = s[i];
- if(c != ' ' && c != '\t' && c != '\n')
- break;
- }
+ neg, i: int;
- # skip possible sign character
- neg := 0;
- if (c == '-' || c == '+') {
- if(c == '-')
- neg = 1;
- i++;
- }
-
- if (base == 0) {
- # parse possible leading base designator
- start := i;
- base = -1;
- for (; i < start+3 && i < len s; i++) {
- c = s[i];
- if (c == 'r' && i > start) {
- base = int s[start:i];
- i++;
- break;
- } else if (c < '0' || c > '9')
- break;
- }
- if (base == -1) {
- i = start;
- base = 10;
- } else if (base == 0 || base > 36)
- return (0, s);
- }
+ (base, neg, i) = startnum(s, base);
+ if(base == 0)
+ return (0, s);
# parse number itself.
- # perhaps this should check for overflow, and max out, as limbo op does?
+ # probably this should check for overflow, and max out, as limbo op does?
start := i;
- dig := '9';
- if (base < 10)
- dig = '0' + base - 1;
n := 0;
- for (; i < len s; i++) {
- c = s[i];
- if ('0' <= c && c <= dig)
- n = (n * base) + (c - '0');
- else if ('a' <= c && c < 'a' + base - 10)
- n = (n * base) + (c - 'a' + 10);
- else if ('A' <= c && c < 'A' + base - 10)
- n = (n * base) + (c - 'A' + 10);
- else
+ for (; i < len s; i++){
+ if((d := digit(s[i], base)) < 0)
break;
+ n = n*base + d;
}
if (i == start)
return (0, s);
@@ -277,6 +235,117 @@ toint(s: string, base: int): (int, string)
return (n, s[i:]);
}
+digit(c: int, base: int): int
+{
+ if ('0' <= c && c <= '0' + base - 1)
+ return c-'0';
+ else if ('a' <= c && c < 'a' + base - 10)
+ return (c - 'a' + 10);
+ else if ('A' <= c && c < 'A' + base - 10)
+ return (c - 'A' + 10);
+ else
+ return -1;
+}
+
+rpow(x: real, n: int): real
+{
+ inv := 0;
+ if(n < 0){
+ n = -n;
+ inv = 1;
+ }
+ r := 1.0;
+ for(;;){
+ if(n&1)
+ r *= x;
+ if((n >>= 1) == 0)
+ break;
+ x *= x;
+ }
+ if(inv)
+ r = 1.0/r;
+ return r;
+}
+
+match(p: string, s: string, i: int): int
+{
+ if(i+len p > len s)
+ return 0;
+ for(j := 0; j < len p; j++){
+ c := s[i++];
+ if(c >= 'A' && c <= 'Z')
+ c += 'a'-'A';
+ if(p[j] != c)
+ return 0;
+ }
+ return 1;
+}
+
+toreal(s: string, base: int): (real, string)
+{
+ neg, i: int;
+
+ (base, neg, i) = startnum(s, base);
+ if(base == 0)
+ return (0.0, s);
+
+ c := s[i];
+ if((c == 'i' || c == 'I') && match("infinity", s, i))
+ return (real s, s[i+8:]);
+ if((c == 'n' || c == 'N') && match("nan", s, i))
+ return (real s, s[i+3:]);
+
+ if(digit(c, base) < 0)
+ return (0.0, s);
+
+ num := 0.0;
+ for(; i < len s && (d := digit(s[i], base)) >= 0; i++)
+ num = num*real base + real d;
+ dig := 0; # digits in fraction
+ if(i < len s && s[i] == '.'){
+ i++;
+ for(; i < len s && (d = digit(s[i], base)) >= 0; i++){
+ num = num*real base + real d;
+ dig++;
+ }
+ }
+ exp := 0;
+ eneg := 0;
+ if(i < len s && ((c = s[i]) == 'e' || c == 'E')){
+ start := i; # might still be badly formed
+ i++;
+ if(i < len s && ((c = s[i]) == '-' || c == '+')){
+ i++;
+ if(c == '-'){
+ dig = -dig;
+ eneg = 1;
+ }
+ }
+ if(i < len s && s[i] >= '0' && s[i] <= '9'){ # exponents are always decimal
+ for(; i < len s && (d = digit(s[i], 10)) >= 0; i++)
+ exp = exp*base + d;
+ }else
+ i = start;
+ }
+ if(base == 10)
+ return (real s[0: i], s[i:]); # conversion can be more accurate
+ exp -= dig;
+ if(exp < 0){
+ exp = -exp;
+ eneg = !eneg;
+ }
+ if(exp < 0 || exp > 19999)
+ exp = 19999; # huge but otherwise arbitrary limit
+ dem := rpow(real base, exp);
+ if(eneg)
+ num /= dem;
+ else
+ num *= dem;
+ if(neg)
+ return (-num,s[i:]);
+ return (num, s[i:]);
+}
+
append(s: string, l: list of string): list of string
{
t: list of string;
diff --git a/dis/lib/string.dis b/dis/lib/string.dis
index f55bd914..19f63987 100644
--- a/dis/lib/string.dis
+++ b/dis/lib/string.dis
Binary files differ
diff --git a/include/version.h b/include/version.h
index be5b53b0..db5adb2b 100644
--- a/include/version.h
+++ b/include/version.h
@@ -1 +1 @@
-#define VERSION "Fourth Edition (20070905)"
+#define VERSION "Fourth Edition (20070906)"
diff --git a/man/2/INDEX b/man/2/INDEX
index 61a1e4d0..2c46d942 100644
--- a/man/2/INDEX
+++ b/man/2/INDEX
@@ -372,6 +372,7 @@ take string
tobig string
toint string
tolower string
+toreal string
toupper string
unquoted string
stringinttab stringinttab
diff --git a/man/2/string b/man/2/string
index 7d1c4298..9ce877ee 100644
--- a/man/2/string
+++ b/man/2/string
@@ -1,7 +1,7 @@
.TH STRING 2
.SH NAME
string: append, drop, in, prefix, quoted, splitl, splitr, splitstrl,
-splitstrr, take, tobig, toint, tolower, toupper, unquoted \- string operations
+splitstrr, take, tobig, toint, toreal, tolower, toupper, unquoted \- string operations
.SH SYNOPSIS
.EX
include "string.m";
@@ -18,6 +18,7 @@ splitstrr: fn(s, t: string): (string, string);
take: fn(s, cl: string): string;
tobig: fn(s: string, base: int): (big, string);
toint: fn(s: string, base: int): (int, string);
+toreal: fn(s: string, base: int): (real, string);
tolower: fn(s: string): string;
toupper: fn(s: string): string;
quoted: fn(args: list of string): string;
@@ -137,6 +138,21 @@ has the same specification as
except that converts to 64-bit
.BR big .
.PP
+.B Toreal
+is similar to
+.BR toint ,
+except that it expects a floating-point number after optional leading white space:
+an optional sign, then a string of digits containing a decimal point, then an optional
+.RB ` e '
+or
+.RB ` E '
+followed by an optionally signed decimal integer exponent.
+The string of digits can optionally be preceded by a base (radix) specifier
+of the form
+.IB B r ,
+as for integers.
+Any exponent is then interpreted as a power of that base.
+.PP
.B Tolower
converts all upper case letters in the string
.I s
diff --git a/module/string.m b/module/string.m
index 41ce5e4e..a5051738 100644
--- a/module/string.m
+++ b/module/string.m
@@ -30,6 +30,7 @@ String: module
# string to int returning value, remainder
toint: fn(s: string, base: int): (int, string);
tobig: fn(s: string, base: int): (big, string);
+ toreal: fn(s: string, base: int): (real, string);
# append s to end of l
append: fn(s: string, l: list of string): list of string;