Changes in / [f5b2522:8cd8bf6] in mainline


Ignore:
Location:
uspace/lib/posix
Files:
8 added
26 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/posix/Makefile

    rf5b2522 r8cd8bf6  
    4040SOURCES = \
    4141        ctype.c \
     42        errno.c \
    4243        fcntl.c \
    4344        fnmatch.c \
     45        locale.c \
    4446        math.c \
    4547        pwd.c \
     48        signal.c \
    4649        stdio.c \
     50        stdio/scanf.c \
    4751        stdlib.c \
    4852        stdlib/strtol.c \
  • uspace/lib/posix/ctype.c

    rf5b2522 r8cd8bf6  
    108108}
    109109
     110/**
     111 * Checks whether character is ASCII. (obsolete)
     112 *
     113 * @param c
     114 * @return
     115 */
     116extern int posix_isascii(int c)
     117{
     118        return c >= 0 && c < 128;
     119}
     120
     121/**
     122 * Converts argument to a 7-bit ASCII character. (obsolete)
     123 *
     124 * @param c
     125 * @return
     126 */
     127extern int posix_toascii(int c)
     128{
     129        return c & 0x7F;
     130}
     131
    110132/** @}
    111133 */
  • uspace/lib/posix/ctype.h

    rf5b2522 r8cd8bf6  
    4747extern int posix_ispunct(int c);
    4848
     49/* Obsolete Functions and Macros */
     50extern int posix_isascii(int c);
     51extern int posix_toascii(int c);
     52#undef _tolower
     53#define _tolower(c) ((c) - 'A' + 'a')
     54#undef _toupper
     55#define _toupper(c) ((c) - 'a' + 'A')
     56
     57
    4958#ifndef LIBPOSIX_INTERNAL
    5059        #define isxdigit posix_isxdigit
     
    5463        #define isprint posix_isprint
    5564        #define ispunct posix_ispunct
     65       
     66        #define isascii posix_isascii
     67        #define toascii posix_toascii
    5668#endif
    5769
  • uspace/lib/posix/fcntl.c

    rf5b2522 r8cd8bf6  
    3838#include "fcntl.h"
    3939
     40#include "libc/unistd.h"
     41#include "libc/vfs/vfs.h"
     42#include "errno.h"
     43
    4044/**
    41  *
    42  * @param fd
    43  * @param cmd
    44  * @param ...
    45  * @return
     45 * Performs set of operations on the opened files.
     46 *
     47 * @param fd File descriptor of the opened file.
     48 * @param cmd Operation to carry out.
     49 * @return Non-negative on success. Might have special meaning corresponding
     50 *     to the requested operation.
    4651 */
    4752int posix_fcntl(int fd, int cmd, ...)
    4853{
    49         // TODO
    50         not_implemented();
     54        int rc;
     55        int flags;
     56
     57        switch (cmd) {
     58        case F_DUPFD:
     59        case F_DUPFD_CLOEXEC: /* FD_CLOEXEC is not supported. */
     60                /* VFS does not provide means to express constraints on the new
     61                 * file descriptor so the third argument is ignored. */
     62
     63                /* Retrieve node triplet corresponding to the file descriptor. */
     64                /* Empty statement after label. */;
     65                fdi_node_t node;
     66                rc = fd_node(fd, &node);
     67                if (rc != EOK) {
     68                        errno = -rc;
     69                        return -1;
     70                }
     71
     72                /* Reopen the node so the fresh file descriptor is generated. */
     73                int newfd = open_node(&node, 0);
     74                if (newfd < 0) {
     75                        errno = -newfd;
     76                        return -1;
     77                }
     78
     79                /* Associate the newly generated descriptor to the file description
     80                 * of the old file descriptor. Just reopened node will be automatically
     81                 * closed. */
     82                rc = dup2(fd, newfd);
     83                if (rc != EOK) {
     84                        errno = -rc;
     85                        return -1;
     86                }
     87
     88                return newfd;
     89        case F_GETFD:
     90                /* FD_CLOEXEC is not supported. There are no other flags. */
     91                return 0;
     92        case F_SETFD:
     93                /* FD_CLOEXEC is not supported. Ignore arguments and report success. */
     94                return 0;
     95        case F_GETFL:
     96                /* File status flags (i.e. O_APPEND) are currently private to the
     97                 * VFS server so it cannot be easily retrieved. */
     98                flags = 0;
     99                /* File access flags are currently not supported for file descriptors.
     100                 * Provide full access. */
     101                flags |= O_RDWR;
     102                return flags;
     103        case F_SETFL:
     104                /* File access flags are currently not supported for file descriptors.
     105                 * Ignore arguments and report success. */
     106                return 0;
     107        case F_GETOWN:
     108        case F_SETOWN:
     109        case F_GETLK:
     110        case F_SETLK:
     111        case F_SETLKW:
     112                /* Signals (SIGURG) and file locks are not supported. */
     113                errno = ENOTSUP;
     114                return -1;
     115        default:
     116                /* Unknown command */
     117                errno = EINVAL;
     118                return -1;
     119        }
    51120}
    52121
  • uspace/lib/posix/fcntl.h

    rf5b2522 r8cd8bf6  
    3636#define POSIX_FCNTL_H_
    3737
     38#include "sys/types.h"
    3839#include "libc/fcntl.h"
     40
     41/* Mask for file access modes. */
     42#undef O_ACCMODE
     43#define O_ACCMODE (O_RDONLY | O_WRONLY | O_RDWR)
    3944
    4045/* fcntl commands */
    4146#undef F_DUPFD
     47#undef F_DUPFD_CLOEXEC
    4248#undef F_GETFD
    4349#undef F_SETFD
     
    4652#undef F_GETOWN
    4753#undef F_SETOWN
    48 #define F_DUPFD         0       /* Duplicate file descriptor. */
    49 #define F_GETFD         1       /* Get file descriptor flags. */
    50 #define F_SETFD         2       /* Set file descriptor flags. */
    51 #define F_GETFL         3       /* Get file status flags. */
    52 #define F_SETFL         4       /* Set file status flags. */
    53 #define F_GETOWN        5       /* Get owner. */
    54 #define F_SETOWN        6       /* Set owner. */
     54#undef F_GETLK
     55#undef F_SETLK
     56#undef F_SETLKW
     57#define F_DUPFD            0 /* Duplicate file descriptor. */
     58#define F_DUPFD_CLOEXEC    1 /* Same as F_DUPFD but with FD_CLOEXEC flag set. */
     59#define F_GETFD            2 /* Get file descriptor flags. */
     60#define F_SETFD            3 /* Set file descriptor flags. */
     61#define F_GETFL            4 /* Get file status and access flags. */
     62#define F_SETFL            5 /* Set file status flags. */
     63#define F_GETOWN           6 /* Get socket owner. */
     64#define F_SETOWN           7 /* Set socket owner. */
     65#define F_GETLK            8 /* Get locking information. */
     66#define F_SETLK            9 /* Set locking information. */
     67#define F_SETLKW          10 /* Set locking information; wait if blocked. */
    5568
    5669/* File descriptor flags used with F_GETFD and F_SETFD. */
    5770#undef FD_CLOEXEC
    58 #define FD_CLOEXEC      1       /* Close on exec. */
     71#define FD_CLOEXEC         1 /* Close on exec. */
    5972
    6073extern int posix_fcntl(int fd, int cmd, ...);
  • uspace/lib/posix/fnmatch.c

    rf5b2522 r8cd8bf6  
    3333 */
    3434
     35// TODO: clean this up a bit
     36
     37#include "stdbool.h"
     38#include "ctype.h"
     39#include "string.h"
     40#include "stdlib.h"
     41#include "assert.h"
     42
    3543#define LIBPOSIX_INTERNAL
    3644
    3745#include "internal/common.h"
    3846#include "fnmatch.h"
     47
     48#define INVALID_PATTERN -1
     49
     50/* Type for collating element, simple identity with characters now,
     51 * but may be extended for better locale support.
     52 */
     53typedef int _coll_elm_t;
     54
     55#define COLL_ELM_INVALID -1
     56
     57/** Get collating element matching a string.
     58 *
     59 * @param str
     60 * @return
     61 */
     62static _coll_elm_t _coll_elm_get(const char* str)
     63{
     64        if (str[0] == '\0' || str[1] != '\0') {
     65                return COLL_ELM_INVALID;
     66        }
     67        return str[0];
     68}
     69
     70/** Get collating element matching a single character.
     71 *
     72 * @param c
     73 * @return
     74 */
     75static _coll_elm_t _coll_elm_char(int c)
     76{
     77        return c;
     78}
     79
     80/** Match collating element with a beginning of a string.
     81 *
     82 * @param elm
     83 * @param str
     84 * @return 0 if the element doesn't match, or the number of characters matched.
     85 */
     86static int _coll_elm_match(_coll_elm_t elm, const char *str)
     87{
     88        return elm == *str;
     89}
     90
     91static int _coll_elm_between(_coll_elm_t first, _coll_elm_t second,
     92    const char *str)
     93{
     94        return *str >= first && *str <= second;
     95}
     96
     97/** Read a string delimited by [? and ?].
     98 *
     99 * @param pattern Pointer to the string to read from. Its position is moved
     100 *    to the first character after the closing ].
     101 * @param seq The character on the inside of brackets.
     102 * @param buf Read buffer.
     103 * @param buf_sz Read buffer's size. If the buffer is not large enough for
     104 *    the entire string, the string is cut with no error indication.
     105 * @return
     106 */
     107static bool _get_delimited(
     108    const char **pattern, int seq,
     109    char *buf, size_t buf_sz, int flags)
     110{
     111        const bool noescape = (flags & FNM_NOESCAPE) != 0;
     112        const bool pathname = (flags & FNM_PATHNAME) != 0;
     113
     114        const char *p = *pattern;
     115        assert(p[0] == '[' && p[1] == seq /* Caller should ensure this. */);
     116        p += 2;
     117
     118        while (true) {
     119                if (*p == seq && *(p + 1) == ']') {
     120                        /* String properly ended, return. */
     121                        *pattern = p + 2;
     122                        *buf = '\0';
     123                        return true;
     124                }
     125                if (!noescape && *p == '\\') {
     126                        p++;
     127                }
     128                if (*p == '\0') {
     129                        /* String not ended properly, invalid pattern. */
     130                        return false;
     131                }
     132                if (pathname && *p == '/') {
     133                        /* Slash in a pathname pattern is invalid. */
     134                        return false;
     135                }
     136                if (buf_sz > 1) {
     137                        /* Only add to the buffer if there is space. */
     138                        *buf = *p;
     139                        buf++;
     140                        buf_sz--;
     141                }
     142                p++;
     143        }
     144}
     145
     146/************** CHARACTER CLASSES ****************/
     147
     148#define MAX_CLASS_OR_COLL_LEN 6
     149
     150struct _char_class {
     151        const char *name;
     152        int (*func) (int);
     153};
     154
     155/* List of supported character classes. */
     156static const struct _char_class _char_classes[] = {
     157        { "alnum", isalnum },
     158        { "alpha", isalpha },
     159        { "blank", isblank },
     160        { "cntrl", iscntrl },
     161        { "digit", isdigit },
     162        { "graph", isgraph },
     163        { "lower", islower },
     164        { "print", isprint },
     165        { "punct", ispunct },
     166        { "space", isspace },
     167        { "upper", isupper },
     168        { "xdigit", isxdigit }
     169};
     170
     171static int _class_compare(const void *key, const void *elem)
     172{
     173        const struct _char_class *class = elem;
     174        return strcmp((const char *) key, class->name);
     175}
     176
     177static bool _is_in_class (const char *cname, int c)
     178{
     179        /* Search for class in the array of supported character classes. */
     180        const struct _char_class *class = bsearch(cname, _char_classes,
     181            sizeof(_char_classes) / sizeof(struct _char_class),
     182            sizeof(struct _char_class), _class_compare);
     183
     184        if (class == NULL) {
     185                /* No such class supported - treat as an empty class. */
     186                return false;
     187        } else {
     188                /* Class matched. */
     189                return class->func(c);
     190        }
     191}
     192
     193static int _match_char_class(const char **pattern, const char *str, int flags)
     194{
     195        char class[MAX_CLASS_OR_COLL_LEN + 1];
     196
     197        if (!_get_delimited(pattern, ':', class, sizeof(class), flags)) {
     198                return INVALID_PATTERN;
     199        }
     200
     201        return _is_in_class(class, *str);
     202}
     203
     204/************** END CHARACTER CLASSES ****************/
     205
     206static _coll_elm_t _next_coll_elm(const char **pattern, int flags)
     207{
     208        const char *p = *pattern;
     209        const bool noescape = (flags & FNM_NOESCAPE) != 0;
     210        const bool pathname = (flags & FNM_PATHNAME) != 0;
     211
     212        if (*p == '[') {
     213                if (*(p + 1) == '.') {
     214                        char buf[MAX_CLASS_OR_COLL_LEN + 1];
     215                        if (!_get_delimited(pattern, '.', buf, sizeof(buf), flags)) {
     216                                return COLL_ELM_INVALID;
     217                        }
     218                        return _coll_elm_get(buf);
     219                }
     220
     221                if (*(p + 1) == '=') {
     222                        char buf[MAX_CLASS_OR_COLL_LEN + 1];
     223                        if (!_get_delimited(pattern, '=', buf, sizeof(buf), flags)) {
     224                                return COLL_ELM_INVALID;
     225                        }
     226                        return _coll_elm_get(buf);
     227                }
     228        }
     229
     230        if (!noescape && *p == '\\') {
     231                p++;
     232        }
     233        if (pathname && *p == '/') {
     234                return COLL_ELM_INVALID;
     235        }
     236
     237        *pattern = p + 1;
     238        return _coll_elm_char(*p);
     239}
     240
     241/**
     242 *
     243 */
     244static int _match_bracket_expr(const char **pattern, const char *str, int flags)
     245{
     246        const bool pathname = (flags & FNM_PATHNAME) != 0;
     247        const bool special_period = (flags & FNM_PERIOD) != 0;
     248        const char *p = *pattern;
     249        bool negative = false;
     250        int matched = 0;
     251
     252        #define _matched(match) { \
     253                int _match = match; \
     254                if (_match < 0) { \
     255                        /* Invalid pattern */ \
     256                        return _match; \
     257                } else if (matched == 0 && _match > 0) { \
     258                        /* First match */ \
     259                        matched = _match; \
     260                } \
     261        }
     262
     263        assert(*p == '[');  /* calling code should ensure this */
     264        p++;
     265
     266        if (*str == '\0' || (pathname && *str == '/') ||
     267            (pathname && special_period && *str == '.' && *(str - 1) == '/')) {
     268                /* No bracket expression matches end of string,
     269                 * slash in pathname match or initial period with FNM_PERIOD
     270                 * option.
     271                 */
     272                return 0;
     273        }
     274
     275        if (*p == '^' || *p == '!') {
     276                negative = true;
     277                p++;
     278        }
     279
     280        if (*p == ']') {
     281                /* When ']' is first, treat it as a normal character. */
     282                _matched(*str == ']');
     283                p++;
     284        }
     285       
     286        _coll_elm_t current_elm = COLL_ELM_INVALID;
     287       
     288        while (*p != ']') {
     289                if (*p == '-' && *(p + 1) != ']' &&
     290                    current_elm != COLL_ELM_INVALID) {
     291                        /* Range expression. */
     292                        p++;
     293                        _coll_elm_t end_elm = _next_coll_elm(&p, flags);
     294                        if (end_elm == COLL_ELM_INVALID) {
     295                                return INVALID_PATTERN;
     296                        }
     297                        _matched(_coll_elm_between(current_elm, end_elm, str));
     298                        continue;
     299                }
     300       
     301                if (*p == '[' && *(p + 1) == ':') {
     302                        current_elm = COLL_ELM_INVALID;
     303                        _matched(_match_char_class(&p, str, flags));
     304                        continue;
     305                }
     306               
     307                current_elm = _next_coll_elm(&p, flags);
     308                if (current_elm == COLL_ELM_INVALID) {
     309                        return INVALID_PATTERN;
     310                }
     311                _matched(_coll_elm_match(current_elm, str));
     312        }
     313
     314        /* No error occured - update pattern pointer. */
     315        *pattern = p + 1;
     316
     317        if (matched == 0) {
     318                /* No match found */
     319                return negative;
     320        } else {
     321                /* Matched 'match' characters. */
     322                return negative ? 0 : matched;
     323        }
     324
     325        #undef _matched
     326}
     327
     328/**
     329 *
     330 */
     331static bool _partial_match(const char **pattern, const char **string, int flags)
     332{
     333        /* Only a single *-delimited subpattern is matched here.
     334         * So in this function, '*' is understood as the end of pattern.
     335         */
     336
     337        const bool pathname = (flags & FNM_PATHNAME) != 0;
     338        const bool special_period = (flags & FNM_PERIOD) != 0;
     339        const bool noescape = (flags & FNM_NOESCAPE) != 0;
     340        const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
     341
     342        const char *s = *string;
     343        const char *p = *pattern;
     344
     345        while (*p != '*') {
     346                /* Bracket expression. */
     347                if (*p == '[') {
     348                        int matched = _match_bracket_expr(&p, s, flags);
     349                        if (matched == 0) {
     350                                /* Doesn't match. */
     351                                return false;
     352                        }
     353                        if (matched != INVALID_PATTERN) {
     354                                s += matched;
     355                                continue;
     356                        }
     357
     358                        assert(matched == INVALID_PATTERN);
     359                        /* Fall through to match [ as an ordinary character. */
     360                }
     361
     362                /* Wildcard match. */
     363                if (*p == '?') {
     364                        if (*s == '\0') {
     365                                /* No character to match. */
     366                                return false;
     367                        }
     368                        if (pathname && *s == '/') {
     369                                /* Slash must be matched explicitly. */
     370                                return false;
     371                        }
     372                        if (special_period && pathname &&
     373                            *s == '.' && *(s - 1) == '/') {
     374                                /* Initial period must be matched explicitly. */
     375                                return false;
     376                        }
     377                       
     378                        /* None of the above, match anything else. */
     379                        p++;
     380                        s++;
     381                        continue;
     382                }
     383
     384                if (!noescape && *p == '\\') {
     385                        /* Escaped character. */
     386                        p++;
     387                }
     388
     389                if (*p == '\0') {
     390                        /* End of pattern, must match end of string or
     391                         * an end of subdirectory name (optional).
     392                         */
     393
     394                        if (*s == '\0' || (leading_dir && *s == '/')) {
     395                                break;
     396                        }
     397
     398                        return false;
     399                }
     400
     401                if (*p == *s) {
     402                        /* Exact match. */
     403                        p++;
     404                        s++;
     405                        continue;
     406                }
     407
     408                /* Nothing matched. */
     409                return false;
     410        }
     411
     412        /* Entire sub-pattern matched. */
     413       
     414        /* postconditions */
     415        assert(*p == '\0' || *p == '*');
     416        assert(*p != '\0' || *s == '\0' || (leading_dir && *s == '/'));
     417       
     418        *pattern = p;
     419        *string = s;
     420        return true;
     421}
     422
     423static bool _full_match(const char *pattern, const char *string, int flags)
     424{
     425        const bool pathname = (flags & FNM_PATHNAME) != 0;
     426        const bool special_period = (flags & FNM_PERIOD) != 0;
     427        const bool leading_dir = (flags & FNM_LEADING_DIR) != 0;
     428
     429        if (special_period && *string == '.') {
     430                /* Initial dot must be matched by an explicit dot in pattern. */
     431                if (*pattern != '.') {
     432                        return false;
     433                }
     434                pattern++;
     435                string++;
     436        }
     437
     438        if (*pattern != '*') {
     439                if (!_partial_match(&pattern, &string, flags)) {
     440                        /* The initial match must succeed. */
     441                        return false;
     442                }
     443        }
     444
     445        while (*pattern != '\0') {
     446                assert(*pattern == '*');
     447                pattern++;
     448
     449                bool matched = false;
     450
     451                const char *end;
     452                if (pathname && special_period &&
     453                    *string == '.' && *(string - 1) == '/') {
     454                        end = string;
     455                } else {
     456                        end= strchrnul(string, pathname ? '/' : '\0');
     457                }
     458
     459                /* Try to match every possible offset. */
     460                while (string <= end) {
     461                        if (_partial_match(&pattern, &string, flags)) {
     462                                matched = true;
     463                                break;
     464                        }
     465                        string++;
     466                }
     467
     468                if (matched) {
     469                        continue;
     470                }
     471
     472                return false;
     473        }
     474
     475        return *string == '\0' || (leading_dir && *string == '/');
     476}
     477
     478static char *_casefold(const char *s)
     479{
     480        char *result = strdup(s);
     481        for (char *i = result; *i != '\0'; ++i) {
     482                *i = tolower(*i);
     483        }
     484        return result;
     485}
    39486
    40487/**
     
    48495int posix_fnmatch(const char *pattern, const char *string, int flags)
    49496{
    50         // TODO
    51         not_implemented();
    52 }
     497        // TODO: don't fold everything in advance, but only when needed
     498
     499        if ((flags & FNM_CASEFOLD) != 0) {
     500                /* Just fold the entire pattern and string. */
     501                pattern = _casefold(pattern);
     502                string = _casefold(string);
     503        }
     504
     505        bool result = _full_match(pattern, string, flags);
     506
     507        if ((flags & FNM_CASEFOLD) != 0) {
     508                free((char *) pattern);
     509                free((char *) string);
     510        }
     511
     512        return result ? 0 : FNM_NOMATCH;
     513}
     514
     515// FIXME: put the testcases somewhere else
     516
     517#if 0
     518
     519#include <stdio.h>
     520
     521void __posix_fnmatch_test()
     522{
     523        int fail = 0;
     524
     525        #undef assert
     526        #define assert(x) { if (x) printf("SUCCESS: "#x"\n"); else { printf("FAILED: "#x"\n"); fail++; } }
     527        #define match(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == 0)
     528        #define nomatch(s1, s2, flags) assert(posix_fnmatch(s1, s2, flags) == FNM_NOMATCH)
     529
     530        assert(FNM_PATHNAME == FNM_FILE_NAME);
     531        match("", "", 0);
     532        match("*", "hello", 0);
     533        match("hello", "hello", 0);
     534        match("hello*", "hello", 0);
     535        nomatch("hello?", "hello", 0);
     536        match("*hello", "prdel hello", 0);
     537        match("he[sl]lo", "hello", 0);
     538        match("he[sl]lo", "heslo", 0);
     539        nomatch("he[sl]lo", "heblo", 0);
     540        nomatch("he[^sl]lo", "hello", 0);
     541        nomatch("he[^sl]lo", "heslo", 0);
     542        match("he[^sl]lo", "heblo", 0);
     543        nomatch("he[!sl]lo", "hello", 0);
     544        nomatch("he[!sl]lo", "heslo", 0);
     545        match("he[!sl]lo", "heblo", 0);
     546        match("al*[c-t]a*vis*ta", "alheimer talir jehovista", 0);
     547        match("al*[c-t]a*vis*ta", "alfons had jehovista", 0);
     548        match("[a-ce-z]", "a", 0);
     549        match("[a-ce-z]", "c", 0);
     550        nomatch("[a-ce-z]", "d", 0);
     551        match("[a-ce-z]", "e", 0);
     552        match("[a-ce-z]", "z", 0);
     553        nomatch("[^a-ce-z]", "a", 0);
     554        nomatch("[^a-ce-z]", "c", 0);
     555        match("[^a-ce-z]", "d", 0);
     556        nomatch("[^a-ce-z]", "e", 0);
     557        nomatch("[^a-ce-z]", "z", 0);
     558        match("helen??", "helenos", 0);
     559        match("****booo****", "booo", 0);
     560       
     561        match("hello[[:space:]]world", "hello world", 0);
     562        nomatch("hello[[:alpha:]]world", "hello world", 0);
     563       
     564        match("/hoooo*", "/hooooooo/hooo", 0);
     565        nomatch("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME);
     566        nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME);
     567        match("/hoooo*/*", "/hooooooo/hooo", FNM_PATHNAME);
     568        match("/hoooo*/hooo", "/hooooooo/hooo", FNM_PATHNAME);
     569        match("/hoooo*", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
     570        nomatch("/hoooo*/", "/hooooooo/hooo", FNM_PATHNAME | FNM_LEADING_DIR);
     571        nomatch("/hoooo", "/hooooooo/hooo", FNM_LEADING_DIR);
     572        match("/hooooooo", "/hooooooo/hooo", FNM_LEADING_DIR);
     573       
     574        match("*", "hell", 0);
     575        match("*?", "hell", 0);
     576        match("?*?", "hell", 0);
     577        match("?*??", "hell", 0);
     578        match("??*??", "hell", 0);
     579        nomatch("???*??", "hell", 0);
     580       
     581        nomatch("", "hell", 0);
     582        nomatch("?", "hell", 0);
     583        nomatch("??", "hell", 0);
     584        nomatch("???", "hell", 0);
     585        match("????", "hell", 0);
     586       
     587        match("*", "h.ello", FNM_PERIOD);
     588        match("*", "h.ello", FNM_PATHNAME | FNM_PERIOD);
     589        nomatch("*", ".hello", FNM_PERIOD);
     590        match("h?ello", "h.ello", FNM_PERIOD);
     591        nomatch("?hello", ".hello", FNM_PERIOD);
     592        match("/home/user/.*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
     593        match("/home/user/*", "/home/user/.hello", FNM_PERIOD);
     594        nomatch("/home/user/*", "/home/user/.hello", FNM_PATHNAME | FNM_PERIOD);
     595
     596        nomatch("HeLlO", "hello", 0);
     597        match("HeLlO", "hello", FNM_CASEFOLD);
     598
     599        printf("Failed: %d\n", fail);
     600}
     601
     602#endif
    53603
    54604/** @}
  • uspace/lib/posix/fnmatch.h

    rf5b2522 r8cd8bf6  
    4848#define FNM_NOESCAPE 4
    4949
     50/* GNU Extensions */
     51#undef FNM_FILE_NAME
     52#undef FNM_LEADING_DIR
     53#undef FNM_CASEFOLD
     54#define FNM_FILE_NAME FNM_PATHNAME
     55#define FNM_LEADING_DIR 8
     56#define FNM_CASEFOLD 16
     57
    5058extern int posix_fnmatch(const char *pattern, const char *string, int flags);
    5159
  • uspace/lib/posix/pwd.c

    rf5b2522 r8cd8bf6  
    4747        .pw_gid = 1,
    4848        .pw_dir = (char *) "/",
    49         .pw_shell = (char *) "bdsh"
     49        .pw_shell = (char *) "/app/bdsh"
    5050};
    5151
  • uspace/lib/posix/signal.h

    rf5b2522 r8cd8bf6  
    3939#include "sys/types.h"
    4040
    41 /* HelenOS doesn't have signals, so calls to functions of this header
    42  * are just replaced with their respective failure return value.
    43  *
    44  * Other macros and constants are here just to satisfy the symbol resolver
    45  * and have no practical value whatsoever, until HelenOS implements some
    46  * equivalent of signals. Maybe something neat based on IPC will be devised
    47  * in the future?
    48  */
     41extern void __posix_default_signal_handler(int signo);
     42extern void __posix_hold_signal_handler(int signo);
     43extern void __posix_ignore_signal_handler(int signo);
    4944
    5045#undef SIG_DFL
    51 #define SIG_DFL ((void (*)(int)) 0)
     46#define SIG_DFL ((void (*)(int)) __posix_default_signal_handler)
    5247#undef SIG_ERR
    53 #define SIG_ERR ((void (*)(int)) 0)
     48#define SIG_ERR ((void (*)(int)) NULL)
    5449#undef SIG_HOLD
    55 #define SIG_HOLD ((void (*)(int)) 0)
     50#define SIG_HOLD ((void (*)(int)) __posix_hold_signal_handler)
    5651#undef SIG_IGN
    57 #define SIG_IGN ((void (*)(int)) 0)
    58 
    59 #define signal(sig,func) (errno = ENOTSUP, SIG_ERR)
    60 #define raise(sig) ((int) -1)
    61 #define kill(pid,sig) (errno = ENOTSUP, (int) -1)
     52#define SIG_IGN ((void (*)(int)) __posix_ignore_signal_handler)
    6253
    6354typedef int posix_sig_atomic_t;
    64 typedef int posix_sigset_t;
     55typedef uint32_t posix_sigset_t;
    6556typedef struct posix_mcontext {
    6657        // FIXME: should not be empty to avoid compiler warnings (-pedantic)
     
    8778        int si_errno;
    8879
    89         pid_t si_pid;
    90         uid_t si_uid;
     80        posix_pid_t si_pid;
     81        posix_uid_t si_uid;
    9182        void *si_addr;
    9283        int si_status;
     
    120111/* Values of posix_sigevent::sigev_notify */
    121112#undef SIGEV_NONE
     113#undef SIGEV_SIGNAL
     114#undef SIGEV_THREAD
    122115#define SIGEV_NONE 0
    123 #undef SIGEV_SIGNAL
    124116#define SIGEV_SIGNAL 0
    125 #undef SIGEV_THREAD
    126117#define SIGEV_THREAD 0
    127118
    128119#undef SIGRT_MIN
     120#undef SIGRT_MAX
    129121#define SIGRT_MIN 0
    130 #undef SIGRT_MAX
    131122#define SIGRT_MAX 0
    132123
    133124#undef SIG_BLOCK
     125#undef SIG_UNBLOCK
     126#undef SIG_SETMASK
    134127#define SIG_BLOCK 0
    135 #undef SIG_UNBLOCK
    136 #define SIG_UNBLOCK 0
    137 #undef SIG_SETMASK
    138 #define SIG_SETMASK 0
     128#define SIG_UNBLOCK 1
     129#define SIG_SETMASK 2
    139130
    140131#undef SA_NOCLDSTOP
    141 #define SA_NOCLDSTOP 0
    142132#undef SA_ONSTACK
    143 #define SA_ONSTACK 0
    144133#undef SA_RESETHAND
    145 #define SA_RESETHAND 0
    146134#undef SA_RESTART
    147 #define SA_RESTART 0
    148135#undef SA_SIGINFO
    149 #define SA_SIGINFO 0
    150136#undef SA_NOCLDWAIT
    151 #define SA_NOCLDWAIT 0
    152137#undef SA_NODEFER
    153 #define SA_NODEFER 0
     138#define SA_NOCLDSTOP (1 << 0)
     139#define SA_ONSTACK (1 << 1)
     140#define SA_RESETHAND (1 << 2)
     141#define SA_RESTART (1 << 3)
     142#define SA_SIGINFO (1 << 4)
     143#define SA_NOCLDWAIT (1 << 5)
     144#define SA_NODEFER (1 << 6)
    154145
    155146#undef SS_ONSTACK
     147#undef SS_DISABLE
    156148#define SS_ONSTACK 0
    157 #undef SS_DISABLE
    158149#define SS_DISABLE 0
    159150
    160151#undef MINSIGSTKSZ
     152#undef SIGSTKSZ
    161153#define MINSIGSTKSZ 0
    162 #undef SIGSTKSZ
    163154#define SIGSTKSZ 0
    164155
    165156/* full POSIX set */
    166157enum {
     158        /* Termination Signals */
    167159        SIGABRT,
     160        SIGQUIT,
     161        SIGINT,
     162        SIGTERM,
     163       
     164        /* Child Signal */
     165        SIGCHLD,
     166       
     167        /* User signals */
     168        SIGUSR1,
     169        SIGUSR2,
     170
     171        /* Timer */
    168172        SIGALRM,
     173        SIGVTALRM,
     174        SIGPROF, /* obsolete */
     175
     176        _TOP_CATCHABLE_SIGNAL = SIGPROF,
     177
     178        /* Process Scheduler Interaction - not supported */
     179        SIGSTOP,
     180        SIGCONT,
     181
     182        /* Process Termination - can't be caught */
     183        SIGKILL,
     184
     185        _TOP_SENDABLE_SIGNAL = SIGKILL,
     186
     187        /* Hardware Exceptions - can't be caught or sent */
     188        SIGFPE,
    169189        SIGBUS,
    170         SIGCHLD,
    171         SIGCONT,
    172         SIGFPE,
     190        SIGILL,
     191        SIGSEGV,
     192
     193        /* Other Exceptions - not supported */
     194        SIGSYS,
     195        SIGXCPU,
     196        SIGXFSZ,
     197
     198        /* Debugging - not supported */
     199        SIGTRAP,
     200
     201        /* Communication Signals - not supported */
    173202        SIGHUP,
    174         SIGILL,
    175         SIGINT,
    176         SIGKILL,
    177203        SIGPIPE,
    178         SIGQUIT,
    179         SIGSEGV,
    180         SIGSTOP,
    181         SIGTERM,
     204        SIGPOLL, /* obsolete */
     205        SIGURG,
     206
     207        /* Terminal Signals - not supported */
    182208        SIGTSTP,
    183209        SIGTTIN,
    184210        SIGTTOU,
    185         SIGUSR1,
    186         SIGUSR2,
    187         SIGPOLL,
    188         SIGPROF,
    189         SIGSYS,
    190         SIGTRAP,
    191         SIGURG,
    192         SIGVTALRM,
    193         SIGXCPU,
    194         SIGXFSZ
    195 };
    196 
    197 /* Just declared to avoid compiler warnings. */
     211       
     212        _TOP_SIGNAL = SIGTTOU
     213};
     214
     215/* Values for sigaction field si_code. */
     216
     217enum {
     218        SI_USER,
     219        SI_QUEUE,
     220        SI_TIMER,
     221        SI_ASYNCIO,
     222        SI_MESGQ,
     223        ILL_ILLOPC,
     224        ILL_ILLOPN,
     225        ILL_ILLADR,
     226        ILL_ILLTRP,
     227        ILL_PRVOPC,
     228        ILL_PRVREG,
     229        ILL_COPROC,
     230        ILL_BADSTK,
     231        FPE_INTDIV,
     232        FPE_INTOVF,
     233        FPE_FLTDIV,
     234        FPE_FLTOVF,
     235        FPE_FLTUND,
     236        FPE_FLTRES,
     237        FPE_FLTINV,
     238        FPE_FLTSUB,
     239        SEGV_MAPERR,
     240        SEGV_ACCERR,
     241        BUS_ADRALN,
     242        BUS_ADRERR,
     243        BUS_OBJERR,
     244        TRAP_BRKPT,
     245        TRAP_TRACE,
     246        CLD_EXITED,
     247        CLD_KILLED,
     248        CLD_DUMPED,
     249        CLD_TRAPPED,
     250        CLD_STOPPED,
     251        CLD_CONTINUED,
     252        POLL_IN,
     253        POLL_OUT,
     254        POLL_MSG,
     255        POLL_ERR,
     256        POLL_PRI,
     257        POLL_HUP
     258};
     259
     260extern int posix_sigaction(int sig, const struct posix_sigaction *restrict act,
     261    struct posix_sigaction *restrict oact);
     262
     263extern void (*posix_signal(int sig, void (*func)(int)))(int);
     264extern int posix_raise(int sig);
     265extern int posix_kill(posix_pid_t pid, int sig);
     266extern int posix_killpg(posix_pid_t pid, int sig);
     267
     268extern void posix_psiginfo(const posix_siginfo_t *pinfo, const char *message);
     269extern void posix_psignal(int signum, const char *message);
     270
    198271extern int posix_sigemptyset(posix_sigset_t *set);
     272extern int posix_sigfillset(posix_sigset_t *set);
     273extern int posix_sigaddset(posix_sigset_t *set, int signo);
     274extern int posix_sigdelset(posix_sigset_t *set, int signo);
     275extern int posix_sigismember(const posix_sigset_t *set, int signo);
     276
     277extern int posix_thread_sigmask(int how, const posix_sigset_t *restrict set,
     278    posix_sigset_t *restrict oset);
    199279extern int posix_sigprocmask(int how, const posix_sigset_t *restrict set,
    200280    posix_sigset_t *restrict oset);
     
    204284        #define sigset_t posix_sigset_t
    205285        #define sigval posix_sigval
    206         #define sigevent posix_sigevent
     286        #ifndef sigevent
     287                #define sigevent posix_sigevent
     288        #endif
    207289        #define sigaction posix_sigaction
    208290        #define mcontext_t posix_mcontext_t
     
    210292        #define stack_t posix_stack_t
    211293        #define siginfo_t posix_siginfo_t
     294
     295        #define signal posix_signal
     296        #define raise posix_raise
     297        #define kill posix_kill
     298        #define killpg posix_killpg
     299
     300        #define psiginfo posix_psiginfo
     301        #define psignal posix_psignal
     302
    212303        #define sigemptyset posix_sigemptyset
     304        #define sigfillset posix_sigfillset
     305        #define sigaddset posix_sigaddset
     306        #define sigdelset posix_sigdelset
     307        #define sigismember posix_sigismember
     308
     309        #define pthread_sigmask posix_thread_sigmask
    213310        #define sigprocmask posix_sigprocmask
    214311#endif
  • uspace/lib/posix/stdbool.h

    rf5b2522 r8cd8bf6  
    4040
    4141#ifdef LIBC_BOOL_H_
    42         #error You can't include bool.h and stdbool.h at the same time.
     42        #error "You can't include bool.h and stdbool.h at the same time."
    4343#endif
    4444#define LIBC_BOOL_H_
  • uspace/lib/posix/stdint.h

    rf5b2522 r8cd8bf6  
    3535#ifndef POSIX_STDINT_H_
    3636#define POSIX_STDINT_H_
     37
     38#include "libc/stdint.h"
    3739
    3840#undef INT8_MAX
  • uspace/lib/posix/stdio.c

    rf5b2522 r8cd8bf6  
    3636#define LIBPOSIX_INTERNAL
    3737
    38 #include <assert.h>
    39 #include <errno.h>
     38/* Has to be first. */
     39#include "stdbool.h"
    4040
    4141#include "internal/common.h"
    4242#include "stdio.h"
     43
     44#include "assert.h"
     45#include "errno.h"
    4346#include "string.h"
    44 
    45 /* not the best of solutions, but freopen will eventually
     47#include "sys/types.h"
     48
     49#include "libc/io/printf_core.h"
     50#include "libc/str.h"
     51#include "libc/malloc.h"
     52
     53
     54/* not the best of solutions, but freopen and ungetc will eventually
    4655 * need to be implemented in libc anyway
    4756 */
    4857#include "../c/generic/private/stdio.h"
    4958
    50 /**
    51  *
    52  * @param c
    53  * @param stream
    54  * @return
     59/** Clears the stream's error and end-of-file indicators.
     60 *
     61 * @param stream Stream whose indicators shall be cleared.
     62 */
     63void posix_clearerr(FILE *stream)
     64{
     65        stream->error = 0;
     66        stream->eof = 0;
     67}
     68
     69/**
     70 * Generate a pathname for the controlling terminal.
     71 *
     72 * @param s Allocated buffer to which the pathname shall be put.
     73 * @return Either s or static location filled with the requested pathname.
     74 */
     75char *posix_ctermid(char *s)
     76{
     77        /* Currently always returns an error value (empty string). */
     78        // TODO: return a real terminal path
     79
     80        static char dummy_path[L_ctermid] = {'\0'};
     81
     82        if (s == NULL) {
     83                return dummy_path;
     84        }
     85
     86        s[0] = '\0';
     87        return s;
     88}
     89
     90/**
     91 * Push byte back into input stream.
     92 *
     93 * @param c Byte to be pushed back.
     94 * @param stream Stream to where the byte shall be pushed.
     95 * @return Provided byte on success or EOF if not possible.
    5596 */
    5697int posix_ungetc(int c, FILE *stream)
    5798{
    58         // TODO
    59         not_implemented();
    60 }
    61 
    62 /**
    63  *
    64  * @param filename
    65  * @param mode
    66  * @param stream
    67  * @return
     99        uint8_t b = (uint8_t) c;
     100
     101        bool can_unget =
     102                /* Provided character is legal. */
     103            c != EOF &&
     104                /* Stream is consistent. */
     105            !stream->error &&
     106                /* Stream is buffered. */
     107            stream->btype != _IONBF &&
     108                /* Last operation on the stream was a read operation. */
     109            stream->buf_state == _bs_read &&
     110                /* Stream buffer is already allocated (i.e. there was already carried
     111                 * out either write or read operation on the stream). This is probably
     112                 * redundant check but let's be safe. */
     113            stream->buf != NULL &&
     114                /* There is still space in the stream to retreat. POSIX demands the
     115                 * possibility to unget at least 1 character. It should be always
     116                 * possible, assuming the last operation on the stream read at least 1
     117                 * character, because the buffer is refilled in the lazily manner. */
     118            stream->buf_tail > stream->buf;
     119
     120        if (can_unget) {
     121                --stream->buf_tail;
     122                stream->buf_tail[0] = b;
     123                stream->eof = false;
     124                return (int) b;
     125        } else {
     126                return EOF;
     127        }
     128}
     129
     130/**
     131 * Read a stream until the delimiter (or EOF) is encountered.
     132 *
     133 * @param lineptr Pointer to the output buffer in which there will be stored
     134 *     nul-terminated string together with the delimiter (if encountered).
     135 *     Will be resized if necessary.
     136 * @param n Pointer to the size of the output buffer. Will be increased if
     137 *     necessary.
     138 * @param delimiter Delimiter on which to finish reading the stream.
     139 * @param stream Input stream.
     140 * @return Number of fetched characters (including delimiter if encountered)
     141 *     or -1 on error (set in errno).
     142 */
     143ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
     144    int delimiter, FILE *restrict stream)
     145{
     146        /* Check arguments for sanity. */
     147        if (!lineptr || !n) {
     148                errno = EINVAL;
     149                return -1;
     150        }
     151
     152        size_t alloc_step = 80; /* Buffer size gain during reallocation. */
     153        char *pos = *lineptr; /* Next free byte of the output buffer. */
     154        size_t cnt = 0; /* Number of fetched characters. */
     155        int c = fgetc(stream); /* Current input character. Might be EOF. */
     156
     157        do {
     158                /* Mask EOF as NUL to terminate string. */
     159                if (c == EOF) {
     160                        c = '\0';
     161                }
     162
     163                /* Ensure there is still space left in the buffer. */
     164                if (pos == *lineptr + *n) {
     165                        *lineptr = realloc(*lineptr, *n + alloc_step);
     166                        if (*lineptr) {
     167                                pos = *lineptr + *n;
     168                                *n += alloc_step;
     169                        } else {
     170                                errno = ENOMEM;
     171                                return -1;
     172                        }
     173                }
     174
     175                /* Store the fetched character. */
     176                *pos = c;
     177
     178                /* Fetch the next character according to the current character. */
     179                if (c != '\0') {
     180                        ++pos;
     181                        ++cnt;
     182                        if (c == delimiter) {
     183                                /* Delimiter was just stored. Provide EOF as the next
     184                                 * character - it will be masked as NUL and output string
     185                                 * will be properly terminated. */
     186                                c = EOF;
     187                        } else {
     188                                /* Neither delimiter nor EOF were encountered. Just fetch
     189                                 * the next character from the stream. */
     190                                c = fgetc(stream);
     191                        }
     192                }
     193        } while (c != '\0');
     194
     195        if (errno == EOK && cnt > 0) {
     196                return cnt;
     197        } else {
     198                /* Either some error occured or the stream was already at EOF. */
     199                return -1;
     200        }
     201}
     202
     203/**
     204 * Read a stream until the newline (or EOF) is encountered.
     205 *
     206 * @param lineptr Pointer to the output buffer in which there will be stored
     207 *     nul-terminated string together with the delimiter (if encountered).
     208 *     Will be resized if necessary.
     209 * @param n Pointer to the size of the output buffer. Will be increased if
     210 *     necessary.
     211 * @param stream Input stream.
     212 * @return Number of fetched characters (including newline if encountered)
     213 *     or -1 on error (set in errno).
     214 */
     215ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
     216    FILE *restrict stream)
     217{
     218        return posix_getdelim(lineptr, n, '\n', stream);
     219}
     220
     221/**
     222 * Reopen a file stream.
     223 *
     224 * @param filename Pathname of a file to be reopened or NULL for changing
     225 *     the mode of the stream.
     226 * @param mode Mode to be used for reopening the file or changing current
     227 *     mode of the stream.
     228 * @param stream Current stream associated with the opened file.
     229 * @return On success, either a stream of the reopened file or the provided
     230 *     stream with a changed mode. NULL otherwise.
    68231 */
    69232FILE *posix_freopen(
     
    115278/**
    116279 *
    117  * @param s
    118  */
    119 void posix_perror(const char *s)
     280 * @param buf
     281 * @param size
     282 * @param mode
     283 * @return
     284 */
     285FILE *posix_fmemopen(void *restrict buf, size_t size,
     286    const char *restrict mode)
    120287{
    121288        // TODO
     
    124291
    125292/**
    126  *
    127  * @param stream
    128  * @param offset
    129  * @param whence
     293 *
     294 * @param bufp
     295 * @param sizep
    130296 * @return
    131297 */
    132 int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
     298FILE *posix_open_memstream(char **bufp, size_t *sizep)
    133299{
    134300        // TODO
     
    137303
    138304/**
    139  *
    140  * @param stream
     305 * Write error messages to standard error.
     306 *
     307 * @param s Error message.
     308 */
     309void posix_perror(const char *s)
     310{
     311        if (s == NULL || s[0] == '\0') {
     312                fprintf(stderr, "%s\n", posix_strerror(errno));
     313        } else {
     314                fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
     315        }
     316}
     317
     318struct _posix_fpos {
     319        off64_t offset;
     320};
     321
     322/** Restores stream a to position previously saved with fgetpos().
     323 *
     324 * @param stream Stream to restore
     325 * @param pos Position to restore
     326 * @return Zero on success, non-zero (with errno set) on failure
     327 */
     328int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
     329{
     330        return fseek(stream, pos->offset, SEEK_SET);
     331}
     332
     333/** Saves the stream's position for later use by fsetpos().
     334 *
     335 * @param stream Stream to save
     336 * @param pos Place to store the position
     337 * @return Zero on success, non-zero (with errno set) on failure
     338 */
     339int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
     340{
     341        off64_t ret = ftell(stream);
     342        if (ret == -1) {
     343                return errno;
     344        }
     345        pos->offset = ret;
     346        return 0;
     347}
     348
     349/**
     350 * Reposition a file-position indicator in a stream.
     351 *
     352 * @param stream Stream to seek in.
     353 * @param offset Direction and amount of bytes to seek.
     354 * @param whence From where to seek.
     355 * @return Zero on success, -1 otherwise.
     356 */
     357int posix_fseek(FILE *stream, long offset, int whence)
     358{
     359        return fseek(stream, (off64_t) offset, whence);
     360}
     361
     362/**
     363 * Reposition a file-position indicator in a stream.
     364 *
     365 * @param stream Stream to seek in.
     366 * @param offset Direction and amount of bytes to seek.
     367 * @param whence From where to seek.
     368 * @return Zero on success, -1 otherwise.
     369 */
     370int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
     371{
     372        return fseek(stream, (off64_t) offset, whence);
     373}
     374
     375/**
     376 * Discover current file offset in a stream.
     377 *
     378 * @param stream Stream for which the offset shall be retrieved.
     379 * @return Current offset or -1 if not possible.
     380 */
     381long posix_ftell(FILE *stream)
     382{
     383        return (long) ftell(stream);
     384}
     385
     386/**
     387 * Discover current file offset in a stream.
     388 *
     389 * @param stream Stream for which the offset shall be retrieved.
     390 * @return Current offset or -1 if not possible.
     391 */
     392posix_off_t posix_ftello(FILE *stream)
     393{
     394        return (posix_off_t) ftell(stream);
     395}
     396
     397/**
     398 * Print formatted output to the opened file.
     399 *
     400 * @param fildes File descriptor of the opened file.
     401 * @param format Format description.
     402 * @return Either the number of printed characters or negative value on error.
     403 */
     404int posix_dprintf(int fildes, const char *restrict format, ...)
     405{
     406        va_list list;
     407        va_start(list, format);
     408        int result = posix_vdprintf(fildes, format, list);
     409        va_end(list);
     410        return result;
     411}
     412
     413/**
     414 * Write ordinary string to the opened file.
     415 *
     416 * @param str String to be written.
     417 * @param size Size of the string (in bytes)..
     418 * @param fd File descriptor of the opened file.
     419 * @return The number of written characters.
     420 */
     421static int _dprintf_str_write(const char *str, size_t size, void *fd)
     422{
     423        ssize_t wr = write(*(int *) fd, str, size);
     424        return str_nlength(str, wr);
     425}
     426
     427/**
     428 * Write wide string to the opened file.
     429 *
     430 * @param str String to be written.
     431 * @param size Size of the string (in bytes).
     432 * @param fd File descriptor of the opened file.
     433 * @return The number of written characters.
     434 */
     435static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd)
     436{
     437        size_t offset = 0;
     438        size_t chars = 0;
     439        size_t sz;
     440        char buf[4];
     441       
     442        while (offset < size) {
     443                sz = 0;
     444                if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
     445                        break;
     446                }
     447               
     448                if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
     449                        break;
     450                }
     451               
     452                chars++;
     453                offset += sizeof(wchar_t);
     454        }
     455       
     456        return chars;
     457}
     458
     459/**
     460 * Print formatted output to the opened file.
     461 *
     462 * @param fildes File descriptor of the opened file.
     463 * @param format Format description.
     464 * @param ap Print arguments.
     465 * @return Either the number of printed characters or negative value on error.
     466 */
     467int posix_vdprintf(int fildes, const char *restrict format, va_list ap)
     468{
     469        printf_spec_t spec = {
     470                .str_write = _dprintf_str_write,
     471                .wstr_write = _dprintf_wstr_write,
     472                .data = &fildes
     473        };
     474       
     475        return printf_core(format, &spec, ap);
     476}
     477
     478/**
     479 * Print formatted output to the string.
     480 *
     481 * @param s Output string.
     482 * @param format Format description.
     483 * @return Either the number of printed characters (excluding null byte) or
     484 *     negative value on error.
     485 */
     486int posix_sprintf(char *s, const char *restrict format, ...)
     487{
     488        va_list list;
     489        va_start(list, format);
     490        int result = posix_vsprintf(s, format, list);
     491        va_end(list);
     492        return result;
     493}
     494
     495/**
     496 * Print formatted output to the string.
     497 *
     498 * @param s Output string.
     499 * @param format Format description.
     500 * @param ap Print arguments.
     501 * @return Either the number of printed characters (excluding null byte) or
     502 *     negative value on error.
     503 */
     504int posix_vsprintf(char *s, const char *restrict format, va_list ap)
     505{
     506        return vsnprintf(s, STR_NO_LIMIT, format, ap);
     507}
     508
     509/**
     510 * Convert formatted input from the stream.
     511 *
     512 * @param stream Input stream.
     513 * @param format Format description.
     514 * @return The number of converted output items or EOF on failure.
     515 */
     516int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
     517{
     518        va_list list;
     519        va_start(list, format);
     520        int result = posix_vfscanf(stream, format, list);
     521        va_end(list);
     522        return result;
     523}
     524
     525/**
     526 * Convert formatted input from the standard input.
     527 *
     528 * @param format Format description.
     529 * @return The number of converted output items or EOF on failure.
     530 */
     531int posix_scanf(const char *restrict format, ...)
     532{
     533        va_list list;
     534        va_start(list, format);
     535        int result = posix_vscanf(format, list);
     536        va_end(list);
     537        return result;
     538}
     539
     540/**
     541 * Convert formatted input from the standard input.
     542 *
     543 * @param format Format description.
     544 * @param arg Output items.
     545 * @return The number of converted output items or EOF on failure.
     546 */
     547int posix_vscanf(const char *restrict format, va_list arg)
     548{
     549        return posix_vfscanf(stdin, format, arg);
     550}
     551
     552/**
     553 * Convert formatted input from the string.
     554 *
     555 * @param s Input string.
     556 * @param format Format description.
     557 * @return The number of converted output items or EOF on failure.
     558 */
     559int posix_sscanf(const char *restrict s, const char *restrict format, ...)
     560{
     561        va_list list;
     562        va_start(list, format);
     563        int result = posix_vsscanf(s, format, list);
     564        va_end(list);
     565        return result;
     566}
     567
     568/**
     569 * Acquire file stream for the thread.
     570 *
     571 * @param file File stream to lock.
     572 */
     573void posix_flockfile(FILE *file)
     574{
     575        /* dummy */
     576}
     577
     578/**
     579 * Acquire file stream for the thread (non-blocking).
     580 *
     581 * @param file File stream to lock.
     582 * @return Zero for success and non-zero if the lock cannot be acquired.
     583 */
     584int posix_ftrylockfile(FILE *file)
     585{
     586        /* dummy */
     587        return 0;
     588}
     589
     590/**
     591 * Relinquish the ownership of the locked file stream.
     592 *
     593 * @param file File stream to unlock.
     594 */
     595void posix_funlockfile(FILE *file)
     596{
     597        /* dummy */
     598}
     599
     600/**
     601 * Get a byte from a stream (thread-unsafe).
     602 *
     603 * @param stream Input file stream.
     604 * @return Either read byte or EOF.
     605 */
     606int posix_getc_unlocked(FILE *stream)
     607{
     608        return getc(stream);
     609}
     610
     611/**
     612 * Get a byte from the standard input stream (thread-unsafe).
     613 *
     614 * @return Either read byte or EOF.
     615 */
     616int posix_getchar_unlocked(void)
     617{
     618        return getchar();
     619}
     620
     621/**
     622 * Put a byte on a stream (thread-unsafe).
     623 *
     624 * @param c Byte to output.
     625 * @param stream Output file stream.
     626 * @return Either written byte or EOF.
     627 */
     628int posix_putc_unlocked(int c, FILE *stream)
     629{
     630        return putc(c, stream);
     631}
     632
     633/**
     634 * Put a byte on the standard output stream (thread-unsafe).
     635 *
     636 * @param c Byte to output.
     637 * @return Either written byte or EOF.
     638 */
     639int posix_putchar_unlocked(int c)
     640{
     641        return putchar(c);
     642}
     643
     644/**
     645 * Remove a file.
     646 *
     647 * @param path Pathname of the file that shall be removed.
     648 * @return Zero on success, -1 otherwise.
     649 */
     650int posix_remove(const char *path)
     651{
     652        // FIXME: unlink() and rmdir() seem to be equivalent at the moment,
     653        //        but that does not have to be true forever
     654        return unlink(path);
     655}
     656
     657/**
     658 *
     659 * @param s
    141660 * @return
    142661 */
    143 posix_off_t posix_ftello(FILE *stream)
    144 {
    145         // TODO
    146         not_implemented();
    147 }
    148 
    149 /**
    150  *
    151  * @param s
    152  * @param format
    153  * @param ...
    154  * @return
    155  */
    156 int posix_sprintf(char *s, const char *format, ...)
    157 {
    158         // TODO
    159         not_implemented();
    160 }
    161 
    162 /**
    163  *
    164  * @param s
    165  * @param format
    166  * @param ...
    167  * @return
    168  */
    169 int posix_vsprintf(char *s, const char *format, va_list ap)
     662char *posix_tmpnam(char *s)
    170663{
    171664        // TODO: low priority, just a compile-time dependency of binutils
     
    173666}
    174667
    175 /**
    176  *
    177  * @param s
    178  * @param format
    179  * @param ...
    180  * @return
    181  */
    182 int posix_sscanf(const char *s, const char *format, ...)
    183 {
    184         // TODO
    185         not_implemented();
    186 }
    187 
    188 /**
    189  *
    190  * @param path
    191  * @return
    192  */
    193 int posix_remove(const char *path)
    194 {
    195         // TODO: low priority, just a compile-time dependency of binutils
    196         not_implemented();
    197 }
    198 
    199 /**
    200  *
    201  * @param s
    202  * @return
    203  */
    204 char *posix_tmpnam(char *s)
    205 {
    206         // TODO: low priority, just a compile-time dependency of binutils
    207         not_implemented();
    208 }
    209 
    210668/** @}
    211669 */
  • uspace/lib/posix/stdio.h

    rf5b2522 r8cd8bf6  
    4040#include "sys/types.h"
    4141#include "libc/stdarg.h"
     42#include "limits.h"
    4243
    43 /* Character Input/Output */
     44#undef L_ctermid
     45#define L_ctermid PATH_MAX
     46
     47extern void posix_clearerr(FILE *stream);
     48extern char *posix_ctermid(char *s);
     49
     50/* Input/Output */
    4451#undef putc
    4552#define putc fputc
     
    4754#define getc fgetc
    4855extern int posix_ungetc(int c, FILE *stream);
     56
     57extern ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
     58    int delimiter, FILE *restrict stream);
     59extern ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
     60    FILE *restrict stream);
    4961
    5062/* Opening Streams */
     
    5466   FILE *restrict stream);
    5567
     68/* Memory Streams */
     69
     70extern FILE *posix_fmemopen(void *restrict buf, size_t size,
     71    const char *restrict mode);
     72extern FILE *posix_open_memstream(char **bufp, size_t *sizep);
     73
    5674/* Error Messages */
    5775extern void posix_perror(const char *s);
    5876
    5977/* File Positioning */
     78
     79typedef struct _posix_fpos posix_fpos_t;
     80extern int posix_fsetpos(FILE *stream, const posix_fpos_t *pos);
     81extern int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos);
     82extern int posix_fseek(FILE *stream, long offset, int whence);
    6083extern int posix_fseeko(FILE *stream, posix_off_t offset, int whence);
     84extern long posix_ftell(FILE *stream);
    6185extern posix_off_t posix_ftello(FILE *stream);
    6286
    6387/* Formatted Input/Output */
    64 extern int posix_sprintf(char *restrict s, const char *restrict format, ...);
     88extern int posix_dprintf(int fildes, const char *restrict format, ...)
     89    PRINTF_ATTRIBUTE(2, 3);
     90extern int posix_vdprintf(int fildes, const char *restrict format, va_list ap);
     91extern int posix_sprintf(char *restrict s, const char *restrict format, ...)
     92    PRINTF_ATTRIBUTE(2, 3);
    6593extern int posix_vsprintf(char *restrict s, const char *restrict format, va_list ap);
    66 extern int posix_sscanf(const char *restrict s, const char *restrict format, ...);
     94
     95extern int posix_fscanf(
     96    FILE *restrict stream, const char *restrict format, ...);
     97extern int posix_vfscanf(
     98    FILE *restrict stream, const char *restrict format, va_list arg);
     99extern int posix_scanf(const char *restrict format, ...);
     100extern int posix_vscanf(const char *restrict format, va_list arg);
     101extern int posix_sscanf(
     102    const char *restrict s, const char *restrict format, ...);
     103extern int posix_vsscanf(
     104    const char *restrict s, const char *restrict format, va_list arg);
     105
     106/* File Locking */
     107
     108extern void posix_flockfile(FILE *file);
     109extern int posix_ftrylockfile(FILE *file);
     110extern void posix_funlockfile(FILE *file);
     111
     112extern int posix_getc_unlocked(FILE *stream);
     113extern int posix_getchar_unlocked(void);
     114extern int posix_putc_unlocked(int c, FILE *stream);
     115extern int posix_putchar_unlocked(int c);
    67116
    68117/* Deleting Files */
     
    76125
    77126#ifndef LIBPOSIX_INTERNAL
     127        #define clearerr posix_clearerr
     128        #define ctermid posix_ctermid
     129
    78130        #define ungetc posix_ungetc
     131
     132        #define getdelim posix_getdelim
     133        #define getline posix_getline
    79134
    80135        #define freopen posix_freopen
    81136
     137        #define fmemopen posix_fmemopen
     138        #define open_memstream posix_open_memstream
     139
    82140        #define perror posix_perror
    83141
     142        #define fpos_t posix_fpos_t
     143        #define fsetpos posix_fsetpos
     144        #define fgetpos posix_fgetpos
     145        #define fseek posix_fseek
    84146        #define fseeko posix_fseeko
     147        #define ftell posix_ftell
    85148        #define ftello posix_ftello
    86149
     150        #define dprintf posix_dprintf
     151        #define vdprintf posix_vdprintf
    87152        #define sprintf posix_sprintf
    88153        #define vsprintf posix_vsprintf
     154
     155        #define fscanf posix_fscanf
     156        #define vfscanf posix_vfscanf
     157        #define vscanf posix_vscanf
     158        #define scanf posix_scanf
    89159        #define sscanf posix_sscanf
     160        #define vsscanf posix_vsscanf
     161
     162        #define flockfile posix_flockfile
     163        #define ftrylockfile posix_ftrylockfile
     164        #define funlockfile posix_funlockfile
     165
     166        #define getc_unlocked posix_getc_unlocked
     167        #define getchar_unlocked posix_getchar_unlocked
     168        #define putc_unlocked posix_putc_unlocked
     169        #define putchar_unlocked posix_putchar_unlocked
    90170
    91171        #define remove posix_remove
  • uspace/lib/posix/stdlib.c

    rf5b2522 r8cd8bf6  
    3636#define LIBPOSIX_INTERNAL
    3737
     38#include "internal/common.h"
    3839#include "stdlib.h"
     40
     41#include "errno.h"
     42
    3943#include "libc/sort.h"
    4044#include "libc/str.h"
    4145#include "libc/vfs/vfs.h"
    42 #include "internal/common.h"
    43 #include <errno.h>  // FIXME: use POSIX errno
    4446
    4547/**
     
    338340}
    339341
     342/**
     343 * Should read system load statistics. Not supported. Always returns -1.
     344 *
     345 * @param loadavg
     346 * @param nelem
     347 * @return
     348 */
     349int bsd_getloadavg(double loadavg[], int nelem)
     350{
     351        return -1;
     352}
     353
    340354/** @}
    341355 */
  • uspace/lib/posix/stdlib.h

    rf5b2522 r8cd8bf6  
    120120/* Legacy Declarations */
    121121extern char *posix_mktemp(char *tmpl);
     122extern int bsd_getloadavg(double loadavg[], int nelem);
    122123
    123124#ifndef LIBPOSIX_INTERNAL
     
    163164
    164165        #define mktemp posix_mktemp
     166        #define getloadavg bsd_getloadavg
    165167#endif
    166168
  • uspace/lib/posix/stdlib/strtol.c

    rf5b2522 r8cd8bf6  
    3737#include "../internal/common.h"
    3838#include "../stdlib.h"
    39 #include <errno.h>  // FIXME: use POSIX errno
     39
    4040#include "../limits.h"
    4141#include "../ctype.h"
     42#include "../errno.h"
    4243
    4344// TODO: documentation
  • uspace/lib/posix/stdlib/strtold.c

    rf5b2522 r8cd8bf6  
    3535#define LIBPOSIX_INTERNAL
    3636
     37/* Must be first. */
     38#include "../stdbool.h"
     39
    3740#include "../internal/common.h"
    38 
    39 #include "../libc/assert.h"
     41#include "../stdlib.h"
     42
     43#include "../assert.h"
    4044#include "../ctype.h"
    41 #include <errno.h> // TODO: use POSIX errno
    42 #include "../libc/bool.h"
    4345#include "../stdint.h"
    44 #include "../stdlib.h"
    4546#include "../strings.h"
     47#include "../errno.h"
    4648
    4749#ifndef HUGE_VALL
  • uspace/lib/posix/string.c

    rf5b2522 r8cd8bf6  
    3636#define LIBPOSIX_INTERNAL
    3737
     38#include "internal/common.h"
    3839#include "string.h"
    3940
    40 #include <assert.h>
    41 #include <str_error.h>
    42 #include <stdlib.h>
    43 #include <errno.h>
    44 
    45 /**
    46  * Defined for convenience. Returns pointer to the terminating nul character.
    47  *
    48  * @param s
    49  * @return
    50  */
    51 static char *strzero(const char *s)
    52 {
    53         while (*s != '\0') {
    54                 s++;
    55         }
    56 
    57         return (char *) s;
    58 }
     41#include "assert.h"
     42#include "errno.h"
     43#include "limits.h"
     44#include "stdlib.h"
     45#include "signal.h"
     46
     47#include "libc/str_error.h"
    5948
    6049/**
     
    183172        assert(src != NULL);
    184173
    185         posix_strcpy(strzero(dest), src);
     174        posix_strcpy(posix_strchr(dest, '\0'), src);
    186175        return dest;
    187176}
     
    199188        assert(src != NULL);
    200189
    201         char *zeroptr = posix_strncpy(strzero(dest), src, n);
     190        char *zeroptr = posix_strncpy(posix_strchr(dest, '\0'), src, n);
    202191        /* strncpy doesn't append the nul terminator, so we do it here */
    203192        zeroptr[n] = '\0';
     
    240229char *posix_strdup(const char *s)
    241230{
    242         // FIXME: SIZE_MAX doesn't work
    243         return posix_strndup(s, STR_NO_LIMIT);
     231        return posix_strndup(s, SIZE_MAX);
    244232}
    245233
     
    360348        assert(s != NULL);
    361349       
    362         /* special handling for the case that zero is searched for */
    363         if (c == '\0') {
    364                 return strzero(s);
    365         }
    366        
    367         /* otherwise just loop through the string until found */
    368         while (*s != (char) c) {
    369                 if (*s == '\0') {
    370                         return NULL;
    371                 }
    372 
    373                 s++;
    374         }
    375        
    376         return (char *) s;
     350        char *res = gnu_strchrnul(s, c);
     351        return (*res == c) ? res : NULL;
    377352}
    378353
     
    387362        assert(s != NULL);
    388363       
    389         const char *ptr = strzero(s);
     364        const char *ptr = posix_strchr(s, '\0');
    390365       
    391366        /* the same as in strchr, except it loops in reverse direction */
     
    399374
    400375        return (char *) ptr;
     376}
     377
     378char *gnu_strchrnul(const char *s, int c)
     379{
     380        assert(s != NULL);
     381       
     382        while (*s != c && *s != '\0') {
     383                s++;
     384        }
     385       
     386        return (char *) s;
    401387}
    402388
     
    524510char *posix_strerror(int errnum)
    525511{
    526         /* uses function from libc, we just have to negate errno
    527          * (POSIX uses positive errorcodes, HelenOS has negative)
     512        /* Uses function from libc, we just have to negate errno
     513         * (POSIX uses positive errorcodes, HelenOS has negative).
    528514         */
    529         return (char *) str_error(-errnum);
     515        // FIXME: not all POSIX error codes are in libc
     516        return (char *) str_error(-posix_abs(errnum));
    530517}
    531518
     
    562549        assert(s != NULL);
    563550       
    564         return (size_t) (strzero(s) - s);
     551        return (size_t) (posix_strchr(s, '\0') - s);
    565552}
    566553
     
    585572}
    586573
     574/**
     575 *
     576 * @param signum
     577 * @return
     578 */
     579char *posix_strsignal(int signum)
     580{
     581        static const char *const sigstrings[] = {
     582                [SIGABRT] = "SIGABRT (Process abort signal)",
     583                [SIGALRM] = "SIGALRM (Alarm clock)",
     584                [SIGBUS] = "SIGBUS (Access to an undefined portion of a memory object)",
     585                [SIGCHLD] = "SIGCHLD (Child process terminated, stopped, or continued)",
     586                [SIGCONT] = "SIGCONT (Continue executing, if stopped)",
     587                [SIGFPE] = "SIGFPE (Erroneous arithmetic operation)",
     588                [SIGHUP] = "SIGHUP (Hangup)",
     589                [SIGILL] = "SIGILL (Illegal instruction)",
     590                [SIGINT] = "SIGINT (Terminal interrupt signal)",
     591                [SIGKILL] = "SIGKILL (Kill process)",
     592                [SIGPIPE] = "SIGPIPE (Write on a pipe with no one to read it)",
     593                [SIGQUIT] = "SIGQUIT (Terminal quit signal)",
     594                [SIGSEGV] = "SIGSEGV (Invalid memory reference)",
     595                [SIGSTOP] = "SIGSTOP (Stop executing)",
     596                [SIGTERM] = "SIGTERM (Termination signal)",
     597                [SIGTSTP] = "SIGTSTP (Terminal stop signal)",
     598                [SIGTTIN] = "SIGTTIN (Background process attempting read)",
     599                [SIGTTOU] = "SIGTTOU (Background process attempting write)",
     600                [SIGUSR1] = "SIGUSR1 (User-defined signal 1)",
     601                [SIGUSR2] = "SIGUSR2 (User-defined signal 2)",
     602                [SIGPOLL] = "SIGPOLL (Pollable event)",
     603                [SIGPROF] = "SIGPROF (Profiling timer expired)",
     604                [SIGSYS] = "SIGSYS (Bad system call)",
     605                [SIGTRAP] = "SIGTRAP (Trace/breakpoint trap)",
     606                [SIGURG] = "SIGURG (High bandwidth data is available at a socket)",
     607                [SIGVTALRM] = "SIGVTALRM (Virtual timer expired)",
     608                [SIGXCPU] = "SIGXCPU (CPU time limit exceeded)",
     609                [SIGXFSZ] = "SIGXFSZ (File size limit exceeded)"
     610        };
     611
     612        if (signum <= _TOP_SIGNAL) {
     613                return (char *) sigstrings[signum];
     614        }
     615
     616        return (char *) "ERROR, Invalid signal number";
     617}
     618
    587619/** @}
    588620 */
  • uspace/lib/posix/string.h

    rf5b2522 r8cd8bf6  
    8585extern char *posix_strchr(const char *s, int c);
    8686extern char *posix_strrchr(const char *s, int c);
     87extern char *gnu_strchrnul(const char *s, int c);
    8788extern char *posix_strpbrk(const char *s1, const char *s2);
    8889extern size_t posix_strcspn(const char *s1, const char *s2);
     
    101102extern size_t posix_strlen(const char *s);
    102103extern size_t posix_strnlen(const char *s, size_t n);
     104
     105/* Signal messages */
     106extern char *posix_strsignal(int signum);
    103107
    104108/* Legacy declarations */
     
    127131        #define strchr posix_strchr
    128132        #define strrchr posix_strrchr
     133        #define strchrnul gnu_strchrnul
    129134        #define strpbrk posix_strpbrk
    130135        #define strcspn posix_strcspn
     
    141146        #define strnlen posix_strnlen
    142147
     148        #define strsignal posix_strsignal
     149
    143150        #define ffs posix_ffs
    144151        #define strcasecmp posix_strcasecmp
  • uspace/lib/posix/strings.c

    rf5b2522 r8cd8bf6  
    3838#include "internal/common.h"
    3939#include "strings.h"
     40
    4041#include "string.h"
    4142#include "ctype.h"
  • uspace/lib/posix/sys/stat.c

    rf5b2522 r8cd8bf6  
    3636#define LIBPOSIX_INTERNAL
    3737
     38#include "../internal/common.h"
    3839#include "stat.h"
    39 #include "../internal/common.h"
    40 #include <mem.h>
     40
     41#include "../errno.h"
     42#include "../libc/mem.h"
    4143
    4244/**
    43  * Convert HelenOS stat struct into POSIX stat struct (if possible)
     45 * Convert HelenOS stat struct into POSIX stat struct (if possible).
    4446 *
    45  * @param dest
    46  * @param src
     47 * @param dest POSIX stat struct.
     48 * @param src HelenOS stat struct.
    4749 */
    4850static void stat_to_posix(struct posix_stat *dest, struct stat *src)
     
    6668
    6769/**
     70 * Retrieve file status for file associated with file descriptor.
    6871 *
    69  * @param fd
    70  * @param st
    71  * @return
     72 * @param fd File descriptor of the opened file.
     73 * @param st Status structure to be filled with information.
     74 * @return Zero on success, -1 otherwise.
    7275 */
    7376int posix_fstat(int fd, struct posix_stat *st)
    7477{
    7578        struct stat hst;
    76         if (fstat(fd, &hst) == -1) {
    77                 // TODO: propagate a POSIX compatible errno
     79        int rc = fstat(fd, &hst);
     80        if (rc < 0) {
     81                /* fstat() returns negative error code instead of using errno.
     82                 */
     83                errno = -rc;
    7884                return -1;
    7985        }
     
    8389
    8490/**
     91 * Retrieve file status for symbolic link.
    8592 *
    86  * @param path
    87  * @param st
    88  * @return
     93 * @param path Path to the symbolic link.
     94 * @param st Status structure to be filled with information.
     95 * @return Zero on success, -1 otherwise.
    8996 */
    90 int posix_lstat(const char *restrict path, struct posix_stat *restrict st)
     97int posix_lstat(const char *path, struct posix_stat *st)
    9198{
    92         // TODO
    93         not_implemented();
     99        /* There are currently no symbolic links in HelenOS. */
     100        return posix_stat(path, st);
    94101}
    95102
    96103/**
     104 * Retrieve file status for regular file (or symbolic link target).
    97105 *
    98  * @param path
    99  * @param st
    100  * @return
     106 * @param path Path to the file/link.
     107 * @param st Status structure to be filled with information.
     108 * @return Zero on success, -1 otherwise.
    101109 */
    102110int posix_stat(const char *path, struct posix_stat *st)
    103111{
    104112        struct stat hst;
    105         if (stat(path, &hst) == -1) {
    106                 // TODO: propagate a POSIX compatible errno
     113        int rc = stat(path, &hst);
     114        if (rc < 0) {
     115                /* stat() returns negative error code instead of using errno.
     116                 */
     117                errno = -rc;
    107118                return -1;
    108119        }
     
    112123
    113124/**
     125 * Change permission bits for the file if possible.
    114126 *
    115  * @param path
    116  * @param mode
    117  * @return
     127 * @param path Path to the file.
     128 * @param mode Permission bits to be set.
     129 * @return Zero on success, -1 otherwise.
    118130 */
    119131int posix_chmod(const char *path, mode_t mode)
    120132{
    121         // TODO
    122         not_implemented();
     133        /* HelenOS doesn't support permissions, return success. */
     134        return 0;
    123135}
    124136
    125137/**
     138 * Set the file mode creation mask of the process.
    126139 *
    127  * @param mask
    128  * @return
     140 * @param mask Set permission bits are cleared in the related creation
     141 *     functions. Non-permission bits are ignored.
     142 * @return Previous file mode creation mask.
    129143 */
    130144mode_t posix_umask(mode_t mask)
    131145{
    132         // TODO
    133         not_implemented();
     146        /* HelenOS doesn't support permissions, return empty mask. */
     147        return 0;
    134148}
    135149
  • uspace/lib/posix/sys/types.h

    rf5b2522 r8cd8bf6  
    5252typedef struct posix_thread_attr posix_thread_attr_t;
    5353
     54/* Clock types */
     55typedef long posix_clock_t;
     56typedef int posix_clockid_t;
     57
    5458#ifndef LIBPOSIX_INTERNAL
    5559        #define ino_t posix_ino_t
     
    6468       
    6569        #define pthread_attr_t posix_thread_attr_t
     70       
     71        #define clock_t posix_clock_t
     72        #define clockid_t posix_clockid_t
    6673#endif
    6774
  • uspace/lib/posix/time.c

    rf5b2522 r8cd8bf6  
    3636#define LIBPOSIX_INTERNAL
    3737
     38/* Must be first. */
     39#include "stdbool.h"
     40
    3841#include "internal/common.h"
    3942#include "time.h"
    4043
     44#include "ctype.h"
     45#include "errno.h"
     46#include "signal.h"
     47
     48#include "libc/malloc.h"
     49#include "libc/task.h"
     50#include "libc/stats.h"
     51#include "libc/sys/time.h"
     52
     53// TODO: documentation
     54// TODO: test everything in this file
     55
     56/* Helper functions ***********************************************************/
     57
     58#define HOURS_PER_DAY (24)
     59#define MINS_PER_HOUR (60)
     60#define SECS_PER_MIN (60)
     61#define MINS_PER_DAY (MINS_PER_HOUR * HOURS_PER_DAY)
     62#define SECS_PER_HOUR (SECS_PER_MIN * MINS_PER_HOUR)
     63#define SECS_PER_DAY (SECS_PER_HOUR * HOURS_PER_DAY)
     64
     65static bool _is_leap_year(time_t year)
     66{
     67        year += 1900;
     68
     69        if (year % 400 == 0)
     70                return true;
     71        if (year % 100 == 0)
     72                return false;
     73        if (year % 4 == 0)
     74                return true;
     75        return false;
     76}
     77
     78static int _days_in_month(time_t year, time_t mon)
     79{
     80        assert(mon >= 0 && mon <= 11);
     81        year += 1900;
     82
     83        static int month_days[] =
     84                { 31, 0, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31 };
     85
     86        if (mon == 1) {
     87                /* february */
     88                return _is_leap_year(year) ? 29 : 28;
     89        } else {
     90                return month_days[mon];
     91        }
     92}
     93
     94static int _day_of_year(time_t year, time_t mon, time_t mday)
     95{
     96        static int mdays[] =
     97            { 0, 31, 59, 90, 120, 151, 181, 212, 243, 273, 304, 334 };
     98        static int leap_mdays[] =
     99            { 0, 31, 60, 91, 121, 152, 182, 213, 244, 274, 305, 335 };
     100
     101        return (_is_leap_year(year) ? leap_mdays[mon] : mdays[mon]) + mday - 1;
     102}
     103
     104/* Integer division that rounds to negative infinity.
     105 */
     106static time_t _floor_div(time_t op1, time_t op2)
     107{
     108        if (op1 >= 0 || op1 % op2 == 0) {
     109                return op1 / op2;
     110        } else {
     111                return op1 / op2 - 1;
     112        }
     113}
     114
     115/* Modulo that rounds to negative infinity.
     116 */
     117static time_t _floor_mod(time_t op1, time_t op2)
     118{
     119        int div = _floor_div(op1, op2);
     120
     121        /* (a / b) * b + a % b == a */
     122        /* thus, a % b == a - (a / b) * b */
     123
     124        int result = op1 - div * op2;
     125       
     126        /* Some paranoid checking to ensure I didn't make a mistake here. */
     127        assert(result >= 0);
     128        assert(result < op2);
     129        assert(div * op2 + result == op1);
     130       
     131        return result;
     132}
     133
     134static time_t _days_since_epoch(time_t year, time_t mon, time_t mday)
     135{
     136        return (year - 70) * 365 + _floor_div(year - 69, 4) -
     137            _floor_div(year - 1, 100) + _floor_div(year + 299, 400) +
     138            _day_of_year(year, mon, mday);
     139}
     140
     141/* Assumes normalized broken-down time. */
     142static time_t _secs_since_epoch(const struct posix_tm *tm)
     143{
     144        return _days_since_epoch(tm->tm_year, tm->tm_mon, tm->tm_mday) *
     145            SECS_PER_DAY + tm->tm_hour * SECS_PER_HOUR +
     146            tm->tm_min * SECS_PER_MIN + tm->tm_sec;
     147}
     148
     149static int _day_of_week(time_t year, time_t mon, time_t mday)
     150{
     151        /* 1970-01-01 is Thursday */
     152        return (_days_since_epoch(year, mon, mday) + 4) % 7;
     153}
     154
     155struct _long_tm {
     156        time_t tm_sec;
     157        time_t tm_min;
     158        time_t tm_hour;
     159        time_t tm_mday;
     160        time_t tm_mon;
     161        time_t tm_year;
     162        int tm_wday;
     163        int tm_yday;
     164        int tm_isdst;
     165};
     166
     167static void _posix_to_long_tm(struct _long_tm *ltm, struct posix_tm *ptm)
     168{
     169        assert(ltm != NULL && ptm != NULL);
     170        ltm->tm_sec = ptm->tm_sec;
     171        ltm->tm_min = ptm->tm_min;
     172        ltm->tm_hour = ptm->tm_hour;
     173        ltm->tm_mday = ptm->tm_mday;
     174        ltm->tm_mon = ptm->tm_mon;
     175        ltm->tm_year = ptm->tm_year;
     176        ltm->tm_wday = ptm->tm_wday;
     177        ltm->tm_yday = ptm->tm_yday;
     178        ltm->tm_isdst = ptm->tm_isdst;
     179}
     180
     181static void _long_to_posix_tm(struct posix_tm *ptm, struct _long_tm *ltm)
     182{
     183        assert(ltm != NULL && ptm != NULL);
     184        // FIXME: the cast should be unnecessary, libarch/common.h brain-damage
     185        assert((ltm->tm_year >= (int) INT_MIN) && (ltm->tm_year <= (int) INT_MAX));
     186
     187        ptm->tm_sec = ltm->tm_sec;
     188        ptm->tm_min = ltm->tm_min;
     189        ptm->tm_hour = ltm->tm_hour;
     190        ptm->tm_mday = ltm->tm_mday;
     191        ptm->tm_mon = ltm->tm_mon;
     192        ptm->tm_year = ltm->tm_year;
     193        ptm->tm_wday = ltm->tm_wday;
     194        ptm->tm_yday = ltm->tm_yday;
     195        ptm->tm_isdst = ltm->tm_isdst;
     196}
     197
     198static void _normalize_time(struct _long_tm *tm)
     199{
     200        // TODO: DST correction
     201
     202        /* Adjust time. */
     203        tm->tm_min += _floor_div(tm->tm_sec, SECS_PER_MIN);
     204        tm->tm_sec = _floor_mod(tm->tm_sec, SECS_PER_MIN);
     205        tm->tm_hour += _floor_div(tm->tm_min, MINS_PER_HOUR);
     206        tm->tm_min = _floor_mod(tm->tm_min, MINS_PER_HOUR);
     207        tm->tm_mday += _floor_div(tm->tm_hour, HOURS_PER_DAY);
     208        tm->tm_hour = _floor_mod(tm->tm_hour, HOURS_PER_DAY);
     209
     210        /* Adjust month. */
     211        tm->tm_year += _floor_div(tm->tm_mon, 12);
     212        tm->tm_mon = _floor_mod(tm->tm_mon, 12);
     213
     214        /* Now the difficult part - days of month. */
     215        /* Slow, but simple. */
     216        // FIXME: do this faster
     217
     218        while (tm->tm_mday < 1) {
     219                tm->tm_mon--;
     220                if (tm->tm_mon == -1) {
     221                        tm->tm_mon = 11;
     222                        tm->tm_year--;
     223                }
     224               
     225                tm->tm_mday += _days_in_month(tm->tm_year, tm->tm_mon);
     226        }
     227
     228        while (tm->tm_mday > _days_in_month(tm->tm_year, tm->tm_mon)) {
     229                tm->tm_mday -= _days_in_month(tm->tm_year, tm->tm_mon);
     230               
     231                tm->tm_mon++;
     232                if (tm->tm_mon == 12) {
     233                        tm->tm_mon = 0;
     234                        tm->tm_year++;
     235                }
     236        }
     237
     238        /* Calculate the remaining two fields. */
     239        tm->tm_yday = _day_of_year(tm->tm_year, tm->tm_mon, tm->tm_mday);
     240        tm->tm_wday = _day_of_week(tm->tm_year, tm->tm_mon, tm->tm_mday);
     241}
     242
     243/* Which day the week-based year starts on relative to the first calendar day.
     244 * E.g. if the year starts on December 31st, the return value is -1.
     245 */
     246static int _wbyear_offset(int year)
     247{
     248        int start_wday = _day_of_week(year, 0, 1);
     249        return _floor_mod(4 - start_wday, 7) - 3;
     250}
     251
     252/* Returns week-based year of the specified time.
     253 * Assumes normalized broken-down time.
     254 */
     255static int _wbyear(const struct posix_tm *tm)
     256{
     257        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     258        if (day < 0) {
     259                /* Last week of previous year. */
     260                return tm->tm_year - 1;
     261        }
     262        if (day > 364 + _is_leap_year(tm->tm_year)){
     263                /* First week of next year. */
     264                return tm->tm_year + 1;
     265        }
     266        /* All the other days are in the calendar year. */
     267        return tm->tm_year;
     268}
     269
     270/** Week number of the year, assuming weeks start on sunday.
     271 *  The first Sunday of January is the first day of week 1;
     272 *  days in the new year before this are in week 0.
     273 *
     274 * @param tm Normalized broken-down time.
     275 * @return The week number (0 - 53).
     276 */
     277static int _sun_week_number(const struct posix_tm *tm)
     278{
     279        int first_day = (7 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     280        return (tm->tm_yday - first_day + 7) / 7;
     281}
     282
     283/** Week number of the year, assuming weeks start on monday.
     284 *  If the week containing January 1st has four or more days in the new year,
     285 *  then it is considered week 1. Otherwise, it is the last week of the previous
     286 *  year, and the next week is week 1. Both January 4th and the first Thursday
     287 *  of January are always in week 1.
     288 *
     289 * @param tm Normalized broken-down time.
     290 * @return The week number (1 - 53).
     291 */
     292static int _iso_week_number(const struct posix_tm *tm)
     293{
     294        int day = tm->tm_yday - _wbyear_offset(tm->tm_year);
     295        if (day < 0) {
     296                /* Last week of previous year. */
     297                return 53;
     298        }
     299        if (day > 364 + _is_leap_year(tm->tm_year)){
     300                /* First week of next year. */
     301                return 1;
     302        }
     303        /* All the other days give correct answer. */
     304        return (day / 7 + 1);
     305}
     306
     307/** Week number of the year, assuming weeks start on monday.
     308 *  The first Monday of January is the first day of week 1;
     309 *  days in the new year before this are in week 0.
     310 *
     311 * @param tm Normalized broken-down time.
     312 * @return The week number (0 - 53).
     313 */
     314static int _mon_week_number(const struct posix_tm *tm)
     315{
     316        int first_day = (1 - _day_of_week(tm->tm_year, 0, 1)) % 7;
     317        return (tm->tm_yday - first_day + 7) / 7;
     318}
     319
     320/******************************************************************************/
     321
     322int posix_daylight;
     323long posix_timezone;
     324char *posix_tzname[2];
     325
     326void posix_tzset(void)
     327{
     328        // TODO: read environment
     329        posix_tzname[0] = (char *) "GMT";
     330        posix_tzname[1] = (char *) "GMT";
     331        posix_daylight = 0;
     332        posix_timezone = 0;
     333}
     334
     335double posix_difftime(time_t time1, time_t time0)
     336{
     337        return (double) (time1 - time0);
     338}
     339
     340/** This function first normalizes the provided broken-down time
     341 *  (moves all values to their proper bounds) and then tries to
     342 *  calculate the appropriate time_t representation.
     343 *
     344 * @param timeptr Broken-down time.
     345 * @return time_t representation of the time, undefined value on overflow
     346 */
     347time_t posix_mktime(struct posix_tm *tm)
     348{
     349        // TODO: take DST flag into account
     350        // TODO: detect overflow
     351
     352        struct _long_tm ltm;
     353        _posix_to_long_tm(&ltm, tm);
     354        _normalize_time(&ltm);
     355        _long_to_posix_tm(tm, &ltm);
     356
     357        return _secs_since_epoch(tm);
     358}
     359
     360struct posix_tm *posix_gmtime(const time_t *timer)
     361{
     362        static struct posix_tm result;
     363        return posix_gmtime_r(timer, &result);
     364}
     365
     366struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
     367    struct posix_tm *restrict result)
     368{
     369        assert(timer != NULL);
     370        assert(result != NULL);
     371
     372        /* Set epoch and seconds to _long_tm struct and normalize to get
     373         * correct values.
     374         */
     375        struct _long_tm ltm = {
     376                .tm_sec = *timer,
     377                .tm_min = 0,
     378                .tm_hour = 0, /* 00:00:xx */
     379                .tm_mday = 1,
     380                .tm_mon = 0, /* January 1st */
     381                .tm_year = 70, /* 1970 */
     382        };
     383        _normalize_time(&ltm);
     384
     385        if (ltm.tm_year < (int) INT_MIN || ltm.tm_year > (int) INT_MAX) {
     386                errno = EOVERFLOW;
     387                return NULL;
     388        }
     389
     390        _long_to_posix_tm(result, &ltm);
     391        return result;
     392}
     393
    41394/**
    42395 *
     
    44397 * @return
    45398 */
    46 struct posix_tm *posix_localtime(const time_t *timep)
    47 {
    48         // TODO
    49         static struct posix_tm result = { 0, 0, 0, 0, 0, 0, 0, 0, 0 };
    50         return &result;
     399struct posix_tm *posix_localtime(const time_t *timer)
     400{
     401        static struct posix_tm result;
     402        return posix_localtime_r(timer, &result);
     403}
     404
     405struct posix_tm *posix_localtime_r(const time_t *restrict timer,
     406    struct posix_tm *restrict result)
     407{
     408        // TODO: deal with timezone
     409        // currently assumes system and all times are in GMT
     410        return posix_gmtime_r(timer, result);
    51411}
    52412
     
    56416 * @return
    57417 */
    58 char *posix_asctime(const struct posix_tm *tm)
    59 {
    60         // TODO
    61         static char result[] = "Sun Jan 01 00:00:00 1900\n";
    62         return result;
     418char *posix_asctime(const struct posix_tm *timeptr)
     419{
     420        static char buf[ASCTIME_BUF_LEN];
     421        return posix_asctime_r(timeptr, buf);
     422}
     423
     424char *posix_asctime_r(const struct posix_tm *restrict timeptr,
     425    char *restrict buf)
     426{
     427        assert(timeptr != NULL);
     428        assert(buf != NULL);
     429
     430        static const char *wday[] = {
     431                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     432        };
     433        static const char *mon[] = {
     434                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     435                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     436        };
     437
     438        snprintf(buf, ASCTIME_BUF_LEN, "%s %s %2d %02d:%02d:%02d %d\n",
     439            wday[timeptr->tm_wday],
     440            mon[timeptr->tm_mon],
     441            timeptr->tm_mday, timeptr->tm_hour,
     442            timeptr->tm_min, timeptr->tm_sec,
     443            1900 + timeptr->tm_year);
     444
     445        return buf;
    63446}
    64447
     
    68451 * @return
    69452 */
    70 char *posix_ctime(const time_t *timep)
    71 {
    72         return posix_asctime(posix_localtime(timep));
     453char *posix_ctime(const time_t *timer)
     454{
     455        struct posix_tm *loctime = posix_localtime(timer);
     456        if (loctime == NULL) {
     457                return NULL;
     458        }
     459        return posix_asctime(loctime);
     460}
     461
     462char *posix_ctime_r(const time_t *timer, char *buf)
     463{
     464        struct posix_tm loctime;
     465        if (posix_localtime_r(timer, &loctime) == NULL) {
     466                return NULL;
     467        }
     468        return posix_asctime_r(&loctime, buf);
    73469}
    74470
     
    81477 * @return
    82478 */
    83 size_t posix_strftime(char *s, size_t maxsize, const char *format, const struct posix_tm *tm)
     479size_t posix_strftime(char *s, size_t maxsize,
     480    const char *format, const struct posix_tm *tm)
     481{
     482        // TODO: use locale
     483        static const char *wday_abbr[] = {
     484                "Sun", "Mon", "Tue", "Wed", "Thu", "Fri", "Sat"
     485        };
     486        static const char *wday[] = {
     487                "Sunday", "Monday", "Tuesday", "Wednesday",
     488                "Thursday", "Friday", "Saturday"
     489        };
     490        static const char *mon_abbr[] = {
     491                "Jan", "Feb", "Mar", "Apr", "May", "Jun",
     492                "Jul", "Aug", "Sep", "Oct", "Nov", "Dec"
     493        };
     494        static const char *mon[] = {
     495                "January", "February", "March", "April", "May", "June", "July",
     496                "August", "September", "October", "November", "December"
     497        };
     498       
     499        if (maxsize < 1) {
     500                return 0;
     501        }
     502       
     503        char *ptr = s;
     504        size_t consumed;
     505        size_t remaining = maxsize;
     506       
     507        #define append(...) { \
     508                /* FIXME: this requires POSIX-correct snprintf */ \
     509                /*        otherwise it won't work with non-ascii chars */ \
     510                consumed = snprintf(ptr, remaining, __VA_ARGS__); \
     511                if (consumed >= remaining) { \
     512                        return 0; \
     513                } \
     514                ptr += consumed; \
     515                remaining -= consumed; \
     516        }
     517       
     518        #define recurse(fmt) { \
     519                consumed = posix_strftime(ptr, remaining, fmt, tm); \
     520                if (consumed == 0) { \
     521                        return 0; \
     522                } \
     523                ptr += consumed; \
     524                remaining -= consumed; \
     525        }
     526       
     527        #define TO_12H(hour) (((hour) > 12) ? ((hour) - 12) : \
     528            (((hour) == 0) ? 12 : (hour)))
     529       
     530        while (*format != '\0') {
     531                if (*format != '%') {
     532                        append("%c", *format);
     533                        format++;
     534                        continue;
     535                }
     536               
     537                format++;
     538                if (*format == '0' || *format == '+') {
     539                        // TODO: padding
     540                        format++;
     541                }
     542                while (isdigit(*format)) {
     543                        // TODO: padding
     544                        format++;
     545                }
     546                if (*format == 'O' || *format == 'E') {
     547                        // TODO: locale's alternative format
     548                        format++;
     549                }
     550               
     551                switch (*format) {
     552                case 'a':
     553                        append("%s", wday_abbr[tm->tm_wday]); break;
     554                case 'A':
     555                        append("%s", wday[tm->tm_wday]); break;
     556                case 'b':
     557                        append("%s", mon_abbr[tm->tm_mon]); break;
     558                case 'B':
     559                        append("%s", mon[tm->tm_mon]); break;
     560                case 'c':
     561                        // TODO: locale-specific datetime format
     562                        recurse("%Y-%m-%d %H:%M:%S"); break;
     563                case 'C':
     564                        append("%02d", (1900 + tm->tm_year) / 100); break;
     565                case 'd':
     566                        append("%02d", tm->tm_mday); break;
     567                case 'D':
     568                        recurse("%m/%d/%y"); break;
     569                case 'e':
     570                        append("%2d", tm->tm_mday); break;
     571                case 'F':
     572                        recurse("%+4Y-%m-%d"); break;
     573                case 'g':
     574                        append("%02d", _wbyear(tm) % 100); break;
     575                case 'G':
     576                        append("%d", _wbyear(tm)); break;
     577                case 'h':
     578                        recurse("%b"); break;
     579                case 'H':
     580                        append("%02d", tm->tm_hour); break;
     581                case 'I':
     582                        append("%02d", TO_12H(tm->tm_hour)); break;
     583                case 'j':
     584                        append("%03d", tm->tm_yday); break;
     585                case 'k':
     586                        append("%2d", tm->tm_hour); break;
     587                case 'l':
     588                        append("%2d", TO_12H(tm->tm_hour)); break;
     589                case 'm':
     590                        append("%02d", tm->tm_mon); break;
     591                case 'M':
     592                        append("%02d", tm->tm_min); break;
     593                case 'n':
     594                        append("\n"); break;
     595                case 'p':
     596                        append("%s", tm->tm_hour < 12 ? "AM" : "PM"); break;
     597                case 'P':
     598                        append("%s", tm->tm_hour < 12 ? "am" : "PM"); break;
     599                case 'r':
     600                        recurse("%I:%M:%S %p"); break;
     601                case 'R':
     602                        recurse("%H:%M"); break;
     603                case 's':
     604                        append("%ld", _secs_since_epoch(tm)); break;
     605                case 'S':
     606                        append("%02d", tm->tm_sec); break;
     607                case 't':
     608                        append("\t"); break;
     609                case 'T':
     610                        recurse("%H:%M:%S"); break;
     611                case 'u':
     612                        append("%d", (tm->tm_wday == 0) ? 7 : tm->tm_wday); break;
     613                case 'U':
     614                        append("%02d", _sun_week_number(tm)); break;
     615                case 'V':
     616                        append("%02d", _iso_week_number(tm)); break;
     617                case 'w':
     618                        append("%d", tm->tm_wday); break;
     619                case 'W':
     620                        append("%02d", _mon_week_number(tm)); break;
     621                case 'x':
     622                        // TODO: locale-specific date format
     623                        recurse("%Y-%m-%d"); break;
     624                case 'X':
     625                        // TODO: locale-specific time format
     626                        recurse("%H:%M:%S"); break;
     627                case 'y':
     628                        append("%02d", tm->tm_year % 100); break;
     629                case 'Y':
     630                        append("%d", 1900 + tm->tm_year); break;
     631                case 'z':
     632                        // TODO: timezone
     633                        break;
     634                case 'Z':
     635                        // TODO: timezone
     636                        break;
     637                case '%':
     638                        append("%%");
     639                        break;
     640                default:
     641                        /* Invalid specifier, print verbatim. */
     642                        while (*format != '%') {
     643                                format--;
     644                        }
     645                        append("%%");
     646                        break;
     647                }
     648                format++;
     649        }
     650       
     651        #undef append
     652        #undef recurse
     653       
     654        return maxsize - remaining;
     655}
     656
     657int posix_clock_getres(posix_clockid_t clock_id, struct posix_timespec *res)
     658{
     659        assert(res != NULL);
     660
     661        switch (clock_id) {
     662                case CLOCK_REALTIME:
     663                        res->tv_sec = 0;
     664                        res->tv_nsec = 1000; /* Microsecond resolution. */
     665                        return 0;
     666                default:
     667                        errno = EINVAL;
     668                        return -1;
     669        }
     670}
     671
     672int posix_clock_gettime(posix_clockid_t clock_id, struct posix_timespec *tp)
     673{
     674        assert(tp != NULL);
     675
     676        switch (clock_id) {
     677                case CLOCK_REALTIME:
     678                        ;
     679                        struct timeval tv;
     680                        gettimeofday(&tv, NULL);
     681                        tp->tv_sec = tv.tv_sec;
     682                        tp->tv_nsec = tv.tv_usec * 1000;
     683                        return 0;
     684                default:
     685                        errno = EINVAL;
     686                        return -1;
     687        }
     688}
     689
     690int posix_clock_settime(posix_clockid_t clock_id,
     691    const struct posix_timespec *tp)
     692{
     693        assert(tp != NULL);
     694
     695        switch (clock_id) {
     696                case CLOCK_REALTIME:
     697                        // TODO: setting clock
     698                        // FIXME: HelenOS doesn't actually support hardware
     699                        //        clock yet
     700                        errno = EPERM;
     701                        return -1;
     702                default:
     703                        errno = EINVAL;
     704                        return -1;
     705        }
     706}
     707
     708int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
     709    const struct posix_timespec *rqtp, struct posix_timespec *rmtp)
     710{
     711        assert(rqtp != NULL);
     712        assert(rmtp != NULL);
     713
     714        switch (clock_id) {
     715                case CLOCK_REALTIME:
     716                        // TODO: interruptible sleep
     717                        if (rqtp->tv_sec != 0) {
     718                                sleep(rqtp->tv_sec);
     719                        }
     720                        if (rqtp->tv_nsec != 0) {
     721                                usleep(rqtp->tv_nsec / 1000);
     722                        }
     723                        return 0;
     724                default:
     725                        errno = EINVAL;
     726                        return -1;
     727        }
     728}
     729
     730#if 0
     731
     732struct __posix_timer {
     733        posix_clockid_t clockid;
     734        struct posix_sigevent evp;
     735};
     736
     737int posix_timer_create(posix_clockid_t clockid,
     738    struct posix_sigevent *restrict evp,
     739    posix_timer_t *restrict timerid)
    84740{
    85741        // TODO
     
    87743}
    88744
    89 /**
    90  *
    91  * @return
    92  */
    93 posix_clock_t posix_clock(void)
     745int posix_timer_delete(posix_timer_t timerid)
    94746{
    95747        // TODO
     
    97749}
    98750
     751int posix_timer_getoverrun(posix_timer_t timerid)
     752{
     753        // TODO
     754        not_implemented();
     755}
     756
     757int posix_timer_gettime(posix_timer_t timerid,
     758    struct posix_itimerspec *value)
     759{
     760        // TODO
     761        not_implemented();
     762}
     763
     764int posix_timer_settime(posix_timer_t timerid, int flags,
     765    const struct posix_itimerspec *restrict value,
     766    struct posix_itimerspec *restrict ovalue)
     767{
     768        // TODO
     769        not_implemented();
     770}
     771
     772#endif
     773
     774/**
     775 * Get CPU time used since the process invocation.
     776 *
     777 * @return Consumed CPU cycles by this process or -1 if not available.
     778 */
     779posix_clock_t posix_clock(void)
     780{
     781        posix_clock_t total_cycles = -1;
     782        stats_task_t *task_stats = stats_get_task(task_get_id());
     783        if (task_stats) {
     784                total_cycles = (posix_clock_t) (task_stats->kcycles + task_stats->ucycles);
     785        }
     786        free(task_stats);
     787        task_stats = 0;
     788
     789        return total_cycles;
     790}
     791
    99792/** @}
    100793 */
  • uspace/lib/posix/time.h

    rf5b2522 r8cd8bf6  
    3838
    3939#include "libc/time.h"
     40#include "sys/types.h"
    4041
    4142#ifndef NULL
    4243        #define NULL  ((void *) 0)
    4344#endif
     45
     46#ifndef CLOCKS_PER_SEC
     47        #define CLOCKS_PER_SEC (1000000L)
     48#endif
     49
     50#ifndef __locale_t_defined
     51        #define __locale_t_defined
     52        typedef struct __posix_locale *posix_locale_t;
     53        #ifndef LIBPOSIX_INTERNAL
     54                #define locale_t posix_locale_t
     55        #endif
     56#endif
     57
     58#ifndef POSIX_SIGNAL_H_
     59        struct posix_sigevent;
     60        #ifndef LIBPOSIX_INTERNAL
     61                #define sigevent posix_sigevent
     62        #endif
     63#endif
     64
     65#undef ASCTIME_BUF_LEN
     66#define ASCTIME_BUF_LEN 26
     67
     68#undef CLOCK_REALTIME
     69#define CLOCK_REALTIME ((posix_clockid_t) 0)
    4470
    4571struct posix_tm {
     
    5581};
    5682
    57 typedef long posix_clock_t;
     83struct posix_timespec {
     84        time_t tv_sec; /* Seconds. */
     85        long tv_nsec; /* Nanoseconds. */
     86};
     87
     88struct posix_itimerspec {
     89        struct posix_timespec it_interval; /* Timer period. */
     90        struct posix_timespec it_value; /* Timer expiration. */
     91};
     92
     93typedef struct __posix_timer *posix_timer_t;
     94
     95/* Timezones */
     96
     97extern int posix_daylight;
     98extern long posix_timezone;
     99extern char *posix_tzname[2];
     100
     101extern void posix_tzset(void);
     102
     103/* time_t */
     104
     105extern double posix_difftime(time_t time1, time_t time0);
    58106
    59107/* Broken-down Time */
    60 extern struct posix_tm *posix_localtime(const time_t *timep);
     108extern time_t posix_mktime(struct posix_tm *timeptr);
     109extern struct posix_tm *posix_gmtime(const time_t *timer);
     110extern struct posix_tm *posix_gmtime_r(const time_t *restrict timer,
     111    struct posix_tm *restrict result);
     112extern struct posix_tm *posix_localtime(const time_t *timer);
     113extern struct posix_tm *posix_localtime_r(const time_t *restrict timer,
     114    struct posix_tm *restrict result);
    61115
    62116/* Formatting Calendar Time */
    63 extern char *posix_asctime(const struct posix_tm *tm);
    64 extern char *posix_ctime(const time_t *timep);
    65 extern size_t posix_strftime(char *restrict s, size_t maxsize, const char *restrict format, const struct posix_tm *restrict tm);
     117extern char *posix_asctime(const struct posix_tm *timeptr);
     118extern char *posix_asctime_r(const struct posix_tm *restrict timeptr,
     119    char *restrict buf);
     120extern char *posix_ctime(const time_t *timer);
     121extern char *posix_ctime_r(const time_t *timer, char *buf);
     122
     123extern size_t posix_strftime(char *restrict s, size_t maxsize,
     124    const char *restrict format, const struct posix_tm *restrict tm);
     125
     126extern size_t posix_strftime_l(char *restrict s, size_t maxsize,
     127    const char *restrict format, const struct posix_tm *restrict tm,
     128    posix_locale_t loc);
     129
     130/* Clocks. */
     131
     132extern int posix_clock_getres(posix_clockid_t clock_id,
     133    struct posix_timespec *res);
     134extern int posix_clock_gettime(posix_clockid_t clock_id,
     135    struct posix_timespec *tp);
     136extern int posix_clock_settime(posix_clockid_t clock_id,
     137    const struct posix_timespec *tp);
     138extern int posix_clock_nanosleep(posix_clockid_t clock_id, int flags,
     139    const struct posix_timespec *rqtp, struct posix_timespec *rmtp);
     140
     141/* Timers. */
     142
     143#if 0
     144
     145extern int posix_timer_create(posix_clockid_t clockid,
     146    struct posix_sigevent *restrict evp,
     147    posix_timer_t *restrict timerid);
     148extern int posix_timer_delete(posix_timer_t timerid);
     149extern int posix_timer_getoverrun(posix_timer_t timerid);
     150extern int posix_timer_gettime(posix_timer_t timerid,
     151    struct posix_itimerspec *value);
     152extern int posix_timer_settime(posix_timer_t timerid, int flags,
     153    const struct posix_itimerspec *restrict value,
     154    struct posix_itimerspec *restrict ovalue);
     155
     156#endif
    66157
    67158/* CPU Time */
    68159extern posix_clock_t posix_clock(void);
    69160
     161
    70162#ifndef LIBPOSIX_INTERNAL
    71163        #define tm posix_tm
    72164
    73         #define clock_t posix_clock_t
    74 
     165        #define timespec posix_timespec
     166        #define itimerspec posix_itimerspec
     167        #define timer_t posix_timer_t
     168
     169        #define difftime posix_difftime
     170        #define mktime posix_mktime
     171        #define gmtime posix_gmtime
     172        #define gmtime_r posix_gmtime_r
    75173        #define localtime posix_localtime
     174        #define localtime_r posix_localtime_r
     175
     176        #define daylight posix_daylight
     177        #define timezone posix_timezone
     178        #define tzname posix_tzname
     179        #define tzset posix_tzset
    76180
    77181        #define asctime posix_asctime
     182        #define asctime_r posix_asctime_r
    78183        #define ctime posix_ctime
     184        #define ctime_r posix_ctime_r
    79185        #define strftime posix_strftime
    80186
     187        #define clock_getres posix_clock_getres
     188        #define clock_gettime posix_clock_gettime
     189        #define clock_settime posix_clock_settime
     190        #define clock_nanosleep posix_clock_nanosleep
     191       
     192        #define timer_create posix_timer_create
     193        #define timer_delete posix_timer_delete
     194        #define timer_getoverrun posix_timer_getoverrun
     195        #define timer_gettime posix_timer_gettime
     196        #define timer_settime posix_timer_settime
     197       
    81198        #define clock posix_clock
    82199#endif
  • uspace/lib/posix/unistd.c

    rf5b2522 r8cd8bf6  
    3838#include "internal/common.h"
    3939#include "unistd.h"
    40 #include <task.h>
     40
     41#include "errno.h"
     42#include "string.h"
     43#include "fcntl.h"
     44
     45#include "libc/task.h"
     46#include "libc/stats.h"
     47#include "libc/malloc.h"
    4148
    4249/* Array of environment variable strings (NAME=VALUE). */
    43 char **environ = NULL;
    44 
    45 /**
    46  * Dummy function. Always returns false, because there is no easy way to find
    47  * out under HelenOS.
    48  *
    49  * @param fd
    50  * @return Always false.
     50char **posix_environ = NULL;
     51
     52/**
     53 * Get current user name.
     54 *
     55 * @return User name (static) string or NULL if not found.
     56 */
     57char *posix_getlogin(void)
     58{
     59        /* There is currently no support for user accounts in HelenOS. */
     60        return (char *) "user";
     61}
     62
     63/**
     64 * Get current user name.
     65 *
     66 * @param name Pointer to a user supplied buffer.
     67 * @param namesize Length of the buffer.
     68 * @return Zero on success, error code otherwise.
     69 */
     70int posix_getlogin_r(char *name, size_t namesize)
     71{
     72        /* There is currently no support for user accounts in HelenOS. */
     73        if (namesize >= 5) {
     74                posix_strcpy(name, (char *) "user");
     75                return 0;
     76        } else {
     77                errno = ERANGE;
     78                return -1;
     79        }
     80}
     81
     82/**
     83 * Test whether open file descriptor is associated with a terminal.
     84 *
     85 * @param fd Open file descriptor to test.
     86 * @return Boolean result of the test.
    5187 */
    5288int posix_isatty(int fd)
    5389{
     90        /* Always returns false, because there is no easy way to find
     91     * out under HelenOS. */
    5492        return false;
    5593}
    5694
    5795/**
    58  *
    59  * @return
     96 * Determine the page size of the current run of the process.
     97 *
     98 * @return Page size of the process.
    6099 */
    61100int posix_getpagesize(void)
     
    65104
    66105/**
    67  *
    68  * @return
     106 * Get the process ID of the calling process.
     107 *
     108 * @return Process ID.
    69109 */
    70110posix_pid_t posix_getpid(void)
     
    74114
    75115/**
    76  *
    77  * @return
     116 * Get the real user ID of the calling process.
     117 *
     118 * @return User ID.
    78119 */
    79120posix_uid_t posix_getuid(void)
    80121{
    81         // TODO
    82         not_implemented();
    83 }
    84 
    85 /**
    86  *
    87  * @return
     122        /* There is currently no support for user accounts in HelenOS. */
     123        return 0;
     124}
     125
     126/**
     127 * Get the real group ID of the calling process.
     128 *
     129 * @return Group ID.
    88130 */
    89131posix_gid_t posix_getgid(void)
    90132{
    91         // TODO
    92         not_implemented();
    93 }
    94 
    95 /**
    96  *
    97  * @param path
    98  * @param amode
    99  * @return
     133        /* There is currently no support for user accounts in HelenOS. */
     134        return 0;
     135}
     136
     137/**
     138 * Determine accessibility of a file.
     139 *
     140 * @param path File to check accessibility for.
     141 * @param amode Either check for existence or intended access mode.
     142 * @return Zero on success, -1 otherwise.
    100143 */
    101144int posix_access(const char *path, int amode)
    102145{
    103         // TODO
    104         not_implemented();
    105 }
    106 
    107 /**
    108  *
    109  * @param name
    110  * @return
     146        if (amode == F_OK) {
     147                /* Check file existence by attempt to open it. */
     148                int fd = open(path, O_RDONLY);
     149                if (fd < 0) {
     150                        /* FIXME: open() returns error code as negative retval. */
     151                        errno = -fd;
     152                        fd = -1;
     153                } else {
     154                        close(fd);
     155                }
     156                return fd;
     157        } else if (amode & (X_OK | W_OK | R_OK)) {
     158                /* HelenOS doesn't support permissions, return success. */
     159                return 0;
     160        } else {
     161                /* Invalid amode argument. */
     162                errno = EINVAL;
     163                return -1;
     164        }
     165}
     166
     167/**
     168 * Get configurable system variables.
     169 *
     170 * @param name Variable name.
     171 * @return Variable value.
    111172 */
    112173long posix_sysconf(int name)
    113174{
    114         // TODO
    115         not_implemented();
     175        long clk_tck = 0;
     176        size_t cpu_count = 0;
     177        stats_cpu_t *cpu_stats = stats_get_cpus(&cpu_count);
     178        if (cpu_stats && cpu_count > 0) {
     179                clk_tck = ((long) cpu_stats[0].frequency_mhz) * 1000000L;
     180        }
     181        free(cpu_stats);
     182        cpu_stats = 0;
     183
     184        long phys_pages = 0;
     185        long avphys_pages = 0;
     186        stats_physmem_t *mem_stats = stats_get_physmem();
     187        if (mem_stats) {
     188                phys_pages = (long) (mem_stats->total / getpagesize());
     189                avphys_pages = (long) (mem_stats->free / getpagesize());
     190        }
     191        free(mem_stats);
     192        mem_stats = 0;
     193
     194        switch (name) {
     195        case _SC_PHYS_PAGES:
     196                return phys_pages;
     197        case _SC_AVPHYS_PAGES:
     198                return avphys_pages;
     199        case _SC_PAGESIZE:
     200                return getpagesize();
     201        case _SC_CLK_TCK:
     202                return clk_tck;
     203        default:
     204                errno = EINVAL;
     205                return -1;
     206        }
    116207}
    117208
  • uspace/lib/posix/unistd.h

    rf5b2522 r8cd8bf6  
    4848extern int getopt(int, char * const [], const char *);
    4949
    50 /* Environmental Variables */
     50/* Environment */
    5151extern char **posix_environ;
     52
     53extern char *posix_getlogin(void);
     54extern int posix_getlogin_r(char *name, size_t namesize);
    5255
    5356/* Identifying Terminals */
     
    126129#ifndef LIBPOSIX_INTERNAL
    127130        #define environ posix_environ
     131        #define getlogin posix_getlogin
     132        #define getlogin_r posix_getlogin_r
    128133
    129134        #define isatty posix_isatty
Note: See TracChangeset for help on using the changeset viewer.