source: mainline/uspace/lib/posix/source/stdlib.c@ 820104d

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 820104d was 820104d, checked in by Vojtech Horky <vojtechhorky@…>, 12 years ago

libposix: do not die in unimplemented function, just warn

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