xref: /plan9/sys/src/libhtml/utils.c (revision c93608cc76758b2be624199c6208a0f90bad298d)
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
_listlen(List * l)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*
_newlist(int val,List * rest)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*
_revlist(List * l)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
_splitl(Rune * s,int n,Rune * cl,Rune ** p1,int * n1,Rune ** p2,int * n2)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
_splitr(Rune * s,int n,Rune * cl,Rune ** p1,int * n1,Rune ** p2,int * n2)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
_splitall(Rune * s,int n,Rune * cl,Rune ** strarr,int * lenarr,int alen)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
_trimwhite(Rune * s,int n,Rune ** pans,int * panslen)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*
_Strclass(Rune * s,Rune * cl)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*
_Strnclass(Rune * s,Rune * cl,int n)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*
_Strrclass(Rune * s,Rune * cl)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*
_Strnrclass(Rune * s,Rune * cl,int n)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
_inclass(Rune c,Rune * cl)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
_prefix(Rune * pre,Rune * s)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
_Strlen(Rune * s)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
_Strcmp(Rune * s1,Rune * s2)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
_Strncmpci(Rune * s1,int n1,Rune * s2)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*
_Strdup(Rune * s)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*
_Strndup(Rune * s,int n)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*
_newstr(int n)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*
_Strdup2(Rune * s,Rune * t)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*
_Strsubstr(Rune * s,int start,int stop)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*
_Stradd(Rune * s1,Rune * s2,int n)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
_Strtol(Rune * nptr,Rune ** endptr,int base)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*
toStr(uchar * buf,int n,int chset)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*
fromStr(Rune * buf,int n,int chset)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 }
581