Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

382 lines
8.1KB

  1. /* FatLib Library
  2. * Copyright (C) 2013 by William Greiman
  3. *
  4. * This file is part of the FatLib Library
  5. *
  6. * This Library is free software: you can redistribute it and/or modify
  7. * it under the terms of the GNU General Public License as published by
  8. * the Free Software Foundation, either version 3 of the License, or
  9. * (at your option) any later version.
  10. *
  11. * This Library is distributed in the hope that it will be useful,
  12. * but WITHOUT ANY WARRANTY; without even the implied warranty of
  13. * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  14. * GNU General Public License for more details.
  15. *
  16. * You should have received a copy of the GNU General Public License
  17. * along with the FatLib Library. If not, see
  18. * <http://www.gnu.org/licenses/>.
  19. */
  20. // #include <ctype.h>
  21. #include <float.h>
  22. #include <ctype.h>
  23. #include "istream.h"
  24. //------------------------------------------------------------------------------
  25. int istream::get() {
  26. int c;
  27. m_gcount = 0;
  28. c = getch();
  29. if (c < 0) {
  30. setstate(failbit);
  31. } else {
  32. m_gcount = 1;
  33. }
  34. return c;
  35. }
  36. //------------------------------------------------------------------------------
  37. istream& istream::get(char& c) {
  38. int tmp = get();
  39. if (tmp >= 0) {
  40. c = tmp;
  41. }
  42. return *this;
  43. }
  44. //------------------------------------------------------------------------------
  45. istream& istream::get(char *str, streamsize n, char delim) {
  46. int c;
  47. FatPos_t pos;
  48. m_gcount = 0;
  49. while ((m_gcount + 1) < n) {
  50. c = getch(&pos);
  51. if (c < 0) {
  52. break;
  53. }
  54. if (c == delim) {
  55. setpos(&pos);
  56. break;
  57. }
  58. str[m_gcount++] = c;
  59. }
  60. if (n > 0) {
  61. str[m_gcount] = '\0';
  62. }
  63. if (m_gcount == 0) {
  64. setstate(failbit);
  65. }
  66. return *this;
  67. }
  68. //------------------------------------------------------------------------------
  69. void istream::getBool(bool *b) {
  70. if ((flags() & boolalpha) == 0) {
  71. getNumber(b);
  72. return;
  73. }
  74. PGM_P truePtr = PSTR("true");
  75. PGM_P falsePtr = PSTR("false");
  76. const uint8_t true_len = 4;
  77. const uint8_t false_len = 5;
  78. bool trueOk = true;
  79. bool falseOk = true;
  80. uint8_t i = 0;
  81. int c = readSkip();
  82. while (1) {
  83. falseOk = falseOk && c == pgm_read_byte(falsePtr + i);
  84. trueOk = trueOk && c == pgm_read_byte(truePtr + i);
  85. if (trueOk == false && falseOk == false) {
  86. break;
  87. }
  88. i++;
  89. if (trueOk && i == true_len) {
  90. *b = true;
  91. return;
  92. }
  93. if (falseOk && i == false_len) {
  94. *b = false;
  95. return;
  96. }
  97. c = getch();
  98. }
  99. setstate(failbit);
  100. }
  101. //------------------------------------------------------------------------------
  102. void istream::getChar(char* ch) {
  103. int16_t c = readSkip();
  104. if (c < 0) {
  105. setstate(failbit);
  106. } else {
  107. *ch = c;
  108. }
  109. }
  110. //------------------------------------------------------------------------------
  111. //
  112. // http://www.exploringbinary.com/category/numbers-in-computers/
  113. //
  114. int16_t const EXP_LIMIT = 100;
  115. static const uint32_t uint32_max = (uint32_t)-1;
  116. bool istream::getDouble(double* value) {
  117. bool got_digit = false;
  118. bool got_dot = false;
  119. bool neg;
  120. int16_t c;
  121. bool expNeg = false;
  122. int16_t exp = 0;
  123. int16_t fracExp = 0;
  124. uint32_t frac = 0;
  125. FatPos_t endPos;
  126. double pow10;
  127. double v;
  128. getpos(&endPos);
  129. c = readSkip();
  130. neg = c == '-';
  131. if (c == '-' || c == '+') {
  132. c = getch();
  133. }
  134. while (1) {
  135. if (isdigit(c)) {
  136. got_digit = true;
  137. if (frac < uint32_max/10) {
  138. frac = frac * 10 + (c - '0');
  139. if (got_dot) {
  140. fracExp--;
  141. }
  142. } else {
  143. if (!got_dot) {
  144. fracExp++;
  145. }
  146. }
  147. } else if (!got_dot && c == '.') {
  148. got_dot = true;
  149. } else {
  150. break;
  151. }
  152. if (fracExp < -EXP_LIMIT || fracExp > EXP_LIMIT) {
  153. goto fail;
  154. }
  155. c = getch(&endPos);
  156. }
  157. if (!got_digit) {
  158. goto fail;
  159. }
  160. if (c == 'e' || c == 'E') {
  161. c = getch();
  162. expNeg = c == '-';
  163. if (c == '-' || c == '+') {
  164. c = getch();
  165. }
  166. while (isdigit(c)) {
  167. if (exp > EXP_LIMIT) {
  168. goto fail;
  169. }
  170. exp = exp * 10 + (c - '0');
  171. c = getch(&endPos);
  172. }
  173. }
  174. v = static_cast<double>(frac);
  175. exp = expNeg ? fracExp - exp : fracExp + exp;
  176. expNeg = exp < 0;
  177. if (expNeg) {
  178. exp = -exp;
  179. }
  180. pow10 = 10.0;
  181. while (exp) {
  182. if (exp & 1) {
  183. if (expNeg) {
  184. // check for underflow
  185. if (v < FLT_MIN * pow10 && frac != 0) {
  186. goto fail;
  187. }
  188. v /= pow10;
  189. } else {
  190. // check for overflow
  191. if (v > FLT_MAX / pow10) {
  192. goto fail;
  193. }
  194. v *= pow10;
  195. }
  196. }
  197. pow10 *= pow10;
  198. exp >>= 1;
  199. }
  200. setpos(&endPos);
  201. *value = neg ? -v : v;
  202. return true;
  203. fail:
  204. // error restore position to last good place
  205. setpos(&endPos);
  206. setstate(failbit);
  207. return false;
  208. }
  209. //------------------------------------------------------------------------------
  210. istream& istream::getline(char *str, streamsize n, char delim) {
  211. FatPos_t pos;
  212. int c;
  213. m_gcount = 0;
  214. if (n > 0) {
  215. str[0] = '\0';
  216. }
  217. while (1) {
  218. c = getch(&pos);
  219. if (c < 0) {
  220. break;
  221. }
  222. if (c == delim) {
  223. m_gcount++;
  224. break;
  225. }
  226. if ((m_gcount + 1) >= n) {
  227. setpos(&pos);
  228. setstate(failbit);
  229. break;
  230. }
  231. str[m_gcount++] = c;
  232. str[m_gcount] = '\0';
  233. }
  234. if (m_gcount == 0) {
  235. setstate(failbit);
  236. }
  237. return *this;
  238. }
  239. //------------------------------------------------------------------------------
  240. bool istream::getNumber(uint32_t posMax, uint32_t negMax, uint32_t* num) {
  241. int16_t c;
  242. int8_t any = 0;
  243. int8_t have_zero = 0;
  244. uint8_t neg;
  245. uint32_t val = 0;
  246. uint32_t cutoff;
  247. uint8_t cutlim;
  248. FatPos_t endPos;
  249. uint8_t f = flags() & basefield;
  250. uint8_t base = f == oct ? 8 : f != hex ? 10 : 16;
  251. getpos(&endPos);
  252. c = readSkip();
  253. neg = c == '-' ? 1 : 0;
  254. if (c == '-' || c == '+') {
  255. c = getch();
  256. }
  257. if (base == 16 && c == '0') { // TESTSUITE
  258. c = getch(&endPos);
  259. if (c == 'X' || c == 'x') {
  260. c = getch();
  261. // remember zero in case no hex digits follow x/X
  262. have_zero = 1;
  263. } else {
  264. any = 1;
  265. }
  266. }
  267. // set values for overflow test
  268. cutoff = neg ? negMax : posMax;
  269. cutlim = cutoff % base;
  270. cutoff /= base;
  271. while (1) {
  272. if (isdigit(c)) {
  273. c -= '0';
  274. } else if (isalpha(c)) {
  275. c -= isupper(c) ? 'A' - 10 : 'a' - 10;
  276. } else {
  277. break;
  278. }
  279. if (c >= base) {
  280. break;
  281. }
  282. if (val > cutoff || (val == cutoff && c > cutlim)) {
  283. // indicate overflow error
  284. any = -1;
  285. break;
  286. }
  287. val = val * base + c;
  288. c = getch(&endPos);
  289. any = 1;
  290. }
  291. setpos(&endPos);
  292. if (any > 0 || (have_zero && any >= 0)) {
  293. *num = neg ? -val : val;
  294. return true;
  295. }
  296. setstate(failbit);
  297. return false;
  298. }
  299. //------------------------------------------------------------------------------
  300. void istream::getStr(char *str) {
  301. FatPos_t pos;
  302. uint16_t i = 0;
  303. uint16_t m = width() ? width() - 1 : 0XFFFE;
  304. if (m != 0) {
  305. getpos(&pos);
  306. int c = readSkip();
  307. while (i < m) {
  308. if (c < 0) {
  309. break;
  310. }
  311. if (isspace(c)) {
  312. setpos(&pos);
  313. break;
  314. }
  315. str[i++] = c;
  316. c = getch(&pos);
  317. }
  318. }
  319. str[i] = '\0';
  320. if (i == 0) {
  321. setstate(failbit);
  322. }
  323. width(0);
  324. }
  325. //------------------------------------------------------------------------------
  326. istream& istream::ignore(streamsize n, int delim) {
  327. int c;
  328. m_gcount = 0;
  329. while (m_gcount < n) {
  330. c = getch();
  331. if (c < 0) {
  332. break;
  333. }
  334. m_gcount++;
  335. if (c == delim) {
  336. break;
  337. }
  338. }
  339. return *this;
  340. }
  341. //------------------------------------------------------------------------------
  342. int istream::peek() {
  343. int16_t c;
  344. FatPos_t pos;
  345. m_gcount = 0;
  346. getpos(&pos);
  347. c = getch();
  348. if (c < 0) {
  349. if (!bad()) {
  350. setstate(eofbit);
  351. }
  352. } else {
  353. setpos(&pos);
  354. }
  355. return c;
  356. }
  357. //------------------------------------------------------------------------------
  358. int16_t istream::readSkip() {
  359. int16_t c;
  360. do {
  361. c = getch();
  362. } while (isspace(c) && (flags() & skipws));
  363. return c;
  364. }
  365. //------------------------------------------------------------------------------
  366. /** used to implement ws() */
  367. void istream::skipWhite() {
  368. int c;
  369. FatPos_t pos;
  370. do {
  371. c = getch(&pos);
  372. } while (isspace(c));
  373. setpos(&pos);
  374. }