source: mainline/uspace/lib/posix/src/stdio.c

Last change on this file was 163e34c, checked in by Jiří Zárevúcky <zarevucky.jiri@…>, 3 months ago

Actually convert the printf outputs everywhere

  • Property mode set to 100644
File size: 9.6 KB
Line 
1/*
2 * Copyright (c) 2011 Jiri Zarevucky
3 * Copyright (c) 2011 Petr Koupy
4 * Copyright (c) 2018 Jiri Svoboda
5 * All rights reserved.
6 *
7 * Redistribution and use in source and binary forms, with or without
8 * modification, are permitted provided that the following conditions
9 * are met:
10 *
11 * - Redistributions of source code must retain the above copyright
12 * notice, this list of conditions and the following disclaimer.
13 * - Redistributions in binary form must reproduce the above copyright
14 * notice, this list of conditions and the following disclaimer in the
15 * documentation and/or other materials provided with the distribution.
16 * - The name of the author may not be used to endorse or promote products
17 * derived from this software without specific prior written permission.
18 *
19 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
20 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
21 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
22 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
23 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
24 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
25 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
26 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
27 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
28 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
29 */
30
31/** @addtogroup libposix
32 * @{
33 */
34/** @file Standard buffered input/output.
35 */
36
37#define _LARGEFILE64_SOURCE
38#undef _FILE_OFFSET_BITS
39
40#include "internal/common.h"
41#include <stdio.h>
42
43#include <assert.h>
44#include <errno.h>
45#include <stdbool.h>
46#include <tmpfile.h>
47
48#include <fcntl.h>
49#include <stdlib.h>
50#include <string.h>
51#include <sys/stat.h>
52#include <sys/types.h>
53#include <unistd.h>
54
55#include <printf_core.h>
56#include <str.h>
57#include <stdlib.h>
58#include <adt/list.h>
59
60/**
61 * Generate a pathname for the controlling terminal.
62 *
63 * @param s Allocated buffer to which the pathname shall be put.
64 * @return Either s or static location filled with the requested pathname.
65 */
66char *ctermid(char *s)
67{
68 /* Currently always returns an error value (empty string). */
69 // TODO: return a real terminal path
70
71 static char dummy_path[L_ctermid] = { '\0' };
72
73 if (s == NULL) {
74 return dummy_path;
75 }
76
77 s[0] = '\0';
78 return s;
79}
80
81/**
82 * Read a stream until the delimiter (or EOF) is encountered.
83 *
84 * @param lineptr Pointer to the output buffer in which there will be stored
85 * nul-terminated string together with the delimiter (if encountered).
86 * Will be resized if necessary.
87 * @param n Pointer to the size of the output buffer. Will be increased if
88 * necessary.
89 * @param delimiter Delimiter on which to finish reading the stream.
90 * @param stream Input stream.
91 * @return Number of fetched characters (including delimiter if encountered)
92 * or -1 on error (set in errno).
93 */
94ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
95 int delimiter, FILE *restrict stream)
96{
97 /* Check arguments for sanity. */
98 if (!lineptr || !n) {
99 errno = EINVAL;
100 return -1;
101 }
102
103 size_t alloc_step = 80; /* Buffer size gain during reallocation. */
104 char *pos = *lineptr; /* Next free byte of the output buffer. */
105 size_t cnt = 0; /* Number of fetched characters. */
106 int c = fgetc(stream); /* Current input character. Might be EOF. */
107
108 do {
109 /* Mask EOF as NUL to terminate string. */
110 if (c == EOF) {
111 c = '\0';
112 }
113
114 /* Ensure there is still space left in the buffer. */
115 if (pos == *lineptr + *n) {
116 *lineptr = realloc(*lineptr, *n + alloc_step);
117 if (*lineptr) {
118 pos = *lineptr + *n;
119 *n += alloc_step;
120 } else {
121 errno = ENOMEM;
122 return -1;
123 }
124 }
125
126 /* Store the fetched character. */
127 *pos = c;
128
129 /* Fetch the next character according to the current character. */
130 if (c != '\0') {
131 ++pos;
132 ++cnt;
133 if (c == delimiter) {
134 /*
135 * Delimiter was just stored. Provide EOF as the next
136 * character - it will be masked as NUL and output string
137 * will be properly terminated.
138 */
139 c = EOF;
140 } else {
141 /*
142 * Neither delimiter nor EOF were encountered. Just fetch
143 * the next character from the stream.
144 */
145 c = fgetc(stream);
146 }
147 }
148 } while (c != '\0');
149
150 if (errno == EOK && cnt > 0) {
151 return cnt;
152 } else {
153 /* Either some error occured or the stream was already at EOF. */
154 return -1;
155 }
156}
157
158/**
159 * Read a stream until the newline (or EOF) is encountered.
160 *
161 * @param lineptr Pointer to the output buffer in which there will be stored
162 * nul-terminated string together with the delimiter (if encountered).
163 * Will be resized if necessary.
164 * @param n Pointer to the size of the output buffer. Will be increased if
165 * necessary.
166 * @param stream Input stream.
167 * @return Number of fetched characters (including newline if encountered)
168 * or -1 on error (set in errno).
169 */
170ssize_t getline(char **restrict lineptr, size_t *restrict n,
171 FILE *restrict stream)
172{
173 return getdelim(lineptr, n, '\n', stream);
174}
175
176/**
177 * Reposition a file-position indicator in a stream.
178 *
179 * @param stream Stream to seek in.
180 * @param offset Direction and amount of bytes to seek.
181 * @param whence From where to seek.
182 * @return Zero on success, -1 otherwise.
183 */
184int fseeko(FILE *stream, off_t offset, int whence)
185{
186 return fseek(stream, offset, whence);
187}
188
189/**
190 * Discover current file offset in a stream.
191 *
192 * @param stream Stream for which the offset shall be retrieved.
193 * @return Current offset or -1 if not possible.
194 */
195off_t ftello(FILE *stream)
196{
197 return ftell(stream);
198}
199
200int fseeko64(FILE *stream, off64_t offset, int whence)
201{
202 return fseek64(stream, offset, whence);
203}
204
205off64_t ftello64(FILE *stream)
206{
207 return ftell64(stream);
208}
209
210/**
211 * Print formatted output to the opened file.
212 *
213 * @param fildes File descriptor of the opened file.
214 * @param format Format description.
215 * @return Either the number of printed characters or negative value on error.
216 */
217int dprintf(int fildes, const char *restrict format, ...)
218{
219 va_list list;
220 va_start(list, format);
221 int result = vdprintf(fildes, format, list);
222 va_end(list);
223 return result;
224}
225
226/**
227 * Write ordinary string to the opened file.
228 *
229 * @param str String to be written.
230 * @param size Size of the string (in bytes)..
231 * @param fd File descriptor of the opened file.
232 * @return The number of written characters.
233 */
234static errno_t _dprintf_str_write(const char *str, size_t size, void *fd)
235{
236 const int fildes = *(int *) fd;
237 size_t wr;
238 return vfs_write(fildes, &posix_pos[fildes], str, size, &wr);
239}
240
241/**
242 * Print formatted output to the opened file.
243 *
244 * @param fildes File descriptor of the opened file.
245 * @param format Format description.
246 * @param ap Print arguments.
247 * @return Either the number of printed characters or negative value on error.
248 */
249int vdprintf(int fildes, const char *restrict format, va_list ap)
250{
251 printf_spec_t spec = {
252 .write = _dprintf_str_write,
253 .data = &fildes
254 };
255
256 return printf_core(format, &spec, ap);
257}
258
259/**
260 * Acquire file stream for the thread.
261 *
262 * @param file File stream to lock.
263 */
264void flockfile(FILE *file)
265{
266 /* dummy */
267}
268
269/**
270 * Acquire file stream for the thread (non-blocking).
271 *
272 * @param file File stream to lock.
273 * @return Zero for success and non-zero if the lock cannot be acquired.
274 */
275int ftrylockfile(FILE *file)
276{
277 /* dummy */
278 return 0;
279}
280
281/**
282 * Relinquish the ownership of the locked file stream.
283 *
284 * @param file File stream to unlock.
285 */
286void funlockfile(FILE *file)
287{
288 /* dummy */
289}
290
291/**
292 * Get a byte from a stream (thread-unsafe).
293 *
294 * @param stream Input file stream.
295 * @return Either read byte or EOF.
296 */
297int getc_unlocked(FILE *stream)
298{
299 return getc(stream);
300}
301
302/**
303 * Get a byte from the standard input stream (thread-unsafe).
304 *
305 * @return Either read byte or EOF.
306 */
307int getchar_unlocked(void)
308{
309 return getchar();
310}
311
312/**
313 * Put a byte on a stream (thread-unsafe).
314 *
315 * @param c Byte to output.
316 * @param stream Output file stream.
317 * @return Either written byte or EOF.
318 */
319int putc_unlocked(int c, FILE *stream)
320{
321 return putc(c, stream);
322}
323
324/**
325 * Put a byte on the standard output stream (thread-unsafe).
326 *
327 * @param c Byte to output.
328 * @return Either written byte or EOF.
329 */
330int putchar_unlocked(int c)
331{
332 return putchar(c);
333}
334
335/** Determine if directory is an 'appropriate' temporary directory.
336 *
337 * @param dir Directory path
338 * @return @c true iff directory is appropriate.
339 */
340static bool is_appropriate_tmpdir(const char *dir)
341{
342 struct stat sbuf;
343
344 /* Must not be NULL */
345 if (dir == NULL)
346 return false;
347
348 /* Must not be empty */
349 if (dir[0] == '\0')
350 return false;
351
352 if (stat(dir, &sbuf) != 0)
353 return false;
354
355 /* Must be a directory */
356 if ((sbuf.st_mode & S_IFMT) != S_IFDIR)
357 return false;
358
359 /* Must be writable */
360 if (access(dir, W_OK) != 0)
361 return false;
362
363 return true;
364}
365
366/** Construct unique file name.
367 *
368 * Never use this function.
369 *
370 * @param dir Path to directory, where the file should be created.
371 * @param pfx Optional prefix up to 5 characters long.
372 * @return Newly allocated unique path for temporary file. NULL on failure.
373 */
374char *tempnam(const char *dir, const char *pfx)
375{
376 const char *dpref;
377 char *d;
378 char *buf;
379 int rc;
380
381 d = getenv("TMPDIR");
382 if (is_appropriate_tmpdir(d))
383 dpref = d;
384 else if (is_appropriate_tmpdir(dir))
385 dpref = dir;
386 else if (is_appropriate_tmpdir(P_tmpdir))
387 dpref = P_tmpdir;
388 else
389 dpref = "/";
390
391 if (dpref[strlen(dpref) - 1] != '/')
392 rc = asprintf(&buf, "%s/%sXXXXXX", dpref, pfx);
393 else
394 rc = asprintf(&buf, "%s%sXXXXXX", dpref, pfx);
395
396 if (rc < 0)
397 return NULL;
398
399 rc = __tmpfile_templ(buf, false);
400 if (rc != 0) {
401 free(buf);
402 return NULL;
403 }
404
405 return buf;
406}
407
408/** @}
409 */
Note: See TracBrowser for help on using the repository browser.