source: mainline/uspace/lib/posix/src/stdio.c@ 163e34c

Last change on this file since 163e34c 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
RevLine 
[09b0b1fb]1/*
2 * Copyright (c) 2011 Jiri Zarevucky
[4f4b4e7]3 * Copyright (c) 2011 Petr Koupy
[4e6a610]4 * Copyright (c) 2018 Jiri Svoboda
[09b0b1fb]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 */
[4cf8ca6]34/** @file Standard buffered input/output.
[09b0b1fb]35 */
36
[ef84413]37#define _LARGEFILE64_SOURCE
38#undef _FILE_OFFSET_BITS
39
[9b1503e]40#include "internal/common.h"
[9b8be79]41#include <stdio.h>
[a6d908c1]42
[e8d3c6f5]43#include <assert.h>
[0d0b319]44#include <errno.h>
[4e6a610]45#include <stdbool.h>
46#include <tmpfile.h>
[0d0b319]47
[9b8be79]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>
[4f4b4e7]54
[694ca3d6]55#include <printf_core.h>
[9b8be79]56#include <str.h>
[44e8541]57#include <stdlib.h>
[9b8be79]58#include <adt/list.h>
[a6d908c1]59
[8b5fb5e]60/**
[1978a5f]61 * Generate a pathname for the controlling terminal.
[8b5fb5e]62 *
[1978a5f]63 * @param s Allocated buffer to which the pathname shall be put.
64 * @return Either s or static location filled with the requested pathname.
[8b5fb5e]65 */
[7f9df7b9]66char *ctermid(char *s)
[8b5fb5e]67{
68 /* Currently always returns an error value (empty string). */
69 // TODO: return a real terminal path
70
[1433ecda]71 static char dummy_path[L_ctermid] = { '\0' };
[8b5fb5e]72
73 if (s == NULL) {
74 return dummy_path;
75 }
76
77 s[0] = '\0';
78 return s;
79}
80
[1978a5f]81/**
[08053f7]82 * Read a stream until the delimiter (or EOF) is encountered.
[1978a5f]83 *
[08053f7]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).
[1978a5f]93 */
[7f9df7b9]94ssize_t getdelim(char **restrict lineptr, size_t *restrict n,
[8b5fb5e]95 int delimiter, FILE *restrict stream)
96{
[08053f7]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) {
[7c3fb9b]134 /*
135 * Delimiter was just stored. Provide EOF as the next
[08053f7]136 * character - it will be masked as NUL and output string
[7c3fb9b]137 * will be properly terminated.
138 */
[08053f7]139 c = EOF;
140 } else {
[7c3fb9b]141 /*
142 * Neither delimiter nor EOF were encountered. Just fetch
143 * the next character from the stream.
144 */
[08053f7]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 }
[8b5fb5e]156}
157
[1978a5f]158/**
[08053f7]159 * Read a stream until the newline (or EOF) is encountered.
[1b20da0]160 *
[08053f7]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).
[1978a5f]169 */
[7f9df7b9]170ssize_t getline(char **restrict lineptr, size_t *restrict n,
[8b5fb5e]171 FILE *restrict stream)
172{
[7f9df7b9]173 return getdelim(lineptr, n, '\n', stream);
[09b0b1fb]174}
175
[8b5fb5e]176/**
[1978a5f]177 * Reposition a file-position indicator in a stream.
[1b20da0]178 *
[1978a5f]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.
[8b5fb5e]183 */
[7f9df7b9]184int fseeko(FILE *stream, off_t offset, int whence)
[b08ef1fd]185{
[ef84413]186 return fseek(stream, offset, whence);
[8b5fb5e]187}
188
189/**
[1978a5f]190 * Discover current file offset in a stream.
[1b20da0]191 *
[1978a5f]192 * @param stream Stream for which the offset shall be retrieved.
193 * @return Current offset or -1 if not possible.
[8b5fb5e]194 */
[7f9df7b9]195off_t ftello(FILE *stream)
[ef84413]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)
[b08ef1fd]206{
[e0f47f5]207 return ftell64(stream);
[8b5fb5e]208}
209
[1978a5f]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 */
[7f9df7b9]217int dprintf(int fildes, const char *restrict format, ...)
[8b5fb5e]218{
219 va_list list;
220 va_start(list, format);
[7f9df7b9]221 int result = vdprintf(fildes, format, list);
[8b5fb5e]222 va_end(list);
223 return result;
224}
225
[1978a5f]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 */
[163e34c]234static errno_t _dprintf_str_write(const char *str, size_t size, void *fd)
[8b5fb5e]235{
[58898d1d]236 const int fildes = *(int *) fd;
[8e3498b]237 size_t wr;
[163e34c]238 return vfs_write(fildes, &posix_pos[fildes], str, size, &wr);
[8b5fb5e]239}
240
[1978a5f]241/**
242 * Print formatted output to the opened file.
[1b20da0]243 *
[1978a5f]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 */
[7f9df7b9]249int vdprintf(int fildes, const char *restrict format, va_list ap)
[8b5fb5e]250{
251 printf_spec_t spec = {
[163e34c]252 .write = _dprintf_str_write,
[8b5fb5e]253 .data = &fildes
254 };
[a35b458]255
[8b5fb5e]256 return printf_core(format, &spec, ap);
[b08ef1fd]257}
258
[1978a5f]259/**
260 * Acquire file stream for the thread.
261 *
262 * @param file File stream to lock.
263 */
[7f9df7b9]264void flockfile(FILE *file)
[8b5fb5e]265{
266 /* dummy */
267}
268
[1978a5f]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 */
[7f9df7b9]275int ftrylockfile(FILE *file)
[8b5fb5e]276{
277 /* dummy */
278 return 0;
279}
280
[1978a5f]281/**
282 * Relinquish the ownership of the locked file stream.
283 *
284 * @param file File stream to unlock.
285 */
[7f9df7b9]286void funlockfile(FILE *file)
[8b5fb5e]287{
288 /* dummy */
289}
290
[1978a5f]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 */
[7f9df7b9]297int getc_unlocked(FILE *stream)
[8b5fb5e]298{
299 return getc(stream);
300}
301
[1978a5f]302/**
303 * Get a byte from the standard input stream (thread-unsafe).
304 *
305 * @return Either read byte or EOF.
306 */
[7f9df7b9]307int getchar_unlocked(void)
[8b5fb5e]308{
309 return getchar();
310}
311
[1978a5f]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 */
[7f9df7b9]319int putc_unlocked(int c, FILE *stream)
[8b5fb5e]320{
321 return putc(c, stream);
322}
323
[1978a5f]324/**
325 * Put a byte on the standard output stream (thread-unsafe).
[1b20da0]326 *
[1978a5f]327 * @param c Byte to output.
328 * @return Either written byte or EOF.
329 */
[7f9df7b9]330int putchar_unlocked(int c)
[8b5fb5e]331{
332 return putchar(c);
333}
334
[4e6a610]335/** Determine if directory is an 'appropriate' temporary directory.
[11544f4]336 *
[4e6a610]337 * @param dir Directory path
338 * @return @c true iff directory is appropriate.
[823a929]339 */
[4e6a610]340static bool is_appropriate_tmpdir(const char *dir)
[823a929]341{
[4e6a610]342 struct stat sbuf;
[a35b458]343
[4e6a610]344 /* Must not be NULL */
345 if (dir == NULL)
346 return false;
[a35b458]347
[4e6a610]348 /* Must not be empty */
349 if (dir[0] == '\0')
350 return false;
[a35b458]351
[4e6a610]352 if (stat(dir, &sbuf) != 0)
353 return false;
[a35b458]354
[4e6a610]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;
[11544f4]364}
365
[4e6a610]366/** Construct unique file name.
367 *
368 * Never use this function.
[11544f4]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 */
[7f9df7b9]374char *tempnam(const char *dir, const char *pfx)
[11544f4]375{
[4e6a610]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)
[11544f4]397 return NULL;
[a35b458]398
[4e6a610]399 rc = __tmpfile_templ(buf, false);
400 if (rc != 0) {
401 free(buf);
[11544f4]402 return NULL;
403 }
[a35b458]404
[4e6a610]405 return buf;
[823a929]406}
407
[09b0b1fb]408/** @}
409 */
Note: See TracBrowser for help on using the repository browser.