source: mainline/uspace/lib/posix/source/stdio.c@ c70703a

lfn serial ticket/834-toolchain-update topic/msim-upgrade topic/simplify-dev-export
Last change on this file since c70703a was bd5414e, checked in by Jiri Svoboda <jiri@…>, 10 years ago

Proper ungetc() in libc.

  • Property mode set to 100644
File size: 18.2 KB
RevLine 
[09b0b1fb]1/*
2 * Copyright (c) 2011 Jiri Zarevucky
[4f4b4e7]3 * Copyright (c) 2011 Petr Koupy
[09b0b1fb]4 * All rights reserved.
5 *
6 * Redistribution and use in source and binary forms, with or without
7 * modification, are permitted provided that the following conditions
8 * are met:
9 *
10 * - Redistributions of source code must retain the above copyright
11 * notice, this list of conditions and the following disclaimer.
12 * - Redistributions in binary form must reproduce the above copyright
13 * notice, this list of conditions and the following disclaimer in the
14 * documentation and/or other materials provided with the distribution.
15 * - The name of the author may not be used to endorse or promote products
16 * derived from this software without specific prior written permission.
17 *
18 * THIS SOFTWARE IS PROVIDED BY THE AUTHOR ``AS IS'' AND ANY EXPRESS OR
19 * IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES
20 * OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED.
21 * IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY DIRECT, INDIRECT,
22 * INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT
23 * NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
24 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
25 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
26 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF
27 * THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
28 */
29
30/** @addtogroup libposix
31 * @{
32 */
[4cf8ca6]33/** @file Standard buffered input/output.
[09b0b1fb]34 */
35
[491e1ee]36#define LIBPOSIX_INTERNAL
[fdf97f6]37#define __POSIX_DEF__(x) posix_##x
[09b0b1fb]38
[9b1503e]39#include "internal/common.h"
[a3da2b2]40#include "posix/stdio.h"
[a6d908c1]41
[a3da2b2]42#include "posix/assert.h"
43#include "posix/errno.h"
44#include "posix/stdlib.h"
45#include "posix/string.h"
46#include "posix/sys/types.h"
47#include "posix/unistd.h"
[4f4b4e7]48
[32b3a12]49#include "libc/stdio.h"
[a6d908c1]50#include "libc/io/printf_core.h"
[3e6a98c5]51#include "libc/stdbool.h"
[a6d908c1]52#include "libc/str.h"
[08053f7]53#include "libc/malloc.h"
[fd4b636]54#include "libc/adt/list.h"
55#include "libc/sys/stat.h"
[a6d908c1]56
57
[1978a5f]58/* not the best of solutions, but freopen and ungetc will eventually
[4f4b4e7]59 * need to be implemented in libc anyway
60 */
[a3da2b2]61#include "../../c/generic/private/stdio.h"
[09b0b1fb]62
[8b5fb5e]63/** Clears the stream's error and end-of-file indicators.
64 *
[1978a5f]65 * @param stream Stream whose indicators shall be cleared.
[8b5fb5e]66 */
67void posix_clearerr(FILE *stream)
68{
69 stream->error = 0;
70 stream->eof = 0;
71}
72
73/**
[1978a5f]74 * Generate a pathname for the controlling terminal.
[8b5fb5e]75 *
[1978a5f]76 * @param s Allocated buffer to which the pathname shall be put.
77 * @return Either s or static location filled with the requested pathname.
[8b5fb5e]78 */
79char *posix_ctermid(char *s)
80{
81 /* Currently always returns an error value (empty string). */
82 // TODO: return a real terminal path
83
84 static char dummy_path[L_ctermid] = {'\0'};
85
86 if (s == NULL) {
87 return dummy_path;
88 }
89
90 s[0] = '\0';
91 return s;
92}
93
[221afc9e]94/**
95 * Put a string on the stream.
96 *
97 * @param s String to be written.
98 * @param stream Output stream.
99 * @return Non-negative on success, EOF on failure.
100 */
101int posix_fputs(const char *restrict s, FILE *restrict stream)
102{
103 int rc = fputs(s, stream);
104 if (rc == 0) {
105 return EOF;
106 } else {
107 return 0;
108 }
109}
110
[59f799b]111/**
[1978a5f]112 * Push byte back into input stream.
[59f799b]113 *
[1978a5f]114 * @param c Byte to be pushed back.
115 * @param stream Stream to where the byte shall be pushed.
[08053f7]116 * @return Provided byte on success or EOF if not possible.
[59f799b]117 */
118int posix_ungetc(int c, FILE *stream)
119{
[bd5414e]120 return ungetc(c, stream);
[59f799b]121}
122
[1978a5f]123/**
[08053f7]124 * Read a stream until the delimiter (or EOF) is encountered.
[1978a5f]125 *
[08053f7]126 * @param lineptr Pointer to the output buffer in which there will be stored
127 * nul-terminated string together with the delimiter (if encountered).
128 * Will be resized if necessary.
129 * @param n Pointer to the size of the output buffer. Will be increased if
130 * necessary.
131 * @param delimiter Delimiter on which to finish reading the stream.
132 * @param stream Input stream.
133 * @return Number of fetched characters (including delimiter if encountered)
134 * or -1 on error (set in errno).
[1978a5f]135 */
[8b5fb5e]136ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n,
137 int delimiter, FILE *restrict stream)
138{
[08053f7]139 /* Check arguments for sanity. */
140 if (!lineptr || !n) {
141 errno = EINVAL;
142 return -1;
143 }
144
145 size_t alloc_step = 80; /* Buffer size gain during reallocation. */
146 char *pos = *lineptr; /* Next free byte of the output buffer. */
147 size_t cnt = 0; /* Number of fetched characters. */
148 int c = fgetc(stream); /* Current input character. Might be EOF. */
149
150 do {
151 /* Mask EOF as NUL to terminate string. */
152 if (c == EOF) {
153 c = '\0';
154 }
155
156 /* Ensure there is still space left in the buffer. */
157 if (pos == *lineptr + *n) {
158 *lineptr = realloc(*lineptr, *n + alloc_step);
159 if (*lineptr) {
160 pos = *lineptr + *n;
161 *n += alloc_step;
162 } else {
163 errno = ENOMEM;
164 return -1;
165 }
166 }
167
168 /* Store the fetched character. */
169 *pos = c;
170
171 /* Fetch the next character according to the current character. */
172 if (c != '\0') {
173 ++pos;
174 ++cnt;
175 if (c == delimiter) {
176 /* Delimiter was just stored. Provide EOF as the next
177 * character - it will be masked as NUL and output string
178 * will be properly terminated. */
179 c = EOF;
180 } else {
181 /* Neither delimiter nor EOF were encountered. Just fetch
182 * the next character from the stream. */
183 c = fgetc(stream);
184 }
185 }
186 } while (c != '\0');
187
188 if (errno == EOK && cnt > 0) {
189 return cnt;
190 } else {
191 /* Either some error occured or the stream was already at EOF. */
192 return -1;
193 }
[8b5fb5e]194}
195
[1978a5f]196/**
[08053f7]197 * Read a stream until the newline (or EOF) is encountered.
[1978a5f]198 *
[08053f7]199 * @param lineptr Pointer to the output buffer in which there will be stored
200 * nul-terminated string together with the delimiter (if encountered).
201 * Will be resized if necessary.
202 * @param n Pointer to the size of the output buffer. Will be increased if
203 * necessary.
204 * @param stream Input stream.
205 * @return Number of fetched characters (including newline if encountered)
206 * or -1 on error (set in errno).
[1978a5f]207 */
[8b5fb5e]208ssize_t posix_getline(char **restrict lineptr, size_t *restrict n,
209 FILE *restrict stream)
210{
[08053f7]211 return posix_getdelim(lineptr, n, '\n', stream);
[8b5fb5e]212}
213
[4f4b4e7]214/**
[1978a5f]215 * Reopen a file stream.
[4f4b4e7]216 *
[1978a5f]217 * @param filename Pathname of a file to be reopened or NULL for changing
218 * the mode of the stream.
219 * @param mode Mode to be used for reopening the file or changing current
220 * mode of the stream.
221 * @param stream Current stream associated with the opened file.
222 * @return On success, either a stream of the reopened file or the provided
223 * stream with a changed mode. NULL otherwise.
[4f4b4e7]224 */
[46ac986]225FILE *posix_freopen(const char *restrict filename,
226 const char *restrict mode, FILE *restrict stream)
[09b0b1fb]227{
[ab547063]228 assert(mode != NULL);
229 assert(stream != NULL);
[fd4b636]230
[ab547063]231 if (filename == NULL) {
[f00af83]232 /* POSIX allows this to be imlementation-defined. HelenOS currently
233 * does not support changing the mode. */
234 // FIXME: handle mode change once it is supported
235 return stream;
[ab547063]236 }
[fd4b636]237
238 /* Open a new stream. */
[f00af83]239 FILE* new = fopen(filename, mode);
[fd4b636]240 if (new == NULL) {
241 fclose(stream);
[f00af83]242 /* errno was set by fopen() */
[ab547063]243 return NULL;
244 }
245
[fd4b636]246 /* Close the original stream without freeing it (ignoring errors). */
247 if (stream->buf != NULL) {
248 fflush(stream);
249 }
250 if (stream->sess != NULL) {
251 async_hangup(stream->sess);
252 }
253 if (stream->fd >= 0) {
254 close(stream->fd);
255 }
256 list_remove(&stream->link);
257
258 /* Move the new stream to the original location. */
259 memcpy(stream, new, sizeof (FILE));
260 free(new);
[ab547063]261
[fd4b636]262 /* Update references in the file list. */
[ab547063]263 stream->link.next->prev = &stream->link;
264 stream->link.prev->next = &stream->link;
265
266 return stream;
[09b0b1fb]267}
268
[4f4b4e7]269/**
[1978a5f]270 * Write error messages to standard error.
[4f4b4e7]271 *
[1978a5f]272 * @param s Error message.
[4f4b4e7]273 */
[09b0b1fb]274void posix_perror(const char *s)
275{
[8b5fb5e]276 if (s == NULL || s[0] == '\0') {
277 fprintf(stderr, "%s\n", posix_strerror(errno));
278 } else {
279 fprintf(stderr, "%s: %s\n", s, posix_strerror(errno));
280 }
281}
282
283/** Restores stream a to position previously saved with fgetpos().
284 *
285 * @param stream Stream to restore
286 * @param pos Position to restore
287 * @return Zero on success, non-zero (with errno set) on failure
288 */
289int posix_fsetpos(FILE *stream, const posix_fpos_t *pos)
290{
291 return fseek(stream, pos->offset, SEEK_SET);
292}
293
294/** Saves the stream's position for later use by fsetpos().
295 *
296 * @param stream Stream to save
297 * @param pos Place to store the position
298 * @return Zero on success, non-zero (with errno set) on failure
299 */
300int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos)
301{
302 off64_t ret = ftell(stream);
[cfbb5d18]303 if (ret != -1) {
304 pos->offset = ret;
305 return 0;
306 } else {
307 return -1;
[8b5fb5e]308 }
309}
310
311/**
[1978a5f]312 * Reposition a file-position indicator in a stream.
[8b5fb5e]313 *
[1978a5f]314 * @param stream Stream to seek in.
315 * @param offset Direction and amount of bytes to seek.
316 * @param whence From where to seek.
317 * @return Zero on success, -1 otherwise.
[8b5fb5e]318 */
319int posix_fseek(FILE *stream, long offset, int whence)
320{
321 return fseek(stream, (off64_t) offset, whence);
[09b0b1fb]322}
323
[b08ef1fd]324/**
[1978a5f]325 * Reposition a file-position indicator in a stream.
[b08ef1fd]326 *
[1978a5f]327 * @param stream Stream to seek in.
328 * @param offset Direction and amount of bytes to seek.
329 * @param whence From where to seek.
330 * @return Zero on success, -1 otherwise.
[b08ef1fd]331 */
332int posix_fseeko(FILE *stream, posix_off_t offset, int whence)
333{
[8b5fb5e]334 return fseek(stream, (off64_t) offset, whence);
335}
336
337/**
[1978a5f]338 * Discover current file offset in a stream.
[8b5fb5e]339 *
[1978a5f]340 * @param stream Stream for which the offset shall be retrieved.
341 * @return Current offset or -1 if not possible.
[8b5fb5e]342 */
343long posix_ftell(FILE *stream)
344{
345 return (long) ftell(stream);
[b08ef1fd]346}
347
348/**
[1978a5f]349 * Discover current file offset in a stream.
[b08ef1fd]350 *
[1978a5f]351 * @param stream Stream for which the offset shall be retrieved.
352 * @return Current offset or -1 if not possible.
[b08ef1fd]353 */
354posix_off_t posix_ftello(FILE *stream)
355{
[8b5fb5e]356 return (posix_off_t) ftell(stream);
357}
358
[221afc9e]359/**
360 * Discard prefetched data or write unwritten data.
361 *
362 * @param stream Stream that shall be flushed.
363 * @return Zero on success, EOF on failure.
364 */
365int posix_fflush(FILE *stream)
366{
367 int rc = fflush(stream);
368 if (rc < 0) {
369 errno = -rc;
370 return EOF;
371 } else {
372 return 0;
373 }
374}
375
[1978a5f]376/**
377 * Print formatted output to the opened file.
378 *
379 * @param fildes File descriptor of the opened file.
380 * @param format Format description.
381 * @return Either the number of printed characters or negative value on error.
382 */
[8b5fb5e]383int posix_dprintf(int fildes, const char *restrict format, ...)
384{
385 va_list list;
386 va_start(list, format);
387 int result = posix_vdprintf(fildes, format, list);
388 va_end(list);
389 return result;
390}
391
[1978a5f]392/**
393 * Write ordinary string to the opened file.
394 *
395 * @param str String to be written.
396 * @param size Size of the string (in bytes)..
397 * @param fd File descriptor of the opened file.
398 * @return The number of written characters.
399 */
[8b5fb5e]400static int _dprintf_str_write(const char *str, size_t size, void *fd)
401{
402 ssize_t wr = write(*(int *) fd, str, size);
403 return str_nlength(str, wr);
404}
405
[1978a5f]406/**
407 * Write wide string to the opened file.
408 *
409 * @param str String to be written.
410 * @param size Size of the string (in bytes).
411 * @param fd File descriptor of the opened file.
412 * @return The number of written characters.
413 */
[8b5fb5e]414static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd)
415{
416 size_t offset = 0;
417 size_t chars = 0;
418 size_t sz;
419 char buf[4];
420
421 while (offset < size) {
422 sz = 0;
423 if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) {
424 break;
425 }
426
427 if (write(*(int *) fd, buf, sz) != (ssize_t) sz) {
428 break;
429 }
430
431 chars++;
432 offset += sizeof(wchar_t);
433 }
434
435 return chars;
436}
437
[1978a5f]438/**
439 * Print formatted output to the opened file.
440 *
441 * @param fildes File descriptor of the opened file.
442 * @param format Format description.
443 * @param ap Print arguments.
444 * @return Either the number of printed characters or negative value on error.
445 */
[8b5fb5e]446int posix_vdprintf(int fildes, const char *restrict format, va_list ap)
447{
448 printf_spec_t spec = {
449 .str_write = _dprintf_str_write,
450 .wstr_write = _dprintf_wstr_write,
451 .data = &fildes
452 };
453
454 return printf_core(format, &spec, ap);
[b08ef1fd]455}
456
[59f799b]457/**
[1978a5f]458 * Print formatted output to the string.
[59f799b]459 *
[1978a5f]460 * @param s Output string.
461 * @param format Format description.
462 * @return Either the number of printed characters (excluding null byte) or
463 * negative value on error.
[59f799b]464 */
[08053f7]465int posix_sprintf(char *s, const char *restrict format, ...)
[59f799b]466{
[8b5fb5e]467 va_list list;
468 va_start(list, format);
469 int result = posix_vsprintf(s, format, list);
470 va_end(list);
471 return result;
[59f799b]472}
473
[823a929]474/**
[1978a5f]475 * Print formatted output to the string.
[823a929]476 *
[1978a5f]477 * @param s Output string.
478 * @param format Format description.
479 * @param ap Print arguments.
480 * @return Either the number of printed characters (excluding null byte) or
481 * negative value on error.
[823a929]482 */
[08053f7]483int posix_vsprintf(char *s, const char *restrict format, va_list ap)
[823a929]484{
[8b5fb5e]485 return vsnprintf(s, STR_NO_LIMIT, format, ap);
486}
487
488/**
[1978a5f]489 * Convert formatted input from the stream.
[8b5fb5e]490 *
[1978a5f]491 * @param stream Input stream.
492 * @param format Format description.
493 * @return The number of converted output items or EOF on failure.
[8b5fb5e]494 */
495int posix_fscanf(FILE *restrict stream, const char *restrict format, ...)
496{
497 va_list list;
498 va_start(list, format);
499 int result = posix_vfscanf(stream, format, list);
500 va_end(list);
501 return result;
502}
503
504/**
[1978a5f]505 * Convert formatted input from the standard input.
[8b5fb5e]506 *
[1978a5f]507 * @param format Format description.
508 * @return The number of converted output items or EOF on failure.
[8b5fb5e]509 */
510int posix_scanf(const char *restrict format, ...)
511{
512 va_list list;
513 va_start(list, format);
514 int result = posix_vscanf(format, list);
515 va_end(list);
516 return result;
517}
518
519/**
[1978a5f]520 * Convert formatted input from the standard input.
[8b5fb5e]521 *
[1978a5f]522 * @param format Format description.
523 * @param arg Output items.
524 * @return The number of converted output items or EOF on failure.
[8b5fb5e]525 */
526int posix_vscanf(const char *restrict format, va_list arg)
527{
528 return posix_vfscanf(stdin, format, arg);
529}
530
[59f799b]531/**
[1978a5f]532 * Convert formatted input from the string.
[59f799b]533 *
[1978a5f]534 * @param s Input string.
535 * @param format Format description.
536 * @return The number of converted output items or EOF on failure.
[59f799b]537 */
[08053f7]538int posix_sscanf(const char *restrict s, const char *restrict format, ...)
[8b5fb5e]539{
540 va_list list;
541 va_start(list, format);
542 int result = posix_vsscanf(s, format, list);
543 va_end(list);
544 return result;
545}
546
[1978a5f]547/**
548 * Acquire file stream for the thread.
549 *
550 * @param file File stream to lock.
551 */
[8b5fb5e]552void posix_flockfile(FILE *file)
553{
554 /* dummy */
555}
556
[1978a5f]557/**
558 * Acquire file stream for the thread (non-blocking).
559 *
560 * @param file File stream to lock.
561 * @return Zero for success and non-zero if the lock cannot be acquired.
562 */
[8b5fb5e]563int posix_ftrylockfile(FILE *file)
564{
565 /* dummy */
566 return 0;
567}
568
[1978a5f]569/**
570 * Relinquish the ownership of the locked file stream.
571 *
572 * @param file File stream to unlock.
573 */
[8b5fb5e]574void posix_funlockfile(FILE *file)
575{
576 /* dummy */
577}
578
[1978a5f]579/**
580 * Get a byte from a stream (thread-unsafe).
581 *
582 * @param stream Input file stream.
583 * @return Either read byte or EOF.
584 */
[8b5fb5e]585int posix_getc_unlocked(FILE *stream)
586{
587 return getc(stream);
588}
589
[1978a5f]590/**
591 * Get a byte from the standard input stream (thread-unsafe).
592 *
593 * @return Either read byte or EOF.
594 */
[8b5fb5e]595int posix_getchar_unlocked(void)
596{
597 return getchar();
598}
599
[1978a5f]600/**
601 * Put a byte on a stream (thread-unsafe).
602 *
603 * @param c Byte to output.
604 * @param stream Output file stream.
605 * @return Either written byte or EOF.
606 */
[8b5fb5e]607int posix_putc_unlocked(int c, FILE *stream)
608{
609 return putc(c, stream);
610}
611
[1978a5f]612/**
613 * Put a byte on the standard output stream (thread-unsafe).
614 *
615 * @param c Byte to output.
616 * @return Either written byte or EOF.
617 */
[8b5fb5e]618int posix_putchar_unlocked(int c)
619{
620 return putchar(c);
621}
622
[823a929]623/**
[58115ae]624 * Remove a file or directory.
[823a929]625 *
[1978a5f]626 * @param path Pathname of the file that shall be removed.
[58115ae]627 * @return Zero on success, -1 (with errno set) otherwise.
[823a929]628 */
629int posix_remove(const char *path)
630{
[58115ae]631 struct stat st;
632 int rc = stat(path, &st);
633
634 if (rc != EOK) {
635 errno = -rc;
636 return -1;
637 }
638
639 if (st.is_directory) {
640 rc = rmdir(path);
641 } else {
642 rc = unlink(path);
643 }
644
645 if (rc != EOK) {
646 errno = -rc;
647 return -1;
648 }
649 return 0;
[823a929]650}
651
[75406dc]652/**
653 * Rename a file or directory.
654 *
[2a53f71]655 * @param old Old pathname.
656 * @param new New pathname.
[75406dc]657 * @return Zero on success, -1 (with errno set) otherwise.
658 */
659int posix_rename(const char *old, const char *new)
660{
661 return errnify(rename, old, new);
662}
663
[823a929]664/**
[11544f4]665 * Get a unique temporary file name (obsolete).
666 *
667 * @param s Buffer for the file name. Must be at least L_tmpnam bytes long.
668 * @return The value of s on success, NULL on failure.
[823a929]669 */
670char *posix_tmpnam(char *s)
671{
[11544f4]672 assert(L_tmpnam >= posix_strlen("/tmp/tnXXXXXX"));
673
674 static char buffer[L_tmpnam + 1];
675 if (s == NULL) {
676 s = buffer;
677 }
678
679 posix_strcpy(s, "/tmp/tnXXXXXX");
680 posix_mktemp(s);
681
682 if (*s == '\0') {
683 /* Errno set by mktemp(). */
684 return NULL;
685 }
686
687 return s;
688}
689
690/**
691 * Get an unique temporary file name with additional constraints (obsolete).
692 *
693 * @param dir Path to directory, where the file should be created.
694 * @param pfx Optional prefix up to 5 characters long.
695 * @return Newly allocated unique path for temporary file. NULL on failure.
696 */
697char *posix_tempnam(const char *dir, const char *pfx)
698{
699 /* Sequence number of the filename. */
700 static int seq = 0;
701
702 size_t dir_len = posix_strlen(dir);
703 if (dir[dir_len - 1] == '/') {
704 dir_len--;
705 }
706
707 size_t pfx_len = posix_strlen(pfx);
708 if (pfx_len > 5) {
709 pfx_len = 5;
710 }
711
712 char *result = malloc(dir_len + /* slash*/ 1 +
713 pfx_len + /* three-digit seq */ 3 + /* .tmp */ 4 + /* nul */ 1);
714
715 if (result == NULL) {
716 errno = ENOMEM;
717 return NULL;
718 }
719
720 char *res_ptr = result;
721 posix_strncpy(res_ptr, dir, dir_len);
722 res_ptr += dir_len;
723 posix_strncpy(res_ptr, pfx, pfx_len);
724 res_ptr += pfx_len;
725
726 for (; seq < 1000; ++seq) {
727 snprintf(res_ptr, 8, "%03d.tmp", seq);
728
729 int orig_errno = errno;
730 errno = 0;
731 /* Check if the file exists. */
732 if (posix_access(result, F_OK) == -1) {
733 if (errno == ENOENT) {
734 errno = orig_errno;
735 break;
736 } else {
737 /* errno set by access() */
738 return NULL;
739 }
740 }
741 }
742
743 if (seq == 1000) {
744 free(result);
745 errno = EINVAL;
746 return NULL;
747 }
748
749 return result;
750}
751
752/**
753 * Create and open an unique temporary file.
754 * The file is automatically removed when the stream is closed.
755 *
756 * @param dir Path to directory, where the file should be created.
757 * @param pfx Optional prefix up to 5 characters long.
758 * @return Newly allocated unique path for temporary file. NULL on failure.
759 */
760FILE *posix_tmpfile(void)
761{
762 char filename[] = "/tmp/tfXXXXXX";
763 int fd = posix_mkstemp(filename);
764 if (fd == -1) {
765 /* errno set by mkstemp(). */
766 return NULL;
767 }
768
769 /* Unlink the created file, so that it's removed on close(). */
770 posix_unlink(filename);
771 return fdopen(fd, "w+");
[823a929]772}
773
[09b0b1fb]774/** @}
775 */
Note: See TracBrowser for help on using the repository browser.