doscan.c 9.9 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450
  1. /*
  2. * doscan.c - scan formatted input
  3. */
  4. /* $Id$ */
  5. #include <stdio.h>
  6. #include <stdlib.h>
  7. #include <ctype.h>
  8. #include <stdarg.h>
  9. #include "loc_incl.h"
  10. #if _EM_WSIZE == _EM_PSIZE
  11. #define set_pointer(flags) /* nothing */
  12. #elif _EM_LSIZE == _EM_PSIZE
  13. #define set_pointer(flags) (flags |= FL_LONG)
  14. #else
  15. #error garbage pointer size
  16. #define set_pointer(flags) /* compilation might continue */
  17. #endif
  18. #define NUMLEN 512
  19. #define NR_CHARS 256
  20. static char Xtable[NR_CHARS];
  21. static char inp_buf[NUMLEN];
  22. /* Collect a number of characters which constitite an ordinal number.
  23. * When the type is 'i', the base can be 8, 10, or 16, depending on the
  24. * first 1 or 2 characters. This means that the base must be adjusted
  25. * according to the format of the number. At the end of the function, base
  26. * is then set to 0, so strtol() will get the right argument.
  27. */
  28. static char *
  29. o_collect(register int c, register FILE *stream, char type,
  30. int width, int *basep)
  31. {
  32. register char *bufp = inp_buf;
  33. register int base;
  34. switch (type) {
  35. case 'i': /* i means octal, decimal or hexadecimal */
  36. case 'p':
  37. case 'x':
  38. case 'X': base = 16; break;
  39. case 'd':
  40. case 'u': base = 10; break;
  41. case 'o': base = 8; break;
  42. case 'b': base = 2; break;
  43. }
  44. if (c == '-' || c == '+') {
  45. *bufp++ = c;
  46. if (--width)
  47. c = getc(stream);
  48. }
  49. if (width && c == '0' && base == 16) {
  50. *bufp++ = c;
  51. if (--width)
  52. c = getc(stream);
  53. if (c != 'x' && c != 'X') {
  54. if (type == 'i') base = 8;
  55. }
  56. else if (width) {
  57. *bufp++ = c;
  58. if (--width)
  59. c = getc(stream);
  60. }
  61. }
  62. else if (type == 'i') base = 10;
  63. while (width) {
  64. if (((base == 10) && isdigit(c))
  65. || ((base == 16) && isxdigit(c))
  66. || ((base == 8) && isdigit(c) && (c < '8'))
  67. || ((base == 2) && isdigit(c) && (c < '2'))) {
  68. *bufp++ = c;
  69. if (--width)
  70. c = getc(stream);
  71. }
  72. else break;
  73. }
  74. if (width && c != EOF) ungetc(c, stream);
  75. if (type == 'i') base = 0;
  76. *basep = base;
  77. *bufp = '\0';
  78. return bufp - 1;
  79. }
  80. #ifndef NOFLOAT
  81. /* The function f_collect() reads a string that has the format of a
  82. * floating-point number. The function returns as soon as a format-error
  83. * is encountered, leaving the offending character in the input. This means
  84. * that 1.el leaves the 'l' in the input queue. Since all detection of
  85. * format errors is done here, _doscan() doesn't call strtod() when it's
  86. * not necessary, although the use of the width field can cause incomplete
  87. * numbers to be passed to strtod(). (e.g. 1.3e+)
  88. */
  89. static char *
  90. f_collect(register int c, register FILE *stream, register int width)
  91. {
  92. register char *bufp = inp_buf;
  93. int digit_seen = 0;
  94. if (c == '-' || c == '+') {
  95. *bufp++ = c;
  96. if (--width)
  97. c = getc(stream);
  98. }
  99. while (width && isdigit(c)) {
  100. digit_seen++;
  101. *bufp++ = c;
  102. if (--width)
  103. c = getc(stream);
  104. }
  105. if (width && c == '.') {
  106. *bufp++ = c;
  107. if(--width)
  108. c = getc(stream);
  109. while (width && isdigit(c)) {
  110. digit_seen++;
  111. *bufp++ = c;
  112. if (--width)
  113. c = getc(stream);
  114. }
  115. }
  116. if (!digit_seen) {
  117. if (width && c != EOF) ungetc(c, stream);
  118. return inp_buf - 1;
  119. }
  120. else digit_seen = 0;
  121. if (width && (c == 'e' || c == 'E')) {
  122. *bufp++ = c;
  123. if (--width)
  124. c = getc(stream);
  125. if (width && (c == '+' || c == '-')) {
  126. *bufp++ = c;
  127. if (--width)
  128. c = getc(stream);
  129. }
  130. while (width && isdigit(c)) {
  131. digit_seen++;
  132. *bufp++ = c;
  133. if (--width)
  134. c = getc(stream);
  135. }
  136. if (!digit_seen) {
  137. if (width && c != EOF) ungetc(c,stream);
  138. return inp_buf - 1;
  139. }
  140. }
  141. if (width && c != EOF) ungetc(c, stream);
  142. *bufp = '\0';
  143. return bufp - 1;
  144. }
  145. #endif /* NOFLOAT */
  146. /*
  147. * the routine that does the scanning
  148. */
  149. int
  150. _doscan(register FILE *stream, const char *format, va_list ap)
  151. {
  152. int done = 0; /* number of items done */
  153. int nrchars = 0; /* number of characters read */
  154. int conv = 0; /* # of conversions */
  155. int base; /* conversion base */
  156. unsigned long val; /* an integer value */
  157. register char *str; /* temporary pointer */
  158. char *tmp_string; /* ditto */
  159. unsigned width; /* width of field */
  160. int flags; /* some flags */
  161. int reverse; /* reverse the checking in [...] */
  162. int kind;
  163. register int ic; /* the input character */
  164. #ifndef NOFLOAT
  165. long double ld_val;
  166. #endif
  167. if (!*format) return 0;
  168. while (1) {
  169. if (isspace(*format)) {
  170. while (isspace(*format))
  171. format++; /* skip whitespace */
  172. ic = getc(stream);
  173. nrchars++;
  174. while (isspace (ic)) {
  175. ic = getc(stream);
  176. nrchars++;
  177. }
  178. if (ic != EOF) ungetc(ic,stream);
  179. nrchars--;
  180. }
  181. if (!*format) break; /* end of format */
  182. if (*format != '%') {
  183. ic = getc(stream);
  184. nrchars++;
  185. if (ic != *format++) {
  186. if (ic != EOF) ungetc(ic,stream);
  187. nrchars--;
  188. break; /* error */
  189. }
  190. continue;
  191. }
  192. format++;
  193. if (*format == '%') {
  194. ic = getc(stream);
  195. nrchars++;
  196. if (ic == '%') {
  197. format++;
  198. continue;
  199. }
  200. else break;
  201. }
  202. flags = 0;
  203. if (*format == '*') {
  204. format++;
  205. flags |= FL_NOASSIGN;
  206. }
  207. if (isdigit (*format)) {
  208. flags |= FL_WIDTHSPEC;
  209. for (width = 0; isdigit (*format);)
  210. width = width * 10 + *format++ - '0';
  211. }
  212. switch (*format) {
  213. case 'h': flags |= FL_SHORT; format++; break;
  214. case 'l': flags |= FL_LONG; format++; break;
  215. case 'L': flags |= FL_LONGDOUBLE; format++; break;
  216. }
  217. kind = *format;
  218. if ((kind != 'c') && (kind != '[') && (kind != 'n')) {
  219. do {
  220. ic = getc(stream);
  221. nrchars++;
  222. } while (isspace(ic));
  223. if (ic == EOF) break; /* outer while */
  224. } else if (kind != 'n') { /* %c or %[ */
  225. ic = getc(stream);
  226. if (ic == EOF) break; /* outer while */
  227. nrchars++;
  228. }
  229. switch (kind) {
  230. default:
  231. /* not recognized, like %q */
  232. return conv || (ic != EOF) ? done : EOF;
  233. break;
  234. case 'n':
  235. if (!(flags & FL_NOASSIGN)) { /* silly, though */
  236. if (flags & FL_SHORT)
  237. *va_arg(ap, short *) = (short) nrchars;
  238. else if (flags & FL_LONG)
  239. *va_arg(ap, long *) = (long) nrchars;
  240. else
  241. *va_arg(ap, int *) = (int) nrchars;
  242. }
  243. break;
  244. case 'p': /* pointer */
  245. set_pointer(flags);
  246. /* fallthrough */
  247. case 'b': /* binary */
  248. case 'd': /* decimal */
  249. case 'i': /* general integer */
  250. case 'o': /* octal */
  251. case 'u': /* unsigned */
  252. case 'x': /* hexadecimal */
  253. case 'X': /* ditto */
  254. if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
  255. width = NUMLEN;
  256. if (!width) return done;
  257. str = o_collect(ic, stream, kind, width, &base);
  258. if (str < inp_buf
  259. || (str == inp_buf
  260. && (*str == '-'
  261. || *str == '+'))) return done;
  262. /*
  263. * Although the length of the number is str-inp_buf+1
  264. * we don't add the 1 since we counted it already
  265. */
  266. nrchars += str - inp_buf;
  267. if (!(flags & FL_NOASSIGN)) {
  268. if (kind == 'd' || kind == 'i')
  269. val = strtol(inp_buf, &tmp_string, base);
  270. else
  271. val = strtoul(inp_buf, &tmp_string, base);
  272. if (flags & FL_LONG)
  273. *va_arg(ap, unsigned long *) = (unsigned long) val;
  274. else if (flags & FL_SHORT)
  275. *va_arg(ap, unsigned short *) = (unsigned short) val;
  276. else
  277. *va_arg(ap, unsigned *) = (unsigned) val;
  278. }
  279. break;
  280. case 'c':
  281. if (!(flags & FL_WIDTHSPEC))
  282. width = 1;
  283. if (!(flags & FL_NOASSIGN))
  284. str = va_arg(ap, char *);
  285. if (!width) return done;
  286. while (width && ic != EOF) {
  287. if (!(flags & FL_NOASSIGN))
  288. *str++ = (char) ic;
  289. if (--width) {
  290. ic = getc(stream);
  291. nrchars++;
  292. }
  293. }
  294. if (width) {
  295. if (ic != EOF) ungetc(ic,stream);
  296. nrchars--;
  297. }
  298. break;
  299. case 's':
  300. if (!(flags & FL_WIDTHSPEC))
  301. width = 0xffff;
  302. if (!(flags & FL_NOASSIGN))
  303. str = va_arg(ap, char *);
  304. if (!width) return done;
  305. while (width && ic != EOF && !isspace(ic)) {
  306. if (!(flags & FL_NOASSIGN))
  307. *str++ = (char) ic;
  308. if (--width) {
  309. ic = getc(stream);
  310. nrchars++;
  311. }
  312. }
  313. /* terminate the string */
  314. if (!(flags & FL_NOASSIGN))
  315. *str = '\0';
  316. if (width) {
  317. if (ic != EOF) ungetc(ic,stream);
  318. nrchars--;
  319. }
  320. break;
  321. case '[':
  322. if (!(flags & FL_WIDTHSPEC))
  323. width = 0xffff;
  324. if (!width) return done;
  325. if ( *++format == '^' ) {
  326. reverse = 1;
  327. format++;
  328. } else
  329. reverse = 0;
  330. for (str = Xtable; str < &Xtable[NR_CHARS]
  331. ; str++)
  332. *str = 0;
  333. if (*format == ']') Xtable[*format++] = 1;
  334. while (*format && *format != ']') {
  335. Xtable[*format++] = 1;
  336. if (*format == '-') {
  337. format++;
  338. if (*format
  339. && *format != ']'
  340. && *(format) >= *(format -2)) {
  341. int c;
  342. for( c = *(format -2) + 1
  343. ; c <= *format ; c++)
  344. Xtable[c] = 1;
  345. format++;
  346. }
  347. else Xtable['-'] = 1;
  348. }
  349. }
  350. if (!*format || !(Xtable[ic] ^ reverse)) {
  351. if (ic != EOF) ungetc(ic, stream);
  352. return done;
  353. }
  354. if (!(flags & FL_NOASSIGN))
  355. str = va_arg(ap, char *);
  356. do {
  357. if (!(flags & FL_NOASSIGN))
  358. *str++ = (char) ic;
  359. if (--width) {
  360. ic = getc(stream);
  361. nrchars++;
  362. }
  363. } while (width && ic != EOF && (Xtable[ic] ^ reverse));
  364. if (width) {
  365. if (ic != EOF) ungetc(ic, stream);
  366. nrchars--;
  367. }
  368. if (!(flags & FL_NOASSIGN)) { /* terminate string */
  369. *str = '\0';
  370. }
  371. break;
  372. #ifndef NOFLOAT
  373. case 'e':
  374. case 'E':
  375. case 'f':
  376. case 'g':
  377. case 'G':
  378. if (!(flags & FL_WIDTHSPEC) || width > NUMLEN)
  379. width = NUMLEN;
  380. if (!width) return done;
  381. str = f_collect(ic, stream, width);
  382. if (str < inp_buf
  383. || (str == inp_buf
  384. && (*str == '-'
  385. || *str == '+'))) return done;
  386. /*
  387. * Although the length of the number is str-inp_buf+1
  388. * we don't add the 1 since we counted it already
  389. */
  390. nrchars += str - inp_buf;
  391. if (!(flags & FL_NOASSIGN)) {
  392. ld_val = strtod(inp_buf, &tmp_string);
  393. if (flags & FL_LONGDOUBLE)
  394. *va_arg(ap, long double *) = (long double) ld_val;
  395. else
  396. if (flags & FL_LONG)
  397. *va_arg(ap, double *) = (double) ld_val;
  398. else
  399. *va_arg(ap, float *) = (float) ld_val;
  400. }
  401. break;
  402. #endif
  403. } /* end switch */
  404. conv++;
  405. if (!(flags & FL_NOASSIGN) && kind != 'n') done++;
  406. format++;
  407. }
  408. return conv || (ic != EOF) ? done : EOF;
  409. }