14a1a9510SRong-En Fan /****************************************************************************
2*21817992SBaptiste Daroussin * Copyright 2019-2020,2021 Thomas E. Dickey *
3e1865124SBaptiste Daroussin * Copyright 1998-2010,2012 Free Software Foundation, Inc. *
44a1a9510SRong-En Fan * *
54a1a9510SRong-En Fan * Permission is hereby granted, free of charge, to any person obtaining a *
64a1a9510SRong-En Fan * copy of this software and associated documentation files (the *
74a1a9510SRong-En Fan * "Software"), to deal in the Software without restriction, including *
84a1a9510SRong-En Fan * without limitation the rights to use, copy, modify, merge, publish, *
94a1a9510SRong-En Fan * distribute, distribute with modifications, sublicense, and/or sell *
104a1a9510SRong-En Fan * copies of the Software, and to permit persons to whom the Software is *
114a1a9510SRong-En Fan * furnished to do so, subject to the following conditions: *
124a1a9510SRong-En Fan * *
134a1a9510SRong-En Fan * The above copyright notice and this permission notice shall be included *
144a1a9510SRong-En Fan * in all copies or substantial portions of the Software. *
154a1a9510SRong-En Fan * *
164a1a9510SRong-En Fan * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
174a1a9510SRong-En Fan * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
184a1a9510SRong-En Fan * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
194a1a9510SRong-En Fan * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
204a1a9510SRong-En Fan * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
214a1a9510SRong-En Fan * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
224a1a9510SRong-En Fan * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
234a1a9510SRong-En Fan * *
244a1a9510SRong-En Fan * Except as contained in this notice, the name(s) of the above copyright *
254a1a9510SRong-En Fan * holders shall not be used in advertising or otherwise to promote the *
264a1a9510SRong-En Fan * sale, use or other dealings in this Software without prior written *
274a1a9510SRong-En Fan * authorization. *
284a1a9510SRong-En Fan ****************************************************************************/
290e3d5408SPeter Wemm
300e3d5408SPeter Wemm /***************************************************************************
310e3d5408SPeter Wemm * *
324a1a9510SRong-En Fan * Author : Juergen Pfeifer *
330e3d5408SPeter Wemm * *
340e3d5408SPeter Wemm ***************************************************************************/
350e3d5408SPeter Wemm
360e3d5408SPeter Wemm #include "form.priv.h"
370e3d5408SPeter Wemm
38*21817992SBaptiste Daroussin MODULE_ID("$Id: fty_num.c,v 1.37 2021/03/27 23:49:58 tom Exp $")
390e3d5408SPeter Wemm
400e3d5408SPeter Wemm #if HAVE_LOCALE_H
410e3d5408SPeter Wemm #include <locale.h>
420e3d5408SPeter Wemm #endif
430e3d5408SPeter Wemm
44aae38d10SBaptiste Daroussin #if HAVE_LOCALE_H && HAVE_LOCALECONV
454a1a9510SRong-En Fan #define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.'))
464a1a9510SRong-En Fan #else
474a1a9510SRong-En Fan #define isDecimalPoint(c) ((c) == '.')
484a1a9510SRong-En Fan #endif
494a1a9510SRong-En Fan
504a1a9510SRong-En Fan #if USE_WIDEC_SUPPORT
514a1a9510SRong-En Fan #define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c)))
524a1a9510SRong-En Fan #else
534a1a9510SRong-En Fan #define isDigit(c) isdigit(UChar(c))
544a1a9510SRong-En Fan #endif
554a1a9510SRong-En Fan
564a1a9510SRong-En Fan #define thisARG numericARG
574a1a9510SRong-En Fan
584a1a9510SRong-En Fan typedef struct
594a1a9510SRong-En Fan {
600e3d5408SPeter Wemm int precision;
610e3d5408SPeter Wemm double low;
620e3d5408SPeter Wemm double high;
630e3d5408SPeter Wemm struct lconv *L;
644a1a9510SRong-En Fan }
654a1a9510SRong-En Fan thisARG;
660e3d5408SPeter Wemm
6706bfebdeSXin LI typedef struct
6806bfebdeSXin LI {
6906bfebdeSXin LI int precision;
7006bfebdeSXin LI double low;
7106bfebdeSXin LI double high;
7206bfebdeSXin LI }
7306bfebdeSXin LI thisPARM;
7406bfebdeSXin LI
7506bfebdeSXin LI /*---------------------------------------------------------------------------
7606bfebdeSXin LI | Facility : libnform
7706bfebdeSXin LI | Function : static void *Generic_This_Type(void * arg)
7806bfebdeSXin LI |
7906bfebdeSXin LI | Description : Allocate structure for numeric type argument.
8006bfebdeSXin LI |
8106bfebdeSXin LI | Return Values : Pointer to argument structure or NULL on error
8206bfebdeSXin LI +--------------------------------------------------------------------------*/
8306bfebdeSXin LI static void *
Generic_This_Type(void * arg)8406bfebdeSXin LI Generic_This_Type(void *arg)
8506bfebdeSXin LI {
8606bfebdeSXin LI thisARG *argn = (thisARG *)0;
8706bfebdeSXin LI thisPARM *args = (thisPARM *)arg;
8806bfebdeSXin LI
8906bfebdeSXin LI if (args)
9006bfebdeSXin LI {
9106bfebdeSXin LI argn = typeMalloc(thisARG, 1);
9206bfebdeSXin LI
9306bfebdeSXin LI if (argn)
9406bfebdeSXin LI {
9506bfebdeSXin LI T((T_CREATE("thisARG %p"), (void *)argn));
9606bfebdeSXin LI argn->precision = args->precision;
9706bfebdeSXin LI argn->low = args->low;
9806bfebdeSXin LI argn->high = args->high;
9906bfebdeSXin LI
100aae38d10SBaptiste Daroussin #if HAVE_LOCALE_H && HAVE_LOCALECONV
10106bfebdeSXin LI argn->L = localeconv();
10206bfebdeSXin LI #else
10306bfebdeSXin LI argn->L = NULL;
10406bfebdeSXin LI #endif
10506bfebdeSXin LI }
10606bfebdeSXin LI }
10706bfebdeSXin LI return (void *)argn;
10806bfebdeSXin LI }
10906bfebdeSXin LI
1100e3d5408SPeter Wemm /*---------------------------------------------------------------------------
1110e3d5408SPeter Wemm | Facility : libnform
1124a1a9510SRong-En Fan | Function : static void *Make_This_Type(va_list * ap)
1130e3d5408SPeter Wemm |
1140e3d5408SPeter Wemm | Description : Allocate structure for numeric type argument.
1150e3d5408SPeter Wemm |
1160e3d5408SPeter Wemm | Return Values : Pointer to argument structure or NULL on error
1170e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1184a1a9510SRong-En Fan static void *
Make_This_Type(va_list * ap)1194a1a9510SRong-En Fan Make_This_Type(va_list *ap)
1200e3d5408SPeter Wemm {
12106bfebdeSXin LI thisPARM arg;
1220e3d5408SPeter Wemm
12306bfebdeSXin LI arg.precision = va_arg(*ap, int);
12406bfebdeSXin LI arg.low = va_arg(*ap, double);
12506bfebdeSXin LI arg.high = va_arg(*ap, double);
1264a1a9510SRong-En Fan
12706bfebdeSXin LI return Generic_This_Type((void *)&arg);
1280e3d5408SPeter Wemm }
1290e3d5408SPeter Wemm
1300e3d5408SPeter Wemm /*---------------------------------------------------------------------------
1310e3d5408SPeter Wemm | Facility : libnform
1324a1a9510SRong-En Fan | Function : static void *Copy_This_Type(const void * argp)
1330e3d5408SPeter Wemm |
1340e3d5408SPeter Wemm | Description : Copy structure for numeric type argument.
1350e3d5408SPeter Wemm |
1360e3d5408SPeter Wemm | Return Values : Pointer to argument structure or NULL on error.
1370e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1384a1a9510SRong-En Fan static void *
Copy_This_Type(const void * argp)1394a1a9510SRong-En Fan Copy_This_Type(const void *argp)
1400e3d5408SPeter Wemm {
1414a1a9510SRong-En Fan const thisARG *ap = (const thisARG *)argp;
1424a1a9510SRong-En Fan thisARG *result = (thisARG *)0;
1430e3d5408SPeter Wemm
1440e3d5408SPeter Wemm if (argp)
1450e3d5408SPeter Wemm {
1465ca44d1cSRong-En Fan result = typeMalloc(thisARG, 1);
1477a656419SBaptiste Daroussin
1480e3d5408SPeter Wemm if (result)
1495ca44d1cSRong-En Fan {
15006bfebdeSXin LI T((T_CREATE("thisARG %p"), (void *)result));
1510e3d5408SPeter Wemm *result = *ap;
1520e3d5408SPeter Wemm }
1535ca44d1cSRong-En Fan }
1540e3d5408SPeter Wemm return (void *)result;
1550e3d5408SPeter Wemm }
1560e3d5408SPeter Wemm
1570e3d5408SPeter Wemm /*---------------------------------------------------------------------------
1580e3d5408SPeter Wemm | Facility : libnform
1594a1a9510SRong-En Fan | Function : static void Free_This_Type(void * argp)
1600e3d5408SPeter Wemm |
1610e3d5408SPeter Wemm | Description : Free structure for numeric type argument.
1620e3d5408SPeter Wemm |
1630e3d5408SPeter Wemm | Return Values : -
1640e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1654a1a9510SRong-En Fan static void
Free_This_Type(void * argp)1664a1a9510SRong-En Fan Free_This_Type(void *argp)
1670e3d5408SPeter Wemm {
1680e3d5408SPeter Wemm if (argp)
1690e3d5408SPeter Wemm free(argp);
1700e3d5408SPeter Wemm }
1710e3d5408SPeter Wemm
1720e3d5408SPeter Wemm /*---------------------------------------------------------------------------
1730e3d5408SPeter Wemm | Facility : libnform
1744a1a9510SRong-En Fan | Function : static bool Check_This_Field(FIELD * field,
1750e3d5408SPeter Wemm | const void * argp)
1760e3d5408SPeter Wemm |
1770e3d5408SPeter Wemm | Description : Validate buffer content to be a valid numeric value
1780e3d5408SPeter Wemm |
1790e3d5408SPeter Wemm | Return Values : TRUE - field is valid
1800e3d5408SPeter Wemm | FALSE - field is invalid
1810e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
1824a1a9510SRong-En Fan static bool
Check_This_Field(FIELD * field,const void * argp)1834a1a9510SRong-En Fan Check_This_Field(FIELD *field, const void *argp)
1840e3d5408SPeter Wemm {
1854a1a9510SRong-En Fan const thisARG *argn = (const thisARG *)argp;
1860e3d5408SPeter Wemm double low = argn->low;
1870e3d5408SPeter Wemm double high = argn->high;
1880e3d5408SPeter Wemm int prec = argn->precision;
1890e3d5408SPeter Wemm unsigned char *bp = (unsigned char *)field_buffer(field, 0);
1900e3d5408SPeter Wemm char *s = (char *)bp;
1910e3d5408SPeter Wemm struct lconv *L = argn->L;
1924a1a9510SRong-En Fan bool result = FALSE;
1930e3d5408SPeter Wemm
194*21817992SBaptiste Daroussin while (*bp == ' ')
1954a1a9510SRong-En Fan bp++;
1960e3d5408SPeter Wemm if (*bp)
1970e3d5408SPeter Wemm {
1980e3d5408SPeter Wemm if (*bp == '-' || *bp == '+')
1990e3d5408SPeter Wemm bp++;
2004a1a9510SRong-En Fan #if USE_WIDEC_SUPPORT
2014a1a9510SRong-En Fan if (*bp)
2024a1a9510SRong-En Fan {
2034a1a9510SRong-En Fan int len;
2044a1a9510SRong-En Fan wchar_t *list = _nc_Widen_String((char *)bp, &len);
2054a1a9510SRong-En Fan
2064a1a9510SRong-En Fan if (list != 0)
2074a1a9510SRong-En Fan {
208*21817992SBaptiste Daroussin bool blank = FALSE;
209*21817992SBaptiste Daroussin int state = 0;
210*21817992SBaptiste Daroussin int n;
211*21817992SBaptiste Daroussin
2124a1a9510SRong-En Fan result = TRUE;
2134a1a9510SRong-En Fan for (n = 0; n < len; ++n)
2144a1a9510SRong-En Fan {
2154a1a9510SRong-En Fan if (blank)
2164a1a9510SRong-En Fan {
2174a1a9510SRong-En Fan if (list[n] != ' ')
2184a1a9510SRong-En Fan {
2194a1a9510SRong-En Fan result = FALSE;
2204a1a9510SRong-En Fan break;
2214a1a9510SRong-En Fan }
2224a1a9510SRong-En Fan }
2234a1a9510SRong-En Fan else if (list[n] == ' ')
2244a1a9510SRong-En Fan {
2254a1a9510SRong-En Fan blank = TRUE;
2264a1a9510SRong-En Fan }
2274a1a9510SRong-En Fan else if (isDecimalPoint(list[n]))
2284a1a9510SRong-En Fan {
2294a1a9510SRong-En Fan if (++state > 1)
2304a1a9510SRong-En Fan {
2314a1a9510SRong-En Fan result = FALSE;
2324a1a9510SRong-En Fan break;
2334a1a9510SRong-En Fan }
2344a1a9510SRong-En Fan }
2354a1a9510SRong-En Fan else if (!isDigit(list[n]))
2364a1a9510SRong-En Fan {
2374a1a9510SRong-En Fan result = FALSE;
2384a1a9510SRong-En Fan break;
2394a1a9510SRong-En Fan }
2404a1a9510SRong-En Fan }
2414a1a9510SRong-En Fan free(list);
2424a1a9510SRong-En Fan }
2434a1a9510SRong-En Fan }
2444a1a9510SRong-En Fan #else
2450e3d5408SPeter Wemm while (*bp)
2460e3d5408SPeter Wemm {
2474a1a9510SRong-En Fan if (!isdigit(UChar(*bp)))
2484a1a9510SRong-En Fan break;
2490e3d5408SPeter Wemm bp++;
2500e3d5408SPeter Wemm }
2514a1a9510SRong-En Fan if (isDecimalPoint(*bp))
2524a1a9510SRong-En Fan {
2534a1a9510SRong-En Fan bp++;
2544a1a9510SRong-En Fan while (*bp)
2554a1a9510SRong-En Fan {
2564a1a9510SRong-En Fan if (!isdigit(UChar(*bp)))
2574a1a9510SRong-En Fan break;
2584a1a9510SRong-En Fan bp++;
2594a1a9510SRong-En Fan }
2604a1a9510SRong-En Fan }
2614a1a9510SRong-En Fan while (*bp && *bp == ' ')
2624a1a9510SRong-En Fan bp++;
2634a1a9510SRong-En Fan result = (*bp == '\0');
2640e3d5408SPeter Wemm #endif
2654a1a9510SRong-En Fan if (result)
2660e3d5408SPeter Wemm {
267*21817992SBaptiste Daroussin double val = atof(s);
268*21817992SBaptiste Daroussin
2690e3d5408SPeter Wemm if (low < high)
2700e3d5408SPeter Wemm {
2714a1a9510SRong-En Fan if (val < low || val > high)
2724a1a9510SRong-En Fan result = FALSE;
2730e3d5408SPeter Wemm }
2744a1a9510SRong-En Fan if (result)
2754a1a9510SRong-En Fan {
276*21817992SBaptiste Daroussin char buf[64];
277*21817992SBaptiste Daroussin
27873f0a83dSXin LI _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf))
27973f0a83dSXin LI "%.*f", (prec > 0 ? prec : 0), val);
2800e3d5408SPeter Wemm set_field_buffer(field, 0, buf);
2810e3d5408SPeter Wemm }
2820e3d5408SPeter Wemm }
2834a1a9510SRong-En Fan }
2844a1a9510SRong-En Fan return (result);
2850e3d5408SPeter Wemm }
2860e3d5408SPeter Wemm
2870e3d5408SPeter Wemm /*---------------------------------------------------------------------------
2880e3d5408SPeter Wemm | Facility : libnform
2894a1a9510SRong-En Fan | Function : static bool Check_This_Character(
2900e3d5408SPeter Wemm | int c,
2910e3d5408SPeter Wemm | const void * argp)
2920e3d5408SPeter Wemm |
2930e3d5408SPeter Wemm | Description : Check a character for the numeric type.
2940e3d5408SPeter Wemm |
2950e3d5408SPeter Wemm | Return Values : TRUE - character is valid
2960e3d5408SPeter Wemm | FALSE - character is invalid
2970e3d5408SPeter Wemm +--------------------------------------------------------------------------*/
2984a1a9510SRong-En Fan static bool
Check_This_Character(int c,const void * argp)2994a1a9510SRong-En Fan Check_This_Character(int c, const void *argp)
3000e3d5408SPeter Wemm {
3014a1a9510SRong-En Fan const thisARG *argn = (const thisARG *)argp;
3020e3d5408SPeter Wemm struct lconv *L = argn->L;
3030e3d5408SPeter Wemm
3044a1a9510SRong-En Fan return ((isDigit(c) ||
3050e3d5408SPeter Wemm c == '+' ||
3060e3d5408SPeter Wemm c == '-' ||
3074a1a9510SRong-En Fan isDecimalPoint(c))
3084a1a9510SRong-En Fan ? TRUE
3094a1a9510SRong-En Fan : FALSE);
3100e3d5408SPeter Wemm }
3110e3d5408SPeter Wemm
3124a1a9510SRong-En Fan static FIELDTYPE typeTHIS =
3134a1a9510SRong-En Fan {
3140e3d5408SPeter Wemm _HAS_ARGS | _RESIDENT,
3150e3d5408SPeter Wemm 1, /* this is mutable, so we can't be const */
3160e3d5408SPeter Wemm (FIELDTYPE *)0,
3170e3d5408SPeter Wemm (FIELDTYPE *)0,
3184a1a9510SRong-En Fan Make_This_Type,
3194a1a9510SRong-En Fan Copy_This_Type,
3204a1a9510SRong-En Fan Free_This_Type,
32106bfebdeSXin LI INIT_FT_FUNC(Check_This_Field),
32206bfebdeSXin LI INIT_FT_FUNC(Check_This_Character),
32306bfebdeSXin LI INIT_FT_FUNC(NULL),
32406bfebdeSXin LI INIT_FT_FUNC(NULL),
32506bfebdeSXin LI #if NCURSES_INTEROP_FUNCS
32606bfebdeSXin LI Generic_This_Type
32706bfebdeSXin LI #endif
3280e3d5408SPeter Wemm };
3290e3d5408SPeter Wemm
3307a656419SBaptiste Daroussin FORM_EXPORT_VAR(FIELDTYPE *) TYPE_NUMERIC = &typeTHIS;
3310e3d5408SPeter Wemm
33206bfebdeSXin LI #if NCURSES_INTEROP_FUNCS
33306bfebdeSXin LI /* The next routines are to simplify the use of ncurses from
3347a656419SBaptiste Daroussin programming languages with restrictions on interop with C level
33506bfebdeSXin LI constructs (e.g. variable access or va_list + ellipsis constructs)
33606bfebdeSXin LI */
3377a656419SBaptiste Daroussin FORM_EXPORT(FIELDTYPE *)
_nc_TYPE_NUMERIC(void)33806bfebdeSXin LI _nc_TYPE_NUMERIC(void)
33906bfebdeSXin LI {
34006bfebdeSXin LI return TYPE_NUMERIC;
34106bfebdeSXin LI }
34206bfebdeSXin LI #endif
34306bfebdeSXin LI
3440e3d5408SPeter Wemm /* fty_num.c ends here */
345