Changeset 2595dab in mainline for uspace/lib/libc/generic/io/io.c


Ignore:
Timestamp:
2009-06-03T19:26:28Z (16 years ago)
Author:
Martin Decky <martin@…>
Branches:
lfn, master, serial, ticket/834-toolchain-update, topic/msim-upgrade, topic/simplify-dev-export
Children:
d00ae4c
Parents:
ca3ba3a
Message:

I/O subsystem overhaul:

  • add more POSIX-like file and stream functions (with real functionality of stdin, stdout, stderr)
  • cleanup console access methods (now generic to any console-like device)
  • remove unsafe stream functions
  • add special open_node(), fd_node(), fd_phone() (file) and fopen_node(), fnode(), fphone() (stream) functions for HelenOS-specific I/O operations
File:
1 edited

Legend:

Unmodified
Added
Removed
  • uspace/lib/libc/generic/io/io.c

    rca3ba3a r2595dab  
    3131 */
    3232/** @file
    33  */ 
    34 
    35 #include <libc.h>
     33 */
     34
     35#include <stdio.h>
    3636#include <unistd.h>
    37 #include <stdio.h>
    38 #include <io/io.h>
     37#include <fcntl.h>
    3938#include <string.h>
    4039#include <errno.h>
    41 #include <console.h>
    42 
    43 const static char nl = '\n';
     40#include <bool.h>
     41#include <malloc.h>
     42#include <io/klog.h>
     43#include <vfs/vfs.h>
     44#include <ipc/devmap.h>
     45
     46FILE stdin_null = {
     47        .fd = -1,
     48        .error = true,
     49        .eof = true,
     50        .klog = false,
     51        .phone = -1
     52};
     53
     54FILE stdout_klog = {
     55        .fd = -1,
     56        .error = false,
     57        .eof = false,
     58        .klog = true,
     59        .phone = -1
     60};
     61
     62FILE *stdin = &stdin_null;
     63FILE *stdout = &stdout_klog;
     64FILE *stderr = &stdout_klog;
     65
     66static bool parse_mode(const char *mode, int *flags)
     67{
     68        /* Parse mode except first character. */
     69        const char *mp = mode;
     70        if (*mp++ == 0) {
     71                errno = EINVAL;
     72                return false;
     73        }
     74       
     75        if ((*mp == 'b') || (*mp == 't'))
     76                mp++;
     77       
     78        bool plus;
     79        if (*mp == '+') {
     80                mp++;
     81                plus = true;
     82        } else
     83                plus = false;
     84       
     85        if (*mp != 0) {
     86                errno = EINVAL;
     87                return false;
     88        }
     89       
     90        /* Parse first character of mode and determine flags for open(). */
     91        switch (mode[0]) {
     92        case 'r':
     93                *flags = plus ? O_RDWR : O_RDONLY;
     94                break;
     95        case 'w':
     96                *flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
     97                break;
     98        case 'a':
     99                /* TODO: a+ must read from beginning, append to the end. */
     100                if (plus) {
     101                        errno = ENOTSUP;
     102                        return false;
     103                }
     104                *flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
     105        default:
     106                errno = EINVAL;
     107                return false;
     108        }
     109       
     110        return true;
     111}
     112
     113/** Open a stream.
     114 *
     115 * @param path Path of the file to open.
     116 * @param mode Mode string, (r|w|a)[b|t][+].
     117 *
     118 */
     119FILE *fopen(const char *path, const char *mode)
     120{
     121        int flags;
     122        if (!parse_mode(mode, &flags))
     123                return NULL;
     124       
     125        /* Open file. */
     126        FILE *stream = malloc(sizeof(FILE));
     127        if (stream == NULL) {
     128                errno = ENOMEM;
     129                return NULL;
     130        }
     131       
     132        stream->fd = open(path, flags, 0666);
     133        if (stream->fd < 0) {
     134                /* errno was set by open() */
     135                free(stream);
     136                return NULL;
     137        }
     138       
     139        stream->error = false;
     140        stream->eof = false;
     141        stream->klog = false;
     142        stream->phone = -1;
     143       
     144        return stream;
     145}
     146
     147FILE *fopen_node(fs_node_t *node, const char *mode)
     148{
     149        int flags;
     150        if (!parse_mode(mode, &flags))
     151                return NULL;
     152       
     153        /* Open file. */
     154        FILE *stream = malloc(sizeof(FILE));
     155        if (stream == NULL) {
     156                errno = ENOMEM;
     157                return NULL;
     158        }
     159       
     160        stream->fd = open_node(node, flags);
     161        if (stream->fd < 0) {
     162                /* errno was set by open_node() */
     163                free(stream);
     164                return NULL;
     165        }
     166       
     167        stream->error = false;
     168        stream->eof = false;
     169        stream->klog = false;
     170        stream->phone = -1;
     171       
     172        return stream;
     173}
     174
     175int fclose(FILE *stream)
     176{
     177        int rc = 0;
     178       
     179        fflush(stream);
     180       
     181        if (stream->phone >= 0)
     182                ipc_hangup(stream->phone);
     183       
     184        if (stream->fd >= 0)
     185                rc = close(stream->fd);
     186       
     187        if ((stream != &stdin_null) && (stream != &stdout_klog))
     188                free(stream);
     189       
     190        stream = NULL;
     191       
     192        if (rc != 0) {
     193                /* errno was set by close() */
     194                return EOF;
     195        }
     196       
     197        return 0;
     198}
     199
     200/** Read from a stream.
     201 *
     202 * @param buf    Destination buffer.
     203 * @param size   Size of each record.
     204 * @param nmemb  Number of records to read.
     205 * @param stream Pointer to the stream.
     206 *
     207 */
     208size_t fread(void *buf, size_t size, size_t nmemb, FILE *stream)
     209{
     210        size_t left = size * nmemb;
     211        size_t done = 0;
     212       
     213        while ((left > 0) && (!stream->error) && (!stream->eof)) {
     214                ssize_t rd = read(stream->fd, buf + done, left);
     215               
     216                if (rd < 0)
     217                        stream->error = true;
     218                else if (rd == 0)
     219                        stream->eof = true;
     220                else {
     221                        left -= rd;
     222                        done += rd;
     223                }
     224        }
     225       
     226        return (done / size);
     227}
     228
     229/** Write to a stream.
     230 *
     231 * @param buf    Source buffer.
     232 * @param size   Size of each record.
     233 * @param nmemb  Number of records to write.
     234 * @param stream Pointer to the stream.
     235 *
     236 */
     237size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *stream)
     238{
     239        size_t left = size * nmemb;
     240        size_t done = 0;
     241       
     242        while ((left > 0) && (!stream->error)) {
     243                ssize_t wr;
     244               
     245                if (stream->klog)
     246                        wr = klog_write(buf + done, left);
     247                else
     248                        wr = write(stream->fd, buf + done, left);
     249               
     250                if (wr <= 0)
     251                        stream->error = true;
     252                else {
     253                        left -= wr;
     254                        done += wr;
     255                }
     256        }
     257       
     258        return (done / size);
     259}
     260
     261int fputc(wchar_t c, FILE *stream)
     262{
     263        char buf[STR_BOUNDS(1)];
     264        size_t sz = 0;
     265       
     266        if (chr_encode(c, buf, &sz, STR_BOUNDS(1)) == EOK) {
     267                size_t wr = fwrite(buf, sz, 1, stream);
     268               
     269                if (wr < sz)
     270                        return EOF;
     271               
     272                return (int) c;
     273        }
     274       
     275        return EOF;
     276}
     277
     278int putchar(wchar_t c)
     279{
     280        return fputc(c, stdout);
     281}
     282
     283int fputs(const char *str, FILE *stream)
     284{
     285        return fwrite(str, str_size(str), 1, stream);
     286}
    44287
    45288int puts(const char *str)
    46289{
    47         size_t count;
    48        
    49         if (str == NULL)
    50                 return putnchars("(NULL)", 6);
    51        
    52         for (count = 0; str[count] != 0; count++);
    53        
    54         if (console_write((void *) str, count) == count) {
    55                 if (console_write(&nl, 1) == 1)
    56                         return 0;
    57         }
    58        
    59         return EOF;
    60 }
    61 
    62 /** Put count chars from buffer to stdout without adding newline
    63  * @param buf Buffer with size at least count bytes - NULL pointer NOT allowed!
    64  * @param count
    65  * @return 0 on succes, EOF on fail
    66  */
    67 int putnchars(const char *buf, size_t count)
    68 {
    69         if (console_write((void *) buf, count) == count)
    70                 return 0;
    71        
    72         return EOF;
    73 }
    74 
    75 /** Same as puts, but does not print newline at end
    76  *
    77  */
    78 int putstr(const char *str)
    79 {
    80         size_t count;
    81        
    82         if (str == NULL)
    83                 return putnchars("(NULL)", 6);
    84 
    85         for (count = 0; str[count] != 0; count++);
    86         if (console_write((void *) str, count) == count)
    87                 return 0;
    88        
    89         return EOF;
    90 }
    91 
    92 int putchar(int c)
    93 {
    94         char buf[STR_BOUNDS(1)];
    95         size_t offs;
    96 
    97         offs = 0;
    98         if (chr_encode(c, buf, &offs, STR_BOUNDS(1)) != EOK)
     290        return fputs(str, stdout);
     291}
     292
     293int fgetc(FILE *stream)
     294{
     295        char c;
     296       
     297        if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
    99298                return EOF;
    100 
    101         if (console_write((void *) buf, offs) == offs)
    102                 return c;
    103 
    104         return EOF;
     299       
     300        return (int) c;
    105301}
    106302
    107303int getchar(void)
    108304{
    109         unsigned char c;
    110        
    111         console_flush();
    112         if (read_stdin((void *) &c, 1) == 1)
    113                 return c;
    114        
    115         return EOF;
    116 }
    117 
    118 int fflush(FILE *f)
    119 {
    120         /* Dummy implementation */
    121         (void) f;
    122         console_flush();
     305        return fgetc(stdin);
     306}
     307
     308int fseek(FILE *stream, long offset, int origin)
     309{
     310        off_t rc = lseek(stream->fd, offset, origin);
     311        if (rc == (off_t) (-1)) {
     312                /* errno has been set by lseek. */
     313                return -1;
     314        }
     315       
     316        stream->eof = false;
     317       
    123318        return 0;
    124319}
    125320
     321int fflush(FILE *stream)
     322{
     323        if (stream->klog) {
     324                klog_update();
     325                return EOK;
     326        }
     327       
     328        if (stream->fd >= 0)
     329                return fsync(stream->fd);
     330       
     331        return ENOENT;
     332}
     333
     334int feof(FILE *stream)
     335{
     336        return stream->eof;
     337}
     338
     339int ferror(FILE *stream)
     340{
     341        return stream->error;
     342}
     343
     344int fphone(FILE *stream)
     345{
     346        if (stream->fd >= 0) {
     347                if (stream->phone < 0)
     348                        stream->phone = fd_phone(stream->fd);
     349               
     350                return stream->phone;
     351        }
     352       
     353        return -1;
     354}
     355
     356void fnode(FILE *stream, fs_node_t *node)
     357{
     358        if (stream->fd >= 0) {
     359                fd_node(stream->fd, node);
     360        } else {
     361                node->fs_handle = 0;
     362                node->dev_handle = 0;
     363                node->index = 0;
     364        }
     365}
     366
    126367/** @}
    127368 */
Note: See TracChangeset for help on using the changeset viewer.