1 /* Libc stub functions */
13 #include <sys/types.h>
14 #ifdef HAVE_SYS_SOCKET_H
15 #include <sys/socket.h> /* SunOS needs this after sys/types.h */
20 #ifdef HAVE_NETINET_IN_H
21 #include <netinet/in.h> /* OS/2 needs this after sys/types.h */
23 #ifdef HAVE_ARPA_INET_H
24 #include <arpa/inet.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
44 elinks_strcasecmp(const char *s1
, const char *s2
)
46 while (*s1
!= '\0' && toupper_equal(s1
, s2
)) {
51 return toupper_delta(s1
, s2
);
53 #endif /* !HAVE_STRCASECMP */
55 #ifndef HAVE_STRNCASECMP
57 elinks_strncasecmp(const char *s1
, const char *s2
, size_t len
)
62 while (len
-- != 0 && toupper_equal(s1
, s2
)) {
63 if (len
== 0 || *s1
== '\0' || *s2
== '\0')
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
);
82 if (haystack_length
< needle_length
)
85 for (i
= haystack_length
- needle_length
+ 1; i
; i
--) {
86 if (!strncasecmp(haystack
, needle
, needle_length
))
87 return (char *) haystack
;
96 NONSTATIC_INLINE
char *
97 elinks_strdup(const char *str
)
99 int str_len
= strlen(str
);
100 char *new = malloc(str_len
+ 1);
103 if (str_len
) memcpy(new, str
, str_len
);
110 #ifndef HAVE_STRERROR
111 /* Many older systems don't have this, but have the global sys_errlist array
115 extern const char *const sys_errlist
[];
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";
123 return (const char *) sys_errlist
[err_no
];
128 /* From http://www.unixpapa.com/incnote/string.html */
129 NONSTATIC_INLINE
char *
130 elinks_strstr(const char *s
, const char *p
)
134 for (sp
= (char *) s
, pp
= (char *) p
; *sp
&& *pp
; )
140 sp
= sp
- (pp
- p
) + 1;
144 return (*pp
? NULL
: sp
- (pp
- p
));
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
;
170 for (dst
+= n
- 1, src
+= n
- 1;
181 NONSTATIC_INLINE
char *
182 elinks_stpcpy(char *dest
, const char *src
)
184 while ((*dest
++ = *src
++));
190 NONSTATIC_INLINE
void *
191 elinks_mempcpy(void *dest
, const void *src
, size_t n
)
193 return (void *) ((char *) memcpy(dest
, src
, n
) + n
);
199 elinks_isdigit(int i
)
201 return i
>= '0' && i
<= '9';
206 NONSTATIC_INLINE
void *
207 elinks_memrchr(const void *s
, int c
, size_t n
)
209 char *pos
= (char *) s
;
212 if (pos
[n
- 1] == (char) c
)
213 return (void *) &pos
[n
- 1];
223 #if !defined(HAVE_KILL) || !defined(HAVE_GETPID)
224 #error The raise() stub function requires kill() and getpid()
228 elinks_raise(int signal
)
230 return(kill(getpid(), signal
));
234 #ifndef HAVE_INET_NTOP
235 /* Original code by Paul Vixie. Modified by Gisle Vanem. */
241 /* TODO: Move and populate. --jonas */
242 #ifdef CONFIG_OS_WIN32
243 #define SET_ERRNO(e) WSASetLastError(errno = (e))
245 #define SET_ERRNO(e) errno = e
248 /* Format an IPv4 address, more or less like inet_ntoa().
250 * Returns `dst' (as a const)
253 * - takes a unsigned char * not an in_addr as input */
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
) {
264 return strcpy(dst
, addr
);
268 /* Convert IPv6 binary address into presentation (printable) format. */
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")];
283 unsigned long words
[IN6ADDRSZ
/ INT16SZ
];
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));
295 for (i
= 0; i
< (IN6ADDRSZ
/ INT16SZ
); i
++) {
298 cur
.base
= i
, cur
.len
= 1;
302 } else if (cur
.base
!= -1) {
303 if (best
.base
== -1 || cur
.len
> best
.len
)
309 if ((cur
.base
!= -1) && (best
.base
== -1 || cur
.len
> best
.len
))
311 if (best
.base
!= -1 && best
.len
< 2)
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
)) {
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
))) {
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
))
347 /* Check for overflow, copy, and we're done. */
348 if ((size_t) (tp
- tmp
) > size
) {
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). */
362 elinks_inet_ntop(int af
, const void *src
, char *dst
, size_t size
)
367 return elinks_inet_ntop4((const unsigned char *) src
, dst
, size
);
370 return elinks_inet_ntop6((const unsigned char *) src
, dst
, size
);
373 SET_ERRNO(EAFNOSUPPORT
);
377 #endif /* HAVE_INET_NTOP */