ncurses 5.5
[ncurses.git] / form / fty_num.c
1 /*
2  * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
3  * You may freely copy it for use as a template for your own field types.
4  * If you develop a field type that might be of general use, please send
5  * it back to the ncurses maintainers for inclusion in the next version.
6  */
7 /***************************************************************************
8 *                                                                          *
9 *  Author : Juergen Pfeifer                                                *
10 *                                                                          *
11 ***************************************************************************/
12
13 #include "form.priv.h"
14
15 MODULE_ID("$Id: fty_num.c,v 1.22 2005/08/20 18:26:16 tom Exp $")
16
17 #if HAVE_LOCALE_H
18 #include <locale.h>
19 #endif
20
21 #if HAVE_LOCALE_H
22 #define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.'))
23 #else
24 #define isDecimalPoint(c) ((c) == '.')
25 #endif
26
27 #if USE_WIDEC_SUPPORT
28 #define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c)))
29 #else
30 #define isDigit(c) isdigit(UChar(c))
31 #endif
32
33 #define thisARG numericARG
34
35 typedef struct
36   {
37     int precision;
38     double low;
39     double high;
40     struct lconv *L;
41   }
42 thisARG;
43
44 /*---------------------------------------------------------------------------
45 |   Facility      :  libnform
46 |   Function      :  static void *Make_This_Type(va_list * ap)
47 |
48 |   Description   :  Allocate structure for numeric type argument.
49 |
50 |   Return Values :  Pointer to argument structure or NULL on error
51 +--------------------------------------------------------------------------*/
52 static void *
53 Make_This_Type(va_list *ap)
54 {
55   thisARG *argn = (thisARG *) malloc(sizeof(thisARG));
56
57   if (argn)
58     {
59       argn->precision = va_arg(*ap, int);
60       argn->low = va_arg(*ap, double);
61       argn->high = va_arg(*ap, double);
62
63 #if HAVE_LOCALE_H
64       argn->L = localeconv();
65 #else
66       argn->L = NULL;
67 #endif
68     }
69   return (void *)argn;
70 }
71
72 /*---------------------------------------------------------------------------
73 |   Facility      :  libnform
74 |   Function      :  static void *Copy_This_Type(const void * argp)
75 |
76 |   Description   :  Copy structure for numeric type argument.
77 |
78 |   Return Values :  Pointer to argument structure or NULL on error.
79 +--------------------------------------------------------------------------*/
80 static void *
81 Copy_This_Type(const void *argp)
82 {
83   const thisARG *ap = (const thisARG *)argp;
84   thisARG *result = (thisARG *) 0;
85
86   if (argp)
87     {
88       result = (thisARG *) malloc(sizeof(thisARG));
89       if (result)
90         *result = *ap;
91     }
92   return (void *)result;
93 }
94
95 /*---------------------------------------------------------------------------
96 |   Facility      :  libnform
97 |   Function      :  static void Free_This_Type(void * argp)
98 |
99 |   Description   :  Free structure for numeric type argument.
100 |
101 |   Return Values :  -
102 +--------------------------------------------------------------------------*/
103 static void
104 Free_This_Type(void *argp)
105 {
106   if (argp)
107     free(argp);
108 }
109
110 /*---------------------------------------------------------------------------
111 |   Facility      :  libnform
112 |   Function      :  static bool Check_This_Field(FIELD * field,
113 |                                                 const void * argp)
114 |
115 |   Description   :  Validate buffer content to be a valid numeric value
116 |
117 |   Return Values :  TRUE  - field is valid
118 |                    FALSE - field is invalid
119 +--------------------------------------------------------------------------*/
120 static bool
121 Check_This_Field(FIELD *field, const void *argp)
122 {
123   const thisARG *argn = (const thisARG *)argp;
124   double low = argn->low;
125   double high = argn->high;
126   int prec = argn->precision;
127   unsigned char *bp = (unsigned char *)field_buffer(field, 0);
128   char *s = (char *)bp;
129   double val = 0.0;
130   struct lconv *L = argn->L;
131   char buf[64];
132   bool result = FALSE;
133
134   while (*bp && *bp == ' ')
135     bp++;
136   if (*bp)
137     {
138       if (*bp == '-' || *bp == '+')
139         bp++;
140 #if USE_WIDEC_SUPPORT
141       if (*bp)
142         {
143           bool blank = FALSE;
144           int state = 0;
145           int len;
146           int n;
147           wchar_t *list = _nc_Widen_String((char *)bp, &len);
148
149           if (list != 0)
150             {
151               result = TRUE;
152               for (n = 0; n < len; ++n)
153                 {
154                   if (blank)
155                     {
156                       if (list[n] != ' ')
157                         {
158                           result = FALSE;
159                           break;
160                         }
161                     }
162                   else if (list[n] == ' ')
163                     {
164                       blank = TRUE;
165                     }
166                   else if (isDecimalPoint(list[n]))
167                     {
168                       if (++state > 1)
169                         {
170                           result = FALSE;
171                           break;
172                         }
173                     }
174                   else if (!isDigit(list[n]))
175                     {
176                       result = FALSE;
177                       break;
178                     }
179                 }
180               free(list);
181             }
182         }
183 #else
184       while (*bp)
185         {
186           if (!isdigit(UChar(*bp)))
187             break;
188           bp++;
189         }
190       if (isDecimalPoint(*bp))
191         {
192           bp++;
193           while (*bp)
194             {
195               if (!isdigit(UChar(*bp)))
196                 break;
197               bp++;
198             }
199         }
200       while (*bp && *bp == ' ')
201         bp++;
202       result = (*bp == '\0');
203 #endif
204       if (result)
205         {
206           val = atof(s);
207           if (low < high)
208             {
209               if (val < low || val > high)
210                 result = FALSE;
211             }
212           if (result)
213             {
214               sprintf(buf, "%.*f", (prec > 0 ? prec : 0), val);
215               set_field_buffer(field, 0, buf);
216             }
217         }
218     }
219   return (result);
220 }
221
222 /*---------------------------------------------------------------------------
223 |   Facility      :  libnform
224 |   Function      :  static bool Check_This_Character(
225 |                                      int c,
226 |                                      const void * argp)
227 |
228 |   Description   :  Check a character for the numeric type.
229 |
230 |   Return Values :  TRUE  - character is valid
231 |                    FALSE - character is invalid
232 +--------------------------------------------------------------------------*/
233 static bool
234 Check_This_Character(int c, const void *argp)
235 {
236   const thisARG *argn = (const thisARG *)argp;
237   struct lconv *L = argn->L;
238
239   return ((isDigit(c) ||
240            c == '+' ||
241            c == '-' ||
242            isDecimalPoint(c))
243           ? TRUE
244           : FALSE);
245 }
246
247 static FIELDTYPE typeTHIS =
248 {
249   _HAS_ARGS | _RESIDENT,
250   1,                            /* this is mutable, so we can't be const */
251   (FIELDTYPE *)0,
252   (FIELDTYPE *)0,
253   Make_This_Type,
254   Copy_This_Type,
255   Free_This_Type,
256   Check_This_Field,
257   Check_This_Character,
258   NULL,
259   NULL
260 };
261
262 NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_NUMERIC = &typeTHIS;
263
264 /* fty_num.c ends here */