19a747e4fSDavid du Colombier #include <u.h> 29a747e4fSDavid du Colombier #include <libc.h> 39a747e4fSDavid du Colombier #include <draw.h> 49a747e4fSDavid du Colombier #include <html.h> 59a747e4fSDavid du Colombier #include "impl.h" 69a747e4fSDavid du Colombier 79a747e4fSDavid du Colombier Rune* whitespace = L" \t\n\r"; 89a747e4fSDavid du Colombier Rune* notwhitespace = L"^ \t\n\r"; 99a747e4fSDavid du Colombier 109a747e4fSDavid du Colombier // All lists start out like List structure. 119a747e4fSDavid du Colombier // List itself can be used as list of int. 129a747e4fSDavid du Colombier int 139a747e4fSDavid du Colombier _listlen(List* l) 149a747e4fSDavid du Colombier { 159a747e4fSDavid du Colombier int n = 0; 169a747e4fSDavid du Colombier 179a747e4fSDavid du Colombier while(l != nil) { 189a747e4fSDavid du Colombier l = l->next; 199a747e4fSDavid du Colombier n++; 209a747e4fSDavid du Colombier } 219a747e4fSDavid du Colombier return n; 229a747e4fSDavid du Colombier } 239a747e4fSDavid du Colombier 249a747e4fSDavid du Colombier // Cons 259a747e4fSDavid du Colombier List* 269a747e4fSDavid du Colombier _newlist(int val, List* rest) 279a747e4fSDavid du Colombier { 289a747e4fSDavid du Colombier List* ans; 299a747e4fSDavid du Colombier 309a747e4fSDavid du Colombier ans = (List*)emalloc(sizeof(List)); 319a747e4fSDavid du Colombier ans->val = val; 329a747e4fSDavid du Colombier ans->next = rest; 339a747e4fSDavid du Colombier return ans; 349a747e4fSDavid du Colombier } 359a747e4fSDavid du Colombier 369a747e4fSDavid du Colombier // Reverse a list in place 379a747e4fSDavid du Colombier List* 389a747e4fSDavid du Colombier _revlist(List* l) 399a747e4fSDavid du Colombier { 409a747e4fSDavid du Colombier List* newl; 419a747e4fSDavid du Colombier List* nextl; 429a747e4fSDavid du Colombier 439a747e4fSDavid du Colombier newl = nil; 449a747e4fSDavid du Colombier while(l != nil) { 459a747e4fSDavid du Colombier nextl = l->next; 469a747e4fSDavid du Colombier l->next = newl; 479a747e4fSDavid du Colombier newl = l; 489a747e4fSDavid du Colombier l = nextl; 499a747e4fSDavid du Colombier } 509a747e4fSDavid du Colombier return newl; 519a747e4fSDavid du Colombier } 529a747e4fSDavid du Colombier 539a747e4fSDavid du Colombier // The next few routines take a "character class" as argument. 549a747e4fSDavid du Colombier // e.g., "a-zA-Z", or "^ \t\n" 559a747e4fSDavid du Colombier // (ranges indicated by - except in first position; 569a747e4fSDavid du Colombier // ^ is first position means "not in" the following class) 579a747e4fSDavid du Colombier 589a747e4fSDavid du Colombier // Splitl splits s[0:n] just before first character of class cl. 599a747e4fSDavid du Colombier // Answers go in (p1, n1) and (p2, n2). 609a747e4fSDavid du Colombier // If no split, the whole thing goes in the first component. 619a747e4fSDavid du Colombier // Note: answers contain pointers into original string. 629a747e4fSDavid du Colombier void 639a747e4fSDavid du Colombier _splitl(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2) 649a747e4fSDavid du Colombier { 659a747e4fSDavid du Colombier Rune* p; 669a747e4fSDavid du Colombier 679a747e4fSDavid du Colombier p = _Strnclass(s, cl, n); 689a747e4fSDavid du Colombier *p1 = s; 699a747e4fSDavid du Colombier if(p == nil) { 709a747e4fSDavid du Colombier *n1 = n; 719a747e4fSDavid du Colombier *p2 = nil; 729a747e4fSDavid du Colombier *n2 = 0; 739a747e4fSDavid du Colombier } 749a747e4fSDavid du Colombier else { 759a747e4fSDavid du Colombier *p2 = p; 769a747e4fSDavid du Colombier *n1 = p-s; 779a747e4fSDavid du Colombier *n2 = n-*n1; 789a747e4fSDavid du Colombier } 799a747e4fSDavid du Colombier } 809a747e4fSDavid du Colombier 819a747e4fSDavid du Colombier // Splitr splits s[0:n] just after last character of class cl. 829a747e4fSDavid du Colombier // Answers go in (p1, n1) and (p2, n2). 839a747e4fSDavid du Colombier // If no split, the whole thing goes in the last component. 849a747e4fSDavid du Colombier // Note: answers contain pointers into original string. 859a747e4fSDavid du Colombier void 869a747e4fSDavid du Colombier _splitr(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2) 879a747e4fSDavid du Colombier { 889a747e4fSDavid du Colombier Rune* p; 899a747e4fSDavid du Colombier 909a747e4fSDavid du Colombier p = _Strnrclass(s, cl, n); 919a747e4fSDavid du Colombier if(p == nil) { 929a747e4fSDavid du Colombier *p1 = nil; 939a747e4fSDavid du Colombier *n1 = 0; 949a747e4fSDavid du Colombier *p2 = s; 959a747e4fSDavid du Colombier *n2 = n; 969a747e4fSDavid du Colombier } 979a747e4fSDavid du Colombier else { 989a747e4fSDavid du Colombier *p1 = s; 999a747e4fSDavid du Colombier *p2 = p+1; 1009a747e4fSDavid du Colombier *n1 = *p2-s; 1019a747e4fSDavid du Colombier *n2 = n-*n1; 1029a747e4fSDavid du Colombier } 1039a747e4fSDavid du Colombier } 1049a747e4fSDavid du Colombier 1059a747e4fSDavid du Colombier // Splitall splits s[0:n] into parts that are separated by characters from class cl. 1069a747e4fSDavid du Colombier // Each part will have nonzero length. 1079a747e4fSDavid du Colombier // At most alen parts are found, and pointers to their starts go into 1089a747e4fSDavid du Colombier // the strarr array, while their lengths go into the lenarr array. 1099a747e4fSDavid du Colombier // The return value is the number of parts found. 1109a747e4fSDavid du Colombier int 1119a747e4fSDavid du Colombier _splitall(Rune* s, int n, Rune* cl, Rune** strarr, int* lenarr, int alen) 1129a747e4fSDavid du Colombier { 1139a747e4fSDavid du Colombier int i; 1149a747e4fSDavid du Colombier Rune* p; 1159a747e4fSDavid du Colombier Rune* q; 1169a747e4fSDavid du Colombier Rune* slast; 1179a747e4fSDavid du Colombier 1189a747e4fSDavid du Colombier if(s == nil || n == 0) 1199a747e4fSDavid du Colombier return 0; 1209a747e4fSDavid du Colombier i = 0; 1219a747e4fSDavid du Colombier p = s; 1229a747e4fSDavid du Colombier slast = s+n; 1239a747e4fSDavid du Colombier while(p < slast && i < alen) { 1249a747e4fSDavid du Colombier while(p < slast && _inclass(*p, cl)) 1259a747e4fSDavid du Colombier p++; 1269a747e4fSDavid du Colombier if(p == slast) 1279a747e4fSDavid du Colombier break; 1289a747e4fSDavid du Colombier q = _Strnclass(p, cl, slast-p); 1299a747e4fSDavid du Colombier if(q == nil) 1309a747e4fSDavid du Colombier q = slast; 1319a747e4fSDavid du Colombier assert(q > p && q <= slast); 1329a747e4fSDavid du Colombier strarr[i] = p; 1339a747e4fSDavid du Colombier lenarr[i] = q-p; 1349a747e4fSDavid du Colombier i++; 1359a747e4fSDavid du Colombier p = q; 1369a747e4fSDavid du Colombier } 1379a747e4fSDavid du Colombier return i; 1389a747e4fSDavid du Colombier } 1399a747e4fSDavid du Colombier 1409a747e4fSDavid du Colombier // Find part of s that excludes leading and trailing whitespace, 1419a747e4fSDavid du Colombier // and return that part in *pans (and its length in *panslen). 1429a747e4fSDavid du Colombier void 1439a747e4fSDavid du Colombier _trimwhite(Rune* s, int n, Rune** pans, int* panslen) 1449a747e4fSDavid du Colombier { 1459a747e4fSDavid du Colombier Rune* p; 1469a747e4fSDavid du Colombier Rune* q; 1479a747e4fSDavid du Colombier 1489a747e4fSDavid du Colombier p = nil; 1499a747e4fSDavid du Colombier if(n > 0) { 1509a747e4fSDavid du Colombier p = _Strnclass(s, notwhitespace, n); 1519a747e4fSDavid du Colombier if(p != nil) { 1529a747e4fSDavid du Colombier q = _Strnrclass(s, notwhitespace, n); 1539a747e4fSDavid du Colombier assert(q != nil); 1549a747e4fSDavid du Colombier n = q+1-p; 1559a747e4fSDavid du Colombier } 1569a747e4fSDavid du Colombier } 1579a747e4fSDavid du Colombier *pans = p; 1589a747e4fSDavid du Colombier *panslen = n; 1599a747e4fSDavid du Colombier } 1609a747e4fSDavid du Colombier 1619a747e4fSDavid du Colombier // _Strclass returns a pointer to the first element of s that is 1629a747e4fSDavid du Colombier // a member of class cl, nil if none. 1639a747e4fSDavid du Colombier Rune* 1649a747e4fSDavid du Colombier _Strclass(Rune* s, Rune* cl) 1659a747e4fSDavid du Colombier { 1669a747e4fSDavid du Colombier Rune* p; 1679a747e4fSDavid du Colombier 1689a747e4fSDavid du Colombier for(p = s; *p != 0; p++) 1699a747e4fSDavid du Colombier if(_inclass(*p, cl)) 1709a747e4fSDavid du Colombier return p; 1719a747e4fSDavid du Colombier return nil; 1729a747e4fSDavid du Colombier } 1739a747e4fSDavid du Colombier 1749a747e4fSDavid du Colombier // _Strnclass returns a pointer to the first element of s[0:n] that is 1759a747e4fSDavid du Colombier // a member of class cl, nil if none. 1769a747e4fSDavid du Colombier Rune* 1779a747e4fSDavid du Colombier _Strnclass(Rune* s, Rune* cl, int n) 1789a747e4fSDavid du Colombier { 1799a747e4fSDavid du Colombier Rune* p; 1809a747e4fSDavid du Colombier 1819a747e4fSDavid du Colombier for(p = s; n-- && *p != 0; p++) 1829a747e4fSDavid du Colombier if(_inclass(*p, cl)) 1839a747e4fSDavid du Colombier return p; 1849a747e4fSDavid du Colombier return nil; 1859a747e4fSDavid du Colombier } 1869a747e4fSDavid du Colombier 1879a747e4fSDavid du Colombier // _Strrclass returns a pointer to the last element of s that is 1889a747e4fSDavid du Colombier // a member of class cl, nil if none 1899a747e4fSDavid du Colombier Rune* 1909a747e4fSDavid du Colombier _Strrclass(Rune* s, Rune* cl) 1919a747e4fSDavid du Colombier { 1929a747e4fSDavid du Colombier Rune* p; 1939a747e4fSDavid du Colombier 1949a747e4fSDavid du Colombier if(s == nil || *s == 0) 1959a747e4fSDavid du Colombier return nil; 1969a747e4fSDavid du Colombier p = s + runestrlen(s) - 1; 1979a747e4fSDavid du Colombier while(p >= s) { 1989a747e4fSDavid du Colombier if(_inclass(*p, cl)) 1999a747e4fSDavid du Colombier return p; 2009a747e4fSDavid du Colombier p--; 2019a747e4fSDavid du Colombier }; 2029a747e4fSDavid du Colombier return nil; 2039a747e4fSDavid du Colombier } 2049a747e4fSDavid du Colombier 2059a747e4fSDavid du Colombier // _Strnrclass returns a pointer to the last element of s[0:n] that is 2069a747e4fSDavid du Colombier // a member of class cl, nil if none 2079a747e4fSDavid du Colombier Rune* 2089a747e4fSDavid du Colombier _Strnrclass(Rune* s, Rune* cl, int n) 2099a747e4fSDavid du Colombier { 2109a747e4fSDavid du Colombier Rune* p; 2119a747e4fSDavid du Colombier 2129a747e4fSDavid du Colombier if(s == nil || *s == 0 || n == 0) 2139a747e4fSDavid du Colombier return nil; 2149a747e4fSDavid du Colombier p = s + n - 1; 2159a747e4fSDavid du Colombier while(p >= s) { 2169a747e4fSDavid du Colombier if(_inclass(*p, cl)) 2179a747e4fSDavid du Colombier return p; 2189a747e4fSDavid du Colombier p--; 2199a747e4fSDavid du Colombier }; 2209a747e4fSDavid du Colombier return nil; 2219a747e4fSDavid du Colombier } 2229a747e4fSDavid du Colombier 2239a747e4fSDavid du Colombier // Is c in the class cl? 2249a747e4fSDavid du Colombier int 2259a747e4fSDavid du Colombier _inclass(Rune c, Rune* cl) 2269a747e4fSDavid du Colombier { 2279a747e4fSDavid du Colombier int n; 2289a747e4fSDavid du Colombier int ans; 2299a747e4fSDavid du Colombier int negate; 2309a747e4fSDavid du Colombier int i; 2319a747e4fSDavid du Colombier 232*5d459b5aSDavid du Colombier n = _Strlen(cl); 2339a747e4fSDavid du Colombier if(n == 0) 2349a747e4fSDavid du Colombier return 0; 2359a747e4fSDavid du Colombier ans = 0; 2369a747e4fSDavid du Colombier negate = 0; 2379a747e4fSDavid du Colombier if(cl[0] == '^') { 2389a747e4fSDavid du Colombier negate = 1; 2399a747e4fSDavid du Colombier cl++; 2409a747e4fSDavid du Colombier n--; 2419a747e4fSDavid du Colombier } 2429a747e4fSDavid du Colombier for(i = 0; i < n; i++) { 2439a747e4fSDavid du Colombier if(cl[i] == '-' && i > 0 && i < n - 1) { 2449a747e4fSDavid du Colombier if(c >= cl[i - 1] && c <= cl[i + 1]) { 2459a747e4fSDavid du Colombier ans = 1; 2469a747e4fSDavid du Colombier break; 2479a747e4fSDavid du Colombier } 2489a747e4fSDavid du Colombier i++; 2499a747e4fSDavid du Colombier } 2509a747e4fSDavid du Colombier else if(c == cl[i]) { 2519a747e4fSDavid du Colombier ans = 1; 2529a747e4fSDavid du Colombier break; 2539a747e4fSDavid du Colombier } 2549a747e4fSDavid du Colombier } 2559a747e4fSDavid du Colombier if(negate) 2569a747e4fSDavid du Colombier ans = !ans; 2579a747e4fSDavid du Colombier return ans; 2589a747e4fSDavid du Colombier } 2599a747e4fSDavid du Colombier 2609a747e4fSDavid du Colombier // Is pre a prefix of s? 2619a747e4fSDavid du Colombier int 2629a747e4fSDavid du Colombier _prefix(Rune* pre, Rune* s) 2639a747e4fSDavid du Colombier { 2649a747e4fSDavid du Colombier int ns; 2659a747e4fSDavid du Colombier int n; 2669a747e4fSDavid du Colombier int k; 2679a747e4fSDavid du Colombier 268*5d459b5aSDavid du Colombier ns = _Strlen(s); 269*5d459b5aSDavid du Colombier n = _Strlen(pre); 2709a747e4fSDavid du Colombier if(ns < n) 2719a747e4fSDavid du Colombier return 0; 2729a747e4fSDavid du Colombier for(k = 0; k < n; k++) { 2739a747e4fSDavid du Colombier if(pre[k] != s[k]) 2749a747e4fSDavid du Colombier return 0; 2759a747e4fSDavid du Colombier } 2769a747e4fSDavid du Colombier return 1; 2779a747e4fSDavid du Colombier } 2789a747e4fSDavid du Colombier 279*5d459b5aSDavid du Colombier // Number of runes in (null-terminated) s 280*5d459b5aSDavid du Colombier int 281*5d459b5aSDavid du Colombier _Strlen(Rune* s) 282*5d459b5aSDavid du Colombier { 283*5d459b5aSDavid du Colombier if(s == nil) 284*5d459b5aSDavid du Colombier return 0; 285*5d459b5aSDavid du Colombier return runestrlen(s); 286*5d459b5aSDavid du Colombier } 287*5d459b5aSDavid du Colombier 288*5d459b5aSDavid du Colombier // -1, 0, 1 as s1 is lexicographically less, equal greater than s2 289*5d459b5aSDavid du Colombier int 290*5d459b5aSDavid du Colombier _Strcmp(Rune *s1, Rune *s2) 291*5d459b5aSDavid du Colombier { 292*5d459b5aSDavid du Colombier if(s1 == nil) 293*5d459b5aSDavid du Colombier return (s2 == nil || *s2 == 0) ? 0 : -1; 294*5d459b5aSDavid du Colombier if(s2 == nil) 295*5d459b5aSDavid du Colombier return (*s1 == 0) ? 0 : 1; 296*5d459b5aSDavid du Colombier return runestrcmp(s1, s2); 297*5d459b5aSDavid du Colombier } 298*5d459b5aSDavid du Colombier 2999a747e4fSDavid du Colombier // Like Strcmp, but use exactly n chars of s1 (assume s1 has at least n chars). 3009a747e4fSDavid du Colombier // Also, do a case-insensitive match, assuming s2 3019a747e4fSDavid du Colombier // has no chars in [A-Z], only their lowercase versions. 3029a747e4fSDavid du Colombier // (This routine is used for in-place keyword lookup, where s2 is in a keyword 3039a747e4fSDavid du Colombier // list and s1 is some substring, possibly mixed-case, in a buffer.) 3049a747e4fSDavid du Colombier int 3059a747e4fSDavid du Colombier _Strncmpci(Rune *s1, int n1, Rune *s2) 3069a747e4fSDavid du Colombier { 3079a747e4fSDavid du Colombier Rune c1, c2; 3089a747e4fSDavid du Colombier 3099a747e4fSDavid du Colombier for(;;) { 3109a747e4fSDavid du Colombier if(n1-- == 0) { 3119a747e4fSDavid du Colombier if(*s2 == 0) 3129a747e4fSDavid du Colombier return 0; 3139a747e4fSDavid du Colombier return -1; 3149a747e4fSDavid du Colombier } 3159a747e4fSDavid du Colombier c1 = *s1++; 3169a747e4fSDavid du Colombier c2 = *s2++; 3179a747e4fSDavid du Colombier if(c1 >= 'A' && c1 <= 'Z') 3189a747e4fSDavid du Colombier c1 = c1 - 'A' + 'a'; 3199a747e4fSDavid du Colombier if(c1 != c2) { 3209a747e4fSDavid du Colombier if(c1 > c2) 3219a747e4fSDavid du Colombier return 1; 3229a747e4fSDavid du Colombier return -1; 3239a747e4fSDavid du Colombier } 3249a747e4fSDavid du Colombier } 3259a747e4fSDavid du Colombier } 3269a747e4fSDavid du Colombier 3279a747e4fSDavid du Colombier // emalloc and copy 3289a747e4fSDavid du Colombier Rune* 3299a747e4fSDavid du Colombier _Strdup(Rune* s) 3309a747e4fSDavid du Colombier { 3319a747e4fSDavid du Colombier if(s == nil) 3329a747e4fSDavid du Colombier return nil; 3339a747e4fSDavid du Colombier return _Strndup(s, runestrlen(s)); 3349a747e4fSDavid du Colombier } 3359a747e4fSDavid du Colombier 3369a747e4fSDavid du Colombier // emalloc and copy n chars of s (assume s is at least that long), 3379a747e4fSDavid du Colombier // and add 0 terminator. 3389a747e4fSDavid du Colombier // Return nil if n==0. 3399a747e4fSDavid du Colombier Rune* 3409a747e4fSDavid du Colombier _Strndup(Rune* s, int n) 3419a747e4fSDavid du Colombier { 3429a747e4fSDavid du Colombier Rune* ans; 3439a747e4fSDavid du Colombier 3449a747e4fSDavid du Colombier if(n <= 0) 3459a747e4fSDavid du Colombier return nil; 3469a747e4fSDavid du Colombier ans = _newstr(n); 3479a747e4fSDavid du Colombier memmove(ans, s, n*sizeof(Rune)); 3489a747e4fSDavid du Colombier ans[n] = 0; 3499a747e4fSDavid du Colombier return ans; 3509a747e4fSDavid du Colombier } 3519a747e4fSDavid du Colombier // emalloc enough room for n Runes, plus 1 null terminator. 3529a747e4fSDavid du Colombier // (Not initialized to anything.) 3539a747e4fSDavid du Colombier Rune* 3549a747e4fSDavid du Colombier _newstr(int n) 3559a747e4fSDavid du Colombier { 3569a747e4fSDavid du Colombier return (Rune*)emalloc((n+1)*sizeof(Rune)); 3579a747e4fSDavid du Colombier } 3589a747e4fSDavid du Colombier 3599a747e4fSDavid du Colombier // emalloc and copy s+t 3609a747e4fSDavid du Colombier Rune* 3619a747e4fSDavid du Colombier _Strdup2(Rune* s, Rune* t) 3629a747e4fSDavid du Colombier { 3639a747e4fSDavid du Colombier int ns, nt; 3649a747e4fSDavid du Colombier Rune* ans; 3659a747e4fSDavid du Colombier Rune* p; 3669a747e4fSDavid du Colombier 367*5d459b5aSDavid du Colombier ns = _Strlen(s); 368*5d459b5aSDavid du Colombier nt = _Strlen(t); 3699a747e4fSDavid du Colombier if(ns+nt == 0) 3709a747e4fSDavid du Colombier return nil; 3719a747e4fSDavid du Colombier ans = _newstr(ns+nt); 3729a747e4fSDavid du Colombier p = _Stradd(ans, s, ns); 3739a747e4fSDavid du Colombier p = _Stradd(p, t, nt); 3749a747e4fSDavid du Colombier *p = 0; 3759a747e4fSDavid du Colombier return ans; 3769a747e4fSDavid du Colombier } 3779a747e4fSDavid du Colombier 3789a747e4fSDavid du Colombier // Return emalloc'd substring s[start:stop], 3799a747e4fSDavid du Colombier Rune* 3809a747e4fSDavid du Colombier _Strsubstr(Rune* s, int start, int stop) 3819a747e4fSDavid du Colombier { 3829a747e4fSDavid du Colombier Rune* t; 3839a747e4fSDavid du Colombier 3849a747e4fSDavid du Colombier if(start == stop) 3859a747e4fSDavid du Colombier return nil; 3869a747e4fSDavid du Colombier t = _Strndup(s+start, stop-start); 3879a747e4fSDavid du Colombier return t; 3889a747e4fSDavid du Colombier } 3899a747e4fSDavid du Colombier 3909a747e4fSDavid du Colombier // Copy n chars to s1 from s2, and return s1+n 3919a747e4fSDavid du Colombier Rune* 3929a747e4fSDavid du Colombier _Stradd(Rune* s1, Rune* s2, int n) 3939a747e4fSDavid du Colombier { 3949a747e4fSDavid du Colombier if(n == 0) 3959a747e4fSDavid du Colombier return s1; 3969a747e4fSDavid du Colombier memmove(s1, s2, n*sizeof(Rune)); 3979a747e4fSDavid du Colombier return s1+n; 3989a747e4fSDavid du Colombier } 3999a747e4fSDavid du Colombier 4009a747e4fSDavid du Colombier // Like strtol, but converting from Rune* string 4019a747e4fSDavid du Colombier 4029a747e4fSDavid du Colombier #define LONG_MAX 2147483647L 4039a747e4fSDavid du Colombier #define LONG_MIN -2147483648L 4049a747e4fSDavid du Colombier 4059a747e4fSDavid du Colombier long 4069a747e4fSDavid du Colombier _Strtol(Rune* nptr, Rune** endptr, int base) 4079a747e4fSDavid du Colombier { 4089a747e4fSDavid du Colombier Rune* p; 4099a747e4fSDavid du Colombier long n, nn; 4109a747e4fSDavid du Colombier int c, ovfl, v, neg, ndig; 4119a747e4fSDavid du Colombier 4129a747e4fSDavid du Colombier p = nptr; 4139a747e4fSDavid du Colombier neg = 0; 4149a747e4fSDavid du Colombier n = 0; 4159a747e4fSDavid du Colombier ndig = 0; 4169a747e4fSDavid du Colombier ovfl = 0; 4179a747e4fSDavid du Colombier 4189a747e4fSDavid du Colombier /* 4199a747e4fSDavid du Colombier * White space 4209a747e4fSDavid du Colombier */ 4219a747e4fSDavid du Colombier for(;;p++){ 4229a747e4fSDavid du Colombier switch(*p){ 4239a747e4fSDavid du Colombier case ' ': 4249a747e4fSDavid du Colombier case '\t': 4259a747e4fSDavid du Colombier case '\n': 4269a747e4fSDavid du Colombier case '\f': 4279a747e4fSDavid du Colombier case '\r': 4289a747e4fSDavid du Colombier case '\v': 4299a747e4fSDavid du Colombier continue; 4309a747e4fSDavid du Colombier } 4319a747e4fSDavid du Colombier break; 4329a747e4fSDavid du Colombier } 4339a747e4fSDavid du Colombier 4349a747e4fSDavid du Colombier /* 4359a747e4fSDavid du Colombier * Sign 4369a747e4fSDavid du Colombier */ 4379a747e4fSDavid du Colombier if(*p=='-' || *p=='+') 4389a747e4fSDavid du Colombier if(*p++ == '-') 4399a747e4fSDavid du Colombier neg = 1; 4409a747e4fSDavid du Colombier 4419a747e4fSDavid du Colombier /* 4429a747e4fSDavid du Colombier * Base 4439a747e4fSDavid du Colombier */ 4449a747e4fSDavid du Colombier if(base==0){ 4459a747e4fSDavid du Colombier if(*p != '0') 4469a747e4fSDavid du Colombier base = 10; 4479a747e4fSDavid du Colombier else{ 4489a747e4fSDavid du Colombier base = 8; 4499a747e4fSDavid du Colombier if(p[1]=='x' || p[1]=='X'){ 4509a747e4fSDavid du Colombier p += 2; 4519a747e4fSDavid du Colombier base = 16; 4529a747e4fSDavid du Colombier } 4539a747e4fSDavid du Colombier } 4549a747e4fSDavid du Colombier }else if(base==16 && *p=='0'){ 4559a747e4fSDavid du Colombier if(p[1]=='x' || p[1]=='X') 4569a747e4fSDavid du Colombier p += 2; 4579a747e4fSDavid du Colombier }else if(base<0 || 36<base) 4589a747e4fSDavid du Colombier goto Return; 4599a747e4fSDavid du Colombier 4609a747e4fSDavid du Colombier /* 4619a747e4fSDavid du Colombier * Non-empty sequence of digits 4629a747e4fSDavid du Colombier */ 4639a747e4fSDavid du Colombier for(;; p++,ndig++){ 4649a747e4fSDavid du Colombier c = *p; 4659a747e4fSDavid du Colombier v = base; 4669a747e4fSDavid du Colombier if('0'<=c && c<='9') 4679a747e4fSDavid du Colombier v = c - '0'; 4689a747e4fSDavid du Colombier else if('a'<=c && c<='z') 4699a747e4fSDavid du Colombier v = c - 'a' + 10; 4709a747e4fSDavid du Colombier else if('A'<=c && c<='Z') 4719a747e4fSDavid du Colombier v = c - 'A' + 10; 4729a747e4fSDavid du Colombier if(v >= base) 4739a747e4fSDavid du Colombier break; 4749a747e4fSDavid du Colombier nn = n*base + v; 4759a747e4fSDavid du Colombier if(nn < n) 4769a747e4fSDavid du Colombier ovfl = 1; 4779a747e4fSDavid du Colombier n = nn; 4789a747e4fSDavid du Colombier } 4799a747e4fSDavid du Colombier 4809a747e4fSDavid du Colombier Return: 4819a747e4fSDavid du Colombier if(ndig == 0) 4829a747e4fSDavid du Colombier p = nptr; 4839a747e4fSDavid du Colombier if(endptr) 4849a747e4fSDavid du Colombier *endptr = p; 4859a747e4fSDavid du Colombier if(ovfl){ 4869a747e4fSDavid du Colombier if(neg) 4879a747e4fSDavid du Colombier return LONG_MIN; 4889a747e4fSDavid du Colombier return LONG_MAX; 4899a747e4fSDavid du Colombier } 4909a747e4fSDavid du Colombier if(neg) 4919a747e4fSDavid du Colombier return -n; 4929a747e4fSDavid du Colombier return n; 4939a747e4fSDavid du Colombier } 4949a747e4fSDavid du Colombier 4959a747e4fSDavid du Colombier // Convert buf[0:n], bytes whose character set is chset, 4969a747e4fSDavid du Colombier // into a emalloc'd null-terminated Unicode string. 4979a747e4fSDavid du Colombier Rune* 4989a747e4fSDavid du Colombier toStr(uchar* buf, int n, int chset) 4999a747e4fSDavid du Colombier { 5009a747e4fSDavid du Colombier int i; 5019a747e4fSDavid du Colombier int m; 5029a747e4fSDavid du Colombier Rune ch; 5039a747e4fSDavid du Colombier Rune* ans; 5049a747e4fSDavid du Colombier 5059a747e4fSDavid du Colombier switch(chset) { 5069a747e4fSDavid du Colombier case US_Ascii: 5079a747e4fSDavid du Colombier case ISO_8859_1: 5089a747e4fSDavid du Colombier ans = (Rune*)emalloc((n+1)*sizeof(Rune)); 5099a747e4fSDavid du Colombier for(i = 0; i < n; i++) 5109a747e4fSDavid du Colombier ans[i] = buf[i]; 5119a747e4fSDavid du Colombier ans[n] = 0; 5129a747e4fSDavid du Colombier break; 5139a747e4fSDavid du Colombier 5149a747e4fSDavid du Colombier case UTF_8: 5159a747e4fSDavid du Colombier m = 0; 5169a747e4fSDavid du Colombier for(i = 0; i < n; ) { 5179a747e4fSDavid du Colombier i += chartorune(&ch, (char*)(buf+i)); 5189a747e4fSDavid du Colombier m++; 5199a747e4fSDavid du Colombier } 5209a747e4fSDavid du Colombier ans = (Rune*)emalloc((m+1)*sizeof(Rune)); 5219a747e4fSDavid du Colombier m = 0; 5229a747e4fSDavid du Colombier for(i = 0; i < n; ) { 5239a747e4fSDavid du Colombier i += chartorune(&ch, (char*)(buf+i)); 5249a747e4fSDavid du Colombier ans[m++] = ch; 5259a747e4fSDavid du Colombier } 5269a747e4fSDavid du Colombier ans[m] = 0; 5279a747e4fSDavid du Colombier break; 5289a747e4fSDavid du Colombier 5299a747e4fSDavid du Colombier default: 5309a747e4fSDavid du Colombier ans = nil; 5319a747e4fSDavid du Colombier assert(0); 5329a747e4fSDavid du Colombier } 5339a747e4fSDavid du Colombier return ans; 5349a747e4fSDavid du Colombier } 5359a747e4fSDavid du Colombier 5369a747e4fSDavid du Colombier // Convert buf[0:n], Unicode characters, 5379a747e4fSDavid du Colombier // into an emalloc'd null-terminated string in character set chset. 5389a747e4fSDavid du Colombier // Use 0x80 for unconvertable characters. 5399a747e4fSDavid du Colombier uchar* 5409a747e4fSDavid du Colombier fromStr(Rune* buf, int n, int chset) 5419a747e4fSDavid du Colombier { 5429a747e4fSDavid du Colombier uchar* ans; 5439a747e4fSDavid du Colombier int i, lim, m; 5449a747e4fSDavid du Colombier Rune ch; 5459a747e4fSDavid du Colombier uchar* p; 5469a747e4fSDavid du Colombier uchar s[UTFmax]; 5479a747e4fSDavid du Colombier 5489a747e4fSDavid du Colombier ans = nil; 5499a747e4fSDavid du Colombier switch(chset) { 5509a747e4fSDavid du Colombier case US_Ascii: 5519a747e4fSDavid du Colombier case ISO_8859_1: 5529a747e4fSDavid du Colombier ans = (uchar*)emalloc(n+1); 5539a747e4fSDavid du Colombier lim = (chset==US_Ascii)? 127 : 255; 5549a747e4fSDavid du Colombier for(i = 0; i < n; i++) { 5559a747e4fSDavid du Colombier ch = buf[i]; 5569a747e4fSDavid du Colombier if(ch > lim) 5579a747e4fSDavid du Colombier ch = 0x80; 5589a747e4fSDavid du Colombier ans[i] = ch; 5599a747e4fSDavid du Colombier } 5609a747e4fSDavid du Colombier ans[n] = 0; 5619a747e4fSDavid du Colombier break; 5629a747e4fSDavid du Colombier 5639a747e4fSDavid du Colombier case UTF_8: 5649a747e4fSDavid du Colombier m = 0; 5659a747e4fSDavid du Colombier for(i = 0; i < n; i++) { 5669a747e4fSDavid du Colombier m += runetochar((char*)s, &buf[i]); 5679a747e4fSDavid du Colombier } 5689a747e4fSDavid du Colombier ans = (uchar*)emalloc(m+1); 5699a747e4fSDavid du Colombier p = ans; 5709a747e4fSDavid du Colombier for(i = 0; i < n; i++) 5719a747e4fSDavid du Colombier p += runetochar((char*)p, &buf[i]); 5729a747e4fSDavid du Colombier *p = 0; 5739a747e4fSDavid du Colombier break; 5749a747e4fSDavid du Colombier 5759a747e4fSDavid du Colombier default: 5769a747e4fSDavid du Colombier assert(0); 5779a747e4fSDavid du Colombier } 5789a747e4fSDavid du Colombier return ans; 5799a747e4fSDavid du Colombier 5809a747e4fSDavid du Colombier } 5819a747e4fSDavid du Colombier 5829a747e4fSDavid du Colombier // Convert n to emalloc'd String. 5839a747e4fSDavid du Colombier Rune* 5849a747e4fSDavid du Colombier _ltoStr(int n) 5859a747e4fSDavid du Colombier { 5869a747e4fSDavid du Colombier int m; 5879a747e4fSDavid du Colombier uchar buf[20]; 5889a747e4fSDavid du Colombier 5899a747e4fSDavid du Colombier m = snprint((char*)buf, sizeof(buf), "%d", n); 5909a747e4fSDavid du Colombier return toStr(buf, m, US_Ascii); 5919a747e4fSDavid du Colombier } 592