source: mainline/uspace/lib/posix/stdlib.c@ 4419c34

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

Implement a few functions for dealing with temporary files.

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