diff options
| author | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
|---|---|---|
| committer | bhgv <bhgv.empire@gmail.com> | 2018-03-01 16:54:45 +0200 |
| commit | b786f20bbab5a59046aa78a2c6c2a11536497202 (patch) | |
| tree | 0851ecdec889eb9b7ba3751cc04d4f0b474e4a9e /appl/lib/string.b | |
inferno-os tree was separated from the inferno-os-android (separated from the Android driver)
Diffstat (limited to 'appl/lib/string.b')
| -rw-r--r-- | appl/lib/string.b | 427 |
1 files changed, 427 insertions, 0 deletions
diff --git a/appl/lib/string.b b/appl/lib/string.b new file mode 100644 index 0000000..fb123f7 --- /dev/null +++ b/appl/lib/string.b @@ -0,0 +1,427 @@ +implement String; + +include "string.m"; + +splitl(s: string, cl: string): (string, string) +{ + n := len s; + for(j := 0; j < n; j++) { + if(in(s[j], cl)) + return (s[0:j], s[j:n]); + } + return (s,""); +} + +splitr(s: string, cl: string): (string, string) +{ + n := len s; + for(j := n-1; j >= 0; j--) { + if(in(s[j], cl)) + return (s[0:j+1], s[j+1:n]); + } + return ("",s); +} + +drop(s: string, cl: string): string +{ + n := len s; + for(j := 0; j < n; j++) { + if(!in(s[j], cl)) + return (s[j:n]); + } + return ""; +} + +take(s: string, cl: string): string +{ + n := len s; + for(j := 0; j < n; j++) { + if(!in(s[j], cl)) + return (s[0:j]); + } + return s; +} + +in(c: int, s: string): int +{ + n := len s; + if(n == 0) + return 0; + ans := 0; + negate := 0; + if(s[0] == '^') { + negate = 1; + s = s[1:]; + n--; + } + for(i := 0; i < n; i++) { + if(s[i] == '-' && i > 0 && i < n-1) { + if(c >= s[i-1] && c <= s[i+1]) { + ans = 1; + break; + } + i++; + } + else + if(c == s[i]) { + ans = 1; + break; + } + } + if(negate) + ans = !ans; + return ans; +} + +splitstrl(s: string, t: string): (string, string) +{ + n := len s; + nt := len t; + if(nt == 0) + return ("", s); + c0 := t[0]; + mainloop: + for(j := 0; j <= n-nt; j++) { + if(s[j] == c0) { + for(k := 1; k < nt; k++) + if(s[j+k] != t[k]) + continue mainloop; + return(s[0:j], s[j:n]); + } + } + return (s,""); +} + +splitstrr(s: string, t: string): (string, string) +{ + n := len s; + nt := len t; + if(nt == 0) + return (s, ""); + c0 := t[0]; + mainloop: + for(j := n-nt; j >= 0; j--) { + if(s[j] == c0) { + for(k := 1; k < nt; k++) + if(s[j+k] != t[k]) + continue mainloop; + return(s[0:j+nt], s[j+nt:n]); + } + } + return ("",s); +} + +prefix(pre: string, s: string): int +{ + if(len s < len pre) + return 0; + for(k := 0; k < len pre; k++) + if(pre[k] != s[k]) + return 0; + return 1; +} + +tolower(s: string): string +{ + for(i := 0; i < len s; i++) { + c := s[i]; + if(c >= 'A' && c <= 'Z') + s[i] += 'a' - 'A'; + } + return s; +} + +toupper(s: string): string +{ + for(i := 0; i < len s; i++) { + c := s[i]; + if(c >= 'a' && c <= 'z') + s[i] += 'A' - 'a'; + } + return s; +} + +startnum(s: string, base: int): (int, int, int) +{ + if(s == nil || base != 0 && (base < 2 || base > 36)) + return (0, 0, 0); + + # skip possible leading white space + c := ' '; + for (i := 0; i < len s; i++) { + c = s[i]; + if(c != ' ' && c != '\t' && c != '\n') + break; + } + + # optional sign + 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, 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. + # probably this should check for overflow, and max out, as limbo op does? + start := i; + n := big 0; + for (; i < len s; i++) { + if((d := digit(s[i], base)) < 0) + break; + n = n*big base + big d; + } + if (i == start) + return (big 0, s); + if (neg) + return (-n, s[i:]); + return (n, s[i:]); +} + +toint(s: string, base: int): (int, string) +{ + neg, i: int; + + (base, neg, i) = startnum(s, base); + if(base == 0) + return (0, s); + + # parse number itself. + # probably this should check for overflow, and max out, as limbo op does? + start := i; + n := 0; + for (; i < len s; i++){ + if((d := digit(s[i], base)) < 0) + break; + n = n*base + d; + } + if (i == start) + return (0, s); + if (neg) + return (-n, s[i:]); + 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; + + # Reverse l, prepend s, and reverse result. + while (l != nil) { + t = hd l :: t; + l = tl l; + } + t = s :: t; + do { + l = hd t :: l; + t = tl t; + } while (t != nil); + return l; +} + +quoted(argv: list of string): string +{ + return quotedc(argv, nil); +} + +quotedc(argv: list of string, cl: string): string +{ + s := ""; + while(argv != nil){ + arg := hd argv; + for(i := 0; i < len arg; i++){ + c := arg[i]; + if(c == ' ' || c == '\t' || c == '\n' || c == '\'' || in(c, cl)) + break; + } + if(i < len arg || arg == nil){ + s += "'" + arg[0:i]; + for(; i < len arg; i++){ + if (arg[i] == '\'') + s[len s] = '\''; + s[len s] = arg[i]; + } + s[len s] = '\''; + }else + s += arg; + if(tl argv != nil) + s[len s] = ' '; + argv = tl argv; + } + return s; +} + +unquoted(s: string): list of string +{ + args: list of string; + word: string; + inquote := 0; + for(j := len s; j > 0;){ + c := s[j-1]; + if(c == ' ' || c == '\t' || c == '\n'){ + j--; + continue; + } + for(i := j-1; i >= 0 && ((c = s[i]) != ' ' && c != '\t' && c != '\n' || inquote); i--){ # collect word + if(c == '\''){ + word = s[i+1:j] + word; + j = i; + if(!inquote || i == 0 || s[i-1] != '\'') + inquote = !inquote; + else + i--; + } + } + args = (s[i+1:j]+word) :: args; + word = nil; + j = i; + } + # if quotes were unbalanced, balance them and try again. + if(inquote) + return unquoted(s + "'"); + return args; +} |
