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