iconv: Bail out of the loop when an illegal sequence of bytes occurs.
[elinks/elinks-j605.git] / src / osdep / stub.c
blob56489d6f6e523b0c6c091af0aa98456222be83f9
1 /* Libc stub functions */
3 #ifdef HAVE_CONFIG_H
4 #include "config.h"
5 #endif
7 #include <errno.h>
8 #include <ctype.h>
9 #include <stdarg.h>
10 #include <stdio.h>
11 #include <stdlib.h>
12 #include <string.h>
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 #include <sys/socket.h> /* SunOS needs this after sys/types.h */
16 #endif
17 #ifdef HAVE_UNISTD_H
18 #include <unistd.h>
19 #endif
20 #ifdef HAVE_NETINET_IN_H
21 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
22 #endif
23 #ifdef HAVE_ARPA_INET_H
24 #include <arpa/inet.h>
25 #endif
27 #include "elinks.h"
29 #include "osdep/stub.h"
30 #include "util/conv.h"
32 /* These stubs are exception to our "Use (unsigned char *)!" rule. This is
33 * because the stubbed functions are defined using (char *), and we could get
34 * in trouble with this. Or when you use (foo ? strstr() : strcasestr()) and
35 * one of these is system and another stub, we're in trouble and get "Pointer
36 * type mismatch in conditional expression", game over. */
39 #define toupper_equal(s1, s2) (toupper(*((char *) s1)) == toupper(*((char *) s2)))
40 #define toupper_delta(s1, s2) (toupper(*((char *) s1)) - toupper(*((char *) s2)))
42 #ifndef HAVE_STRCASECMP
43 NONSTATIC_INLINE int
44 elinks_strcasecmp(const char *s1, const char *s2)
46 while (*s1 != '\0' && toupper_equal(s1, s2)) {
47 s1++;
48 s2++;
51 return toupper_delta(s1, s2);
53 #endif /* !HAVE_STRCASECMP */
55 #ifndef HAVE_STRNCASECMP
56 NONSTATIC_INLINE int
57 elinks_strncasecmp(const char *s1, const char *s2, size_t len)
59 if (len == 0)
60 return 0;
62 while (len-- != 0 && toupper_equal(s1, s2)) {
63 if (len == 0 || *s1 == '\0' || *s2 == '\0')
64 return 0;
65 s1++;
66 s2++;
69 return toupper_delta(s1, s2);
71 #endif /* !HAVE_STRNCASECMP */
73 #ifndef HAVE_STRCASESTR
74 /* Stub for strcasestr(), GNU extension */
75 NONSTATIC_INLINE char *
76 elinks_strcasestr(const char *haystack, const char *needle)
78 size_t haystack_length = strlen(haystack);
79 size_t needle_length = strlen(needle);
80 int i;
82 if (haystack_length < needle_length)
83 return NULL;
85 for (i = haystack_length - needle_length + 1; i; i--) {
86 if (!strncasecmp(haystack, needle, needle_length))
87 return (char *) haystack;
88 haystack++;
91 return NULL;
93 #endif
95 #ifndef HAVE_STRDUP
96 NONSTATIC_INLINE char *
97 elinks_strdup(const char *str)
99 int str_len = strlen(str);
100 char *new = malloc(str_len + 1);
102 if (new) {
103 if (str_len) memcpy(new, str, str_len);
104 new[str_len] = '\0';
106 return new;
108 #endif
110 #ifndef HAVE_STRERROR
111 /* Many older systems don't have this, but have the global sys_errlist array
112 * instead. */
113 #if 0
114 extern int sys_nerr;
115 extern const char *const sys_errlist[];
116 #endif
117 NONSTATIC_INLINE const char *
118 elinks_strerror(int err_no)
120 if (err_no < 0 || err_no > sys_nerr)
121 return (const char *) "Unknown Error";
122 else
123 return (const char *) sys_errlist[err_no];
125 #endif
127 #ifndef HAVE_STRSTR
128 /* From http://www.unixpapa.com/incnote/string.html */
129 NONSTATIC_INLINE char *
130 elinks_strstr(const char *s, const char *p)
132 char *sp, *pp;
134 for (sp = (char *) s, pp = (char *) p; *sp && *pp; )
136 if (*sp == *pp) {
137 sp++;
138 pp++;
139 } else {
140 sp = sp - (pp - p) + 1;
141 pp = (char *) p;
144 return (*pp ? NULL : sp - (pp - p));
146 #endif
148 #if !defined(HAVE_MEMMOVE) && !defined(HAVE_BCOPY)
149 /* The memmove() function is a bit rarer than the other memory functions -
150 * some systems that have the others don't have this. It is identical to
151 * memcpy() but is guaranteed to work even if the strings overlap.
152 * Most systems that don't have memmove() do have
153 * the BSD bcopy() though some really old systems have neither.
154 * Note that bcopy() has the order of the source and destination
155 * arguments reversed.
156 * From http://www.unixpapa.com/incnote/string.html */
157 /* Modified for ELinks by Zas. */
158 NONSTATIC_INLINE void *
159 elinks_memmove(void *d, const void *s, size_t n)
161 register char *dst = (char *) d;
162 register char *src = (char *) s;
164 if (!n || src == dst) return (void *) dst;
166 if (src > dst)
167 for (; n > 0; n--)
168 *(dst++) = *(src++);
169 else
170 for (dst += n - 1, src += n - 1;
171 n > 0;
172 n--)
173 *(dst--) = *(src--);
175 return (void *) dst;
177 #endif
180 #ifndef HAVE_STPCPY
181 NONSTATIC_INLINE char *
182 elinks_stpcpy(char *dest, const char *src)
184 while ((*dest++ = *src++));
185 return (dest - 1);
187 #endif
189 #ifndef HAVE_MEMPCPY
190 NONSTATIC_INLINE void *
191 elinks_mempcpy(void *dest, const void *src, size_t n)
193 return (void *) ((char *) memcpy(dest, src, n) + n);
195 #endif
197 #ifndef HAVE_ISDIGIT
198 NONSTATIC_INLINE int
199 elinks_isdigit(int i)
201 return i >= '0' && i <= '9';
203 #endif
205 #ifndef HAVE_MEMRCHR
206 NONSTATIC_INLINE void *
207 elinks_memrchr(const void *s, int c, size_t n)
209 char *pos = (char *) s;
211 while (n > 0) {
212 if (pos[n - 1] == (char) c)
213 return (void *) &pos[n - 1];
214 n--;
217 return NULL;
219 #endif
221 #ifndef HAVE_RAISE
223 #if !defined(HAVE_KILL) || !defined(HAVE_GETPID)
224 #error The raise() stub function requires kill() and getpid()
225 #endif
228 elinks_raise(int signal)
230 return(kill(getpid(), signal));
232 #endif
234 #ifndef HAVE_INET_NTOP
235 /* Original code by Paul Vixie. Modified by Gisle Vanem. */
237 #define IN6ADDRSZ 16
238 #define INADDRSZ 4
239 #define INT16SZ 2
241 /* TODO: Move and populate. --jonas */
242 #ifdef CONFIG_OS_WIN32
243 #define SET_ERRNO(e) WSASetLastError(errno = (e))
244 #else
245 #define SET_ERRNO(e) errno = e
246 #endif
248 /* Format an IPv4 address, more or less like inet_ntoa().
250 * Returns `dst' (as a const)
251 * Note:
252 * - uses no statics
253 * - takes a unsigned char * not an in_addr as input */
254 static const char *
255 elinks_inet_ntop4(const unsigned char *src, unsigned char *dst, size_t size)
257 const unsigned char *addr = inet_ntoa(*(struct in_addr*)src);
259 if (strlen(addr) >= size) {
260 SET_ERRNO(ENOSPC);
261 return NULL;
264 return strcpy(dst, addr);
267 #ifdef CONFIG_IPV6
268 /* Convert IPv6 binary address into presentation (printable) format. */
269 static const char *
270 elinks_inet_ntop6(const unsigned char *src, char *dst, size_t size)
272 /* Note that int32_t and int16_t need only be "at least" large enough
273 * to contain a value of the specified size. On some systems, like
274 * Crays, there is no such thing as an integer variable with 16 bits.
275 * Keep this in mind if you think this function should have been coded
276 * to use pointer overlays. All the world's not a VAX. */
277 unsigned char tmp[sizeof("ffff:ffff:ffff:ffff:ffff:ffff:255.255.255.255")];
278 unsigned char *tp;
279 struct {
280 long base;
281 long len;
282 } best, cur;
283 unsigned long words[IN6ADDRSZ / INT16SZ];
284 int i;
286 /* Preprocess:
287 * Copy the input (bytewise) array into a wordwise array.
288 * Find the longest run of 0x00's in src[] for :: shorthanding. */
289 memset(words, 0, sizeof(words));
290 for (i = 0; i < IN6ADDRSZ; i++)
291 words[i/2] |= (src[i] << ((1 - (i % 2)) << 3));
293 best.base = -1;
294 cur.base = -1;
295 for (i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
296 if (words[i] == 0) {
297 if (cur.base == -1)
298 cur.base = i, cur.len = 1;
299 else
300 cur.len++;
302 } else if (cur.base != -1) {
303 if (best.base == -1 || cur.len > best.len)
304 best = cur;
305 cur.base = -1;
309 if ((cur.base != -1) && (best.base == -1 || cur.len > best.len))
310 best = cur;
311 if (best.base != -1 && best.len < 2)
312 best.base = -1;
314 /* Format the result. */
315 for (tp = tmp, i = 0; i < (IN6ADDRSZ / INT16SZ); i++) {
316 /* Are we inside the best run of 0x00's? */
317 if (best.base != -1 && i >= best.base && i < (best.base + best.len)) {
318 if (i == best.base)
319 *tp++ = ':';
320 continue;
323 /* Are we following an initial run of 0x00s or any real hex? */
324 if (i != 0) *tp++ = ':';
326 /* Is this address an encapsulated IPv4? */
327 if (i == 6 && best.base == 0
328 && (best.len == 6 || (best.len == 5 && words[5] == 0xffff))) {
330 if (!elinks_inet_ntop4(src + 12, tp, sizeof(tmp) - (tp - tmp))) {
331 SET_ERRNO(ENOSPC);
332 return NULL;
335 tp += strlen(tp);
336 break;
339 tp += snprintf(tp, 5, "%lx", words[i]);
342 /* Was it a trailing run of 0x00's? */
343 if (best.base != -1 && (best.base + best.len) == (IN6ADDRSZ / INT16SZ))
344 *tp++ = ':';
345 *tp++ = '\0';
347 /* Check for overflow, copy, and we're done. */
348 if ((size_t) (tp - tmp) > size) {
349 SET_ERRNO(ENOSPC);
350 return NULL;
353 return strcpy(dst, tmp);
355 #endif /* CONFIG_IPV6 */
357 /* Convert a network format address to presentation format.
359 * Returns pointer to presentation format address (`dst'),
360 * Returns NULL on error (see errno). */
361 const char *
362 elinks_inet_ntop(int af, const void *src, char *dst, size_t size)
365 switch (af) {
366 case AF_INET:
367 return elinks_inet_ntop4((const unsigned char *) src, dst, size);
368 #ifdef CONFIG_IPV6
369 case AF_INET6:
370 return elinks_inet_ntop6((const unsigned char *) src, dst, size);
371 #endif
372 default:
373 SET_ERRNO(EAFNOSUPPORT);
374 return NULL;
377 #endif /* HAVE_INET_NTOP */