Changeset 8cd8bf6 in mainline for uspace/lib/posix/stdio.c


Ignore:
Timestamp:
2011-07-08T17:25:53Z (13 years ago)
Author:
Petr Koupy <petr.koupy@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
11809eab
Parents:
f5b2522 (diff), ddc63fd (diff)
Note: this is a merge changeset, the changes displayed below correspond to the merge itself.
Use the (diff) links above to see all the changes relative to each parent.
Message:

Merge libposix changes.

File:
1 edited

Legend:

Unmodified
Added
Removed
  • 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 */
Note: See TracChangeset for help on using the changeset viewer.