Ignore:
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/posix/stdio.c

    r9b1503e r221afc9e  
    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 * Put a string on the stream.
     92 *
     93 * @param s String to be written.
     94 * @param stream Output stream.
     95 * @return Non-negative on success, EOF on failure.
     96 */
     97int posix_fputs(const char *restrict s, FILE *restrict stream)
     98{
     99        int rc = fputs(s, stream);
     100        if (rc == 0) {
     101                return EOF;
     102        } else {
     103                return 0;
     104        }
     105}
     106
     107/**
     108 * Push byte back into input stream.
     109 *
     110 * @param c Byte to be pushed back.
     111 * @param stream Stream to where the byte shall be pushed.
     112 * @return Provided byte on success or EOF if not possible.
    55113 */
    56114int posix_ungetc(int c, FILE *stream)
    57115{
    58         // TODO
    59         not_implemented();
    60 }
    61 
    62 /**
    63  *
    64  * @param filename
    65  * @param mode
    66  * @param stream
    67  * @return
    68  */
    69 FILE *posix_freopen(
    70     const char *restrict filename,
    71     const char *restrict mode,
     116        uint8_t b = (uint8_t) c;
     117
     118        bool can_unget =
     119            /* Provided character is legal. */
     120            c != EOF &&
     121            /* Stream is consistent. */
     122            !stream->error &&
     123            /* Stream is buffered. */
     124            stream->btype != _IONBF &&
     125            /* Last operation on the stream was a read operation. */
     126            stream->buf_state == _bs_read &&
     127            /* Stream buffer is already allocated (i.e. there was already carried
     128             * out either write or read operation on the stream). This is probably
     129             * redundant check but let's be safe. */
     130            stream->buf != NULL &&
     131            /* There is still space in the stream to retreat. POSIX demands the
     132             * possibility to unget at least 1 character. It should be always
     133             * possible, assuming the last operation on the stream read at least 1
     134             * character, because the buffer is refilled in the lazily manner. */
     135            stream->buf_tail > stream->buf;
     136
     137        if (can_unget) {
     138                --stream->buf_tail;
     139                stream->buf_tail[0] = b;
     140                stream->eof = false;
     141                return (int) b;
     142        } else {
     143                return EOF;
     144        }
     145}
     146
     147/**
     148 * Read a stream until the delimiter (or EOF) is encountered.
     149 *
     150 * @param lineptr Pointer to the output buffer in which there will be stored
     151 *     nul-terminated string together with the delimiter (if encountered).
     152 *     Will be resized if necessary.
     153 * @param n Pointer to the size of the output buffer. Will be increased if
     154 *     necessary.
     155 * @param delimiter Delimiter on which to finish reading the stream.
     156 * @param stream Input stream.
     157 * @return Number of fetched characters (including delimiter if encountered)
     158 *     or -1 on error (set in errno).
     159 */
     160ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
     161    int delimiter, FILE *restrict stream)
     162{
     163        /* Check arguments for sanity. */
     164        if (!lineptr || !n) {
     165                errno = EINVAL;
     166                return -1;
     167        }
     168
     169        size_t alloc_step = 80; /* Buffer size gain during reallocation. */
     170        char *pos = *lineptr; /* Next free byte of the output buffer. */
     171        size_t cnt = 0; /* Number of fetched characters. */
     172        int c = fgetc(stream); /* Current input character. Might be EOF. */
     173
     174        do {
     175                /* Mask EOF as NUL to terminate string. */
     176                if (c == EOF) {
     177                        c = '\0';
     178                }
     179
     180                /* Ensure there is still space left in the buffer. */
     181                if (pos == *lineptr + *n) {
     182                        *lineptr = realloc(*lineptr, *n + alloc_step);
     183                        if (*lineptr) {
     184                                pos = *lineptr + *n;
     185                                *n += alloc_step;
     186                        } else {
     187                                errno = ENOMEM;
     188                                return -1;
     189                        }
     190                }
     191
     192                /* Store the fetched character. */
     193                *pos = c;
     194
     195                /* Fetch the next character according to the current character. */
     196                if (c != '\0') {
     197                        ++pos;
     198                        ++cnt;
     199                        if (c == delimiter) {
     200                                /* Delimiter was just stored. Provide EOF as the next
     201                                 * character - it will be masked as NUL and output string
     202                                 * will be properly terminated. */
     203                                c = EOF;
     204                        } else {
     205                                /* Neither delimiter nor EOF were encountered. Just fetch
     206                                 * the next character from the stream. */
     207                                c = fgetc(stream);
     208                        }
     209                }
     210        } while (c != '\0');
     211
     212        if (errno == EOK && cnt > 0) {
     213                return cnt;
     214        } else {
     215                /* Either some error occured or the stream was already at EOF. */
     216                return -1;
     217        }
     218}
     219
     220/**
     221 * Read a stream until the newline (or EOF) is encountered.
     222 *
     223 * @param lineptr Pointer to the output buffer in which there will be stored
     224 *     nul-terminated string together with the delimiter (if encountered).
     225 *     Will be resized if necessary.
     226 * @param n Pointer to the size of the output buffer. Will be increased if
     227 *     necessary.
     228 * @param stream Input stream.
     229 * @return Number of fetched characters (including newline if encountered)
     230 *     or -1 on error (set in errno).
     231 */
     232ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
    72233    FILE *restrict stream)
     234{
     235        return posix_getdelim(lineptr, n, '\n', stream);
     236}
     237
     238/**
     239 * Reopen a file stream.
     240 *
     241 * @param filename Pathname of a file to be reopened or NULL for changing
     242 *     the mode of the stream.
     243 * @param mode Mode to be used for reopening the file or changing current
     244 *     mode of the stream.
     245 * @param stream Current stream associated with the opened file.
     246 * @return On success, either a stream of the reopened file or the provided
     247 *     stream with a changed mode. NULL otherwise.
     248 */
     249FILE *posix_freopen(const char *restrict filename,
     250    const char *restrict mode, FILE *restrict stream)
    73251{
    74252        assert(mode != NULL);
     
    115293/**
    116294 *
    117  * @param s
    118  */
    119 void posix_perror(const char *s)
     295 * @param buf
     296 * @param size
     297 * @param mode
     298 * @return
     299 */
     300FILE *posix_fmemopen(void *restrict buf, size_t size,
     301    const char *restrict mode)
    120302{
    121303        // TODO
     
    124306
    125307/**
    126  *
    127  * @param stream
    128  * @param offset
    129  * @param whence
     308 *
     309 * @param bufp
     310 * @param sizep
    130311 * @return
    131312 */
    132 int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
     313FILE *posix_open_memstream(char **bufp, size_t *sizep)
    133314{
    134315        // TODO
     
    137318
    138319/**
    139  *
    140  * @param stream
     320 * Write error messages to standard error.
     321 *
     322 * @param s Error message.
     323 */
     324void posix_perror(const char *s)
     325{
     326        if (s == NULL || s[0] == '\0') {
     327                fprintf(stderr, "%s\n", posix_strerror(errno));
     328        } else {
     329                fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
     330        }
     331}
     332
     333struct _posix_fpos {
     334        off64_t offset;
     335};
     336
     337/** Restores stream a to position previously saved with fgetpos().
     338 *
     339 * @param stream Stream to restore
     340 * @param pos Position to restore
     341 * @return Zero on success, non-zero (with errno set) on failure
     342 */
     343int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
     344{
     345        return fseek(stream, pos->offset, SEEK_SET);
     346}
     347
     348/** Saves the stream's position for later use by fsetpos().
     349 *
     350 * @param stream Stream to save
     351 * @param pos Place to store the position
     352 * @return Zero on success, non-zero (with errno set) on failure
     353 */
     354int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
     355{
     356        off64_t ret = ftell(stream);
     357        if (ret == -1) {
     358                return errno;
     359        }
     360        pos->offset = ret;
     361        return 0;
     362}
     363
     364/**
     365 * Reposition a file-position indicator in a stream.
     366 *
     367 * @param stream Stream to seek in.
     368 * @param offset Direction and amount of bytes to seek.
     369 * @param whence From where to seek.
     370 * @return Zero on success, -1 otherwise.
     371 */
     372int posix_fseek(FILE *stream, long offset, int whence)
     373{
     374        return fseek(stream, (off64_t) offset, whence);
     375}
     376
     377/**
     378 * Reposition a file-position indicator in a stream.
     379 *
     380 * @param stream Stream to seek in.
     381 * @param offset Direction and amount of bytes to seek.
     382 * @param whence From where to seek.
     383 * @return Zero on success, -1 otherwise.
     384 */
     385int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
     386{
     387        return fseek(stream, (off64_t) offset, whence);
     388}
     389
     390/**
     391 * Discover current file offset in a stream.
     392 *
     393 * @param stream Stream for which the offset shall be retrieved.
     394 * @return Current offset or -1 if not possible.
     395 */
     396long posix_ftell(FILE *stream)
     397{
     398        return (long) ftell(stream);
     399}
     400
     401/**
     402 * Discover current file offset in a stream.
     403 *
     404 * @param stream Stream for which the offset shall be retrieved.
     405 * @return Current offset or -1 if not possible.
     406 */
     407posix_off_t posix_ftello(FILE *stream)
     408{
     409        return (posix_off_t) ftell(stream);
     410}
     411
     412/**
     413 * Discard prefetched data or write unwritten data.
     414 *
     415 * @param stream Stream that shall be flushed.
     416 * @return Zero on success, EOF on failure.
     417 */
     418int posix_fflush(FILE *stream)
     419{
     420        int rc = fflush(stream);
     421        if (rc < 0) {
     422                errno = -rc;
     423                return EOF;
     424        } else {
     425                return 0;
     426        }
     427}
     428
     429/**
     430 * Print formatted output to the opened file.
     431 *
     432 * @param fildes File descriptor of the opened file.
     433 * @param format Format description.
     434 * @return Either the number of printed characters or negative value on error.
     435 */
     436int posix_dprintf(int fildes, const char *restrict format, ...)
     437{
     438        va_list list;
     439        va_start(list, format);
     440        int result = posix_vdprintf(fildes, format, list);
     441        va_end(list);
     442        return result;
     443}
     444
     445/**
     446 * Write ordinary string to the opened file.
     447 *
     448 * @param str String to be written.
     449 * @param size Size of the string (in bytes)..
     450 * @param fd File descriptor of the opened file.
     451 * @return The number of written characters.
     452 */
     453static int _dprintf_str_write(const char *str, size_t size, void *fd)
     454{
     455        ssize_t wr = write(*(int *) fd, str, size);
     456        return str_nlength(str, wr);
     457}
     458
     459/**
     460 * Write wide string to the opened file.
     461 *
     462 * @param str String to be written.
     463 * @param size Size of the string (in bytes).
     464 * @param fd File descriptor of the opened file.
     465 * @return The number of written characters.
     466 */
     467static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd)
     468{
     469        size_t offset = 0;
     470        size_t chars = 0;
     471        size_t sz;
     472        char buf[4];
     473       
     474        while (offset < size) {
     475                sz = 0;
     476                if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
     477                        break;
     478                }
     479               
     480                if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
     481                        break;
     482                }
     483               
     484                chars++;
     485                offset += sizeof(wchar_t);
     486        }
     487       
     488        return chars;
     489}
     490
     491/**
     492 * Print formatted output to the opened file.
     493 *
     494 * @param fildes File descriptor of the opened file.
     495 * @param format Format description.
     496 * @param ap Print arguments.
     497 * @return Either the number of printed characters or negative value on error.
     498 */
     499int posix_vdprintf(int fildes, const char *restrict format, va_list ap)
     500{
     501        printf_spec_t spec = {
     502                .str_write = _dprintf_str_write,
     503                .wstr_write = _dprintf_wstr_write,
     504                .data = &fildes
     505        };
     506       
     507        return printf_core(format, &spec, ap);
     508}
     509
     510/**
     511 * Print formatted output to the string.
     512 *
     513 * @param s Output string.
     514 * @param format Format description.
     515 * @return Either the number of printed characters (excluding null byte) or
     516 *     negative value on error.
     517 */
     518int posix_sprintf(char *s, const char *restrict format, ...)
     519{
     520        va_list list;
     521        va_start(list, format);
     522        int result = posix_vsprintf(s, format, list);
     523        va_end(list);
     524        return result;
     525}
     526
     527/**
     528 * Print formatted output to the string.
     529 *
     530 * @param s Output string.
     531 * @param format Format description.
     532 * @param ap Print arguments.
     533 * @return Either the number of printed characters (excluding null byte) or
     534 *     negative value on error.
     535 */
     536int posix_vsprintf(char *s, const char *restrict format, va_list ap)
     537{
     538        return vsnprintf(s, STR_NO_LIMIT, format, ap);
     539}
     540
     541/**
     542 * Convert formatted input from the stream.
     543 *
     544 * @param stream Input stream.
     545 * @param format Format description.
     546 * @return The number of converted output items or EOF on failure.
     547 */
     548int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
     549{
     550        va_list list;
     551        va_start(list, format);
     552        int result = posix_vfscanf(stream, format, list);
     553        va_end(list);
     554        return result;
     555}
     556
     557/**
     558 * Convert formatted input from the standard input.
     559 *
     560 * @param format Format description.
     561 * @return The number of converted output items or EOF on failure.
     562 */
     563int posix_scanf(const char *restrict format, ...)
     564{
     565        va_list list;
     566        va_start(list, format);
     567        int result = posix_vscanf(format, list);
     568        va_end(list);
     569        return result;
     570}
     571
     572/**
     573 * Convert formatted input from the standard input.
     574 *
     575 * @param format Format description.
     576 * @param arg Output items.
     577 * @return The number of converted output items or EOF on failure.
     578 */
     579int posix_vscanf(const char *restrict format, va_list arg)
     580{
     581        return posix_vfscanf(stdin, format, arg);
     582}
     583
     584/**
     585 * Convert formatted input from the string.
     586 *
     587 * @param s Input string.
     588 * @param format Format description.
     589 * @return The number of converted output items or EOF on failure.
     590 */
     591int posix_sscanf(const char *restrict s, const char *restrict format, ...)
     592{
     593        va_list list;
     594        va_start(list, format);
     595        int result = posix_vsscanf(s, format, list);
     596        va_end(list);
     597        return result;
     598}
     599
     600/**
     601 * Acquire file stream for the thread.
     602 *
     603 * @param file File stream to lock.
     604 */
     605void posix_flockfile(FILE *file)
     606{
     607        /* dummy */
     608}
     609
     610/**
     611 * Acquire file stream for the thread (non-blocking).
     612 *
     613 * @param file File stream to lock.
     614 * @return Zero for success and non-zero if the lock cannot be acquired.
     615 */
     616int posix_ftrylockfile(FILE *file)
     617{
     618        /* dummy */
     619        return 0;
     620}
     621
     622/**
     623 * Relinquish the ownership of the locked file stream.
     624 *
     625 * @param file File stream to unlock.
     626 */
     627void posix_funlockfile(FILE *file)
     628{
     629        /* dummy */
     630}
     631
     632/**
     633 * Get a byte from a stream (thread-unsafe).
     634 *
     635 * @param stream Input file stream.
     636 * @return Either read byte or EOF.
     637 */
     638int posix_getc_unlocked(FILE *stream)
     639{
     640        return getc(stream);
     641}
     642
     643/**
     644 * Get a byte from the standard input stream (thread-unsafe).
     645 *
     646 * @return Either read byte or EOF.
     647 */
     648int posix_getchar_unlocked(void)
     649{
     650        return getchar();
     651}
     652
     653/**
     654 * Put a byte on a stream (thread-unsafe).
     655 *
     656 * @param c Byte to output.
     657 * @param stream Output file stream.
     658 * @return Either written byte or EOF.
     659 */
     660int posix_putc_unlocked(int c, FILE *stream)
     661{
     662        return putc(c, stream);
     663}
     664
     665/**
     666 * Put a byte on the standard output stream (thread-unsafe).
     667 *
     668 * @param c Byte to output.
     669 * @return Either written byte or EOF.
     670 */
     671int posix_putchar_unlocked(int c)
     672{
     673        return putchar(c);
     674}
     675
     676/**
     677 * Remove a file.
     678 *
     679 * @param path Pathname of the file that shall be removed.
     680 * @return Zero on success, -1 otherwise.
     681 */
     682int posix_remove(const char *path)
     683{
     684        // FIXME: unlink() and rmdir() seem to be equivalent at the moment,
     685        //        but that does not have to be true forever
     686        return unlink(path);
     687}
     688
     689/**
     690 *
     691 * @param s
    141692 * @return
    142693 */
    143 posix_off_t posix_ftello(FILE *stream)
    144 {
    145         // TODO
     694char *posix_tmpnam(char *s)
     695{
     696        // TODO: low priority, just a compile-time dependency of binutils
    146697        not_implemented();
    147698}
    148699
    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_sscanf(const char *s, const char *format, ...)
    170 {
    171         // TODO
    172         not_implemented();
    173 }
    174 
    175700/** @}
    176701 */
Note: See TracChangeset for help on using the changeset viewer.