xref: /plan9/sys/src/libhtml/utils.c (revision 9a747e4fd48b9f4522c70c07e8f882a15030f964)
1*9a747e4fSDavid du Colombier #include <u.h>
2*9a747e4fSDavid du Colombier #include <libc.h>
3*9a747e4fSDavid du Colombier #include <draw.h>
4*9a747e4fSDavid du Colombier #include <html.h>
5*9a747e4fSDavid du Colombier #include "impl.h"
6*9a747e4fSDavid du Colombier 
7*9a747e4fSDavid du Colombier Rune* whitespace = L" \t\n\r";
8*9a747e4fSDavid du Colombier Rune* notwhitespace = L"^ \t\n\r";
9*9a747e4fSDavid du Colombier 
10*9a747e4fSDavid du Colombier // All lists start out like List structure.
11*9a747e4fSDavid du Colombier // List itself can be used as list of int.
12*9a747e4fSDavid du Colombier int
13*9a747e4fSDavid du Colombier _listlen(List* l)
14*9a747e4fSDavid du Colombier {
15*9a747e4fSDavid du Colombier 	int n = 0;
16*9a747e4fSDavid du Colombier 
17*9a747e4fSDavid du Colombier 	while(l != nil) {
18*9a747e4fSDavid du Colombier 		l = l->next;
19*9a747e4fSDavid du Colombier 		n++;
20*9a747e4fSDavid du Colombier 	}
21*9a747e4fSDavid du Colombier 	return n;
22*9a747e4fSDavid du Colombier }
23*9a747e4fSDavid du Colombier 
24*9a747e4fSDavid du Colombier // Cons
25*9a747e4fSDavid du Colombier List*
26*9a747e4fSDavid du Colombier _newlist(int val, List* rest)
27*9a747e4fSDavid du Colombier {
28*9a747e4fSDavid du Colombier 	List* ans;
29*9a747e4fSDavid du Colombier 
30*9a747e4fSDavid du Colombier 	ans = (List*)emalloc(sizeof(List));
31*9a747e4fSDavid du Colombier 	ans->val = val;
32*9a747e4fSDavid du Colombier 	ans->next = rest;
33*9a747e4fSDavid du Colombier 	return ans;
34*9a747e4fSDavid du Colombier }
35*9a747e4fSDavid du Colombier 
36*9a747e4fSDavid du Colombier // Reverse a list in place
37*9a747e4fSDavid du Colombier List*
38*9a747e4fSDavid du Colombier _revlist(List* l)
39*9a747e4fSDavid du Colombier {
40*9a747e4fSDavid du Colombier 	List* newl;
41*9a747e4fSDavid du Colombier 	List* nextl;
42*9a747e4fSDavid du Colombier 
43*9a747e4fSDavid du Colombier 	newl = nil;
44*9a747e4fSDavid du Colombier 	while(l != nil) {
45*9a747e4fSDavid du Colombier 		nextl = l->next;
46*9a747e4fSDavid du Colombier 		l->next = newl;
47*9a747e4fSDavid du Colombier 		newl = l;
48*9a747e4fSDavid du Colombier 		l = nextl;
49*9a747e4fSDavid du Colombier 	}
50*9a747e4fSDavid du Colombier 	return newl;
51*9a747e4fSDavid du Colombier }
52*9a747e4fSDavid du Colombier 
53*9a747e4fSDavid du Colombier // The next few routines take a "character class" as argument.
54*9a747e4fSDavid du Colombier //    e.g., "a-zA-Z", or "^ \t\n"
55*9a747e4fSDavid du Colombier // (ranges indicated by - except in first position;
56*9a747e4fSDavid du Colombier //  ^ is first position means "not in" the following class)
57*9a747e4fSDavid du Colombier 
58*9a747e4fSDavid du Colombier // Splitl splits s[0:n] just before first character of class cl.
59*9a747e4fSDavid du Colombier // Answers go in (p1, n1) and (p2, n2).
60*9a747e4fSDavid du Colombier // If no split, the whole thing goes in the first component.
61*9a747e4fSDavid du Colombier // Note: answers contain pointers into original string.
62*9a747e4fSDavid du Colombier void
63*9a747e4fSDavid du Colombier _splitl(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2)
64*9a747e4fSDavid du Colombier {
65*9a747e4fSDavid du Colombier 	Rune* p;
66*9a747e4fSDavid du Colombier 
67*9a747e4fSDavid du Colombier 	p = _Strnclass(s, cl, n);
68*9a747e4fSDavid du Colombier 	*p1 = s;
69*9a747e4fSDavid du Colombier 	if(p == nil) {
70*9a747e4fSDavid du Colombier 		*n1 = n;
71*9a747e4fSDavid du Colombier 		*p2 = nil;
72*9a747e4fSDavid du Colombier 		*n2 = 0;
73*9a747e4fSDavid du Colombier 	}
74*9a747e4fSDavid du Colombier 	else {
75*9a747e4fSDavid du Colombier 		*p2 = p;
76*9a747e4fSDavid du Colombier 		*n1 = p-s;
77*9a747e4fSDavid du Colombier 		*n2 = n-*n1;
78*9a747e4fSDavid du Colombier 	}
79*9a747e4fSDavid du Colombier }
80*9a747e4fSDavid du Colombier 
81*9a747e4fSDavid du Colombier // Splitr splits s[0:n] just after last character of class cl.
82*9a747e4fSDavid du Colombier // Answers go in (p1, n1) and (p2, n2).
83*9a747e4fSDavid du Colombier // If no split, the whole thing goes in the last component.
84*9a747e4fSDavid du Colombier // Note: answers contain pointers into original string.
85*9a747e4fSDavid du Colombier void
86*9a747e4fSDavid du Colombier _splitr(Rune* s, int n, Rune* cl, Rune** p1, int* n1, Rune** p2, int* n2)
87*9a747e4fSDavid du Colombier {
88*9a747e4fSDavid du Colombier 	Rune* p;
89*9a747e4fSDavid du Colombier 
90*9a747e4fSDavid du Colombier 	p = _Strnrclass(s, cl, n);
91*9a747e4fSDavid du Colombier 	if(p == nil) {
92*9a747e4fSDavid du Colombier 		*p1 = nil;
93*9a747e4fSDavid du Colombier 		*n1 = 0;
94*9a747e4fSDavid du Colombier 		*p2 = s;
95*9a747e4fSDavid du Colombier 		*n2 = n;
96*9a747e4fSDavid du Colombier 	}
97*9a747e4fSDavid du Colombier 	else {
98*9a747e4fSDavid du Colombier 		*p1 = s;
99*9a747e4fSDavid du Colombier 		*p2 = p+1;
100*9a747e4fSDavid du Colombier 		*n1 = *p2-s;
101*9a747e4fSDavid du Colombier 		*n2 = n-*n1;
102*9a747e4fSDavid du Colombier 	}
103*9a747e4fSDavid du Colombier }
104*9a747e4fSDavid du Colombier 
105*9a747e4fSDavid du Colombier // Splitall splits s[0:n] into parts that are separated by characters from class cl.
106*9a747e4fSDavid du Colombier // Each part will have nonzero length.
107*9a747e4fSDavid du Colombier // At most alen parts are found, and pointers to their starts go into
108*9a747e4fSDavid du Colombier // the strarr array, while their lengths go into the lenarr array.
109*9a747e4fSDavid du Colombier // The return value is the number of parts found.
110*9a747e4fSDavid du Colombier int
111*9a747e4fSDavid du Colombier _splitall(Rune* s, int n, Rune* cl, Rune** strarr, int* lenarr, int alen)
112*9a747e4fSDavid du Colombier {
113*9a747e4fSDavid du Colombier 	int i;
114*9a747e4fSDavid du Colombier 	Rune* p;
115*9a747e4fSDavid du Colombier 	Rune* q;
116*9a747e4fSDavid du Colombier 	Rune* slast;
117*9a747e4fSDavid du Colombier 
118*9a747e4fSDavid du Colombier 	if(s == nil || n == 0)
119*9a747e4fSDavid du Colombier 		return 0;
120*9a747e4fSDavid du Colombier 	i = 0;
121*9a747e4fSDavid du Colombier 	p = s;
122*9a747e4fSDavid du Colombier 	slast = s+n;
123*9a747e4fSDavid du Colombier 	while(p < slast && i < alen) {
124*9a747e4fSDavid du Colombier 		while(p < slast && _inclass(*p, cl))
125*9a747e4fSDavid du Colombier 			p++;
126*9a747e4fSDavid du Colombier 		if(p == slast)
127*9a747e4fSDavid du Colombier 			break;
128*9a747e4fSDavid du Colombier 		q = _Strnclass(p, cl, slast-p);
129*9a747e4fSDavid du Colombier 		if(q == nil)
130*9a747e4fSDavid du Colombier 			q = slast;
131*9a747e4fSDavid du Colombier 		assert(q > p && q <= slast);
132*9a747e4fSDavid du Colombier 		strarr[i] = p;
133*9a747e4fSDavid du Colombier 		lenarr[i] = q-p;
134*9a747e4fSDavid du Colombier 		i++;
135*9a747e4fSDavid du Colombier 		p = q;
136*9a747e4fSDavid du Colombier 	}
137*9a747e4fSDavid du Colombier 	return i;
138*9a747e4fSDavid du Colombier }
139*9a747e4fSDavid du Colombier 
140*9a747e4fSDavid du Colombier // Find part of s that excludes leading and trailing whitespace,
141*9a747e4fSDavid du Colombier // and return that part in *pans (and its length in *panslen).
142*9a747e4fSDavid du Colombier void
143*9a747e4fSDavid du Colombier _trimwhite(Rune* s, int n, Rune** pans, int* panslen)
144*9a747e4fSDavid du Colombier {
145*9a747e4fSDavid du Colombier 	Rune* p;
146*9a747e4fSDavid du Colombier 	Rune* q;
147*9a747e4fSDavid du Colombier 
148*9a747e4fSDavid du Colombier 	p = nil;
149*9a747e4fSDavid du Colombier 	if(n > 0) {
150*9a747e4fSDavid du Colombier 		p = _Strnclass(s, notwhitespace, n);
151*9a747e4fSDavid du Colombier 		if(p != nil) {
152*9a747e4fSDavid du Colombier 			q = _Strnrclass(s, notwhitespace, n);
153*9a747e4fSDavid du Colombier 			assert(q != nil);
154*9a747e4fSDavid du Colombier 			n = q+1-p;
155*9a747e4fSDavid du Colombier 		}
156*9a747e4fSDavid du Colombier 	}
157*9a747e4fSDavid du Colombier 	*pans = p;
158*9a747e4fSDavid du Colombier 	*panslen = n;
159*9a747e4fSDavid du Colombier }
160*9a747e4fSDavid du Colombier 
161*9a747e4fSDavid du Colombier // _Strclass returns a pointer to the first element of s that is
162*9a747e4fSDavid du Colombier // a member of class cl, nil if none.
163*9a747e4fSDavid du Colombier Rune*
164*9a747e4fSDavid du Colombier _Strclass(Rune* s, Rune* cl)
165*9a747e4fSDavid du Colombier {
166*9a747e4fSDavid du Colombier 	Rune* p;
167*9a747e4fSDavid du Colombier 
168*9a747e4fSDavid du Colombier 	for(p = s; *p != 0; p++)
169*9a747e4fSDavid du Colombier 		if(_inclass(*p, cl))
170*9a747e4fSDavid du Colombier 			return p;
171*9a747e4fSDavid du Colombier 	return nil;
172*9a747e4fSDavid du Colombier }
173*9a747e4fSDavid du Colombier 
174*9a747e4fSDavid du Colombier // _Strnclass returns a pointer to the first element of s[0:n] that is
175*9a747e4fSDavid du Colombier // a member of class cl, nil if none.
176*9a747e4fSDavid du Colombier Rune*
177*9a747e4fSDavid du Colombier _Strnclass(Rune* s, Rune* cl, int n)
178*9a747e4fSDavid du Colombier {
179*9a747e4fSDavid du Colombier 	Rune* p;
180*9a747e4fSDavid du Colombier 
181*9a747e4fSDavid du Colombier 	for(p = s; n-- && *p != 0; p++)
182*9a747e4fSDavid du Colombier 		if(_inclass(*p, cl))
183*9a747e4fSDavid du Colombier 			return p;
184*9a747e4fSDavid du Colombier 	return nil;
185*9a747e4fSDavid du Colombier }
186*9a747e4fSDavid du Colombier 
187*9a747e4fSDavid du Colombier // _Strrclass returns a pointer to the last element of s that is
188*9a747e4fSDavid du Colombier // a member of class cl, nil if none
189*9a747e4fSDavid du Colombier Rune*
190*9a747e4fSDavid du Colombier _Strrclass(Rune* s, Rune* cl)
191*9a747e4fSDavid du Colombier {
192*9a747e4fSDavid du Colombier 	Rune* p;
193*9a747e4fSDavid du Colombier 
194*9a747e4fSDavid du Colombier 	if(s == nil || *s == 0)
195*9a747e4fSDavid du Colombier 		return nil;
196*9a747e4fSDavid du Colombier 	p = s + runestrlen(s) - 1;
197*9a747e4fSDavid du Colombier 	while(p >= s) {
198*9a747e4fSDavid du Colombier 		if(_inclass(*p, cl))
199*9a747e4fSDavid du Colombier 			return p;
200*9a747e4fSDavid du Colombier 		p--;
201*9a747e4fSDavid du Colombier 	};
202*9a747e4fSDavid du Colombier 	return nil;
203*9a747e4fSDavid du Colombier }
204*9a747e4fSDavid du Colombier 
205*9a747e4fSDavid du Colombier // _Strnrclass returns a pointer to the last element of s[0:n] that is
206*9a747e4fSDavid du Colombier // a member of class cl, nil if none
207*9a747e4fSDavid du Colombier Rune*
208*9a747e4fSDavid du Colombier _Strnrclass(Rune* s, Rune* cl, int n)
209*9a747e4fSDavid du Colombier {
210*9a747e4fSDavid du Colombier 	Rune* p;
211*9a747e4fSDavid du Colombier 
212*9a747e4fSDavid du Colombier 	if(s == nil || *s == 0 || n == 0)
213*9a747e4fSDavid du Colombier 		return nil;
214*9a747e4fSDavid du Colombier 	p = s + n - 1;
215*9a747e4fSDavid du Colombier 	while(p >= s) {
216*9a747e4fSDavid du Colombier 		if(_inclass(*p, cl))
217*9a747e4fSDavid du Colombier 			return p;
218*9a747e4fSDavid du Colombier 		p--;
219*9a747e4fSDavid du Colombier 	};
220*9a747e4fSDavid du Colombier 	return nil;
221*9a747e4fSDavid du Colombier }
222*9a747e4fSDavid du Colombier 
223*9a747e4fSDavid du Colombier // Is c in the class cl?
224*9a747e4fSDavid du Colombier int
225*9a747e4fSDavid du Colombier _inclass(Rune c, Rune* cl)
226*9a747e4fSDavid du Colombier {
227*9a747e4fSDavid du Colombier 	int	n;
228*9a747e4fSDavid du Colombier 	int	ans;
229*9a747e4fSDavid du Colombier 	int	negate;
230*9a747e4fSDavid du Colombier 	int	i;
231*9a747e4fSDavid du Colombier 
232*9a747e4fSDavid du Colombier 	n = runestrlen(cl);
233*9a747e4fSDavid du Colombier 	if(n == 0)
234*9a747e4fSDavid du Colombier 		return 0;
235*9a747e4fSDavid du Colombier 	ans = 0;
236*9a747e4fSDavid du Colombier 	negate = 0;
237*9a747e4fSDavid du Colombier 	if(cl[0] == '^') {
238*9a747e4fSDavid du Colombier 		negate = 1;
239*9a747e4fSDavid du Colombier 		cl++;
240*9a747e4fSDavid du Colombier 		n--;
241*9a747e4fSDavid du Colombier 	}
242*9a747e4fSDavid du Colombier 	for(i = 0; i < n; i++) {
243*9a747e4fSDavid du Colombier 		if(cl[i] == '-' && i > 0 && i < n - 1) {
244*9a747e4fSDavid du Colombier 			if(c >= cl[i - 1] && c <= cl[i + 1]) {
245*9a747e4fSDavid du Colombier 				ans = 1;
246*9a747e4fSDavid du Colombier 				break;
247*9a747e4fSDavid du Colombier 			}
248*9a747e4fSDavid du Colombier 			i++;
249*9a747e4fSDavid du Colombier 		}
250*9a747e4fSDavid du Colombier 		else if(c == cl[i]) {
251*9a747e4fSDavid du Colombier 			ans = 1;
252*9a747e4fSDavid du Colombier 			break;
253*9a747e4fSDavid du Colombier 		}
254*9a747e4fSDavid du Colombier 	}
255*9a747e4fSDavid du Colombier 	if(negate)
256*9a747e4fSDavid du Colombier 		ans = !ans;
257*9a747e4fSDavid du Colombier 	return ans;
258*9a747e4fSDavid du Colombier }
259*9a747e4fSDavid du Colombier 
260*9a747e4fSDavid du Colombier // Is pre a prefix of s?
261*9a747e4fSDavid du Colombier int
262*9a747e4fSDavid du Colombier _prefix(Rune* pre, Rune* s)
263*9a747e4fSDavid du Colombier {
264*9a747e4fSDavid du Colombier 	int	ns;
265*9a747e4fSDavid du Colombier 	int	n;
266*9a747e4fSDavid du Colombier 	int	k;
267*9a747e4fSDavid du Colombier 
268*9a747e4fSDavid du Colombier 	ns = runestrlen(s);
269*9a747e4fSDavid du Colombier 	n = runestrlen(pre);
270*9a747e4fSDavid du Colombier 	if(ns < n)
271*9a747e4fSDavid du Colombier 		return 0;
272*9a747e4fSDavid du Colombier 	for(k = 0; k < n; k++) {
273*9a747e4fSDavid du Colombier 		if(pre[k] != s[k])
274*9a747e4fSDavid du Colombier 			return 0;
275*9a747e4fSDavid du Colombier 	}
276*9a747e4fSDavid du Colombier 	return 1;
277*9a747e4fSDavid du Colombier }
278*9a747e4fSDavid du Colombier 
279*9a747e4fSDavid du Colombier // Like Strcmp, but use exactly n chars of s1 (assume s1 has at least n chars).
280*9a747e4fSDavid du Colombier // Also, do a case-insensitive match, assuming s2
281*9a747e4fSDavid du Colombier // has no chars in [A-Z], only their lowercase versions.
282*9a747e4fSDavid du Colombier // (This routine is used for in-place keyword lookup, where s2 is in a keyword
283*9a747e4fSDavid du Colombier // list and s1 is some substring, possibly mixed-case, in a buffer.)
284*9a747e4fSDavid du Colombier int
285*9a747e4fSDavid du Colombier _Strncmpci(Rune *s1, int n1, Rune *s2)
286*9a747e4fSDavid du Colombier {
287*9a747e4fSDavid du Colombier 	Rune c1, c2;
288*9a747e4fSDavid du Colombier 
289*9a747e4fSDavid du Colombier 	for(;;) {
290*9a747e4fSDavid du Colombier 		if(n1-- == 0) {
291*9a747e4fSDavid du Colombier 			if(*s2 == 0)
292*9a747e4fSDavid du Colombier 				return 0;
293*9a747e4fSDavid du Colombier 			return -1;
294*9a747e4fSDavid du Colombier 		}
295*9a747e4fSDavid du Colombier 		c1 = *s1++;
296*9a747e4fSDavid du Colombier 		c2 = *s2++;
297*9a747e4fSDavid du Colombier 		if(c1 >= 'A' && c1 <= 'Z')
298*9a747e4fSDavid du Colombier 			c1 = c1 - 'A' + 'a';
299*9a747e4fSDavid du Colombier 		if(c1 != c2) {
300*9a747e4fSDavid du Colombier 			if(c1 > c2)
301*9a747e4fSDavid du Colombier 				return 1;
302*9a747e4fSDavid du Colombier 			return -1;
303*9a747e4fSDavid du Colombier 		}
304*9a747e4fSDavid du Colombier 	}
305*9a747e4fSDavid du Colombier }
306*9a747e4fSDavid du Colombier 
307*9a747e4fSDavid du Colombier // emalloc and copy
308*9a747e4fSDavid du Colombier Rune*
309*9a747e4fSDavid du Colombier _Strdup(Rune* s)
310*9a747e4fSDavid du Colombier {
311*9a747e4fSDavid du Colombier 	if(s == nil)
312*9a747e4fSDavid du Colombier 		return nil;
313*9a747e4fSDavid du Colombier 	return _Strndup(s, runestrlen(s));
314*9a747e4fSDavid du Colombier }
315*9a747e4fSDavid du Colombier 
316*9a747e4fSDavid du Colombier // emalloc and copy n chars of s (assume s is at least that long),
317*9a747e4fSDavid du Colombier // and add 0 terminator.
318*9a747e4fSDavid du Colombier // Return nil if n==0.
319*9a747e4fSDavid du Colombier Rune*
320*9a747e4fSDavid du Colombier _Strndup(Rune* s, int n)
321*9a747e4fSDavid du Colombier {
322*9a747e4fSDavid du Colombier 	Rune* ans;
323*9a747e4fSDavid du Colombier 
324*9a747e4fSDavid du Colombier 	if(n <= 0)
325*9a747e4fSDavid du Colombier 		return nil;
326*9a747e4fSDavid du Colombier 	ans = _newstr(n);
327*9a747e4fSDavid du Colombier 	memmove(ans, s, n*sizeof(Rune));
328*9a747e4fSDavid du Colombier 	ans[n] = 0;
329*9a747e4fSDavid du Colombier 	return ans;
330*9a747e4fSDavid du Colombier }
331*9a747e4fSDavid du Colombier // emalloc enough room for n Runes, plus 1 null terminator.
332*9a747e4fSDavid du Colombier // (Not initialized to anything.)
333*9a747e4fSDavid du Colombier Rune*
334*9a747e4fSDavid du Colombier _newstr(int n)
335*9a747e4fSDavid du Colombier {
336*9a747e4fSDavid du Colombier 	return (Rune*)emalloc((n+1)*sizeof(Rune));
337*9a747e4fSDavid du Colombier }
338*9a747e4fSDavid du Colombier 
339*9a747e4fSDavid du Colombier // emalloc and copy s+t
340*9a747e4fSDavid du Colombier Rune*
341*9a747e4fSDavid du Colombier _Strdup2(Rune* s, Rune* t)
342*9a747e4fSDavid du Colombier {
343*9a747e4fSDavid du Colombier 	int ns, nt;
344*9a747e4fSDavid du Colombier 	Rune* ans;
345*9a747e4fSDavid du Colombier 	Rune* p;
346*9a747e4fSDavid du Colombier 
347*9a747e4fSDavid du Colombier 	ns = runestrlen(s);
348*9a747e4fSDavid du Colombier 	nt = runestrlen(t);
349*9a747e4fSDavid du Colombier 	if(ns+nt == 0)
350*9a747e4fSDavid du Colombier 		return nil;
351*9a747e4fSDavid du Colombier 	ans = _newstr(ns+nt);
352*9a747e4fSDavid du Colombier 	p = _Stradd(ans, s, ns);
353*9a747e4fSDavid du Colombier 	p = _Stradd(p, t, nt);
354*9a747e4fSDavid du Colombier 	*p = 0;
355*9a747e4fSDavid du Colombier 	return ans;
356*9a747e4fSDavid du Colombier }
357*9a747e4fSDavid du Colombier 
358*9a747e4fSDavid du Colombier // Return emalloc'd substring s[start:stop],
359*9a747e4fSDavid du Colombier Rune*
360*9a747e4fSDavid du Colombier _Strsubstr(Rune* s, int start, int stop)
361*9a747e4fSDavid du Colombier {
362*9a747e4fSDavid du Colombier 	Rune* t;
363*9a747e4fSDavid du Colombier 
364*9a747e4fSDavid du Colombier 	if(start == stop)
365*9a747e4fSDavid du Colombier 		return nil;
366*9a747e4fSDavid du Colombier 	t = _Strndup(s+start, stop-start);
367*9a747e4fSDavid du Colombier 	return t;
368*9a747e4fSDavid du Colombier }
369*9a747e4fSDavid du Colombier 
370*9a747e4fSDavid du Colombier // Copy n chars to s1 from s2, and return s1+n
371*9a747e4fSDavid du Colombier Rune*
372*9a747e4fSDavid du Colombier _Stradd(Rune* s1, Rune* s2, int n)
373*9a747e4fSDavid du Colombier {
374*9a747e4fSDavid du Colombier 	if(n == 0)
375*9a747e4fSDavid du Colombier 		return s1;
376*9a747e4fSDavid du Colombier 	memmove(s1, s2, n*sizeof(Rune));
377*9a747e4fSDavid du Colombier 	return s1+n;
378*9a747e4fSDavid du Colombier }
379*9a747e4fSDavid du Colombier 
380*9a747e4fSDavid du Colombier // Like strtol, but converting from Rune* string
381*9a747e4fSDavid du Colombier 
382*9a747e4fSDavid du Colombier #define LONG_MAX	2147483647L
383*9a747e4fSDavid du Colombier #define LONG_MIN	-2147483648L
384*9a747e4fSDavid du Colombier 
385*9a747e4fSDavid du Colombier long
386*9a747e4fSDavid du Colombier _Strtol(Rune* nptr, Rune** endptr, int base)
387*9a747e4fSDavid du Colombier {
388*9a747e4fSDavid du Colombier 	Rune* p;
389*9a747e4fSDavid du Colombier 	long n, nn;
390*9a747e4fSDavid du Colombier 	int c, ovfl, v, neg, ndig;
391*9a747e4fSDavid du Colombier 
392*9a747e4fSDavid du Colombier 	p = nptr;
393*9a747e4fSDavid du Colombier 	neg = 0;
394*9a747e4fSDavid du Colombier 	n = 0;
395*9a747e4fSDavid du Colombier 	ndig = 0;
396*9a747e4fSDavid du Colombier 	ovfl = 0;
397*9a747e4fSDavid du Colombier 
398*9a747e4fSDavid du Colombier 	/*
399*9a747e4fSDavid du Colombier 	 * White space
400*9a747e4fSDavid du Colombier 	 */
401*9a747e4fSDavid du Colombier 	for(;;p++){
402*9a747e4fSDavid du Colombier 		switch(*p){
403*9a747e4fSDavid du Colombier 		case ' ':
404*9a747e4fSDavid du Colombier 		case '\t':
405*9a747e4fSDavid du Colombier 		case '\n':
406*9a747e4fSDavid du Colombier 		case '\f':
407*9a747e4fSDavid du Colombier 		case '\r':
408*9a747e4fSDavid du Colombier 		case '\v':
409*9a747e4fSDavid du Colombier 			continue;
410*9a747e4fSDavid du Colombier 		}
411*9a747e4fSDavid du Colombier 		break;
412*9a747e4fSDavid du Colombier 	}
413*9a747e4fSDavid du Colombier 
414*9a747e4fSDavid du Colombier 	/*
415*9a747e4fSDavid du Colombier 	 * Sign
416*9a747e4fSDavid du Colombier 	 */
417*9a747e4fSDavid du Colombier 	if(*p=='-' || *p=='+')
418*9a747e4fSDavid du Colombier 		if(*p++ == '-')
419*9a747e4fSDavid du Colombier 			neg = 1;
420*9a747e4fSDavid du Colombier 
421*9a747e4fSDavid du Colombier 	/*
422*9a747e4fSDavid du Colombier 	 * Base
423*9a747e4fSDavid du Colombier 	 */
424*9a747e4fSDavid du Colombier 	if(base==0){
425*9a747e4fSDavid du Colombier 		if(*p != '0')
426*9a747e4fSDavid du Colombier 			base = 10;
427*9a747e4fSDavid du Colombier 		else{
428*9a747e4fSDavid du Colombier 			base = 8;
429*9a747e4fSDavid du Colombier 			if(p[1]=='x' || p[1]=='X'){
430*9a747e4fSDavid du Colombier 				p += 2;
431*9a747e4fSDavid du Colombier 				base = 16;
432*9a747e4fSDavid du Colombier 			}
433*9a747e4fSDavid du Colombier 		}
434*9a747e4fSDavid du Colombier 	}else if(base==16 && *p=='0'){
435*9a747e4fSDavid du Colombier 		if(p[1]=='x' || p[1]=='X')
436*9a747e4fSDavid du Colombier 			p += 2;
437*9a747e4fSDavid du Colombier 	}else if(base<0 || 36<base)
438*9a747e4fSDavid du Colombier 		goto Return;
439*9a747e4fSDavid du Colombier 
440*9a747e4fSDavid du Colombier 	/*
441*9a747e4fSDavid du Colombier 	 * Non-empty sequence of digits
442*9a747e4fSDavid du Colombier 	 */
443*9a747e4fSDavid du Colombier 	for(;; p++,ndig++){
444*9a747e4fSDavid du Colombier 		c = *p;
445*9a747e4fSDavid du Colombier 		v = base;
446*9a747e4fSDavid du Colombier 		if('0'<=c && c<='9')
447*9a747e4fSDavid du Colombier 			v = c - '0';
448*9a747e4fSDavid du Colombier 		else if('a'<=c && c<='z')
449*9a747e4fSDavid du Colombier 			v = c - 'a' + 10;
450*9a747e4fSDavid du Colombier 		else if('A'<=c && c<='Z')
451*9a747e4fSDavid du Colombier 			v = c - 'A' + 10;
452*9a747e4fSDavid du Colombier 		if(v >= base)
453*9a747e4fSDavid du Colombier 			break;
454*9a747e4fSDavid du Colombier 		nn = n*base + v;
455*9a747e4fSDavid du Colombier 		if(nn < n)
456*9a747e4fSDavid du Colombier 			ovfl = 1;
457*9a747e4fSDavid du Colombier 		n = nn;
458*9a747e4fSDavid du Colombier 	}
459*9a747e4fSDavid du Colombier 
460*9a747e4fSDavid du Colombier     Return:
461*9a747e4fSDavid du Colombier 	if(ndig == 0)
462*9a747e4fSDavid du Colombier 		p = nptr;
463*9a747e4fSDavid du Colombier 	if(endptr)
464*9a747e4fSDavid du Colombier 		*endptr = p;
465*9a747e4fSDavid du Colombier 	if(ovfl){
466*9a747e4fSDavid du Colombier 		if(neg)
467*9a747e4fSDavid du Colombier 			return LONG_MIN;
468*9a747e4fSDavid du Colombier 		return LONG_MAX;
469*9a747e4fSDavid du Colombier 	}
470*9a747e4fSDavid du Colombier 	if(neg)
471*9a747e4fSDavid du Colombier 		return -n;
472*9a747e4fSDavid du Colombier 	return n;
473*9a747e4fSDavid du Colombier }
474*9a747e4fSDavid du Colombier 
475*9a747e4fSDavid du Colombier // Convert buf[0:n], bytes whose character set is chset,
476*9a747e4fSDavid du Colombier // into a emalloc'd null-terminated Unicode string.
477*9a747e4fSDavid du Colombier Rune*
478*9a747e4fSDavid du Colombier toStr(uchar* buf, int n, int chset)
479*9a747e4fSDavid du Colombier {
480*9a747e4fSDavid du Colombier 	int i;
481*9a747e4fSDavid du Colombier 	int m;
482*9a747e4fSDavid du Colombier 	Rune ch;
483*9a747e4fSDavid du Colombier 	Rune* ans;
484*9a747e4fSDavid du Colombier 
485*9a747e4fSDavid du Colombier 	switch(chset) {
486*9a747e4fSDavid du Colombier 	case US_Ascii:
487*9a747e4fSDavid du Colombier 	case ISO_8859_1:
488*9a747e4fSDavid du Colombier 		ans = (Rune*)emalloc((n+1)*sizeof(Rune));
489*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++)
490*9a747e4fSDavid du Colombier 			ans[i] = buf[i];
491*9a747e4fSDavid du Colombier 		ans[n] = 0;
492*9a747e4fSDavid du Colombier 		break;
493*9a747e4fSDavid du Colombier 
494*9a747e4fSDavid du Colombier 	case UTF_8:
495*9a747e4fSDavid du Colombier 		m = 0;
496*9a747e4fSDavid du Colombier 		for(i = 0; i < n; ) {
497*9a747e4fSDavid du Colombier 			i += chartorune(&ch, (char*)(buf+i));
498*9a747e4fSDavid du Colombier 			m++;
499*9a747e4fSDavid du Colombier 		}
500*9a747e4fSDavid du Colombier 		ans = (Rune*)emalloc((m+1)*sizeof(Rune));
501*9a747e4fSDavid du Colombier 		m = 0;
502*9a747e4fSDavid du Colombier 		for(i = 0; i < n; ) {
503*9a747e4fSDavid du Colombier 			i += chartorune(&ch, (char*)(buf+i));
504*9a747e4fSDavid du Colombier 			ans[m++] = ch;
505*9a747e4fSDavid du Colombier 		}
506*9a747e4fSDavid du Colombier 		ans[m] = 0;
507*9a747e4fSDavid du Colombier 		break;
508*9a747e4fSDavid du Colombier 
509*9a747e4fSDavid du Colombier 	default:
510*9a747e4fSDavid du Colombier 		ans = nil;
511*9a747e4fSDavid du Colombier 		assert(0);
512*9a747e4fSDavid du Colombier 	}
513*9a747e4fSDavid du Colombier 	return ans;
514*9a747e4fSDavid du Colombier }
515*9a747e4fSDavid du Colombier 
516*9a747e4fSDavid du Colombier // Convert buf[0:n], Unicode characters,
517*9a747e4fSDavid du Colombier // into an emalloc'd null-terminated string in character set chset.
518*9a747e4fSDavid du Colombier // Use 0x80 for unconvertable characters.
519*9a747e4fSDavid du Colombier uchar*
520*9a747e4fSDavid du Colombier fromStr(Rune* buf, int n, int chset)
521*9a747e4fSDavid du Colombier {
522*9a747e4fSDavid du Colombier 	uchar* ans;
523*9a747e4fSDavid du Colombier 	int i, lim, m;
524*9a747e4fSDavid du Colombier 	Rune ch;
525*9a747e4fSDavid du Colombier 	uchar* p;
526*9a747e4fSDavid du Colombier 	uchar s[UTFmax];
527*9a747e4fSDavid du Colombier 
528*9a747e4fSDavid du Colombier 	ans = nil;
529*9a747e4fSDavid du Colombier 	switch(chset) {
530*9a747e4fSDavid du Colombier 	case US_Ascii:
531*9a747e4fSDavid du Colombier 	case ISO_8859_1:
532*9a747e4fSDavid du Colombier 		ans = (uchar*)emalloc(n+1);
533*9a747e4fSDavid du Colombier 		lim = (chset==US_Ascii)? 127 : 255;
534*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++) {
535*9a747e4fSDavid du Colombier 			ch = buf[i];
536*9a747e4fSDavid du Colombier 			if(ch > lim)
537*9a747e4fSDavid du Colombier 				ch = 0x80;
538*9a747e4fSDavid du Colombier 			ans[i] = ch;
539*9a747e4fSDavid du Colombier 		}
540*9a747e4fSDavid du Colombier 		ans[n] = 0;
541*9a747e4fSDavid du Colombier 		break;
542*9a747e4fSDavid du Colombier 
543*9a747e4fSDavid du Colombier 	case UTF_8:
544*9a747e4fSDavid du Colombier 		m = 0;
545*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++) {
546*9a747e4fSDavid du Colombier 			m += runetochar((char*)s, &buf[i]);
547*9a747e4fSDavid du Colombier 		}
548*9a747e4fSDavid du Colombier 		ans = (uchar*)emalloc(m+1);
549*9a747e4fSDavid du Colombier 		p = ans;
550*9a747e4fSDavid du Colombier 		for(i = 0; i < n; i++)
551*9a747e4fSDavid du Colombier 			p += runetochar((char*)p, &buf[i]);
552*9a747e4fSDavid du Colombier 		*p = 0;
553*9a747e4fSDavid du Colombier 		break;
554*9a747e4fSDavid du Colombier 
555*9a747e4fSDavid du Colombier 	default:
556*9a747e4fSDavid du Colombier 		assert(0);
557*9a747e4fSDavid du Colombier 	}
558*9a747e4fSDavid du Colombier 	return ans;
559*9a747e4fSDavid du Colombier 
560*9a747e4fSDavid du Colombier }
561*9a747e4fSDavid du Colombier 
562*9a747e4fSDavid du Colombier // Convert n to emalloc'd String.
563*9a747e4fSDavid du Colombier Rune*
564*9a747e4fSDavid du Colombier _ltoStr(int n)
565*9a747e4fSDavid du Colombier {
566*9a747e4fSDavid du Colombier 	int m;
567*9a747e4fSDavid du Colombier 	uchar buf[20];
568*9a747e4fSDavid du Colombier 
569*9a747e4fSDavid du Colombier 	m = snprint((char*)buf, sizeof(buf), "%d", n);
570*9a747e4fSDavid du Colombier 	return toStr(buf, m, US_Ascii);
571*9a747e4fSDavid du Colombier }
572