1 /* string.c
2  * (c) 2002 Mikulas Patocka
3  * This file is a part of the Links program, released under GPL.
4  */
5 
6 #include "links.h"
7 
snprint(unsigned char * s,int n,my_uintptr_t num)8 int snprint(unsigned char *s, int n, my_uintptr_t num)
9 {
10 	my_uintptr_t q = 1;
11 	while (q <= num / 10) q *= 10;
12 	while (n-- > 1 && q) {
13 		*(s++) = (unsigned char)(num / q + '0');
14 		num %= q;
15 #ifdef __DECC_VER
16 		do_not_optimize_here(&q);	/* compiler bug */
17 #endif
18 		q /= 10;
19 	}
20 	*s = 0;
21 	return !!q;
22 }
23 
snzprint(unsigned char * s,int n,off_t num)24 int snzprint(unsigned char *s, int n, off_t num)
25 {
26 	off_t q = 1;
27 	if (n > 1 && num < 0) *(s++) = '-', num = -num, n--;
28 	while (q <= num / 10) q *= 10;
29 	while (n-- > 1 && q) {
30 		*(s++) = (unsigned char)(num / q + '0');
31 		num %= q;
32 #ifdef __DECC_VER
33 		do_not_optimize_here(&q);	/* compiler bug */
34 #endif
35 		q /= 10;
36 	}
37 	*s = 0;
38 	return !!q;
39 }
40 
add_to_strn(unsigned char ** s,unsigned char * a)41 void add_to_strn(unsigned char **s, unsigned char *a)
42 {
43 	unsigned char *p;
44 	size_t l1 = strlen(cast_const_char *s), l2 = strlen(cast_const_char a);
45 	if (((l1 | l2) | (l1 + l2 + 1)) > MAXINT) overalloc();
46 	p = (unsigned char *)mem_realloc(*s, l1 + l2 + 1);
47 	strcat(cast_char p, cast_const_char a);
48 	*s = p;
49 }
50 
extend_str(unsigned char ** s,int n)51 void extend_str(unsigned char **s, int n)
52 {
53 	size_t l = strlen(cast_const_char *s);
54 	if (((l | n) | (l + n + 1)) > MAXINT) overalloc();
55 	*s = (unsigned char *)mem_realloc(*s, l + n + 1);
56 }
57 
add_bytes_to_str(unsigned char ** s,int * l,unsigned char * a,size_t ll)58 void add_bytes_to_str(unsigned char **s, int *l, unsigned char *a, size_t ll)
59 {
60 	unsigned char *p;
61 	size_t old_length;
62 	size_t new_length;
63 	size_t x;
64 
65 	if (!ll)
66 		return;
67 
68 	p = *s;
69 	old_length = (unsigned)*l;
70 	if (ll + old_length >= (unsigned)MAXINT / 2 || ll + old_length < ll) overalloc();
71 	new_length = old_length + ll;
72 	*l = (int)new_length;
73 	x = old_length ^ new_length;
74 	if (x >= old_length) {
75 		/* Need to realloc */
76 #ifdef HAVE___BUILTIN_CLZ
77 #if !(									\
78 	defined(__tune_i386__) ||					\
79 	defined(__tune_i486__) ||					\
80 	defined(__tune_i586__) ||					\
81 	defined(__tune_k6__) ||						\
82 	defined(__tune_lakemont__) ||					\
83 	(defined(__alpha__) && !defined(__alpha_cix__)) ||		\
84 	(defined(__mips) && __mips < 32) ||				\
85 	(defined(__ARM_ARCH) && __ARM_ARCH < 5) ||			\
86 	(defined(__sparc__) && (!defined(__VIS__) || __VIS__ < 0x300)) ||\
87 	defined(__hppa) ||						\
88 	defined(__riscv) ||						\
89 	defined(__sh__))
90 		if (!(sizeof(unsigned) & (sizeof(unsigned) - 1))) {
91 			new_length = 2U << ((sizeof(unsigned) * 8 - 1)
92 #ifdef __ICC
93 				-
94 #else
95 				^
96 #endif
97 				__builtin_clz(new_length));
98 		} else
99 #endif
100 #endif
101 		{
102 			new_length |= new_length >> 1;
103 			new_length |= new_length >> 2;
104 			new_length |= new_length >> 4;
105 			new_length |= new_length >> 8;
106 			new_length |= new_length >> 16;
107 			new_length++;
108 		}
109 		p = (unsigned char *)mem_realloc(p, new_length);
110 		*s = p;
111 	}
112 	p[*l] = 0;
113 	memcpy(p + old_length, a, ll);
114 }
115 
add_to_str(unsigned char ** s,int * l,unsigned char * a)116 void add_to_str(unsigned char **s, int *l, unsigned char *a)
117 {
118 	add_bytes_to_str(s, l, a, strlen(cast_const_char a));
119 }
120 
add_chr_to_str(unsigned char ** s,int * l,unsigned char a)121 void add_chr_to_str(unsigned char **s, int *l, unsigned char a)
122 {
123 	add_bytes_to_str(s, l, &a, 1);
124 }
125 
add_unsigned_long_num_to_str(unsigned char ** s,int * l,my_uintptr_t n)126 void add_unsigned_long_num_to_str(unsigned char **s, int *l, my_uintptr_t n)
127 {
128 	unsigned char a[64];
129 	snprint(a, 64, n);
130 	add_to_str(s, l, a);
131 }
132 
add_num_to_str(unsigned char ** s,int * l,off_t n)133 void add_num_to_str(unsigned char **s, int *l, off_t n)
134 {
135 	unsigned char a[64];
136 	if (n >= 0 && n < 1000) {
137 		unsigned sn = (unsigned)n;
138 		unsigned char *p = a;
139 		if (sn >= 100) {
140 			*p++ = '0' + sn / 100;
141 			sn %= 100;
142 			goto d10;
143 		}
144 		if (sn >= 10) {
145 			d10:
146 			*p++ = '0' + sn / 10;
147 			sn %= 10;
148 		}
149 		*p++ = '0' + sn;
150 		add_bytes_to_str(s, l, a, p - a);
151 	} else {
152 		snzprint(a, 64, n);
153 		add_to_str(s, l, a);
154 	}
155 }
156 
add_knum_to_str(unsigned char ** s,int * l,off_t n)157 void add_knum_to_str(unsigned char **s, int *l, off_t n)
158 {
159 	unsigned char a[13];
160 	if (n && n / (1024 * 1024) * (1024 * 1024) == n) snzprint(a, 12, n / (1024 * 1024)), a[strlen(cast_const_char a) + 1] = 0, a[strlen(cast_const_char a)] = 'M';
161 	else if (n && n / 1024 * 1024 == n) snzprint(a, 12, n / 1024), a[strlen(cast_const_char a) + 1] = 0, a[strlen(cast_const_char a)] = 'k';
162 	else snzprint(a, 13, n);
163 	add_to_str(s, l, a);
164 }
165 
strtolx(unsigned char * c,unsigned char ** end)166 long strtolx(unsigned char *c, unsigned char **end)
167 {
168 	char *end_c;
169 	long l;
170 	if (c[0] == '0' && upcase(c[1]) == 'X' && c[2]) l = strtol(cast_const_char(c + 2), &end_c, 16);
171 	else l = strtol(cast_const_char c, &end_c, 10);
172 	*end = cast_uchar end_c;
173 	if (upcase(**end) == 'K') {
174 		(*end)++;
175 		if (l < -MAXINT / 1024) return -MAXINT;
176 		if (l > MAXINT / 1024) return MAXINT;
177 		return l * 1024;
178 	}
179 	if (upcase(**end) == 'M') {
180 		(*end)++;
181 		if (l < -MAXINT / (1024 * 1024)) return -MAXINT;
182 		if (l > MAXINT / (1024 * 1024)) return MAXINT;
183 		return l * (1024 * 1024);
184 	}
185 	return l;
186 }
187 
my_strtoll(unsigned char * string,unsigned char ** end)188 my_strtoll_t my_strtoll(unsigned char *string, unsigned char **end)
189 {
190 	char *end_c;
191 	my_strtoll_t f;
192 	errno = 0;
193 #if defined(HAVE_STRTOLL)
194 	f = strtoll(cast_const_char string, &end_c, 10);
195 #elif defined(HAVE_STRTOQ)
196 	f = strtoq(cast_const_char string, &end_c, 10);
197 #elif defined(HAVE_STRTOIMAX)
198 	f = strtoimax(cast_const_char string, &end_c, 10);
199 #else
200 	f = strtol(cast_const_char string, &end_c, 10);
201 #endif
202 	if (end)
203 		*end = cast_uchar end_c;
204 	if (f < 0 || errno) return -1;
205 	return f;
206 }
207 
208 /* Copies at most dst_size chars into dst. Ensures null termination of dst. */
safe_strncpy(unsigned char * dst,const unsigned char * src,size_t dst_size)209 void safe_strncpy(unsigned char *dst, const unsigned char *src, size_t dst_size)
210 {
211 	dst[dst_size - 1] = 0;
212 	strncpy(cast_char dst, cast_const_char src, dst_size - 1);
213 }
214 
215 #ifdef JS
216 /* deletes all nonprintable characters from string */
skip_nonprintable(unsigned char * txt)217 void skip_nonprintable(unsigned char *txt)
218 {
219 	unsigned char *txt1=txt;
220 
221 	if (!txt||!*txt)return;
222 	for (;*txt;txt++)
223 		switch(*txt)
224 		{
225 			case 1:
226 			case 2:
227 			case 3:
228 			case 4:
229 			case 5:
230 			case 6:
231 			case 7:
232 			case 8:
233 			case 11:
234 			case 12:
235 			case 13:
236 			case 14:
237 			case 15:
238 			case 16:
239 			case 17:
240 			case 18:
241 			case 19:
242 			case 20:
243 			case 21:
244 			case 22:
245 			case 23:
246 			case 24:
247 			case 25:
248 			case 26:
249 			case 27:
250 			case 28:
251 			case 29:
252 			case 30:
253 			case 31:
254 			break;
255 
256 			case 9:
257 			*txt1=' ';
258 			txt1++;
259 			break;
260 
261 			default:
262 			*txt1=*txt;
263 			txt1++;
264 			break;
265 		}
266 	*txt1=0;
267 }
268 #endif
269 
270 /* don't use strcasecmp because it depends on locale */
casestrcmp(const unsigned char * s1,const unsigned char * s2)271 int casestrcmp(const unsigned char *s1, const unsigned char *s2)
272 {
273 	while (1) {
274 		unsigned char c1 = *s1;
275 		unsigned char c2 = *s2;
276 		c1 = locase(c1);
277 		c2 = locase(c2);
278 		if (c1 != c2) {
279 			return (int)c1 - (int)c2;
280 		}
281 		if (!*s1) break;
282 		s1++, s2++;
283 	}
284 	return 0;
285 }
286 
287 /* case insensitive compare of 2 strings */
288 /* comparison ends after len (or less) characters */
289 /* return value: 1=strings differ, 0=strings are same */
casecmp(const unsigned char * c1,const unsigned char * c2,size_t len)290 int casecmp(const unsigned char *c1, const unsigned char *c2, size_t len)
291 {
292 	size_t i;
293 	for (i = 0; i < len; i++) if (srch_cmp(c1[i], c2[i])) return 1;
294 	return 0;
295 }
296 
casestrstr(const unsigned char * h,const unsigned char * n)297 int casestrstr(const unsigned char *h, const unsigned char *n)
298 {
299 	const unsigned char *p;
300 
301 	for (p=h;*p;p++)
302 	{
303 		if (!srch_cmp(*p,*n))  /* same */
304 		{
305 			const unsigned char *q, *r;
306 			for (q=n, r=p;*r&&*q;)
307 			{
308 				if (!srch_cmp(*q,*r)) r++,q++;    /* same */
309 				else break;
310 			}
311 			if (!*q) return 1;
312 		}
313 	}
314 
315 	return 0;
316 }
317 
hash_string(unsigned char * u)318 unsigned hash_string(unsigned char *u)
319 {
320 	unsigned hash = 0;
321 	for (; *u; u++)
322 		hash = hash * 0x11 + *u;
323 	return hash;
324 }
325