1 /**************************************************************************** 2 * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc. * 3 * * 4 * Permission is hereby granted, free of charge, to any person obtaining a * 5 * copy of this software and associated documentation files (the * 6 * "Software"), to deal in the Software without restriction, including * 7 * without limitation the rights to use, copy, modify, merge, publish, * 8 * distribute, distribute with modifications, sublicense, and/or sell * 9 * copies of the Software, and to permit persons to whom the Software is * 10 * furnished to do so, subject to the following conditions: * 11 * * 12 * The above copyright notice and this permission notice shall be included * 13 * in all copies or substantial portions of the Software. * 14 * * 15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS * 16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF * 17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. * 18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, * 19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR * 20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR * 21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE. * 22 * * 23 * Except as contained in this notice, the name(s) of the above copyright * 24 * holders shall not be used in advertising or otherwise to promote the * 25 * sale, use or other dealings in this Software without prior written * 26 * authorization. * 27 ****************************************************************************/ 28 29 /*************************************************************************** 30 * * 31 * Author : Juergen Pfeifer * 32 * * 33 ***************************************************************************/ 34 35 #include "form.priv.h" 36 37 MODULE_ID("$Id: fty_num.c,v 1.29 2012/02/23 10:02:15 tom Exp $") 38 39 #if HAVE_LOCALE_H 40 #include <locale.h> 41 #endif 42 43 #if HAVE_LOCALE_H 44 #define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.')) 45 #else 46 #define isDecimalPoint(c) ((c) == '.') 47 #endif 48 49 #if USE_WIDEC_SUPPORT 50 #define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c))) 51 #else 52 #define isDigit(c) isdigit(UChar(c)) 53 #endif 54 55 #define thisARG numericARG 56 57 typedef struct 58 { 59 int precision; 60 double low; 61 double high; 62 struct lconv *L; 63 } 64 thisARG; 65 66 typedef struct 67 { 68 int precision; 69 double low; 70 double high; 71 } 72 thisPARM; 73 74 /*--------------------------------------------------------------------------- 75 | Facility : libnform 76 | Function : static void *Generic_This_Type(void * arg) 77 | 78 | Description : Allocate structure for numeric type argument. 79 | 80 | Return Values : Pointer to argument structure or NULL on error 81 +--------------------------------------------------------------------------*/ 82 static void * 83 Generic_This_Type(void *arg) 84 { 85 thisARG *argn = (thisARG *) 0; 86 thisPARM *args = (thisPARM *) arg; 87 88 if (args) 89 { 90 argn = typeMalloc(thisARG, 1); 91 92 if (argn) 93 { 94 T((T_CREATE("thisARG %p"), (void *)argn)); 95 argn->precision = args->precision; 96 argn->low = args->low; 97 argn->high = args->high; 98 99 #if HAVE_LOCALE_H 100 argn->L = localeconv(); 101 #else 102 argn->L = NULL; 103 #endif 104 } 105 } 106 return (void *)argn; 107 } 108 109 /*--------------------------------------------------------------------------- 110 | Facility : libnform 111 | Function : static void *Make_This_Type(va_list * ap) 112 | 113 | Description : Allocate structure for numeric type argument. 114 | 115 | Return Values : Pointer to argument structure or NULL on error 116 +--------------------------------------------------------------------------*/ 117 static void * 118 Make_This_Type(va_list *ap) 119 { 120 thisPARM arg; 121 122 arg.precision = va_arg(*ap, int); 123 arg.low = va_arg(*ap, double); 124 arg.high = va_arg(*ap, double); 125 126 return Generic_This_Type((void *)&arg); 127 } 128 129 /*--------------------------------------------------------------------------- 130 | Facility : libnform 131 | Function : static void *Copy_This_Type(const void * argp) 132 | 133 | Description : Copy structure for numeric type argument. 134 | 135 | Return Values : Pointer to argument structure or NULL on error. 136 +--------------------------------------------------------------------------*/ 137 static void * 138 Copy_This_Type(const void *argp) 139 { 140 const thisARG *ap = (const thisARG *)argp; 141 thisARG *result = (thisARG *) 0; 142 143 if (argp) 144 { 145 result = typeMalloc(thisARG, 1); 146 if (result) 147 { 148 T((T_CREATE("thisARG %p"), (void *)result)); 149 *result = *ap; 150 } 151 } 152 return (void *)result; 153 } 154 155 /*--------------------------------------------------------------------------- 156 | Facility : libnform 157 | Function : static void Free_This_Type(void * argp) 158 | 159 | Description : Free structure for numeric type argument. 160 | 161 | Return Values : - 162 +--------------------------------------------------------------------------*/ 163 static void 164 Free_This_Type(void *argp) 165 { 166 if (argp) 167 free(argp); 168 } 169 170 /*--------------------------------------------------------------------------- 171 | Facility : libnform 172 | Function : static bool Check_This_Field(FIELD * field, 173 | const void * argp) 174 | 175 | Description : Validate buffer content to be a valid numeric value 176 | 177 | Return Values : TRUE - field is valid 178 | FALSE - field is invalid 179 +--------------------------------------------------------------------------*/ 180 static bool 181 Check_This_Field(FIELD *field, const void *argp) 182 { 183 const thisARG *argn = (const thisARG *)argp; 184 double low = argn->low; 185 double high = argn->high; 186 int prec = argn->precision; 187 unsigned char *bp = (unsigned char *)field_buffer(field, 0); 188 char *s = (char *)bp; 189 double val = 0.0; 190 struct lconv *L = argn->L; 191 char buf[64]; 192 bool result = FALSE; 193 194 while (*bp && *bp == ' ') 195 bp++; 196 if (*bp) 197 { 198 if (*bp == '-' || *bp == '+') 199 bp++; 200 #if USE_WIDEC_SUPPORT 201 if (*bp) 202 { 203 bool blank = FALSE; 204 int state = 0; 205 int len; 206 int n; 207 wchar_t *list = _nc_Widen_String((char *)bp, &len); 208 209 if (list != 0) 210 { 211 result = TRUE; 212 for (n = 0; n < len; ++n) 213 { 214 if (blank) 215 { 216 if (list[n] != ' ') 217 { 218 result = FALSE; 219 break; 220 } 221 } 222 else if (list[n] == ' ') 223 { 224 blank = TRUE; 225 } 226 else if (isDecimalPoint(list[n])) 227 { 228 if (++state > 1) 229 { 230 result = FALSE; 231 break; 232 } 233 } 234 else if (!isDigit(list[n])) 235 { 236 result = FALSE; 237 break; 238 } 239 } 240 free(list); 241 } 242 } 243 #else 244 while (*bp) 245 { 246 if (!isdigit(UChar(*bp))) 247 break; 248 bp++; 249 } 250 if (isDecimalPoint(*bp)) 251 { 252 bp++; 253 while (*bp) 254 { 255 if (!isdigit(UChar(*bp))) 256 break; 257 bp++; 258 } 259 } 260 while (*bp && *bp == ' ') 261 bp++; 262 result = (*bp == '\0'); 263 #endif 264 if (result) 265 { 266 val = atof(s); 267 if (low < high) 268 { 269 if (val < low || val > high) 270 result = FALSE; 271 } 272 if (result) 273 { 274 _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf)) 275 "%.*f", (prec > 0 ? prec : 0), val); 276 set_field_buffer(field, 0, buf); 277 } 278 } 279 } 280 return (result); 281 } 282 283 /*--------------------------------------------------------------------------- 284 | Facility : libnform 285 | Function : static bool Check_This_Character( 286 | int c, 287 | const void * argp) 288 | 289 | Description : Check a character for the numeric type. 290 | 291 | Return Values : TRUE - character is valid 292 | FALSE - character is invalid 293 +--------------------------------------------------------------------------*/ 294 static bool 295 Check_This_Character(int c, const void *argp) 296 { 297 const thisARG *argn = (const thisARG *)argp; 298 struct lconv *L = argn->L; 299 300 return ((isDigit(c) || 301 c == '+' || 302 c == '-' || 303 isDecimalPoint(c)) 304 ? TRUE 305 : FALSE); 306 } 307 308 static FIELDTYPE typeTHIS = 309 { 310 _HAS_ARGS | _RESIDENT, 311 1, /* this is mutable, so we can't be const */ 312 (FIELDTYPE *)0, 313 (FIELDTYPE *)0, 314 Make_This_Type, 315 Copy_This_Type, 316 Free_This_Type, 317 INIT_FT_FUNC(Check_This_Field), 318 INIT_FT_FUNC(Check_This_Character), 319 INIT_FT_FUNC(NULL), 320 INIT_FT_FUNC(NULL), 321 #if NCURSES_INTEROP_FUNCS 322 Generic_This_Type 323 #endif 324 }; 325 326 NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_NUMERIC = &typeTHIS; 327 328 #if NCURSES_INTEROP_FUNCS 329 /* The next routines are to simplify the use of ncurses from 330 programming languages with restictions on interop with C level 331 constructs (e.g. variable access or va_list + ellipsis constructs) 332 */ 333 NCURSES_EXPORT(FIELDTYPE *) 334 _nc_TYPE_NUMERIC(void) 335 { 336 return TYPE_NUMERIC; 337 } 338 #endif 339 340 /* fty_num.c ends here */ 341