Subversion Repositories HelenOS

Rev

Rev 4491 | Rev 4508 | Go to most recent revision | Blame | Compare with Previous | Last modification | View Log | Download | RSS feed

  1. /*
  2.  * Copyright (c) 2005 Martin Decky
  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. /** @file
  33.  */
  34.  
  35. #include <stdio.h>
  36. #include <unistd.h>
  37. #include <fcntl.h>
  38. #include <string.h>
  39. #include <errno.h>
  40. #include <bool.h>
  41. #include <malloc.h>
  42. #include <io/klog.h>
  43. #include <vfs/vfs.h>
  44. #include <ipc/devmap.h>
  45.  
  46. FILE stdin_null = {
  47.     .fd = -1,
  48.     .error = true,
  49.     .eof = true,
  50.     .klog = false,
  51.     .phone = -1
  52. };
  53.  
  54. FILE stdout_klog = {
  55.     .fd = -1,
  56.     .error = false,
  57.     .eof = false,
  58.     .klog = true,
  59.     .phone = -1
  60. };
  61.  
  62. FILE *stdin = &stdin_null;
  63. FILE *stdout = &stdout_klog;
  64. FILE *stderr = &stdout_klog;
  65.  
  66. static 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.  */
  119. FILE *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.  
  147. FILE *fopen_node(fdi_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.  
  175. int 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.  */
  208. size_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.  */
  237. size_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.  
  261. int 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.  
  278. int putchar(wchar_t c)
  279. {
  280.     return fputc(c, stdout);
  281. }
  282.  
  283. int fputs(const char *str, FILE *stream)
  284. {
  285.     return fwrite(str, str_size(str), 1, stream);
  286. }
  287.  
  288. int puts(const char *str)
  289. {
  290.     return fputs(str, stdout);
  291. }
  292.  
  293. int fgetc(FILE *stream)
  294. {
  295.     char c;
  296.    
  297.     if (fread(&c, sizeof(char), 1, stream) < sizeof(char))
  298.         return EOF;
  299.    
  300.     return (int) c;
  301. }
  302.  
  303. int getchar(void)
  304. {
  305.     return fgetc(stdin);
  306. }
  307.  
  308. int 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.    
  318.     return 0;
  319. }
  320.  
  321. int 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.  
  334. int feof(FILE *stream)
  335. {
  336.     return stream->eof;
  337. }
  338.  
  339. int ferror(FILE *stream)
  340. {
  341.     return stream->error;
  342. }
  343.  
  344. int 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.  
  356. void fnode(FILE *stream, fdi_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.  
  367. /** @}
  368.  */
  369.