StdioStream.cpp 12 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527
  1. /**
  2. * Copyright (c) 20011-2017 Bill Greiman
  3. * This file is part of the SdFat library for SD memory cards.
  4. *
  5. * MIT License
  6. *
  7. * Permission is hereby granted, free of charge, to any person obtaining a
  8. * copy of this software and associated documentation files (the "Software"),
  9. * to deal in the Software without restriction, including without limitation
  10. * the rights to use, copy, modify, merge, publish, distribute, sublicense,
  11. * and/or sell copies of the Software, and to permit persons to whom the
  12. * Software is furnished to do so, subject to the following conditions:
  13. *
  14. * The above copyright notice and this permission notice shall be included
  15. * in all copies or substantial portions of the Software.
  16. *
  17. * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS
  18. * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
  19. * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
  20. * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
  21. * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING
  22. * FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER
  23. * DEALINGS IN THE SOFTWARE.
  24. */
  25. #include "StdioStream.h"
  26. #include "FmtNumber.h"
  27. //------------------------------------------------------------------------------
  28. int StdioStream::fclose() {
  29. int rtn = 0;
  30. if (!m_flags) {
  31. return EOF;
  32. }
  33. if (m_flags & F_SWR) {
  34. if (!flushBuf()) {
  35. rtn = EOF;
  36. }
  37. }
  38. if (!FatFile::close()) {
  39. rtn = EOF;
  40. }
  41. m_r = 0;
  42. m_w = 0;
  43. m_flags = 0;
  44. return rtn;
  45. }
  46. //------------------------------------------------------------------------------
  47. int StdioStream::fflush() {
  48. if ((m_flags & (F_SWR | F_SRW)) && !(m_flags & F_SRD)) {
  49. if (flushBuf() && FatFile::sync()) {
  50. return 0;
  51. }
  52. }
  53. return EOF;
  54. }
  55. //------------------------------------------------------------------------------
  56. char* StdioStream::fgets(char* str, size_t num, size_t* len) {
  57. char* s = str;
  58. size_t n;
  59. if (num-- == 0) {
  60. return 0;
  61. }
  62. while (num) {
  63. if ((n = m_r) == 0) {
  64. if (!fillBuf()) {
  65. if (s == str) {
  66. return 0;
  67. }
  68. break;
  69. }
  70. n = m_r;
  71. }
  72. if (n > num) {
  73. n = num;
  74. }
  75. uint8_t* end = reinterpret_cast<uint8_t*>(memchr(m_p, '\n', n));
  76. if (end != 0) {
  77. n = ++end - m_p;
  78. memcpy(s, m_p, n);
  79. m_r -= n;
  80. m_p = end;
  81. s += n;
  82. break;
  83. }
  84. memcpy(s, m_p, n);
  85. m_r -= n;
  86. m_p += n;
  87. s += n;
  88. num -= n;
  89. }
  90. *s = 0;
  91. if (len) {
  92. *len = s - str;
  93. }
  94. return str;
  95. }
  96. //------------------------------------------------------------------------------
  97. bool StdioStream::fopen(const char* path, const char* mode) {
  98. uint8_t oflag;
  99. switch (*mode++) {
  100. case 'a':
  101. m_flags = F_SWR;
  102. oflag = O_WRITE | O_CREAT | O_APPEND | O_AT_END;
  103. break;
  104. case 'r':
  105. m_flags = F_SRD;
  106. oflag = O_READ;
  107. break;
  108. case 'w':
  109. m_flags = F_SWR;
  110. oflag = O_WRITE | O_CREAT | O_TRUNC;
  111. break;
  112. default:
  113. goto fail;
  114. }
  115. while (*mode) {
  116. switch (*mode++) {
  117. case '+':
  118. m_flags |= F_SRW;
  119. oflag |= O_RDWR;
  120. break;
  121. case 'b':
  122. break;
  123. case 'x':
  124. oflag |= O_EXCL;
  125. break;
  126. default:
  127. goto fail;
  128. }
  129. }
  130. if ((oflag & O_EXCL) && !(oflag & O_WRITE)) {
  131. goto fail;
  132. }
  133. if (!FatFile::open(path, oflag)) {
  134. goto fail;
  135. }
  136. m_r = 0;
  137. m_w = 0;
  138. m_p = m_buf;
  139. return true;
  140. fail:
  141. m_flags = 0;
  142. return false;
  143. }
  144. //------------------------------------------------------------------------------
  145. int StdioStream::fputs(const char* str) {
  146. size_t len = strlen(str);
  147. return fwrite(str, 1, len) == len ? len : EOF;
  148. }
  149. //------------------------------------------------------------------------------
  150. size_t StdioStream::fread(void* ptr, size_t size, size_t count) {
  151. uint8_t* dst = reinterpret_cast<uint8_t*>(ptr);
  152. size_t total = size*count;
  153. if (total == 0) {
  154. return 0;
  155. }
  156. size_t need = total;
  157. while (need > m_r) {
  158. memcpy(dst, m_p, m_r);
  159. dst += m_r;
  160. m_p += m_r;
  161. need -= m_r;
  162. if (!fillBuf()) {
  163. return (total - need)/size;
  164. }
  165. }
  166. memcpy(dst, m_p, need);
  167. m_r -= need;
  168. m_p += need;
  169. return count;
  170. }
  171. //------------------------------------------------------------------------------
  172. int StdioStream::fseek(int32_t offset, int origin) {
  173. int32_t pos;
  174. if (m_flags & F_SWR) {
  175. if (!flushBuf()) {
  176. goto fail;
  177. }
  178. }
  179. switch (origin) {
  180. case SEEK_CUR:
  181. pos = ftell();
  182. if (pos < 0) {
  183. goto fail;
  184. }
  185. pos += offset;
  186. if (!FatFile::seekCur(pos)) {
  187. goto fail;
  188. }
  189. break;
  190. case SEEK_SET:
  191. if (!FatFile::seekSet(offset)) {
  192. goto fail;
  193. }
  194. break;
  195. case SEEK_END:
  196. if (!FatFile::seekEnd(offset)) {
  197. goto fail;
  198. }
  199. break;
  200. default:
  201. goto fail;
  202. }
  203. m_r = 0;
  204. m_p = m_buf;
  205. return 0;
  206. fail:
  207. return EOF;
  208. }
  209. //------------------------------------------------------------------------------
  210. int32_t StdioStream::ftell() {
  211. uint32_t pos = FatFile::curPosition();
  212. if (m_flags & F_SRD) {
  213. if (m_r > pos) {
  214. return -1L;
  215. }
  216. pos -= m_r;
  217. } else if (m_flags & F_SWR) {
  218. pos += m_p - m_buf;
  219. }
  220. return pos;
  221. }
  222. //------------------------------------------------------------------------------
  223. size_t StdioStream::fwrite(const void* ptr, size_t size, size_t count) {
  224. return write(ptr, count*size) < 0 ? EOF : count;
  225. #if 0 ////////////////////////////////////////////////////////////////////////////////////
  226. const uint8_t* src = static_cast<const uint8_t*>(ptr);
  227. size_t total = count*size;
  228. if (total == 0) {
  229. return 0;
  230. }
  231. size_t todo = total;
  232. while (todo > m_w) {
  233. memcpy(m_p, src, m_w);
  234. m_p += m_w;
  235. src += m_w;
  236. todo -= m_w;
  237. if (!flushBuf()) {
  238. return (total - todo)/size;
  239. }
  240. }
  241. memcpy(m_p, src, todo);
  242. m_p += todo;
  243. m_w -= todo;
  244. return count;
  245. #endif //////////////////////////////////////////////////////////////////////////////////
  246. }
  247. //------------------------------------------------------------------------------
  248. int StdioStream::write(const void* buf, size_t count) {
  249. const uint8_t* src = static_cast<const uint8_t*>(buf);
  250. size_t todo = count;
  251. while (todo > m_w) {
  252. memcpy(m_p, src, m_w);
  253. m_p += m_w;
  254. src += m_w;
  255. todo -= m_w;
  256. if (!flushBuf()) {
  257. return EOF;
  258. }
  259. }
  260. memcpy(m_p, src, todo);
  261. m_p += todo;
  262. m_w -= todo;
  263. return count;
  264. }
  265. //------------------------------------------------------------------------------
  266. #if (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
  267. size_t StdioStream::print(const __FlashStringHelper *str) {
  268. const char *p = (const char*)str;
  269. uint8_t c;
  270. while ((c = pgm_read_byte(p))) {
  271. if (putc(c) < 0) {
  272. return 0;
  273. }
  274. p++;
  275. }
  276. return p - (const char*)str;
  277. }
  278. #endif // (defined(ARDUINO) && ENABLE_ARDUINO_FEATURES) || defined(DOXYGEN)
  279. //------------------------------------------------------------------------------
  280. int StdioStream::printDec(float value, uint8_t prec) {
  281. char buf[24];
  282. char *ptr = fmtFloat(value, buf + sizeof(buf), prec);
  283. return write(ptr, buf + sizeof(buf) - ptr);
  284. }
  285. //------------------------------------------------------------------------------
  286. int StdioStream::printDec(signed char n) {
  287. if (n < 0) {
  288. if (fputc('-') < 0) {
  289. return -1;
  290. }
  291. n = -n;
  292. }
  293. return printDec((unsigned char)n);
  294. }
  295. //------------------------------------------------------------------------------
  296. int StdioStream::printDec(int16_t n) {
  297. int s;
  298. uint8_t rtn = 0;
  299. if (n < 0) {
  300. if (fputc('-') < 0) {
  301. return -1;
  302. }
  303. n = -n;
  304. rtn++;
  305. }
  306. if ((s = printDec((uint16_t)n)) < 0) {
  307. return s;
  308. }
  309. return rtn;
  310. }
  311. //------------------------------------------------------------------------------
  312. int StdioStream::printDec(uint16_t n) {
  313. #define NEW_WAY
  314. #ifdef NEW_WAY
  315. char buf[5];
  316. char *ptr = fmtDec(n, buf + sizeof(buf));
  317. uint8_t len = buf + sizeof(buf) - ptr;
  318. return write(ptr, len);
  319. #else
  320. uint8_t len;
  321. if (n < 100) {
  322. len = n < 10 ? 1 : 2;
  323. } else {
  324. len = n < 1000 ? 3 : n < 10000 ? 4 : 5;
  325. }
  326. char* str = fmtSpace(len);
  327. if (!str) {
  328. return -1;
  329. }
  330. fmtDec(n, str);
  331. return len;
  332. #endif
  333. }
  334. //------------------------------------------------------------------------------
  335. int StdioStream::printDec(int32_t n) {
  336. uint8_t s = 0;
  337. if (n < 0) {
  338. if (fputc('-') < 0) {
  339. return -1;
  340. }
  341. n = -n;
  342. s = 1;
  343. }
  344. int rtn = printDec((uint32_t)n);
  345. return rtn > 0 ? rtn + s : -1;
  346. }
  347. //------------------------------------------------------------------------------
  348. int StdioStream::printDec(uint32_t n) {
  349. #ifdef NEW_WAY
  350. char buf[10];
  351. char *ptr = fmtDec(n, buf + sizeof(buf));
  352. uint8_t len = buf + sizeof(buf) - ptr;
  353. return write(ptr, len);
  354. #else
  355. uint8_t len;
  356. if (n < 0X10000) {
  357. return printDec((uint16_t)n);
  358. }
  359. if (n < 10000000) {
  360. len = n < 100000 ? 5 : n < 1000000 ? 6 : 7;
  361. } else {
  362. len = n < 100000000 ? 8 : n < 1000000000 ? 9 : 10;
  363. }
  364. char* str = fmtSpace(len);
  365. if (!str) {
  366. return -1;
  367. }
  368. fmtDec(n, str);
  369. return len;
  370. #endif
  371. }
  372. //------------------------------------------------------------------------------
  373. int StdioStream::printHex(uint32_t n) {
  374. #ifdef NEW_WAY
  375. char buf[8];
  376. char *ptr = fmtHex(n, buf + sizeof(buf));
  377. uint8_t len = buf + sizeof(buf) - ptr;
  378. return write(ptr, len);
  379. #else
  380. size_t len;
  381. if (n < 0X10000) {
  382. len = n < 0X10 ? 1 : n < 0X100 ? 2 : n < 0X1000 ? 3 : 4;
  383. } else {
  384. len = n < 0X100000 ? 5 : n < 0X1000000 ? 6 : n < 0X10000000 ? 7 : 8;
  385. }
  386. char* str = fmtSpace(len);
  387. if (!str) {
  388. return -1;
  389. }
  390. do {
  391. uint8_t h = n & 0XF;
  392. *str-- = h + (h < 10 ? '0' : 'A' - 10);
  393. n >>= 4;
  394. } while (n);
  395. return len;
  396. #endif
  397. }
  398. //------------------------------------------------------------------------------
  399. bool StdioStream::rewind() {
  400. if (m_flags & F_SWR) {
  401. if (!flushBuf()) {
  402. return false;
  403. }
  404. }
  405. FatFile::seekSet(0);
  406. m_r = 0;
  407. return true;
  408. }
  409. //------------------------------------------------------------------------------
  410. int StdioStream::ungetc(int c) {
  411. // error if EOF.
  412. if (c == EOF) {
  413. return EOF;
  414. }
  415. // error if not reading.
  416. if ((m_flags & F_SRD) == 0) {
  417. return EOF;
  418. }
  419. // error if no space.
  420. if (m_p == m_buf) {
  421. return EOF;
  422. }
  423. m_r++;
  424. m_flags &= ~F_EOF;
  425. return *--m_p = (uint8_t)c;
  426. }
  427. //==============================================================================
  428. // private
  429. //------------------------------------------------------------------------------
  430. int StdioStream::fillGet() {
  431. if (!fillBuf()) {
  432. return EOF;
  433. }
  434. m_r--;
  435. return *m_p++;
  436. }
  437. //------------------------------------------------------------------------------
  438. // private
  439. bool StdioStream::fillBuf() {
  440. if (!(m_flags &
  441. F_SRD)) { // check for F_ERR and F_EOF ??/////////////////
  442. if (!(m_flags & F_SRW)) {
  443. m_flags |= F_ERR;
  444. return false;
  445. }
  446. if (m_flags & F_SWR) {
  447. if (!flushBuf()) {
  448. return false;
  449. }
  450. m_flags &= ~F_SWR;
  451. m_flags |= F_SRD;
  452. m_w = 0;
  453. }
  454. }
  455. m_p = m_buf + UNGETC_BUF_SIZE;
  456. int nr = FatFile::read(m_p, sizeof(m_buf) - UNGETC_BUF_SIZE);
  457. if (nr <= 0) {
  458. m_flags |= nr < 0 ? F_ERR : F_EOF;
  459. m_r = 0;
  460. return false;
  461. }
  462. m_r = nr;
  463. return true;
  464. }
  465. //------------------------------------------------------------------------------
  466. // private
  467. bool StdioStream::flushBuf() {
  468. if (!(m_flags &
  469. F_SWR)) { // check for F_ERR ??////////////////////////
  470. if (!(m_flags & F_SRW)) {
  471. m_flags |= F_ERR;
  472. return false;
  473. }
  474. m_flags &= ~F_SRD;
  475. m_flags |= F_SWR;
  476. m_r = 0;
  477. m_w = sizeof(m_buf);
  478. m_p = m_buf;
  479. return true;
  480. }
  481. uint8_t n = m_p - m_buf;
  482. m_p = m_buf;
  483. m_w = sizeof(m_buf);
  484. if (FatFile::write(m_buf, n) == n) {
  485. return true;
  486. }
  487. m_flags |= F_ERR;
  488. return false;
  489. }
  490. //------------------------------------------------------------------------------
  491. int StdioStream::flushPut(uint8_t c) {
  492. if (!flushBuf()) {
  493. return EOF;
  494. }
  495. m_w--;
  496. return *m_p++ = c;
  497. }
  498. //------------------------------------------------------------------------------
  499. char* StdioStream::fmtSpace(uint8_t len) {
  500. if (m_w < len) {
  501. if (!flushBuf() || m_w < len) {
  502. return 0;
  503. }
  504. }
  505. if (len > m_w) {
  506. return 0;
  507. }
  508. m_p += len;
  509. m_w -= len;
  510. return reinterpret_cast<char*>(m_p);
  511. }