pdcurses/scanw.c

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

mercurial