scanf.c 8.6 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312
  1. /* Copyright (c) 2003-2004, Roger Dingledine
  2. * Copyright (c) 2004-2006, Roger Dingledine, Nick Mathewson.
  3. * Copyright (c) 2007-2018, The Tor Project, Inc. */
  4. /* See LICENSE for licensing information */
  5. #include "lib/string/scanf.h"
  6. #include "lib/string/compat_ctype.h"
  7. #include "lib/cc/torint.h"
  8. #include "lib/err/torerr.h"
  9. #include <stdlib.h>
  10. #define MAX_SCANF_WIDTH 9999
  11. /** Helper: given an ASCII-encoded decimal digit, return its numeric value.
  12. * NOTE: requires that its input be in-bounds. */
  13. static int
  14. digit_to_num(char d)
  15. {
  16. int num = ((int)d) - (int)'0';
  17. raw_assert(num <= 9 && num >= 0);
  18. return num;
  19. }
  20. /** Helper: Read an unsigned int from *<b>bufp</b> of up to <b>width</b>
  21. * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
  22. * success, store the result in <b>out</b>, advance bufp to the next
  23. * character, and return 0. On failure, return -1. */
  24. static int
  25. scan_unsigned(const char **bufp, unsigned long *out, int width, unsigned base)
  26. {
  27. unsigned long result = 0;
  28. int scanned_so_far = 0;
  29. const int hex = base==16;
  30. raw_assert(base == 10 || base == 16);
  31. if (!bufp || !*bufp || !out)
  32. return -1;
  33. if (width<0)
  34. width=MAX_SCANF_WIDTH;
  35. while (**bufp && (hex?TOR_ISXDIGIT(**bufp):TOR_ISDIGIT(**bufp))
  36. && scanned_so_far < width) {
  37. unsigned digit = hex?hex_decode_digit(*(*bufp)++):digit_to_num(*(*bufp)++);
  38. // Check for overflow beforehand, without actually causing any overflow
  39. // This preserves functionality on compilers that don't wrap overflow
  40. // (i.e. that trap or optimise away overflow)
  41. // result * base + digit > ULONG_MAX
  42. // result * base > ULONG_MAX - digit
  43. if (result > (ULONG_MAX - digit)/base)
  44. return -1; /* Processing this digit would overflow */
  45. result = result * base + digit;
  46. ++scanned_so_far;
  47. }
  48. if (!scanned_so_far) /* No actual digits scanned */
  49. return -1;
  50. *out = result;
  51. return 0;
  52. }
  53. /** Helper: Read an signed int from *<b>bufp</b> of up to <b>width</b>
  54. * characters. (Handle arbitrary width if <b>width</b> is less than 0.) On
  55. * success, store the result in <b>out</b>, advance bufp to the next
  56. * character, and return 0. On failure, return -1. */
  57. static int
  58. scan_signed(const char **bufp, long *out, int width)
  59. {
  60. int neg = 0;
  61. unsigned long result = 0;
  62. if (!bufp || !*bufp || !out)
  63. return -1;
  64. if (width<0)
  65. width=MAX_SCANF_WIDTH;
  66. if (**bufp == '-') {
  67. neg = 1;
  68. ++*bufp;
  69. --width;
  70. }
  71. if (scan_unsigned(bufp, &result, width, 10) < 0)
  72. return -1;
  73. if (neg && result > 0) {
  74. if (result > ((unsigned long)LONG_MAX) + 1)
  75. return -1; /* Underflow */
  76. else if (result == ((unsigned long)LONG_MAX) + 1)
  77. *out = LONG_MIN;
  78. else {
  79. /* We once had a far more clever no-overflow conversion here, but
  80. * some versions of GCC apparently ran it into the ground. Now
  81. * we just check for LONG_MIN explicitly.
  82. */
  83. *out = -(long)result;
  84. }
  85. } else {
  86. if (result > LONG_MAX)
  87. return -1; /* Overflow */
  88. *out = (long)result;
  89. }
  90. return 0;
  91. }
  92. /** Helper: Read a decimal-formatted double from *<b>bufp</b> of up to
  93. * <b>width</b> characters. (Handle arbitrary width if <b>width</b> is less
  94. * than 0.) On success, store the result in <b>out</b>, advance bufp to the
  95. * next character, and return 0. On failure, return -1. */
  96. static int
  97. scan_double(const char **bufp, double *out, int width)
  98. {
  99. int neg = 0;
  100. double result = 0;
  101. int scanned_so_far = 0;
  102. if (!bufp || !*bufp || !out)
  103. return -1;
  104. if (width<0)
  105. width=MAX_SCANF_WIDTH;
  106. if (**bufp == '-') {
  107. neg = 1;
  108. ++*bufp;
  109. }
  110. while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
  111. const int digit = digit_to_num(*(*bufp)++);
  112. result = result * 10 + digit;
  113. ++scanned_so_far;
  114. }
  115. if (**bufp == '.') {
  116. double fracval = 0, denominator = 1;
  117. ++*bufp;
  118. ++scanned_so_far;
  119. while (**bufp && TOR_ISDIGIT(**bufp) && scanned_so_far < width) {
  120. const int digit = digit_to_num(*(*bufp)++);
  121. fracval = fracval * 10 + digit;
  122. denominator *= 10;
  123. ++scanned_so_far;
  124. }
  125. result += fracval / denominator;
  126. }
  127. if (!scanned_so_far) /* No actual digits scanned */
  128. return -1;
  129. *out = neg ? -result : result;
  130. return 0;
  131. }
  132. /** Helper: copy up to <b>width</b> non-space characters from <b>bufp</b> to
  133. * <b>out</b>. Make sure <b>out</b> is nul-terminated. Advance <b>bufp</b>
  134. * to the next non-space character or the EOS. */
  135. static int
  136. scan_string(const char **bufp, char *out, int width)
  137. {
  138. int scanned_so_far = 0;
  139. if (!bufp || !out || width < 0)
  140. return -1;
  141. while (**bufp && ! TOR_ISSPACE(**bufp) && scanned_so_far < width) {
  142. *out++ = *(*bufp)++;
  143. ++scanned_so_far;
  144. }
  145. *out = '\0';
  146. return 0;
  147. }
  148. /** Locale-independent, minimal, no-surprises scanf variant, accepting only a
  149. * restricted pattern format. For more info on what it supports, see
  150. * tor_sscanf() documentation. */
  151. int
  152. tor_vsscanf(const char *buf, const char *pattern, va_list ap)
  153. {
  154. int n_matched = 0;
  155. while (*pattern) {
  156. if (*pattern != '%') {
  157. if (*buf == *pattern) {
  158. ++buf;
  159. ++pattern;
  160. continue;
  161. } else {
  162. return n_matched;
  163. }
  164. } else {
  165. int width = -1;
  166. int longmod = 0;
  167. ++pattern;
  168. if (TOR_ISDIGIT(*pattern)) {
  169. width = digit_to_num(*pattern++);
  170. while (TOR_ISDIGIT(*pattern)) {
  171. width *= 10;
  172. width += digit_to_num(*pattern++);
  173. if (width > MAX_SCANF_WIDTH)
  174. return -1;
  175. }
  176. if (!width) /* No zero-width things. */
  177. return -1;
  178. }
  179. if (*pattern == 'l') {
  180. longmod = 1;
  181. ++pattern;
  182. }
  183. if (*pattern == 'u' || *pattern == 'x') {
  184. unsigned long u;
  185. const int base = (*pattern == 'u') ? 10 : 16;
  186. if (!*buf)
  187. return n_matched;
  188. if (scan_unsigned(&buf, &u, width, base)<0)
  189. return n_matched;
  190. if (longmod) {
  191. unsigned long *out = va_arg(ap, unsigned long *);
  192. *out = u;
  193. } else {
  194. unsigned *out = va_arg(ap, unsigned *);
  195. if (u > UINT_MAX)
  196. return n_matched;
  197. *out = (unsigned) u;
  198. }
  199. ++pattern;
  200. ++n_matched;
  201. } else if (*pattern == 'f') {
  202. double *d = va_arg(ap, double *);
  203. if (!longmod)
  204. return -1; /* float not supported */
  205. if (!*buf)
  206. return n_matched;
  207. if (scan_double(&buf, d, width)<0)
  208. return n_matched;
  209. ++pattern;
  210. ++n_matched;
  211. } else if (*pattern == 'd') {
  212. long lng=0;
  213. if (scan_signed(&buf, &lng, width)<0)
  214. return n_matched;
  215. if (longmod) {
  216. long *out = va_arg(ap, long *);
  217. *out = lng;
  218. } else {
  219. int *out = va_arg(ap, int *);
  220. #if LONG_MAX > INT_MAX
  221. if (lng < INT_MIN || lng > INT_MAX)
  222. return n_matched;
  223. #endif
  224. *out = (int)lng;
  225. }
  226. ++pattern;
  227. ++n_matched;
  228. } else if (*pattern == 's') {
  229. char *s = va_arg(ap, char *);
  230. if (longmod)
  231. return -1;
  232. if (width < 0)
  233. return -1;
  234. if (scan_string(&buf, s, width)<0)
  235. return n_matched;
  236. ++pattern;
  237. ++n_matched;
  238. } else if (*pattern == 'c') {
  239. char *ch = va_arg(ap, char *);
  240. if (longmod)
  241. return -1;
  242. if (width != -1)
  243. return -1;
  244. if (!*buf)
  245. return n_matched;
  246. *ch = *buf++;
  247. ++pattern;
  248. ++n_matched;
  249. } else if (*pattern == '%') {
  250. if (*buf != '%')
  251. return n_matched;
  252. if (longmod)
  253. return -1;
  254. ++buf;
  255. ++pattern;
  256. } else {
  257. return -1; /* Unrecognized pattern component. */
  258. }
  259. }
  260. }
  261. return n_matched;
  262. }
  263. /** Minimal sscanf replacement: parse <b>buf</b> according to <b>pattern</b>
  264. * and store the results in the corresponding argument fields. Differs from
  265. * sscanf in that:
  266. * <ul><li>It only handles %u, %lu, %x, %lx, %[NUM]s, %d, %ld, %lf, and %c.
  267. * <li>It only handles decimal inputs for %lf. (12.3, not 1.23e1)
  268. * <li>It does not handle arbitrarily long widths.
  269. * <li>Numbers do not consume any space characters.
  270. * <li>It is locale-independent.
  271. * <li>%u and %x do not consume any space.
  272. * <li>It returns -1 on malformed patterns.</ul>
  273. *
  274. * (As with other locale-independent functions, we need this to parse data that
  275. * is in ASCII without worrying that the C library's locale-handling will make
  276. * miscellaneous characters look like numbers, spaces, and so on.)
  277. */
  278. int
  279. tor_sscanf(const char *buf, const char *pattern, ...)
  280. {
  281. int r;
  282. va_list ap;
  283. va_start(ap, pattern);
  284. r = tor_vsscanf(buf, pattern, ap);
  285. va_end(ap);
  286. return r;
  287. }