source: mainline/uspace/lib/posix/source/stdlib.c@ 0d0b319

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 0d0b319 was 0d0b319, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 7 years ago

Flip error constants to positive values, and update libposix for the change.

  • Property mode set to 100644
File size: 11.8 KB
Line 
1/*
2 * Copyright (c) 2011 Petr Koupy
3 * Copyright (c) 2011 Jiri Zarevucky
4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libposix
31 * @{
32 */
33/** @file Standard library definitions.
34 */
35
36#define LIBPOSIX_INTERNAL
37#define __POSIX_DEF__(x) posix_##x
38
39#include "internal/common.h"
40#include "posix/stdlib.h"
41
42#include <errno.h>
43
44#include "posix/fcntl.h"
45#include "posix/limits.h"
46#include "posix/string.h"
47#include "posix/sys/stat.h"
48#include "posix/unistd.h"
49
50#include "libc/qsort.h"
51#include "libc/str.h"
52#include "libc/vfs/vfs.h"
53#include "libc/stats.h"
54
55/**
56 *
57 * @param array
58 * @param count
59 * @param size
60 * @param compare
61 */
62int posix_atexit(void (*func)(void))
63{
64 // TODO: low priority, just a compile-time dependency of binutils
65 not_implemented();
66 return 0;
67}
68
69/**
70 * Integer absolute value.
71 *
72 * @param i Input value.
73 * @return Absolute value of the parameter.
74 */
75int posix_abs(int i)
76{
77 return i < 0 ? -i : i;
78}
79
80/**
81 * Long integer absolute value.
82 *
83 * @param i Input value.
84 * @return Absolute value of the parameter.
85 */
86long posix_labs(long i)
87{
88 return i < 0 ? -i : i;
89}
90
91/**
92 * Long long integer absolute value.
93 *
94 * @param i Input value.
95 * @return Absolute value of the parameter.
96 */
97long long posix_llabs(long long i)
98{
99 return i < 0 ? -i : i;
100}
101
102/**
103 * Compute the quotient and remainder of an integer division.
104 *
105 * @param numer Numerator.
106 * @param denom Denominator.
107 * @return Quotient and remainder packed into structure.
108 */
109posix_div_t posix_div(int numer, int denom)
110{
111 return (posix_div_t) { .quot = numer / denom, .rem = numer % denom };
112}
113
114/**
115 * Compute the quotient and remainder of a long integer division.
116 *
117 * @param numer Numerator.
118 * @param denom Denominator.
119 * @return Quotient and remainder packed into structure.
120 */
121posix_ldiv_t posix_ldiv(long numer, long denom)
122{
123 return (posix_ldiv_t) { .quot = numer / denom, .rem = numer % denom };
124}
125
126/**
127 * Compute the quotient and remainder of a long long integer division.
128 *
129 * @param numer Numerator.
130 * @param denom Denominator.
131 * @return Quotient and remainder packed into structure.
132 */
133posix_lldiv_t posix_lldiv(long long numer, long long denom)
134{
135 return (posix_lldiv_t) { .quot = numer / denom, .rem = numer % denom };
136}
137
138/**
139 * Array sorting utilizing the quicksort algorithm.
140 *
141 * @param array Array of elements to sort.
142 * @param count Number of elements in the array.
143 * @param size Width of each element.
144 * @param compare Decides relative ordering of two elements.
145 */
146void posix_qsort(void *array, size_t count, size_t size,
147 int (*compare)(const void *, const void *))
148{
149 qsort(array, count, size, compare);
150}
151
152/**
153 * Binary search in a sorted array.
154 *
155 * @param key Object to search for.
156 * @param base Pointer to the first element of the array.
157 * @param nmemb Number of elements in the array.
158 * @param size Size of each array element.
159 * @param compar Comparison function.
160 * @return Pointer to a matching element, or NULL if none can be found.
161 */
162void *posix_bsearch(const void *key, const void *base,
163 size_t nmemb, size_t size, int (*compar)(const void *, const void *))
164{
165 while (nmemb > 0) {
166 const void *middle = base + (nmemb / 2) * size;
167 int cmp = compar(key, middle);
168 if (cmp == 0) {
169 return (void *) middle;
170 }
171 if (middle == base) {
172 /* There is just one member left to check and it
173 * didn't match the key. Avoid infinite loop.
174 */
175 break;
176 }
177 if (cmp < 0) {
178 nmemb = nmemb / 2;
179 } else if (cmp > 0) {
180 nmemb = nmemb - (nmemb / 2);
181 base = middle;
182 }
183 }
184
185 return NULL;
186}
187
188/**
189 * Retrieve a value of the given environment variable.
190 *
191 * Since HelenOS doesn't support env variables at the moment,
192 * this function always returns NULL.
193 *
194 * @param name Name of the variable.
195 * @return Value of the variable or NULL if such variable does not exist.
196 */
197char *posix_getenv(const char *name)
198{
199 return NULL;
200}
201
202/**
203 *
204 * @param name
205 * @param resolved
206 * @return
207 */
208int posix_putenv(char *string)
209{
210 // TODO: low priority, just a compile-time dependency of binutils
211 not_implemented();
212 return 0;
213}
214
215/**
216 * Issue a command.
217 *
218 * @param string String to be passed to a command interpreter or NULL.
219 * @return Termination status of the command if the command is not NULL,
220 * otherwise indicate whether there is a command interpreter (non-zero)
221 * or not (zero).
222 */
223int posix_system(const char *string) {
224 // TODO: does nothing at the moment
225 not_implemented();
226 return 0;
227}
228
229/**
230 * Resolve absolute pathname.
231 *
232 * @param name Pathname to be resolved.
233 * @param resolved Either buffer for the resolved absolute pathname or NULL.
234 * @return On success, either resolved (if it was not NULL) or pointer to the
235 * newly allocated buffer containing the absolute pathname (if resolved was
236 * NULL). Otherwise NULL.
237 *
238 */
239char *posix_realpath(const char *restrict name, char *restrict resolved)
240{
241 #ifndef PATH_MAX
242 assert(resolved == NULL);
243 #endif
244
245 if (name == NULL) {
246 errno = EINVAL;
247 return NULL;
248 }
249
250 // TODO: symlink resolution
251
252 /* Function absolutize is implemented in libc and declared in vfs.h.
253 * No more processing is required as HelenOS doesn't have symlinks
254 * so far (as far as I can tell), although this function will need
255 * to be updated when that support is implemented.
256 */
257 char* absolute = vfs_absolutize(name, NULL);
258
259 if (absolute == NULL) {
260 /* POSIX requires some specific errnos to be set
261 * for some cases, but there is no way to find out from
262 * absolutize().
263 */
264 errno = EINVAL;
265 return NULL;
266 }
267
268 if (resolved == NULL) {
269 return absolute;
270 } else {
271 #ifdef PATH_MAX
272 str_cpy(resolved, PATH_MAX, absolute);
273 #endif
274 free(absolute);
275 return resolved;
276 }
277}
278
279/**
280 * Converts a string representation of a floating-point number to
281 * its native representation. See posix_strtold().
282 *
283 * @param nptr String representation of a floating-point number.
284 * @return Double-precision number resulting from the string conversion.
285 */
286double posix_atof(const char *nptr)
287{
288 return posix_strtod(nptr, NULL);
289}
290
291/**
292 * Converts a string representation of a floating-point number to
293 * its native representation. See posix_strtold().
294 *
295 * @param nptr String representation of a floating-point number.
296 * @param endptr Pointer to the final part of the string which
297 * was not used for conversion.
298 * @return Single-precision number resulting from the string conversion.
299 */
300float posix_strtof(const char *restrict nptr, char **restrict endptr)
301{
302 return (float) posix_strtold(nptr, endptr);
303}
304
305/**
306 * Converts a string representation of a floating-point number to
307 * its native representation. See posix_strtold().
308 *
309 * @param nptr String representation of a floating-point number.
310 * @param endptr Pointer to the final part of the string which
311 * was not used for conversion.
312 * @return Double-precision number resulting from the string conversion.
313 */
314double posix_strtod(const char *restrict nptr, char **restrict endptr)
315{
316 return (double) posix_strtold(nptr, endptr);
317}
318
319/**
320 * Allocate memory chunk.
321 *
322 * @param size Size of the chunk to allocate.
323 * @return Either pointer to the allocated chunk or NULL if not possible.
324 */
325void *posix_malloc(size_t size)
326{
327 return malloc(size);
328}
329
330/**
331 * Allocate memory for an array of elements.
332 *
333 * @param nelem Number of elements in the array.
334 * @param elsize Size of each element.
335 * @return Either pointer to the allocated array or NULL if not possible.
336 */
337void *posix_calloc(size_t nelem, size_t elsize)
338{
339 return calloc(nelem, elsize);
340}
341
342/**
343 * Reallocate memory chunk to a new size.
344 *
345 * @param ptr Memory chunk to reallocate. Might be NULL.
346 * @param size Size of the reallocated chunk. Might be zero.
347 * @return Either NULL or the pointer to the newly reallocated chunk.
348 */
349void *posix_realloc(void *ptr, size_t size)
350{
351 if (ptr != NULL && size == 0) {
352 /* Native realloc does not handle this special case. */
353 free(ptr);
354 return NULL;
355 } else {
356 return realloc(ptr, size);
357 }
358}
359
360/**
361 * Free allocated memory chunk.
362 *
363 * @param ptr Memory chunk to be freed.
364 */
365void posix_free(void *ptr)
366{
367 if (ptr) {
368 free(ptr);
369 }
370}
371
372/**
373 * Generate a pseudo random integer in the range 0 to RAND_MAX inclusive.
374 *
375 * @return The pseudo random integer.
376 */
377int posix_rand(void)
378{
379 return (int) random();
380}
381
382/**
383 * Initialize a new sequence of pseudo-random integers.
384 *
385 * @param seed The seed of the new sequence.
386 */
387void posix_srand(unsigned int seed)
388{
389 srandom(seed);
390}
391
392/**
393 * Creates and opens an unique temporary file from template.
394 *
395 * @param tmpl Template. Last six characters must be XXXXXX.
396 * @return The opened file descriptor or -1 on error.
397 */
398int posix_mkstemp(char *tmpl)
399{
400 int fd = -1;
401
402 char *tptr = tmpl + posix_strlen(tmpl) - 6;
403
404 while (fd < 0) {
405 if (*posix_mktemp(tmpl) == '\0') {
406 /* Errno set by mktemp(). */
407 return -1;
408 }
409
410 fd = posix_open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
411
412 if (fd == -1) {
413 /* Restore template to it's original state. */
414 snprintf(tptr, 7, "XXXXXX");
415 }
416 }
417
418 return fd;
419}
420
421/**
422 * Creates an unique temporary file name from template.
423 *
424 * @param tmpl Template. Last six characters must be XXXXXX.
425 * @return The value of tmpl. The template is modified in place.
426 * If no temporary file name can be created, template is
427 * reduced to an empty string.
428 */
429char *posix_mktemp(char *tmpl)
430{
431 int tmpl_len = posix_strlen(tmpl);
432 if (tmpl_len < 6) {
433 errno = EINVAL;
434 *tmpl = '\0';
435 return tmpl;
436 }
437
438 char *tptr = tmpl + tmpl_len - 6;
439 if (posix_strcmp(tptr, "XXXXXX") != 0) {
440 errno = EINVAL;
441 *tmpl = '\0';
442 return tmpl;
443 }
444
445 static int seq = 0;
446
447 for (; seq < 1000000; ++seq) {
448 snprintf(tptr, 7, "%06d", seq);
449
450 int orig_errno = errno;
451 errno = 0;
452 /* Check if the file exists. */
453 if (posix_access(tmpl, F_OK) == -1) {
454 if (errno == ENOENT) {
455 errno = orig_errno;
456 break;
457 } else {
458 /* errno set by access() */
459 *tmpl = '\0';
460 return tmpl;
461 }
462 }
463 }
464
465 if (seq == 10000000) {
466 errno = EEXIST;
467 *tmpl = '\0';
468 return tmpl;
469 }
470
471 return tmpl;
472}
473
474/**
475 * Get system load average statistics.
476 *
477 * @param loadavg Array where the load averages shall be placed.
478 * @param nelem Maximum number of elements to be placed into the array.
479 * @return Number of elements placed into the array on success, -1 otherwise.
480 */
481int bsd_getloadavg(double loadavg[], int nelem)
482{
483 assert(nelem > 0);
484
485 size_t count;
486 load_t *loads = stats_get_load(&count);
487
488 if (loads == NULL) {
489 return -1;
490 }
491
492 if (((size_t) nelem) < count) {
493 count = nelem;
494 }
495
496 for (size_t i = 0; i < count; ++i) {
497 loadavg[i] = (double) loads[i];
498 }
499
500 free(loads);
501 return count;
502}
503
504/** @}
505 */
Note: See TracBrowser for help on using the repository browser.