Ignore:
File:
1 edited

Legend:

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

    r221afc9e r9b1503e  
    3636#define LIBPOSIX_INTERNAL
    3737
    38 /* Has to be first. */
    39 #include "stdbool.h"
     38#include <assert.h>
     39#include <errno.h>
    4040
    4141#include "internal/common.h"
    4242#include "stdio.h"
     43#include "string.h"
    4344
    44 #include "assert.h"
    45 #include "errno.h"
    46 #include "string.h"
    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
     45/* not the best of solutions, but freopen will eventually
    5546 * need to be implemented in libc anyway
    5647 */
    5748#include "../c/generic/private/stdio.h"
    5849
    59 /** Clears the stream's error and end-of-file indicators.
    60  *
    61  * @param stream Stream whose indicators shall be cleared.
     50/**
     51 *
     52 * @param c
     53 * @param stream
     54 * @return
    6255 */
    63 void posix_clearerr(FILE *stream)
     56int posix_ungetc(int c, FILE *stream)
    6457{
    65         stream->error = 0;
    66         stream->eof = 0;
     58        // TODO
     59        not_implemented();
    6760}
    6861
    6962/**
    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.
     63 *
     64 * @param filename
     65 * @param mode
     66 * @param stream
     67 * @return
    7468 */
    75 char *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  */
    97 int 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.
    113  */
    114 int posix_ungetc(int c, FILE *stream)
    115 {
    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  */
    160 ssize_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  */
    232 ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
     69FILE *posix_freopen(
     70    const char *restrict filename,
     71    const char *restrict mode,
    23372    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  */
    249 FILE *posix_freopen(const char *restrict filename,
    250     const char *restrict mode, FILE *restrict stream)
    25173{
    25274        assert(mode != NULL);
     
    293115/**
    294116 *
    295  * @param buf
    296  * @param size
    297  * @param mode
    298  * @return
     117 * @param s
    299118 */
    300 FILE *posix_fmemopen(void *restrict buf, size_t size,
    301     const char *restrict mode)
     119void posix_perror(const char *s)
    302120{
    303121        // TODO
     
    306124
    307125/**
    308  *
    309  * @param bufp
    310  * @param sizep
     126 *
     127 * @param stream
     128 * @param offset
     129 * @param whence
    311130 * @return
    312131 */
    313 FILE *posix_open_memstream(char **bufp, size_t *sizep)
     132int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
    314133{
    315134        // TODO
     
    318137
    319138/**
    320  * Write error messages to standard error.
    321  *
    322  * @param s Error message.
    323  */
    324 void 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 
    333 struct _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  */
    343 int 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  */
    354 int 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.
    366139 *
    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  */
    372 int 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  */
    385 int 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  */
    396 long 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.
     140 * @param stream
     141 * @return
    406142 */
    407143posix_off_t posix_ftello(FILE *stream)
    408144{
    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  */
    418 int 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  */
    436 int 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  */
    453 static 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  */
    467 static 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  */
    499 int 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  */
    518 int 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  */
    536 int 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  */
    548 int 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  */
    563 int 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  */
    579 int 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  */
    591 int 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  */
    605 void 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  */
    616 int 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  */
    627 void 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  */
    638 int 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  */
    648 int 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  */
    660 int 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  */
    671 int 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  */
    682 int 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);
     145        // TODO
     146        not_implemented();
    687147}
    688148
     
    690150 *
    691151 * @param s
     152 * @param format
     153 * @param ...
    692154 * @return
    693155 */
    694 char *posix_tmpnam(char *s)
     156int posix_sprintf(char *s, const char *format, ...)
    695157{
    696         // TODO: low priority, just a compile-time dependency of binutils
     158        // TODO
     159        not_implemented();
     160}
     161
     162/**
     163 *
     164 * @param s
     165 * @param format
     166 * @param ...
     167 * @return
     168 */
     169int posix_sscanf(const char *s, const char *format, ...)
     170{
     171        // TODO
    697172        not_implemented();
    698173}
Note: See TracChangeset for help on using the changeset viewer.