source: mainline/uspace/lib/posix/source/stdlib.c@ 10de842

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 10de842 was f2460a50, checked in by Jiri Svoboda <jiri@…>, 8 years ago

qsort() compliant with C standard.

  • 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 "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/qsort.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 * Array sorting utilizing the quicksort algorithm.
139 *
140 * @param array Array of elements to sort.
141 * @param count Number of elements in the array.
142 * @param size Width of each element.
143 * @param compare Decides relative ordering of two elements.
144 */
145void posix_qsort(void *array, size_t count, size_t size,
146 int (*compare)(const void *, const void *))
147{
148 qsort(array, count, size, compare);
149}
150
151/**
152 * Binary search in a sorted array.
153 *
154 * @param key Object to search for.
155 * @param base Pointer to the first element of the array.
156 * @param nmemb Number of elements in the array.
157 * @param size Size of each array element.
158 * @param compar Comparison function.
159 * @return Pointer to a matching element, or NULL if none can be found.
160 */
161void *posix_bsearch(const void *key, const void *base,
162 size_t nmemb, size_t size, int (*compar)(const void *, const void *))
163{
164 while (nmemb > 0) {
165 const void *middle = base + (nmemb / 2) * size;
166 int cmp = compar(key, middle);
167 if (cmp == 0) {
168 return (void *) middle;
169 }
170 if (middle == base) {
171 /* There is just one member left to check and it
172 * didn't match the key. Avoid infinite loop.
173 */
174 break;
175 }
176 if (cmp < 0) {
177 nmemb = nmemb / 2;
178 } else if (cmp > 0) {
179 nmemb = nmemb - (nmemb / 2);
180 base = middle;
181 }
182 }
183
184 return NULL;
185}
186
187/**
188 * Retrieve a value of the given environment variable.
189 *
190 * Since HelenOS doesn't support env variables at the moment,
191 * this function always returns NULL.
192 *
193 * @param name Name of the variable.
194 * @return Value of the variable or NULL if such variable does not exist.
195 */
196char *posix_getenv(const char *name)
197{
198 return NULL;
199}
200
201/**
202 *
203 * @param name
204 * @param resolved
205 * @return
206 */
207int posix_putenv(char *string)
208{
209 // TODO: low priority, just a compile-time dependency of binutils
210 not_implemented();
211 return 0;
212}
213
214/**
215 * Issue a command.
216 *
217 * @param string String to be passed to a command interpreter or NULL.
218 * @return Termination status of the command if the command is not NULL,
219 * otherwise indicate whether there is a command interpreter (non-zero)
220 * or not (zero).
221 */
222int posix_system(const char *string) {
223 // TODO: does nothing at the moment
224 not_implemented();
225 return 0;
226}
227
228/**
229 * Resolve absolute pathname.
230 *
231 * @param name Pathname to be resolved.
232 * @param resolved Either buffer for the resolved absolute pathname or NULL.
233 * @return On success, either resolved (if it was not NULL) or pointer to the
234 * newly allocated buffer containing the absolute pathname (if resolved was
235 * NULL). Otherwise NULL.
236 *
237 */
238char *posix_realpath(const char *restrict name, char *restrict resolved)
239{
240 #ifndef PATH_MAX
241 assert(resolved == NULL);
242 #endif
243
244 if (name == NULL) {
245 errno = EINVAL;
246 return NULL;
247 }
248
249 // TODO: symlink resolution
250
251 /* Function absolutize is implemented in libc and declared in vfs.h.
252 * No more processing is required as HelenOS doesn't have symlinks
253 * so far (as far as I can tell), although this function will need
254 * to be updated when that support is implemented.
255 */
256 char* absolute = vfs_absolutize(name, NULL);
257
258 if (absolute == NULL) {
259 /* POSIX requires some specific errnos to be set
260 * for some cases, but there is no way to find out from
261 * absolutize().
262 */
263 errno = EINVAL;
264 return NULL;
265 }
266
267 if (resolved == NULL) {
268 return absolute;
269 } else {
270 #ifdef PATH_MAX
271 str_cpy(resolved, PATH_MAX, absolute);
272 #endif
273 free(absolute);
274 return resolved;
275 }
276}
277
278/**
279 * Converts a string representation of a floating-point number to
280 * its native representation. See posix_strtold().
281 *
282 * @param nptr String representation of a floating-point number.
283 * @return Double-precision number resulting from the string conversion.
284 */
285double posix_atof(const char *nptr)
286{
287 return posix_strtod(nptr, NULL);
288}
289
290/**
291 * Converts a string representation of a floating-point number to
292 * its native representation. See posix_strtold().
293 *
294 * @param nptr String representation of a floating-point number.
295 * @param endptr Pointer to the final part of the string which
296 * was not used for conversion.
297 * @return Single-precision number resulting from the string conversion.
298 */
299float posix_strtof(const char *restrict nptr, char **restrict endptr)
300{
301 return (float) posix_strtold(nptr, endptr);
302}
303
304/**
305 * Converts a string representation of a floating-point number to
306 * its native representation. See posix_strtold().
307 *
308 * @param nptr String representation of a floating-point number.
309 * @param endptr Pointer to the final part of the string which
310 * was not used for conversion.
311 * @return Double-precision number resulting from the string conversion.
312 */
313double posix_strtod(const char *restrict nptr, char **restrict endptr)
314{
315 return (double) posix_strtold(nptr, endptr);
316}
317
318/**
319 * Allocate memory chunk.
320 *
321 * @param size Size of the chunk to allocate.
322 * @return Either pointer to the allocated chunk or NULL if not possible.
323 */
324void *posix_malloc(size_t size)
325{
326 return malloc(size);
327}
328
329/**
330 * Allocate memory for an array of elements.
331 *
332 * @param nelem Number of elements in the array.
333 * @param elsize Size of each element.
334 * @return Either pointer to the allocated array or NULL if not possible.
335 */
336void *posix_calloc(size_t nelem, size_t elsize)
337{
338 return calloc(nelem, elsize);
339}
340
341/**
342 * Reallocate memory chunk to a new size.
343 *
344 * @param ptr Memory chunk to reallocate. Might be NULL.
345 * @param size Size of the reallocated chunk. Might be zero.
346 * @return Either NULL or the pointer to the newly reallocated chunk.
347 */
348void *posix_realloc(void *ptr, size_t size)
349{
350 if (ptr != NULL && size == 0) {
351 /* Native realloc does not handle this special case. */
352 free(ptr);
353 return NULL;
354 } else {
355 return realloc(ptr, size);
356 }
357}
358
359/**
360 * Free allocated memory chunk.
361 *
362 * @param ptr Memory chunk to be freed.
363 */
364void posix_free(void *ptr)
365{
366 if (ptr) {
367 free(ptr);
368 }
369}
370
371/**
372 * Generate a pseudo random integer in the range 0 to RAND_MAX inclusive.
373 *
374 * @return The pseudo random integer.
375 */
376int posix_rand(void)
377{
378 return (int) random();
379}
380
381/**
382 * Initialize a new sequence of pseudo-random integers.
383 *
384 * @param seed The seed of the new sequence.
385 */
386void posix_srand(unsigned int seed)
387{
388 srandom(seed);
389}
390
391/**
392 * Creates and opens an unique temporary file from template.
393 *
394 * @param tmpl Template. Last six characters must be XXXXXX.
395 * @return The opened file descriptor or -1 on error.
396 */
397int posix_mkstemp(char *tmpl)
398{
399 int fd = -1;
400
401 char *tptr = tmpl + posix_strlen(tmpl) - 6;
402
403 while (fd < 0) {
404 if (*posix_mktemp(tmpl) == '\0') {
405 /* Errno set by mktemp(). */
406 return -1;
407 }
408
409 fd = posix_open(tmpl, O_RDWR | O_CREAT | O_EXCL, S_IRUSR | S_IWUSR);
410
411 if (fd == -1) {
412 /* Restore template to it's original state. */
413 snprintf(tptr, 7, "XXXXXX");
414 }
415 }
416
417 return fd;
418}
419
420/**
421 * Creates an unique temporary file name from template.
422 *
423 * @param tmpl Template. Last six characters must be XXXXXX.
424 * @return The value of tmpl. The template is modified in place.
425 * If no temporary file name can be created, template is
426 * reduced to an empty string.
427 */
428char *posix_mktemp(char *tmpl)
429{
430 int tmpl_len = posix_strlen(tmpl);
431 if (tmpl_len < 6) {
432 errno = EINVAL;
433 *tmpl = '\0';
434 return tmpl;
435 }
436
437 char *tptr = tmpl + tmpl_len - 6;
438 if (posix_strcmp(tptr, "XXXXXX") != 0) {
439 errno = EINVAL;
440 *tmpl = '\0';
441 return tmpl;
442 }
443
444 static int seq = 0;
445
446 for (; seq < 1000000; ++seq) {
447 snprintf(tptr, 7, "%06d", seq);
448
449 int orig_errno = errno;
450 errno = 0;
451 /* Check if the file exists. */
452 if (posix_access(tmpl, F_OK) == -1) {
453 if (errno == ENOENT) {
454 errno = orig_errno;
455 break;
456 } else {
457 /* errno set by access() */
458 *tmpl = '\0';
459 return tmpl;
460 }
461 }
462 }
463
464 if (seq == 10000000) {
465 errno = EEXIST;
466 *tmpl = '\0';
467 return tmpl;
468 }
469
470 return tmpl;
471}
472
473/**
474 * Get system load average statistics.
475 *
476 * @param loadavg Array where the load averages shall be placed.
477 * @param nelem Maximum number of elements to be placed into the array.
478 * @return Number of elements placed into the array on success, -1 otherwise.
479 */
480int bsd_getloadavg(double loadavg[], int nelem)
481{
482 assert(nelem > 0);
483
484 size_t count;
485 load_t *loads = stats_get_load(&count);
486
487 if (loads == NULL) {
488 return -1;
489 }
490
491 if (((size_t) nelem) < count) {
492 count = nelem;
493 }
494
495 for (size_t i = 0; i < count; ++i) {
496 loadavg[i] = (double) loads[i];
497 }
498
499 free(loads);
500 return count;
501}
502
503/** @}
504 */
Note: See TracBrowser for help on using the repository browser.