stdio.cpp 16 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710
  1. /*
  2. * Copyright (c) 2018-2020, Andreas Kling <kling@serenityos.org>
  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 are met:
  7. *
  8. * 1. Redistributions of source code must retain the above copyright notice, this
  9. * list of conditions and the following disclaimer.
  10. *
  11. * 2. Redistributions in binary form must reproduce the above copyright notice,
  12. * this list of conditions and the following disclaimer in the documentation
  13. * and/or other materials provided with the distribution.
  14. *
  15. * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS"
  16. * AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
  17. * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
  18. * DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE
  19. * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
  20. * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
  21. * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER
  22. * CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
  23. * OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
  24. * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
  25. */
  26. #include <AK/LogStream.h>
  27. #include <AK/PrintfImplementation.h>
  28. #include <AK/ScopedValueRollback.h>
  29. #include <AK/StdLibExtras.h>
  30. #include <Kernel/Syscall.h>
  31. #include <assert.h>
  32. #include <errno.h>
  33. #include <fcntl.h>
  34. #include <stdarg.h>
  35. #include <stdio.h>
  36. #include <stdlib.h>
  37. #include <string.h>
  38. #include <sys/types.h>
  39. #include <sys/wait.h>
  40. #include <unistd.h>
  41. extern "C" {
  42. static FILE __default_streams[3];
  43. FILE* stdin;
  44. FILE* stdout;
  45. FILE* stderr;
  46. void init_FILE(FILE& fp, int fd, int mode)
  47. {
  48. fp.fd = fd;
  49. fp.buffer = fp.default_buffer;
  50. fp.buffer_size = BUFSIZ;
  51. fp.mode = mode;
  52. }
  53. static FILE* make_FILE(int fd)
  54. {
  55. auto* fp = (FILE*)malloc(sizeof(FILE));
  56. memset(fp, 0, sizeof(FILE));
  57. init_FILE(*fp, fd, isatty(fd));
  58. return fp;
  59. }
  60. void __stdio_init()
  61. {
  62. stdin = &__default_streams[0];
  63. stdout = &__default_streams[1];
  64. stderr = &__default_streams[2];
  65. init_FILE(*stdin, 0, isatty(0) ? _IOLBF : _IOFBF);
  66. init_FILE(*stdout, 1, isatty(1) ? _IOLBF : _IOFBF);
  67. init_FILE(*stderr, 2, _IONBF);
  68. }
  69. int setvbuf(FILE* stream, char* buf, int mode, size_t size)
  70. {
  71. if (mode != _IONBF && mode != _IOLBF && mode != _IOFBF) {
  72. errno = EINVAL;
  73. return -1;
  74. }
  75. stream->mode = mode;
  76. if (buf) {
  77. stream->buffer = buf;
  78. stream->buffer_size = size;
  79. } else {
  80. stream->buffer = stream->default_buffer;
  81. stream->buffer_size = BUFSIZ;
  82. }
  83. stream->buffer_index = 0;
  84. return 0;
  85. }
  86. void setbuf(FILE* stream, char* buf)
  87. {
  88. setvbuf(stream, buf, buf ? _IOFBF : _IONBF, BUFSIZ);
  89. }
  90. void setlinebuf(FILE* stream)
  91. {
  92. setvbuf(stream, nullptr, _IOLBF, 0);
  93. }
  94. int fileno(FILE* stream)
  95. {
  96. assert(stream);
  97. return stream->fd;
  98. }
  99. int feof(FILE* stream)
  100. {
  101. assert(stream);
  102. return stream->eof;
  103. }
  104. int fflush(FILE* stream)
  105. {
  106. if (!stream) {
  107. dbg() << "FIXME: fflush(nullptr) should flush all open streams";
  108. return 0;
  109. }
  110. if (!stream->buffer_index)
  111. return 0;
  112. int rc = write(stream->fd, stream->buffer, stream->buffer_index);
  113. stream->buffer_index = 0;
  114. stream->error = 0;
  115. stream->eof = 0;
  116. stream->have_ungotten = false;
  117. stream->ungotten = 0;
  118. if (rc < 0) {
  119. stream->error = errno;
  120. return EOF;
  121. }
  122. return 0;
  123. }
  124. char* fgets(char* buffer, int size, FILE* stream)
  125. {
  126. ASSERT(stream);
  127. ASSERT(size);
  128. ssize_t nread = 0;
  129. while (nread < (size - 1)) {
  130. int ch = fgetc(stream);
  131. if (ch == EOF)
  132. break;
  133. buffer[nread++] = ch;
  134. if (ch == '\n')
  135. break;
  136. }
  137. if (nread) {
  138. buffer[nread] = '\0';
  139. return buffer;
  140. }
  141. return nullptr;
  142. }
  143. int fgetc(FILE* stream)
  144. {
  145. assert(stream);
  146. char ch;
  147. size_t nread = fread(&ch, sizeof(char), 1, stream);
  148. if (nread == 1)
  149. return ch;
  150. return EOF;
  151. }
  152. int getc(FILE* stream)
  153. {
  154. return fgetc(stream);
  155. }
  156. int getc_unlocked(FILE* stream)
  157. {
  158. return fgetc(stream);
  159. }
  160. int getchar()
  161. {
  162. return getc(stdin);
  163. }
  164. ssize_t getdelim(char** lineptr, size_t* n, int delim, FILE* stream)
  165. {
  166. char *ptr, *eptr;
  167. if (*lineptr == nullptr || *n == 0) {
  168. *n = BUFSIZ;
  169. if ((*lineptr = static_cast<char*>(malloc(*n))) == nullptr) {
  170. return -1;
  171. }
  172. }
  173. for (ptr = *lineptr, eptr = *lineptr + *n;;) {
  174. int c = fgetc(stream);
  175. if (c == -1) {
  176. if (feof(stream)) {
  177. *ptr = '\0';
  178. return ptr == *lineptr ? -1 : ptr - *lineptr;
  179. } else {
  180. return -1;
  181. }
  182. }
  183. *ptr++ = c;
  184. if (c == delim) {
  185. *ptr = '\0';
  186. return ptr - *lineptr;
  187. }
  188. if (ptr + 2 >= eptr) {
  189. char* nbuf;
  190. size_t nbuf_sz = *n * 2;
  191. ssize_t d = ptr - *lineptr;
  192. if ((nbuf = static_cast<char*>(realloc(*lineptr, nbuf_sz))) == nullptr) {
  193. return -1;
  194. }
  195. *lineptr = nbuf;
  196. *n = nbuf_sz;
  197. eptr = nbuf + nbuf_sz;
  198. ptr = nbuf + d;
  199. }
  200. }
  201. }
  202. ssize_t getline(char** lineptr, size_t* n, FILE* stream)
  203. {
  204. return getdelim(lineptr, n, '\n', stream);
  205. }
  206. int ungetc(int c, FILE* stream)
  207. {
  208. ASSERT(stream);
  209. if (c == EOF)
  210. return EOF;
  211. if (stream->have_ungotten)
  212. return EOF;
  213. stream->have_ungotten = true;
  214. stream->ungotten = c;
  215. stream->eof = false;
  216. return c;
  217. }
  218. int fputc(int ch, FILE* stream)
  219. {
  220. assert(stream);
  221. assert(stream->buffer_index < stream->buffer_size);
  222. stream->buffer[stream->buffer_index++] = ch;
  223. if (stream->buffer_index >= stream->buffer_size)
  224. fflush(stream);
  225. else if (stream->mode == _IONBF || (stream->mode == _IOLBF && ch == '\n'))
  226. fflush(stream);
  227. if (stream->eof || stream->error)
  228. return EOF;
  229. return (u8)ch;
  230. }
  231. int putc(int ch, FILE* stream)
  232. {
  233. return fputc(ch, stream);
  234. }
  235. int putchar(int ch)
  236. {
  237. return putc(ch, stdout);
  238. }
  239. int fputs(const char* s, FILE* stream)
  240. {
  241. for (; *s; ++s) {
  242. int rc = putc(*s, stream);
  243. if (rc == EOF)
  244. return EOF;
  245. }
  246. return 1;
  247. }
  248. int puts(const char* s)
  249. {
  250. int rc = fputs(s, stdout);
  251. if (rc == EOF)
  252. return EOF;
  253. return fputc('\n', stdout);
  254. }
  255. void clearerr(FILE* stream)
  256. {
  257. assert(stream);
  258. stream->eof = false;
  259. stream->error = 0;
  260. }
  261. int ferror(FILE* stream)
  262. {
  263. return stream->error;
  264. }
  265. size_t fread(void* ptr, size_t size, size_t nmemb, FILE* stream)
  266. {
  267. assert(stream);
  268. if (!size)
  269. return 0;
  270. ssize_t nread = 0;
  271. if (stream->have_ungotten) {
  272. // FIXME: Support ungotten character even if size != 1.
  273. ASSERT(size == 1);
  274. ((char*)ptr)[0] = stream->ungotten;
  275. stream->have_ungotten = false;
  276. --nmemb;
  277. if (!nmemb)
  278. return 1;
  279. ptr = &((char*)ptr)[1];
  280. ++nread;
  281. }
  282. ssize_t rc = read(stream->fd, ptr, nmemb * size);
  283. if (rc < 0) {
  284. stream->error = errno;
  285. return 0;
  286. }
  287. if (rc == 0)
  288. stream->eof = true;
  289. nread += rc;
  290. return nread / size;
  291. }
  292. size_t fwrite(const void* ptr, size_t size, size_t nmemb, FILE* stream)
  293. {
  294. assert(stream);
  295. auto* bytes = (const u8*)ptr;
  296. ssize_t nwritten = 0;
  297. for (size_t i = 0; i < (size * nmemb); ++i) {
  298. int rc = fputc(bytes[i], stream);
  299. if (rc == EOF)
  300. break;
  301. ++nwritten;
  302. }
  303. return nwritten / size;
  304. }
  305. int fseek(FILE* stream, long offset, int whence)
  306. {
  307. assert(stream);
  308. fflush(stream);
  309. off_t off = lseek(stream->fd, offset, whence);
  310. if (off < 0)
  311. return off;
  312. stream->eof = false;
  313. stream->error = 0;
  314. stream->have_ungotten = false;
  315. stream->ungotten = 0;
  316. return 0;
  317. }
  318. long ftell(FILE* stream)
  319. {
  320. assert(stream);
  321. fflush(stream);
  322. return lseek(stream->fd, 0, SEEK_CUR);
  323. }
  324. int fgetpos(FILE* stream, fpos_t* pos)
  325. {
  326. assert(stream);
  327. assert(pos);
  328. long val = ftell(stream);
  329. if (val == -1L)
  330. return 1;
  331. *pos = val;
  332. return 0;
  333. }
  334. int fsetpos(FILE* stream, const fpos_t* pos)
  335. {
  336. assert(stream);
  337. assert(pos);
  338. return fseek(stream, (long) *pos, SEEK_SET);
  339. }
  340. void rewind(FILE* stream)
  341. {
  342. ASSERT(stream);
  343. int rc = fseek(stream, 0, SEEK_SET);
  344. ASSERT(rc == 0);
  345. }
  346. int dbgprintf(const char* fmt, ...)
  347. {
  348. va_list ap;
  349. va_start(ap, fmt);
  350. int ret = printf_internal([](char*&, char ch) { dbgputch(ch); }, nullptr, fmt, ap);
  351. va_end(ap);
  352. return ret;
  353. }
  354. [[gnu::always_inline]] inline void stdout_putch(char*&, char ch)
  355. {
  356. putchar(ch);
  357. }
  358. static FILE* __current_stream = nullptr;
  359. [[gnu::always_inline]] inline static void stream_putch(char*&, char ch)
  360. {
  361. fputc(ch, __current_stream);
  362. }
  363. int vfprintf(FILE* stream, const char* fmt, va_list ap)
  364. {
  365. __current_stream = stream;
  366. return printf_internal(stream_putch, nullptr, fmt, ap);
  367. }
  368. int fprintf(FILE* stream, const char* fmt, ...)
  369. {
  370. va_list ap;
  371. va_start(ap, fmt);
  372. int ret = vfprintf(stream, fmt, ap);
  373. va_end(ap);
  374. return ret;
  375. }
  376. int vprintf(const char* fmt, va_list ap)
  377. {
  378. return printf_internal(stdout_putch, nullptr, fmt, ap);
  379. }
  380. int printf(const char* fmt, ...)
  381. {
  382. va_list ap;
  383. va_start(ap, fmt);
  384. int ret = vprintf(fmt, ap);
  385. va_end(ap);
  386. return ret;
  387. }
  388. static void buffer_putch(char*& bufptr, char ch)
  389. {
  390. *bufptr++ = ch;
  391. }
  392. int vsprintf(char* buffer, const char* fmt, va_list ap)
  393. {
  394. int ret = printf_internal(buffer_putch, buffer, fmt, ap);
  395. buffer[ret] = '\0';
  396. return ret;
  397. }
  398. int sprintf(char* buffer, const char* fmt, ...)
  399. {
  400. va_list ap;
  401. va_start(ap, fmt);
  402. int ret = vsprintf(buffer, fmt, ap);
  403. va_end(ap);
  404. return ret;
  405. }
  406. static size_t __vsnprintf_space_remaining;
  407. [[gnu::always_inline]] inline void sized_buffer_putch(char*& bufptr, char ch)
  408. {
  409. if (__vsnprintf_space_remaining) {
  410. *bufptr++ = ch;
  411. --__vsnprintf_space_remaining;
  412. }
  413. }
  414. int vsnprintf(char* buffer, size_t size, const char* fmt, va_list ap)
  415. {
  416. __vsnprintf_space_remaining = size;
  417. int ret = printf_internal(sized_buffer_putch, buffer, fmt, ap);
  418. if (__vsnprintf_space_remaining) {
  419. buffer[ret] = '\0';
  420. }
  421. return ret;
  422. }
  423. int snprintf(char* buffer, size_t size, const char* fmt, ...)
  424. {
  425. va_list ap;
  426. va_start(ap, fmt);
  427. int ret = vsnprintf(buffer, size, fmt, ap);
  428. va_end(ap);
  429. return ret;
  430. }
  431. void perror(const char* s)
  432. {
  433. int saved_errno = errno;
  434. dbg() << "perror(): " << s << ": " << strerror(saved_errno);
  435. fprintf(stderr, "%s: %s\n", s, strerror(saved_errno));
  436. }
  437. FILE* fopen(const char* pathname, const char* mode)
  438. {
  439. int flags = 0;
  440. // NOTE: rt is a non-standard mode which opens a file for read, explicitly
  441. // specifying that it's a text file
  442. if (!strcmp(mode, "r") || !strcmp(mode, "rb") || !strcmp(mode, "rt"))
  443. flags = O_RDONLY;
  444. else if (!strcmp(mode, "r+") || !strcmp(mode, "rb+"))
  445. flags = O_RDWR;
  446. else if (!strcmp(mode, "w") || !strcmp(mode, "wb"))
  447. flags = O_WRONLY | O_CREAT | O_TRUNC;
  448. else if (!strcmp(mode, "w+") || !strcmp(mode, "wb+"))
  449. flags = O_RDWR | O_CREAT | O_TRUNC;
  450. else if (!strcmp(mode, "a") || !strcmp(mode, "ab"))
  451. flags = O_WRONLY | O_APPEND | O_CREAT;
  452. else if (!strcmp(mode, "a+") || !strcmp(mode, "ab+"))
  453. flags = O_RDWR | O_APPEND | O_CREAT;
  454. else {
  455. fprintf(stderr, "FIXME(LibC): fopen('%s', '%s')\n", pathname, mode);
  456. ASSERT_NOT_REACHED();
  457. }
  458. int fd = open(pathname, flags, 0666);
  459. if (fd < 0)
  460. return nullptr;
  461. return make_FILE(fd);
  462. }
  463. FILE* freopen(const char* pathname, const char* mode, FILE* stream)
  464. {
  465. (void)pathname;
  466. (void)mode;
  467. (void)stream;
  468. ASSERT_NOT_REACHED();
  469. }
  470. FILE* fdopen(int fd, const char* mode)
  471. {
  472. UNUSED_PARAM(mode);
  473. // FIXME: Verify that the mode matches how fd is already open.
  474. if (fd < 0)
  475. return nullptr;
  476. return make_FILE(fd);
  477. }
  478. int fclose(FILE* stream)
  479. {
  480. fflush(stream);
  481. int rc = close(stream->fd);
  482. if (stream != &__default_streams[0] && stream != &__default_streams[1] && stream != &__default_streams[2])
  483. free(stream);
  484. return rc;
  485. }
  486. int rename(const char* oldpath, const char* newpath)
  487. {
  488. if (!oldpath || !newpath) {
  489. errno = EFAULT;
  490. return -1;
  491. }
  492. Syscall::SC_rename_params params { { oldpath, strlen(oldpath) }, { newpath, strlen(newpath) } };
  493. int rc = syscall(SC_rename, &params);
  494. __RETURN_WITH_ERRNO(rc, rc, -1);
  495. }
  496. void dbgputch(char ch)
  497. {
  498. syscall(SC_dbgputch, ch);
  499. }
  500. int dbgputstr(const char* characters, int length)
  501. {
  502. int rc = syscall(SC_dbgputstr, characters, length);
  503. __RETURN_WITH_ERRNO(rc, rc, -1);
  504. }
  505. char* tmpnam(char*)
  506. {
  507. ASSERT_NOT_REACHED();
  508. }
  509. FILE* popen(const char* command, const char* type)
  510. {
  511. if (!type || (*type != 'r' && *type != 'w')) {
  512. errno = EINVAL;
  513. return nullptr;
  514. }
  515. int pipe_fds[2];
  516. int rc = pipe(pipe_fds);
  517. if (rc < 0) {
  518. ScopedValueRollback rollback(errno);
  519. perror("pipe");
  520. return nullptr;
  521. }
  522. pid_t child_pid = fork();
  523. if (!child_pid) {
  524. if (*type == 'r') {
  525. int rc = dup2(pipe_fds[1], STDOUT_FILENO);
  526. if (rc < 0) {
  527. perror("dup2");
  528. exit(1);
  529. }
  530. close(pipe_fds[0]);
  531. close(pipe_fds[1]);
  532. } else if (*type == 'w') {
  533. int rc = dup2(pipe_fds[0], STDIN_FILENO);
  534. if (rc < 0) {
  535. perror("dup2");
  536. exit(1);
  537. }
  538. close(pipe_fds[0]);
  539. close(pipe_fds[1]);
  540. }
  541. int rc = execl("/bin/sh", "sh", "-c", command, nullptr);
  542. if (rc < 0)
  543. perror("execl");
  544. exit(1);
  545. }
  546. FILE* fp = nullptr;
  547. if (*type == 'r') {
  548. fp = make_FILE(pipe_fds[0]);
  549. close(pipe_fds[1]);
  550. } else if (*type == 'w') {
  551. fp = make_FILE(pipe_fds[1]);
  552. close(pipe_fds[0]);
  553. }
  554. fp->popen_child = child_pid;
  555. return fp;
  556. }
  557. int pclose(FILE* fp)
  558. {
  559. ASSERT(fp);
  560. ASSERT(fp->popen_child != 0);
  561. int wstatus = 0;
  562. int rc = waitpid(fp->popen_child, &wstatus, 0);
  563. if (rc < 0)
  564. return rc;
  565. return wstatus;
  566. }
  567. int remove(const char* pathname)
  568. {
  569. int rc = unlink(pathname);
  570. if (rc < 0 && errno != EISDIR)
  571. return -1;
  572. return rmdir(pathname);
  573. }
  574. int scanf(const char* fmt, ...)
  575. {
  576. va_list ap;
  577. va_start(ap, fmt);
  578. int count = vfscanf(stdin, fmt, ap);
  579. va_end(ap);
  580. return count;
  581. }
  582. int fscanf(FILE* stream, const char* fmt, ...)
  583. {
  584. va_list ap;
  585. va_start(ap, fmt);
  586. int count = vfscanf(stream, fmt, ap);
  587. va_end(ap);
  588. return count;
  589. }
  590. int sscanf(const char* buffer, const char* fmt, ...)
  591. {
  592. va_list ap;
  593. va_start(ap, fmt);
  594. int count = vsscanf(buffer, fmt, ap);
  595. va_end(ap);
  596. return count;
  597. }
  598. int vfscanf(FILE* stream, const char* fmt, va_list ap)
  599. {
  600. char buffer[BUFSIZ];
  601. if (!fgets(buffer, sizeof(buffer) - 1, stream))
  602. return -1;
  603. return vsscanf(buffer, fmt, ap);
  604. }
  605. void flockfile(FILE* filehandle)
  606. {
  607. (void)filehandle;
  608. dbgprintf("FIXME: Implement flockfile()\n");
  609. }
  610. void funlockfile(FILE* filehandle)
  611. {
  612. (void)filehandle;
  613. dbgprintf("FIXME: Implement funlockfile()\n");
  614. }
  615. FILE* tmpfile()
  616. {
  617. char tmp_path[] = "/tmp/XXXXXX";
  618. if (__generate_unique_filename(tmp_path) < 0)
  619. return nullptr;
  620. int fd = open(tmp_path, O_CREAT | O_EXCL | O_RDWR, S_IWUSR | S_IRUSR);
  621. if (fd < 0)
  622. return nullptr;
  623. // FIXME: instead of using this hack, implement with O_TMPFILE or similar
  624. unlink(tmp_path);
  625. return make_FILE(fd);
  626. }
  627. }