source: mainline/uspace/lib/libc/generic/io/stdio.c@ 63088cc1

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since 63088cc1 was 63088cc1, checked in by Jiri Svoboda <jirik.svoboda@…>, 17 years ago

fgetc(), fputc(), fputs(), fseek().

  • Property mode set to 100644
File size: 5.1 KB
Line 
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/**
47 * Open a stream.
48 *
49 * @param file_name Name of the file to open.
50 * @param mode Mode string, (r|w|a)[b|t][+].
51 */
52FILE *fopen(const char *file_name, const char *mode)
53{
54 FILE *f;
55 int flags;
56 bool plus;
57 const char *mp;
58
59 /* Parse mode except first character. */
60
61 mp = mode;
62 if (*mp++ == '\0') {
63 errno = EINVAL;
64 return NULL;
65 }
66
67 if (*mp == 'b' || *mp == 't') ++mp;
68
69 if (*mp == '+') {
70 ++mp;
71 plus = true;
72 } else {
73 plus = false;
74 }
75
76 if (*mp != '\0') {
77 errno = EINVAL;
78 return NULL;
79 }
80
81 /* Parse first character of mode and determine flags for open(). */
82
83 switch (mode[0]) {
84 case 'r':
85 flags = plus ? O_RDWR : O_RDONLY;
86 break;
87 case 'w':
88 flags = (O_TRUNC | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
89 break;
90 case 'a':
91 /* TODO: a+ must read from beginning, append to the end. */
92 if (plus) {
93 errno = ENOTSUP;
94 return NULL;
95 }
96 flags = (O_APPEND | O_CREAT) | (plus ? O_RDWR : O_WRONLY);
97 default:
98 errno = EINVAL;
99 return NULL;
100 }
101
102 /* Open file. */
103
104 f = malloc(sizeof(FILE));
105 if (f == NULL) {
106 errno = ENOMEM;
107 return NULL;
108 }
109
110 f->fd = open(file_name, flags, 0666);
111 if (f->fd < 0) {
112 free(f);
113 return NULL; /* errno was set by open() */
114 }
115
116 f->error = 0;
117 f->eof = 0;
118
119 return f;
120}
121
122/** Close a stream.
123 *
124 * @param f Pointer to stream.
125 * @return 0 on success, EOF on error.
126 */
127int fclose(FILE *f)
128{
129 int rc;
130
131 rc = close(f->fd);
132 free(f);
133
134 if (rc != 0)
135 return EOF; /* errno was set by close() */
136
137 return 0;
138}
139
140/** Read from a stream.
141 *
142 * @param buf Destination buffer.
143 * @param size Size of each record.
144 * @param nmemb Number of records to read.
145 * @param f Pointer to the stream.
146 */
147size_t fread(void *buf, size_t size, size_t nmemb, FILE *f)
148{
149 size_t left, done, n;
150
151 left = size * nmemb;
152 done = 0;
153
154 while (left > 0 && !f->error && !f->eof) {
155 n = read(f->fd, buf + done, left);
156
157 if (n < 0) {
158 f->error = 1;
159 } else if (n == 0) {
160 f->eof = 1;
161 } else {
162 left -= n;
163 done += n;
164 }
165 }
166
167 return done / size;
168}
169
170
171/** Write to a stream.
172 *
173 * @param buf Source buffer.
174 * @param size Size of each record.
175 * @param nmemb Number of records to write.
176 * @param f Pointer to the stream.
177 */
178size_t fwrite(const void *buf, size_t size, size_t nmemb, FILE *f)
179{
180 size_t left, done, n;
181
182 left = size * nmemb;
183 done = 0;
184
185 while (left > 0 && !f->error) {
186 n = write(f->fd, buf + done, left);
187
188 if (n <= 0) {
189 f->error = 1;
190 } else {
191 left -= n;
192 done += n;
193 }
194 }
195
196 return done / size;
197}
198
199/** Return the end-of-file indicator of a stream. */
200int feof(FILE *f)
201{
202 return f->eof;
203}
204
205/** Return the error indicator of a stream. */
206int ferror(FILE *f)
207{
208 return f->error;
209}
210
211/** Clear the error and end-of-file indicators of a stream. */
212void clearerr(FILE *f)
213{
214 f->eof = 0;
215 f->error = 0;
216}
217
218/** Read character from a stream. */
219int fgetc(FILE *f)
220{
221 unsigned char c;
222 size_t n;
223
224 n = fread(&c, sizeof(c), 1, f);
225 if (n < 1) return EOF;
226
227 return (int) c;
228}
229
230/** Write character to a stream. */
231int fputc(int c, FILE *f)
232{
233 unsigned char cc;
234 size_t n;
235
236 cc = (unsigned char) c;
237 n = fwrite(&cc, sizeof(cc), 1, f);
238 if (n < 1) return EOF;
239
240 return (int) cc;
241}
242
243/** Write string to a stream. */
244int fputs(const char *s, FILE *f)
245{
246 int rc;
247
248 rc = 0;
249
250 while (*s && rc >= 0) {
251 rc = fputc(*s++, f);
252 }
253
254 if (rc < 0) return EOF;
255
256 return 0;
257}
258
259/** Seek to position in stream. */
260int fseek(FILE *f, long offset, int origin)
261{
262 off_t rc;
263
264 rc = lseek(f->fd, offset, origin);
265 if (rc == (off_t) (-1)) {
266 /* errno has been set by lseek. */
267 return -1;
268 }
269
270 f->eof = 0;
271
272 return 0;
273}
274
275/** @}
276 */
Note: See TracBrowser for help on using the repository browser.