Changes in uspace/lib/posix/stdio.c [9b1503e:221afc9e] in mainline
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
uspace/lib/posix/stdio.c
r9b1503e r221afc9e 36 36 #define LIBPOSIX_INTERNAL 37 37 38 #include <assert.h> 39 #include <errno.h>38 /* Has to be first. */ 39 #include "stdbool.h" 40 40 41 41 #include "internal/common.h" 42 42 #include "stdio.h" 43 44 #include "assert.h" 45 #include "errno.h" 43 46 #include "string.h" 44 45 /* not the best of solutions, but freopen will eventually 47 #include "sys/types.h" 48 49 #include "libc/io/printf_core.h" 50 #include "libc/str.h" 51 #include "libc/malloc.h" 52 53 54 /* not the best of solutions, but freopen and ungetc will eventually 46 55 * need to be implemented in libc anyway 47 56 */ 48 57 #include "../c/generic/private/stdio.h" 49 58 50 /** 51 * 52 * @param c 53 * @param stream 54 * @return 59 /** Clears the stream's error and end-of-file indicators. 60 * 61 * @param stream Stream whose indicators shall be cleared. 62 */ 63 void posix_clearerr(FILE *stream) 64 { 65 stream->error = 0; 66 stream->eof = 0; 67 } 68 69 /** 70 * Generate a pathname for the controlling terminal. 71 * 72 * @param s Allocated buffer to which the pathname shall be put. 73 * @return Either s or static location filled with the requested pathname. 74 */ 75 char *posix_ctermid(char *s) 76 { 77 /* Currently always returns an error value (empty string). */ 78 // TODO: return a real terminal path 79 80 static char dummy_path[L_ctermid] = {'\0'}; 81 82 if (s == NULL) { 83 return dummy_path; 84 } 85 86 s[0] = '\0'; 87 return s; 88 } 89 90 /** 91 * Put a string on the stream. 92 * 93 * @param s String to be written. 94 * @param stream Output stream. 95 * @return Non-negative on success, EOF on failure. 96 */ 97 int posix_fputs(const char *restrict s, FILE *restrict stream) 98 { 99 int rc = fputs(s, stream); 100 if (rc == 0) { 101 return EOF; 102 } else { 103 return 0; 104 } 105 } 106 107 /** 108 * Push byte back into input stream. 109 * 110 * @param c Byte to be pushed back. 111 * @param stream Stream to where the byte shall be pushed. 112 * @return Provided byte on success or EOF if not possible. 55 113 */ 56 114 int posix_ungetc(int c, FILE *stream) 57 115 { 58 // TODO 59 not_implemented(); 60 } 61 62 /** 63 * 64 * @param filename 65 * @param mode 66 * @param stream 67 * @return 68 */ 69 FILE *posix_freopen( 70 const char *restrict filename, 71 const char *restrict mode, 116 uint8_t b = (uint8_t) c; 117 118 bool can_unget = 119 /* Provided character is legal. */ 120 c != EOF && 121 /* Stream is consistent. */ 122 !stream->error && 123 /* Stream is buffered. */ 124 stream->btype != _IONBF && 125 /* Last operation on the stream was a read operation. */ 126 stream->buf_state == _bs_read && 127 /* Stream buffer is already allocated (i.e. there was already carried 128 * out either write or read operation on the stream). This is probably 129 * redundant check but let's be safe. */ 130 stream->buf != NULL && 131 /* There is still space in the stream to retreat. POSIX demands the 132 * possibility to unget at least 1 character. It should be always 133 * possible, assuming the last operation on the stream read at least 1 134 * character, because the buffer is refilled in the lazily manner. */ 135 stream->buf_tail > stream->buf; 136 137 if (can_unget) { 138 --stream->buf_tail; 139 stream->buf_tail[0] = b; 140 stream->eof = false; 141 return (int) b; 142 } else { 143 return EOF; 144 } 145 } 146 147 /** 148 * Read a stream until the delimiter (or EOF) is encountered. 149 * 150 * @param lineptr Pointer to the output buffer in which there will be stored 151 * nul-terminated string together with the delimiter (if encountered). 152 * Will be resized if necessary. 153 * @param n Pointer to the size of the output buffer. Will be increased if 154 * necessary. 155 * @param delimiter Delimiter on which to finish reading the stream. 156 * @param stream Input stream. 157 * @return Number of fetched characters (including delimiter if encountered) 158 * or -1 on error (set in errno). 159 */ 160 ssize_t posix_getdelim(char **restrict lineptr, size_t *restrict n, 161 int delimiter, FILE *restrict stream) 162 { 163 /* Check arguments for sanity. */ 164 if (!lineptr || !n) { 165 errno = EINVAL; 166 return -1; 167 } 168 169 size_t alloc_step = 80; /* Buffer size gain during reallocation. */ 170 char *pos = *lineptr; /* Next free byte of the output buffer. */ 171 size_t cnt = 0; /* Number of fetched characters. */ 172 int c = fgetc(stream); /* Current input character. Might be EOF. */ 173 174 do { 175 /* Mask EOF as NUL to terminate string. */ 176 if (c == EOF) { 177 c = '\0'; 178 } 179 180 /* Ensure there is still space left in the buffer. */ 181 if (pos == *lineptr + *n) { 182 *lineptr = realloc(*lineptr, *n + alloc_step); 183 if (*lineptr) { 184 pos = *lineptr + *n; 185 *n += alloc_step; 186 } else { 187 errno = ENOMEM; 188 return -1; 189 } 190 } 191 192 /* Store the fetched character. */ 193 *pos = c; 194 195 /* Fetch the next character according to the current character. */ 196 if (c != '\0') { 197 ++pos; 198 ++cnt; 199 if (c == delimiter) { 200 /* Delimiter was just stored. Provide EOF as the next 201 * character - it will be masked as NUL and output string 202 * will be properly terminated. */ 203 c = EOF; 204 } else { 205 /* Neither delimiter nor EOF were encountered. Just fetch 206 * the next character from the stream. */ 207 c = fgetc(stream); 208 } 209 } 210 } while (c != '\0'); 211 212 if (errno == EOK && cnt > 0) { 213 return cnt; 214 } else { 215 /* Either some error occured or the stream was already at EOF. */ 216 return -1; 217 } 218 } 219 220 /** 221 * Read a stream until the newline (or EOF) is encountered. 222 * 223 * @param lineptr Pointer to the output buffer in which there will be stored 224 * nul-terminated string together with the delimiter (if encountered). 225 * Will be resized if necessary. 226 * @param n Pointer to the size of the output buffer. Will be increased if 227 * necessary. 228 * @param stream Input stream. 229 * @return Number of fetched characters (including newline if encountered) 230 * or -1 on error (set in errno). 231 */ 232 ssize_t posix_getline(char **restrict lineptr, size_t *restrict n, 72 233 FILE *restrict stream) 234 { 235 return posix_getdelim(lineptr, n, '\n', stream); 236 } 237 238 /** 239 * Reopen a file stream. 240 * 241 * @param filename Pathname of a file to be reopened or NULL for changing 242 * the mode of the stream. 243 * @param mode Mode to be used for reopening the file or changing current 244 * mode of the stream. 245 * @param stream Current stream associated with the opened file. 246 * @return On success, either a stream of the reopened file or the provided 247 * stream with a changed mode. NULL otherwise. 248 */ 249 FILE *posix_freopen(const char *restrict filename, 250 const char *restrict mode, FILE *restrict stream) 73 251 { 74 252 assert(mode != NULL); … … 115 293 /** 116 294 * 117 * @param s 118 */ 119 void posix_perror(const char *s) 295 * @param buf 296 * @param size 297 * @param mode 298 * @return 299 */ 300 FILE *posix_fmemopen(void *restrict buf, size_t size, 301 const char *restrict mode) 120 302 { 121 303 // TODO … … 124 306 125 307 /** 126 * 127 * @param stream 128 * @param offset 129 * @param whence 308 * 309 * @param bufp 310 * @param sizep 130 311 * @return 131 312 */ 132 int posix_fseeko(FILE *stream, posix_off_t offset, int whence)313 FILE *posix_open_memstream(char **bufp, size_t *sizep) 133 314 { 134 315 // TODO … … 137 318 138 319 /** 139 * 140 * @param stream 320 * Write error messages to standard error. 321 * 322 * @param s Error message. 323 */ 324 void posix_perror(const char *s) 325 { 326 if (s == NULL || s[0] == '\0') { 327 fprintf(stderr, "%s\n", posix_strerror(errno)); 328 } else { 329 fprintf(stderr, "%s: %s\n", s, posix_strerror(errno)); 330 } 331 } 332 333 struct _posix_fpos { 334 off64_t offset; 335 }; 336 337 /** Restores stream a to position previously saved with fgetpos(). 338 * 339 * @param stream Stream to restore 340 * @param pos Position to restore 341 * @return Zero on success, non-zero (with errno set) on failure 342 */ 343 int posix_fsetpos(FILE *stream, const posix_fpos_t *pos) 344 { 345 return fseek(stream, pos->offset, SEEK_SET); 346 } 347 348 /** Saves the stream's position for later use by fsetpos(). 349 * 350 * @param stream Stream to save 351 * @param pos Place to store the position 352 * @return Zero on success, non-zero (with errno set) on failure 353 */ 354 int posix_fgetpos(FILE *restrict stream, posix_fpos_t *restrict pos) 355 { 356 off64_t ret = ftell(stream); 357 if (ret == -1) { 358 return errno; 359 } 360 pos->offset = ret; 361 return 0; 362 } 363 364 /** 365 * Reposition a file-position indicator in a stream. 366 * 367 * @param stream Stream to seek in. 368 * @param offset Direction and amount of bytes to seek. 369 * @param whence From where to seek. 370 * @return Zero on success, -1 otherwise. 371 */ 372 int posix_fseek(FILE *stream, long offset, int whence) 373 { 374 return fseek(stream, (off64_t) offset, whence); 375 } 376 377 /** 378 * Reposition a file-position indicator in a stream. 379 * 380 * @param stream Stream to seek in. 381 * @param offset Direction and amount of bytes to seek. 382 * @param whence From where to seek. 383 * @return Zero on success, -1 otherwise. 384 */ 385 int posix_fseeko(FILE *stream, posix_off_t offset, int whence) 386 { 387 return fseek(stream, (off64_t) offset, whence); 388 } 389 390 /** 391 * Discover current file offset in a stream. 392 * 393 * @param stream Stream for which the offset shall be retrieved. 394 * @return Current offset or -1 if not possible. 395 */ 396 long posix_ftell(FILE *stream) 397 { 398 return (long) ftell(stream); 399 } 400 401 /** 402 * Discover current file offset in a stream. 403 * 404 * @param stream Stream for which the offset shall be retrieved. 405 * @return Current offset or -1 if not possible. 406 */ 407 posix_off_t posix_ftello(FILE *stream) 408 { 409 return (posix_off_t) ftell(stream); 410 } 411 412 /** 413 * Discard prefetched data or write unwritten data. 414 * 415 * @param stream Stream that shall be flushed. 416 * @return Zero on success, EOF on failure. 417 */ 418 int posix_fflush(FILE *stream) 419 { 420 int rc = fflush(stream); 421 if (rc < 0) { 422 errno = -rc; 423 return EOF; 424 } else { 425 return 0; 426 } 427 } 428 429 /** 430 * Print formatted output to the opened file. 431 * 432 * @param fildes File descriptor of the opened file. 433 * @param format Format description. 434 * @return Either the number of printed characters or negative value on error. 435 */ 436 int posix_dprintf(int fildes, const char *restrict format, ...) 437 { 438 va_list list; 439 va_start(list, format); 440 int result = posix_vdprintf(fildes, format, list); 441 va_end(list); 442 return result; 443 } 444 445 /** 446 * Write ordinary string to the opened file. 447 * 448 * @param str String to be written. 449 * @param size Size of the string (in bytes).. 450 * @param fd File descriptor of the opened file. 451 * @return The number of written characters. 452 */ 453 static int _dprintf_str_write(const char *str, size_t size, void *fd) 454 { 455 ssize_t wr = write(*(int *) fd, str, size); 456 return str_nlength(str, wr); 457 } 458 459 /** 460 * Write wide string to the opened file. 461 * 462 * @param str String to be written. 463 * @param size Size of the string (in bytes). 464 * @param fd File descriptor of the opened file. 465 * @return The number of written characters. 466 */ 467 static int _dprintf_wstr_write(const wchar_t *str, size_t size, void *fd) 468 { 469 size_t offset = 0; 470 size_t chars = 0; 471 size_t sz; 472 char buf[4]; 473 474 while (offset < size) { 475 sz = 0; 476 if (chr_encode(str[chars], buf, &sz, sizeof(buf)) != EOK) { 477 break; 478 } 479 480 if (write(*(int *) fd, buf, sz) != (ssize_t) sz) { 481 break; 482 } 483 484 chars++; 485 offset += sizeof(wchar_t); 486 } 487 488 return chars; 489 } 490 491 /** 492 * Print formatted output to the opened file. 493 * 494 * @param fildes File descriptor of the opened file. 495 * @param format Format description. 496 * @param ap Print arguments. 497 * @return Either the number of printed characters or negative value on error. 498 */ 499 int posix_vdprintf(int fildes, const char *restrict format, va_list ap) 500 { 501 printf_spec_t spec = { 502 .str_write = _dprintf_str_write, 503 .wstr_write = _dprintf_wstr_write, 504 .data = &fildes 505 }; 506 507 return printf_core(format, &spec, ap); 508 } 509 510 /** 511 * Print formatted output to the string. 512 * 513 * @param s Output string. 514 * @param format Format description. 515 * @return Either the number of printed characters (excluding null byte) or 516 * negative value on error. 517 */ 518 int posix_sprintf(char *s, const char *restrict format, ...) 519 { 520 va_list list; 521 va_start(list, format); 522 int result = posix_vsprintf(s, format, list); 523 va_end(list); 524 return result; 525 } 526 527 /** 528 * Print formatted output to the string. 529 * 530 * @param s Output string. 531 * @param format Format description. 532 * @param ap Print arguments. 533 * @return Either the number of printed characters (excluding null byte) or 534 * negative value on error. 535 */ 536 int posix_vsprintf(char *s, const char *restrict format, va_list ap) 537 { 538 return vsnprintf(s, STR_NO_LIMIT, format, ap); 539 } 540 541 /** 542 * Convert formatted input from the stream. 543 * 544 * @param stream Input stream. 545 * @param format Format description. 546 * @return The number of converted output items or EOF on failure. 547 */ 548 int posix_fscanf(FILE *restrict stream, const char *restrict format, ...) 549 { 550 va_list list; 551 va_start(list, format); 552 int result = posix_vfscanf(stream, format, list); 553 va_end(list); 554 return result; 555 } 556 557 /** 558 * Convert formatted input from the standard input. 559 * 560 * @param format Format description. 561 * @return The number of converted output items or EOF on failure. 562 */ 563 int posix_scanf(const char *restrict format, ...) 564 { 565 va_list list; 566 va_start(list, format); 567 int result = posix_vscanf(format, list); 568 va_end(list); 569 return result; 570 } 571 572 /** 573 * Convert formatted input from the standard input. 574 * 575 * @param format Format description. 576 * @param arg Output items. 577 * @return The number of converted output items or EOF on failure. 578 */ 579 int posix_vscanf(const char *restrict format, va_list arg) 580 { 581 return posix_vfscanf(stdin, format, arg); 582 } 583 584 /** 585 * Convert formatted input from the string. 586 * 587 * @param s Input string. 588 * @param format Format description. 589 * @return The number of converted output items or EOF on failure. 590 */ 591 int posix_sscanf(const char *restrict s, const char *restrict format, ...) 592 { 593 va_list list; 594 va_start(list, format); 595 int result = posix_vsscanf(s, format, list); 596 va_end(list); 597 return result; 598 } 599 600 /** 601 * Acquire file stream for the thread. 602 * 603 * @param file File stream to lock. 604 */ 605 void posix_flockfile(FILE *file) 606 { 607 /* dummy */ 608 } 609 610 /** 611 * Acquire file stream for the thread (non-blocking). 612 * 613 * @param file File stream to lock. 614 * @return Zero for success and non-zero if the lock cannot be acquired. 615 */ 616 int posix_ftrylockfile(FILE *file) 617 { 618 /* dummy */ 619 return 0; 620 } 621 622 /** 623 * Relinquish the ownership of the locked file stream. 624 * 625 * @param file File stream to unlock. 626 */ 627 void posix_funlockfile(FILE *file) 628 { 629 /* dummy */ 630 } 631 632 /** 633 * Get a byte from a stream (thread-unsafe). 634 * 635 * @param stream Input file stream. 636 * @return Either read byte or EOF. 637 */ 638 int posix_getc_unlocked(FILE *stream) 639 { 640 return getc(stream); 641 } 642 643 /** 644 * Get a byte from the standard input stream (thread-unsafe). 645 * 646 * @return Either read byte or EOF. 647 */ 648 int posix_getchar_unlocked(void) 649 { 650 return getchar(); 651 } 652 653 /** 654 * Put a byte on a stream (thread-unsafe). 655 * 656 * @param c Byte to output. 657 * @param stream Output file stream. 658 * @return Either written byte or EOF. 659 */ 660 int posix_putc_unlocked(int c, FILE *stream) 661 { 662 return putc(c, stream); 663 } 664 665 /** 666 * Put a byte on the standard output stream (thread-unsafe). 667 * 668 * @param c Byte to output. 669 * @return Either written byte or EOF. 670 */ 671 int posix_putchar_unlocked(int c) 672 { 673 return putchar(c); 674 } 675 676 /** 677 * Remove a file. 678 * 679 * @param path Pathname of the file that shall be removed. 680 * @return Zero on success, -1 otherwise. 681 */ 682 int posix_remove(const char *path) 683 { 684 // FIXME: unlink() and rmdir() seem to be equivalent at the moment, 685 // but that does not have to be true forever 686 return unlink(path); 687 } 688 689 /** 690 * 691 * @param s 141 692 * @return 142 693 */ 143 posix_off_t posix_ftello(FILE *stream)144 { 145 // TODO 694 char *posix_tmpnam(char *s) 695 { 696 // TODO: low priority, just a compile-time dependency of binutils 146 697 not_implemented(); 147 698 } 148 699 149 /**150 *151 * @param s152 * @param format153 * @param ...154 * @return155 */156 int posix_sprintf(char *s, const char *format, ...)157 {158 // TODO159 not_implemented();160 }161 162 /**163 *164 * @param s165 * @param format166 * @param ...167 * @return168 */169 int posix_sscanf(const char *s, const char *format, ...)170 {171 // TODO172 not_implemented();173 }174 175 700 /** @} 176 701 */
Note:
See TracChangeset
for help on using the changeset viewer.