Subversion Repositories HelenOS

Rev

Go to most recent revision | Blame | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2008 Jiri Svoboda
  3.  * All rights reserved.
  4.  *
  5.  * Redistribution and use in source and binary forms, with or without
  6.  * modification, are permitted provided that the following conditions
  7.  * are met:
  8.  *
  9.  * - Redistributions of source code must retain the above copyright
  10.  *   notice, this list of conditions and the following disclaimer.
  11.  * - Redistributions in binary form must reproduce the above copyright
  12.  *   notice, this list of conditions and the following disclaimer in the
  13.  *   documentation and/or other materials provided with the distribution.
  14.  * - The name of the author may not be used to endorse or promote products
  15.  *   derived from this software without specific prior written permission.
  16.  *
  17.  * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
  18.  * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
  19.  * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
  20.  * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
  21.  * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
  22.  * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
  23.  * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
  24.  * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
  25.  * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
  26.  * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  27.  */
  28.  
  29. /** @addtogroup libc
  30.  * @{
  31.  */
  32. /**
  33.  * @file
  34.  * @brief ANSI C Stream I/O.
  35.  */
  36.  
  37. #include <stdlib.h>
  38. #include <sys/types.h>
  39. #include <sys/stat.h>
  40. #include <fcntl.h>
  41. #include <unistd.h>
  42. #include <errno.h>
  43. #include <bool.h>
  44. #include <stdio.h>
  45.  
  46. FILE *stdin, *stdout, *stderr;
  47.  
  48. /**
  49.  * Open a stream.
  50.  *
  51.  * @param file_name Name of the file to open.
  52.  * @param mode      Mode string, (r|w|a)[b|t][+].
  53.  */
  54. FILE *fopen(const char *file_name, const char *mode)
  55. {
  56.     FILE *f;
  57.     int flags;
  58.     bool plus;
  59.     const char *mp;
  60.  
  61.     /* Parse mode except first character. */
  62.  
  63.     mp = mode;
  64.     if (*mp++ == '\0') {
  65.         errno = EINVAL;
  66.         return NULL;
  67.     }
  68.  
  69.     if (*mp == 'b' || *mp == 't') ++mp;
  70.  
  71.     if (*mp == '+') {
  72.         ++mp;
  73.         plus = true;
  74.     } else {
  75.         plus = false;
  76.     }
  77.  
  78.     if (*mp != '\0') {
  79.         errno = EINVAL;
  80.         return NULL;
  81.     }
  82.  
  83.     /* Parse first character of mode and determine flags for open(). */
  84.  
  85.     switch (mode[0]) {
  86.     case 'r':
  87.         flags = plus ? O_RDWR : O_RDONLY;
  88.         break;
  89.     case 'w':
  90.         flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
  91.         break;
  92.     case 'a':
  93.         /* TODO: a+ must read from beginning, append to the end. */
  94.         if (plus) {
  95.             errno = ENOTSUP;
  96.             return NULL;
  97.         }
  98.         flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
  99.     default:
  100.         errno = EINVAL;
  101.         return NULL;
  102.     }
  103.  
  104.     /* Open file. */
  105.    
  106.     f = malloc(sizeof(FILE));
  107.     if (f == NULL) {
  108.         errno = ENOMEM;
  109.         return NULL;
  110.     }
  111.  
  112.     f->fd = open(file_name, flags, 0666);
  113.     if (f->fd < 0) {
  114.         free(f);
  115.         return NULL; /* errno was set by open() */
  116.     }
  117.  
  118.     f->error = 0;
  119.     f->eof = 0;
  120.  
  121.     return f;
  122. }
  123.  
  124. /** Close a stream.
  125.  *
  126.  * @param f Pointer to stream.
  127.  * @return  0 on success, EOF on error.
  128.  */
  129. int fclose(FILE *f)
  130. {
  131.     int rc;
  132.  
  133.     rc = close(f->fd);
  134.     free(f);
  135.  
  136.     if (rc != 0)
  137.         return EOF; /* errno was set by close() */
  138.  
  139.     return 0;
  140. }
  141.  
  142. /** Read from a stream.
  143.  *
  144.  * @param buf   Destination buffer.
  145.  * @param size  Size of each record.
  146.  * @param nmemb Number of records to read.
  147.  * @param f Pointer to the stream.
  148.  */
  149. size_t fread(void *buf, size_t size, size_t nmemb, FILE *f)
  150. {
  151.     size_t left, done, n;
  152.  
  153.     left = size * nmemb;
  154.     done = 0;
  155.  
  156.     while (left > 0 && !f->error && !f->eof) {
  157.         n = read(f->fd, buf + done, left);
  158.  
  159.         if (n < 0) {
  160.             f->error = 1;
  161.         } else if (n == 0) {
  162.             f->eof = 1;
  163.         } else {
  164.             left -= n;
  165.             done += n;
  166.         }
  167.     }
  168.  
  169.     return done / size;
  170. }
  171.  
  172.  
  173. /** Write to a stream.
  174.  *
  175.  * @param buf   Source buffer.
  176.  * @param size  Size of each record.
  177.  * @param nmemb Number of records to write.
  178.  * @param f Pointer to the stream.
  179.  */
  180. size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *f)
  181. {
  182.     size_t left, done, n;
  183.  
  184.     left = size * nmemb;
  185.     done = 0;
  186.  
  187.     while (left > 0 && !f->error) {
  188.         n = write(f->fd, buf + done, left);
  189.  
  190.         if (n <= 0) {
  191.             f->error = 1;
  192.         } else {
  193.             left -= n;
  194.             done += n;
  195.         }
  196.     }
  197.  
  198.     return done / size;
  199. }
  200.  
  201. /** Return the end-of-file indicator of a stream. */
  202. int feof(FILE *f)
  203. {
  204.     return f->eof;
  205. }
  206.  
  207. /** Return the error indicator of a stream. */
  208. int ferror(FILE *f)
  209. {
  210.     return f->error;
  211. }
  212.  
  213. /** Clear the error and end-of-file indicators of a stream. */
  214. void clearerr(FILE *f)
  215. {
  216.     f->eof = 0;
  217.     f->error = 0;
  218. }
  219.  
  220. /** Read character from a stream. */
  221. int fgetc(FILE *f)
  222. {
  223.     unsigned char c;
  224.     size_t n;
  225.  
  226.     n = fread(&c, sizeof(c), 1, f);
  227.     if (n < 1) return EOF;
  228.  
  229.     return (int) c;
  230. }
  231.  
  232. /** Write character to a stream. */
  233. int fputc(int c, FILE *f)
  234. {
  235.     unsigned char cc;
  236.     size_t n;
  237.  
  238.     cc = (unsigned char) c;
  239.     n = fwrite(&cc, sizeof(cc), 1, f);
  240.     if (n < 1) return EOF;
  241.  
  242.     return (int) cc;
  243. }
  244.  
  245. /** Write string to a stream. */
  246. int fputs(const char *s, FILE *f)
  247. {
  248.     int rc;
  249.  
  250.     rc = 0;
  251.  
  252.     while (*s && rc >= 0) {
  253.         rc = fputc(*s++, f);
  254.     }
  255.  
  256.     if (rc < 0) return EOF;
  257.  
  258.     return 0;
  259. }
  260.  
  261. /** Seek to position in stream. */
  262. int fseek(FILE *f, long offset, int origin)
  263. {
  264.     off_t rc;
  265.  
  266.     rc = lseek(f->fd, offset, origin);
  267.     if (rc == (off_t) (-1)) {
  268.         /* errno has been set by lseek. */
  269.         return -1;
  270.     }
  271.  
  272.     f->eof = 0;
  273.  
  274.     return 0;
  275. }
  276.  
  277. /** @}
  278.  */
  279.