blob: 04ef2466b6e23ba07e74df9879be6abfcec70bac
1 | /* |
2 | * Replacements for common but usually nonstandard functions that aren't |
3 | * supplied by all platforms. |
4 | * |
5 | * Copyright (C) 2009 by Dan Fandrich <dan@coneharvesters.com>, et. al. |
6 | * |
7 | * Licensed under GPLv2, see file LICENSE in this source tree. |
8 | */ |
9 | #include "libbb.h" |
10 | |
11 | #ifndef HAVE_STRCHRNUL |
12 | char* FAST_FUNC strchrnul(const char *s, int c) |
13 | { |
14 | while (*s != '\0' && *s != c) |
15 | s++; |
16 | return (char*)s; |
17 | } |
18 | #endif |
19 | |
20 | #ifndef HAVE_USLEEP |
21 | int FAST_FUNC usleep(unsigned usec) |
22 | { |
23 | struct timespec ts; |
24 | ts.tv_sec = usec / 1000000u; |
25 | ts.tv_nsec = (usec % 1000000u) * 1000u; |
26 | /* |
27 | * If a signal has non-default handler, nanosleep returns early. |
28 | * Our version of usleep doesn't return early |
29 | * if interrupted by such signals: |
30 | * |
31 | */ |
32 | while (nanosleep(&ts, &ts) != 0) |
33 | continue; |
34 | return 0; |
35 | } |
36 | #endif |
37 | |
38 | #ifndef HAVE_VASPRINTF |
39 | int FAST_FUNC vasprintf(char **string_ptr, const char *format, va_list p) |
40 | { |
41 | int r; |
42 | va_list p2; |
43 | char buf[128]; |
44 | |
45 | va_copy(p2, p); |
46 | r = vsnprintf(buf, 128, format, p); |
47 | va_end(p); |
48 | |
49 | /* Note: can't use xstrdup/xmalloc, they call vasprintf (us) on failure! */ |
50 | |
51 | if (r < 128) { |
52 | va_end(p2); |
53 | *string_ptr = strdup(buf); |
54 | return (*string_ptr ? r : -1); |
55 | } |
56 | |
57 | *string_ptr = malloc(r+1); |
58 | r = (*string_ptr ? vsnprintf(*string_ptr, r+1, format, p2) : -1); |
59 | va_end(p2); |
60 | |
61 | return r; |
62 | } |
63 | #endif |
64 | |
65 | #ifndef HAVE_DPRINTF |
66 | /* dprintf is now part of POSIX.1, but was only added in 2008 */ |
67 | int dprintf(int fd, const char *format, ...) |
68 | { |
69 | va_list p; |
70 | int r; |
71 | char *string_ptr; |
72 | |
73 | va_start(p, format); |
74 | r = vasprintf(&string_ptr, format, p); |
75 | va_end(p); |
76 | if (r >= 0) { |
77 | r = full_write(fd, string_ptr, r); |
78 | free(string_ptr); |
79 | } |
80 | return r; |
81 | } |
82 | #endif |
83 | |
84 | #ifndef HAVE_MEMRCHR |
85 | /* Copyright (C) 2005 Free Software Foundation, Inc. |
86 | * memrchr() is a GNU function that might not be available everywhere. |
87 | * It's basically the inverse of memchr() - search backwards in a |
88 | * memory block for a particular character. |
89 | */ |
90 | void* FAST_FUNC memrchr(const void *s, int c, size_t n) |
91 | { |
92 | const char *start = s, *end = s; |
93 | |
94 | end += n - 1; |
95 | |
96 | while (end >= start) { |
97 | if (*end == (char)c) |
98 | return (void *) end; |
99 | end--; |
100 | } |
101 | |
102 | return NULL; |
103 | } |
104 | #endif |
105 | |
106 | #ifndef HAVE_MKDTEMP |
107 | #ifdef __BIONIC__ |
108 | #define mktemp(s) bb_mktemp(s) |
109 | #endif |
110 | /* This is now actually part of POSIX.1, but was only added in 2008 */ |
111 | char* FAST_FUNC mkdtemp(char *template) |
112 | { |
113 | if (mktemp(template) == NULL || mkdir(template, 0700) != 0) |
114 | return NULL; |
115 | return template; |
116 | } |
117 | #endif |
118 | |
119 | #ifndef HAVE_STRCASESTR |
120 | /* Copyright (c) 1999, 2000 The ht://Dig Group */ |
121 | char* FAST_FUNC strcasestr(const char *s, const char *pattern) |
122 | { |
123 | int length = strlen(pattern); |
124 | |
125 | while (*s) { |
126 | if (strncasecmp(s, pattern, length) == 0) |
127 | return (char *)s; |
128 | s++; |
129 | } |
130 | return 0; |
131 | } |
132 | #endif |
133 | |
134 | #ifndef HAVE_STRSEP |
135 | /* Copyright (C) 2004 Free Software Foundation, Inc. */ |
136 | char* FAST_FUNC strsep(char **stringp, const char *delim) |
137 | { |
138 | char *start = *stringp; |
139 | char *ptr; |
140 | |
141 | if (!start) |
142 | return NULL; |
143 | |
144 | if (!*delim) |
145 | ptr = start + strlen(start); |
146 | else { |
147 | ptr = strpbrk(start, delim); |
148 | if (!ptr) { |
149 | *stringp = NULL; |
150 | return start; |
151 | } |
152 | } |
153 | |
154 | *ptr = '\0'; |
155 | *stringp = ptr + 1; |
156 | |
157 | return start; |
158 | } |
159 | #endif |
160 | |
161 | #ifndef HAVE_STPCPY |
162 | char* FAST_FUNC stpcpy(char *p, const char *to_add) |
163 | { |
164 | while ((*p = *to_add) != '\0') { |
165 | p++; |
166 | to_add++; |
167 | } |
168 | return p; |
169 | } |
170 | #endif |
171 | |
172 | #ifndef HAVE_GETLINE |
173 | ssize_t FAST_FUNC getline(char **lineptr, size_t *n, FILE *stream) |
174 | { |
175 | int ch; |
176 | char *line = *lineptr; |
177 | size_t alloced = *n; |
178 | size_t len = 0; |
179 | |
180 | do { |
181 | ch = fgetc(stream); |
182 | if (ch == EOF) |
183 | break; |
184 | if (len + 1 >= alloced) { |
185 | alloced += alloced/4 + 64; |
186 | line = xrealloc(line, alloced); |
187 | } |
188 | line[len++] = ch; |
189 | } while (ch != '\n'); |
190 | |
191 | if (len == 0) |
192 | return -1; |
193 | |
194 | line[len] = '\0'; |
195 | *lineptr = line; |
196 | *n = alloced; |
197 | return len; |
198 | } |
199 | #endif |
200 | |
201 | #ifndef HAVE_TTYNAME_R |
202 | int ttyname_r(int fd, char *buf, size_t buflen) |
203 | { |
204 | int r; |
205 | char path[sizeof("/proc/self/fd/%d") + sizeof(int)*3]; |
206 | |
207 | if (!isatty(fd)) |
208 | return errno == EINVAL ? ENOTTY : errno; |
209 | sprintf(path, "/proc/self/fd/%d", fd); |
210 | r = readlink(path, buf, buflen); |
211 | if (r < 0) |
212 | return errno; |
213 | if (r >= buflen) |
214 | return ERANGE; |
215 | buf[r] = '\0'; |
216 | return 0; |
217 | } |
218 | #endif |
219 |