1 /* Public Domain Curses */
2
3 #include <curspriv.h>
4
5 /*man-start**************************************************************
6
7 scanw
8 -----
9
10 ### Synopsis
11
12 int scanw(const char *fmt, ...);
13 int wscanw(WINDOW *win, const char *fmt, ...);
14 int mvscanw(int y, int x, const char *fmt, ...);
15 int mvwscanw(WINDOW *win, int y, int x, const char *fmt, ...);
16 int vwscanw(WINDOW *win, const char *fmt, va_list varglist);
17 int vw_scanw(WINDOW *win, const char *fmt, va_list varglist);
18
19 ### Description
20
21 These routines correspond to the standard C library's scanf()
22 family. Each gets a string from the window via wgetnstr(), and
23 uses the resulting line as input for the scan.
24
25 ### Return Value
26
27 On successful completion, these functions return the number of
28 items successfully matched. Otherwise they return ERR.
29
30 ### Portability
31 X/Open BSD SYS V
32 scanw Y Y Y
33 wscanw Y Y Y
34 mvscanw Y Y Y
35 mvwscanw Y Y Y
36 vwscanw Y - 4.0
37 vw_scanw Y
38
39 **man-end****************************************************************/
40
41 #include <string.h>
42
43 #ifndef HAVE_VSSCANF
44 # include <stdlib.h>
45 # include <ctype.h>
46 # include <limits.h>
47
48 static int _pdc_vsscanf(const char *, const char *, va_list);
49
50 # define vsscanf _pdc_vsscanf
51 #endif
52
vwscanw(WINDOW * win,const char * fmt,va_list varglist)53 int vwscanw(WINDOW *win, const char *fmt, va_list varglist)
54 {
55 char scanbuf[256];
56
57 PDC_LOG(("vwscanw() - called\n"));
58
59 if (wgetnstr(win, scanbuf, 255) == ERR)
60 return ERR;
61
62 return vsscanf(scanbuf, fmt, varglist);
63 }
64
scanw(const char * fmt,...)65 int scanw(const char *fmt, ...)
66 {
67 va_list args;
68 int retval;
69
70 PDC_LOG(("scanw() - called\n"));
71
72 va_start(args, fmt);
73 retval = vwscanw(stdscr, fmt, args);
74 va_end(args);
75
76 return retval;
77 }
78
wscanw(WINDOW * win,const char * fmt,...)79 int wscanw(WINDOW *win, const char *fmt, ...)
80 {
81 va_list args;
82 int retval;
83
84 PDC_LOG(("wscanw() - called\n"));
85
86 va_start(args, fmt);
87 retval = vwscanw(win, fmt, args);
88 va_end(args);
89
90 return retval;
91 }
92
mvscanw(int y,int x,const char * fmt,...)93 int mvscanw(int y, int x, const char *fmt, ...)
94 {
95 va_list args;
96 int retval;
97
98 PDC_LOG(("mvscanw() - called\n"));
99
100 if (move(y, x) == ERR)
101 return ERR;
102
103 va_start(args, fmt);
104 retval = vwscanw(stdscr, fmt, args);
105 va_end(args);
106
107 return retval;
108 }
109
mvwscanw(WINDOW * win,int y,int x,const char * fmt,...)110 int mvwscanw(WINDOW *win, int y, int x, const char *fmt, ...)
111 {
112 va_list args;
113 int retval;
114
115 PDC_LOG(("mvscanw() - called\n"));
116
117 if (wmove(win, y, x) == ERR)
118 return ERR;
119
120 va_start(args, fmt);
121 retval = vwscanw(win, fmt, args);
122 va_end(args);
123
124 return retval;
125 }
126
vw_scanw(WINDOW * win,const char * fmt,va_list varglist)127 int vw_scanw(WINDOW *win, const char *fmt, va_list varglist)
128 {
129 PDC_LOG(("vw_scanw() - called\n"));
130
131 return vwscanw(win, fmt, varglist);
132 }
133
134 #ifndef HAVE_VSSCANF
135
136 /* _pdc_vsscanf() - Internal routine to parse and format an input
137 buffer. It scans a series of input fields; each field is formatted
138 according to a supplied format string and the formatted input is
139 stored in the variable number of addresses passed. Returns the number
140 of input fields or EOF on error.
141
142 Don't compile this unless required. Some compilers (at least Borland
143 C++ 3.0) have to link with math libraries due to the use of floats.
144
145 Based on vsscanf.c and input.c from emx 0.8f library source,
146 Copyright (c) 1990-1992 by Eberhard Mattes, who has kindly agreed to
147 its inclusion in PDCurses. */
148
149 #define WHITE(x) ((x) == ' ' || (x) == '\t' || (x) == '\n')
150
151 #define NEXT(x) \
152 do { \
153 x = *buf++; \
154 if (!x) \
155 return (count ? count : EOF); \
156 ++chars; \
157 } while (0)
158
159 #define UNGETC() \
160 do { \
161 --buf; --chars; \
162 } while (0)
163
_pdc_vsscanf(const char * buf,const char * fmt,va_list arg_ptr)164 static int _pdc_vsscanf(const char *buf, const char *fmt, va_list arg_ptr)
165 {
166 int count, chars, c, width, radix, d, i;
167 int *int_ptr;
168 long *long_ptr;
169 short *short_ptr;
170 char *char_ptr;
171 unsigned char f;
172 char neg, assign, ok, size;
173 long n;
174 char map[256], end;
175 double dx, dd, *dbl_ptr;
176 float *flt_ptr;
177 int exp;
178 char eneg;
179
180 count = 0;
181 chars = 0;
182 c = 0;
183 while ((f = *fmt) != 0)
184 {
185 if (WHITE(f))
186 {
187 do
188 {
189 ++fmt;
190 f = *fmt;
191 }
192 while (WHITE(f));
193 do
194 {
195 c = *buf++;
196 if (!c)
197 {
198 if (!f || count)
199 return count;
200 else
201 return EOF;
202 } else
203 ++chars;
204 }
205 while (WHITE(c));
206 UNGETC();
207 } else if (f != '%')
208 {
209 NEXT(c);
210 if (c != f)
211 return count;
212 ++fmt;
213 } else
214 {
215 assign = TRUE;
216 width = INT_MAX;
217 char_ptr = NULL;
218 ++fmt;
219 if (*fmt == '*')
220 {
221 assign = FALSE;
222 ++fmt;
223 }
224 if (isdigit(*fmt))
225 {
226 width = 0;
227 while (isdigit(*fmt))
228 width = width * 10 + (*fmt++ - '0');
229 if (!width)
230 width = INT_MAX;
231 }
232 size = 0;
233 if (*fmt == 'h' || *fmt == 'l')
234 size = *fmt++;
235 f = *fmt;
236 switch (f)
237 {
238 case 'c':
239 if (width == INT_MAX)
240 width = 1;
241 if (assign)
242 char_ptr = va_arg(arg_ptr, char *);
243 while (width > 0)
244 {
245 --width;
246 NEXT(c);
247 if (assign)
248 {
249 *char_ptr++ = (char) c;
250 ++count;
251 }
252 }
253 break;
254 case '[':
255 memset(map, 0, 256);
256 end = 0;
257 ++fmt;
258 if (*fmt == '^')
259 {
260 ++fmt;
261 end = 1;
262 }
263 i = 0;
264 for (;;)
265 {
266 f = (unsigned char) *fmt;
267 switch (f)
268 {
269 case 0:
270 /* avoid skipping past 0 */
271 --fmt;
272 NEXT(c);
273 goto string;
274 case ']':
275 if (i > 0)
276 {
277 NEXT(c);
278 goto string;
279 }
280 /* no break */
281 default:
282 if (fmt[1] == '-' && fmt[2]
283 && f < (unsigned char)fmt[2])
284 {
285 memset(map + f, 1, (unsigned char)fmt[2] - f);
286 fmt += 2;
287 }
288 else
289 map[f] = 1;
290 break;
291 }
292 ++fmt;
293 ++i;
294 }
295 case 's':
296 memset(map, 0, 256);
297 map[' '] = 1;
298 map['\n'] = 1;
299 map['\r'] = 1;
300 map['\t'] = 1;
301 end = 1;
302 do
303 {
304 NEXT(c);
305 }
306 while (WHITE(c));
307 string:
308 if (assign)
309 char_ptr = va_arg(arg_ptr, char *);
310 while (width > 0 && map[(unsigned char) c] != end)
311 {
312 --width;
313 if (assign)
314 *char_ptr++ = (char) c;
315 c = *buf++;
316 if (!c)
317 break;
318 else
319 ++chars;
320 }
321 if (assign)
322 {
323 *char_ptr = 0;
324 ++count;
325 }
326 if (!c)
327 return count;
328 else
329 UNGETC();
330 break;
331 case 'f':
332 case 'e':
333 case 'E':
334 case 'g':
335 case 'G':
336 neg = ok = FALSE;
337 dx = 0.0;
338 do
339 {
340 NEXT(c);
341 }
342 while (WHITE(c));
343 if (c == '+')
344 {
345 NEXT(c);
346 --width;
347 } else if (c == '-')
348 {
349 neg = TRUE;
350 NEXT(c);
351 --width;
352 }
353 while (width > 0 && isdigit(c))
354 {
355 --width;
356 dx = dx * 10.0 + (double) (c - '0');
357 ok = TRUE;
358 c = *buf++;
359 if (!c)
360 break;
361 else
362 ++chars;
363 }
364 if (width > 0 && c == '.')
365 {
366 --width;
367 dd = 10.0;
368 NEXT(c);
369 while (width > 0 && isdigit(c))
370 {
371 --width;
372 dx += (double) (c - '0') / dd;
373 dd *= 10.0;
374 ok = TRUE;
375 c = *buf++;
376 if (!c)
377 break;
378 else
379 ++chars;
380 }
381 }
382 if (!ok)
383 return count;
384 if (width > 0 && (c == 'e' || c == 'E'))
385 {
386 eneg = FALSE;
387 exp = 0;
388 NEXT(c);
389 --width;
390 if (width > 0 && c == '+')
391 {
392 NEXT(c);
393 --width;
394 } else if (width > 0 && c == '-')
395 {
396 eneg = TRUE;
397 NEXT(c);
398 --width;
399 }
400 if (!(width > 0 && isdigit(c)))
401 {
402 UNGETC();
403 return count;
404 }
405 while (width > 0 && isdigit(c))
406 {
407 --width;
408 exp = exp * 10 + (c - '0');
409 c = *buf++;
410 if (!c)
411 break;
412 else
413 ++chars;
414 }
415 if (eneg)
416 exp = -exp;
417 while (exp > 0)
418 {
419 dx *= 10.0;
420 --exp;
421 }
422 while (exp < 0)
423 {
424 dx /= 10.0;
425 ++exp;
426 }
427 }
428 if (assign)
429 {
430 if (neg)
431 dx = -dx;
432 if (size == 'l')
433 {
434 dbl_ptr = va_arg(arg_ptr, double *);
435 *dbl_ptr = dx;
436 }
437 else
438 {
439 flt_ptr = va_arg(arg_ptr, float *);
440 *flt_ptr = (float)dx;
441 }
442 ++count;
443 }
444 if (!c)
445 return count;
446 else
447 UNGETC();
448 break;
449 case 'i':
450 neg = FALSE;
451 radix = 10;
452 do
453 {
454 NEXT(c);
455 }
456 while (WHITE(c));
457 if (!(width > 0 && c == '0'))
458 goto scan_complete_number;
459 NEXT(c);
460 --width;
461 if (width > 0 && (c == 'x' || c == 'X'))
462 {
463 NEXT(c);
464 radix = 16;
465 --width;
466 }
467 else if (width > 0 && (c >= '0' && c <= '7'))
468 radix = 8;
469 goto scan_unsigned_number;
470 case 'd':
471 case 'u':
472 case 'o':
473 case 'x':
474 case 'X':
475 do
476 {
477 NEXT(c);
478 }
479 while (WHITE(c));
480 switch (f)
481 {
482 case 'o':
483 radix = 8;
484 break;
485 case 'x':
486 case 'X':
487 radix = 16;
488 break;
489 default:
490 radix = 10;
491 break;
492 }
493 scan_complete_number:
494 neg = FALSE;
495 if (width > 0 && c == '+')
496 {
497 NEXT(c);
498 --width;
499 }
500 else if (width > 0 && c == '-' && radix == 10)
501 {
502 neg = TRUE;
503 NEXT(c);
504 --width;
505 }
506 scan_unsigned_number:
507 n = 0;
508 ok = FALSE;
509 while (width > 0)
510 {
511 --width;
512 if (isdigit(c))
513 d = c - '0';
514 else if (isupper(c))
515 d = c - 'A' + 10;
516 else if (islower(c))
517 d = c - 'a' + 10;
518 else
519 break;
520 if (d < 0 || d >= radix)
521 break;
522 ok = TRUE;
523 n = n * radix + d;
524 c = *buf++;
525 if (!c)
526 break;
527 else
528 ++chars;
529 }
530 if (!ok)
531 return count;
532 if (assign)
533 {
534 if (neg)
535 n = -n;
536 switch (size)
537 {
538 case 'h':
539 short_ptr = va_arg(arg_ptr, short *);
540 *short_ptr = (short) n;
541 break;
542 case 'l':
543 long_ptr = va_arg(arg_ptr, long *);
544 *long_ptr = (long) n;
545 break;
546 default:
547 int_ptr = va_arg(arg_ptr, int *);
548 *int_ptr = (int) n;
549 }
550 ++count;
551 }
552 if (!c)
553 return count;
554 else
555 UNGETC();
556 break;
557 case 'n':
558 if (assign)
559 {
560 int_ptr = va_arg(arg_ptr, int *);
561 *int_ptr = chars;
562 ++count;
563 }
564 break;
565 default:
566 if (!f) /* % at end of string */
567 return count;
568 NEXT(c);
569 if (c != f)
570 return count;
571 break;
572 }
573 ++fmt;
574 }
575 }
576 return count;
577 }
578 #endif /* HAVE_VSSCANF */
579