1*c7ef0cfcSnicm /* $OpenBSD: fty_num.c,v 1.10 2023/10/17 09:52:10 nicm Exp $ */
281d8c4e1Snicm /****************************************************************************
3*c7ef0cfcSnicm * Copyright 2019-2020,2021 Thomas E. Dickey *
4*c7ef0cfcSnicm * Copyright 1998-2010,2012 Free Software Foundation, Inc. *
581d8c4e1Snicm * *
681d8c4e1Snicm * Permission is hereby granted, free of charge, to any person obtaining a *
781d8c4e1Snicm * copy of this software and associated documentation files (the *
881d8c4e1Snicm * "Software"), to deal in the Software without restriction, including *
981d8c4e1Snicm * without limitation the rights to use, copy, modify, merge, publish, *
1081d8c4e1Snicm * distribute, distribute with modifications, sublicense, and/or sell *
1181d8c4e1Snicm * copies of the Software, and to permit persons to whom the Software is *
1281d8c4e1Snicm * furnished to do so, subject to the following conditions: *
1381d8c4e1Snicm * *
1481d8c4e1Snicm * The above copyright notice and this permission notice shall be included *
1581d8c4e1Snicm * in all copies or substantial portions of the Software. *
1681d8c4e1Snicm * *
1781d8c4e1Snicm * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS *
1881d8c4e1Snicm * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF *
1981d8c4e1Snicm * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. *
2081d8c4e1Snicm * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, *
2181d8c4e1Snicm * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR *
2281d8c4e1Snicm * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR *
2381d8c4e1Snicm * THE USE OR OTHER DEALINGS IN THE SOFTWARE. *
2481d8c4e1Snicm * *
2581d8c4e1Snicm * Except as contained in this notice, the name(s) of the above copyright *
2681d8c4e1Snicm * holders shall not be used in advertising or otherwise to promote the *
2781d8c4e1Snicm * sale, use or other dealings in this Software without prior written *
2881d8c4e1Snicm * authorization. *
2981d8c4e1Snicm ****************************************************************************/
308d0fca71Smillert
316cd90de4Smillert /***************************************************************************
326cd90de4Smillert * *
3381d8c4e1Snicm * Author : Juergen Pfeifer *
346cd90de4Smillert * *
356cd90de4Smillert ***************************************************************************/
36ae611fdaStholo
37ae611fdaStholo #include "form.priv.h"
386cd90de4Smillert
39*c7ef0cfcSnicm MODULE_ID("$Id: fty_num.c,v 1.10 2023/10/17 09:52:10 nicm Exp $")
406cd90de4Smillert
416cd90de4Smillert #if HAVE_LOCALE_H
42ae611fdaStholo #include <locale.h>
436cd90de4Smillert #endif
44ae611fdaStholo
45*c7ef0cfcSnicm #if HAVE_LOCALE_H && HAVE_LOCALECONV
4681d8c4e1Snicm #define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.'))
4781d8c4e1Snicm #else
4881d8c4e1Snicm #define isDecimalPoint(c) ((c) == '.')
4981d8c4e1Snicm #endif
5081d8c4e1Snicm
5181d8c4e1Snicm #if USE_WIDEC_SUPPORT
5281d8c4e1Snicm #define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c)))
5381d8c4e1Snicm #else
5481d8c4e1Snicm #define isDigit(c) isdigit(UChar(c))
5581d8c4e1Snicm #endif
5681d8c4e1Snicm
5781d8c4e1Snicm #define thisARG numericARG
5881d8c4e1Snicm
5981d8c4e1Snicm typedef struct
6081d8c4e1Snicm {
61ae611fdaStholo int precision;
62ae611fdaStholo double low;
63ae611fdaStholo double high;
64ae611fdaStholo struct lconv *L;
6581d8c4e1Snicm }
6681d8c4e1Snicm thisARG;
67ae611fdaStholo
68*c7ef0cfcSnicm typedef struct
69*c7ef0cfcSnicm {
70*c7ef0cfcSnicm int precision;
71*c7ef0cfcSnicm double low;
72*c7ef0cfcSnicm double high;
73*c7ef0cfcSnicm }
74*c7ef0cfcSnicm thisPARM;
75*c7ef0cfcSnicm
76*c7ef0cfcSnicm /*---------------------------------------------------------------------------
77*c7ef0cfcSnicm | Facility : libnform
78*c7ef0cfcSnicm | Function : static void *Generic_This_Type(void * arg)
79*c7ef0cfcSnicm |
80*c7ef0cfcSnicm | Description : Allocate structure for numeric type argument.
81*c7ef0cfcSnicm |
82*c7ef0cfcSnicm | Return Values : Pointer to argument structure or NULL on error
83*c7ef0cfcSnicm +--------------------------------------------------------------------------*/
84*c7ef0cfcSnicm static void *
Generic_This_Type(void * arg)85*c7ef0cfcSnicm Generic_This_Type(void *arg)
86*c7ef0cfcSnicm {
87*c7ef0cfcSnicm thisARG *argn = (thisARG *)0;
88*c7ef0cfcSnicm thisPARM *args = (thisPARM *)arg;
89*c7ef0cfcSnicm
90*c7ef0cfcSnicm if (args)
91*c7ef0cfcSnicm {
92*c7ef0cfcSnicm argn = typeMalloc(thisARG, 1);
93*c7ef0cfcSnicm
94*c7ef0cfcSnicm if (argn)
95*c7ef0cfcSnicm {
96*c7ef0cfcSnicm T((T_CREATE("thisARG %p"), (void *)argn));
97*c7ef0cfcSnicm argn->precision = args->precision;
98*c7ef0cfcSnicm argn->low = args->low;
99*c7ef0cfcSnicm argn->high = args->high;
100*c7ef0cfcSnicm
101*c7ef0cfcSnicm #if HAVE_LOCALE_H && HAVE_LOCALECONV
102*c7ef0cfcSnicm argn->L = localeconv();
103*c7ef0cfcSnicm #else
104*c7ef0cfcSnicm argn->L = NULL;
105*c7ef0cfcSnicm #endif
106*c7ef0cfcSnicm }
107*c7ef0cfcSnicm }
108*c7ef0cfcSnicm return (void *)argn;
109*c7ef0cfcSnicm }
110*c7ef0cfcSnicm
111ae611fdaStholo /*---------------------------------------------------------------------------
112ae611fdaStholo | Facility : libnform
11381d8c4e1Snicm | Function : static void *Make_This_Type(va_list * ap)
114ae611fdaStholo |
115ae611fdaStholo | Description : Allocate structure for numeric type argument.
116ae611fdaStholo |
117ae611fdaStholo | Return Values : Pointer to argument structure or NULL on error
118ae611fdaStholo +--------------------------------------------------------------------------*/
11981d8c4e1Snicm static void *
Make_This_Type(va_list * ap)12081d8c4e1Snicm Make_This_Type(va_list *ap)
121ae611fdaStholo {
122*c7ef0cfcSnicm thisPARM arg;
123ae611fdaStholo
124*c7ef0cfcSnicm arg.precision = va_arg(*ap, int);
125*c7ef0cfcSnicm arg.low = va_arg(*ap, double);
126*c7ef0cfcSnicm arg.high = va_arg(*ap, double);
12781d8c4e1Snicm
128*c7ef0cfcSnicm return Generic_This_Type((void *)&arg);
129ae611fdaStholo }
130ae611fdaStholo
131ae611fdaStholo /*---------------------------------------------------------------------------
132ae611fdaStholo | Facility : libnform
13381d8c4e1Snicm | Function : static void *Copy_This_Type(const void * argp)
134ae611fdaStholo |
135ae611fdaStholo | Description : Copy structure for numeric type argument.
136ae611fdaStholo |
137ae611fdaStholo | Return Values : Pointer to argument structure or NULL on error.
138ae611fdaStholo +--------------------------------------------------------------------------*/
13981d8c4e1Snicm static void *
Copy_This_Type(const void * argp)14081d8c4e1Snicm Copy_This_Type(const void *argp)
141ae611fdaStholo {
14281d8c4e1Snicm const thisARG *ap = (const thisARG *)argp;
14381d8c4e1Snicm thisARG *result = (thisARG *)0;
144ae611fdaStholo
145ae611fdaStholo if (argp)
146ae611fdaStholo {
14781d8c4e1Snicm result = typeMalloc(thisARG, 1);
148*c7ef0cfcSnicm
1498d0fca71Smillert if (result)
15081d8c4e1Snicm {
151*c7ef0cfcSnicm T((T_CREATE("thisARG %p"), (void *)result));
1528d0fca71Smillert *result = *ap;
153ae611fdaStholo }
15481d8c4e1Snicm }
1558d0fca71Smillert return (void *)result;
156ae611fdaStholo }
157ae611fdaStholo
158ae611fdaStholo /*---------------------------------------------------------------------------
159ae611fdaStholo | Facility : libnform
16081d8c4e1Snicm | Function : static void Free_This_Type(void * argp)
161ae611fdaStholo |
162ae611fdaStholo | Description : Free structure for numeric type argument.
163ae611fdaStholo |
164ae611fdaStholo | Return Values : -
165ae611fdaStholo +--------------------------------------------------------------------------*/
16681d8c4e1Snicm static void
Free_This_Type(void * argp)16781d8c4e1Snicm Free_This_Type(void *argp)
168ae611fdaStholo {
169ae611fdaStholo if (argp)
170ae611fdaStholo free(argp);
171ae611fdaStholo }
172ae611fdaStholo
173ae611fdaStholo /*---------------------------------------------------------------------------
174ae611fdaStholo | Facility : libnform
17581d8c4e1Snicm | Function : static bool Check_This_Field(FIELD * field,
176ae611fdaStholo | const void * argp)
177ae611fdaStholo |
178ae611fdaStholo | Description : Validate buffer content to be a valid numeric value
179ae611fdaStholo |
180ae611fdaStholo | Return Values : TRUE - field is valid
181ae611fdaStholo | FALSE - field is invalid
182ae611fdaStholo +--------------------------------------------------------------------------*/
18381d8c4e1Snicm static bool
Check_This_Field(FIELD * field,const void * argp)18481d8c4e1Snicm Check_This_Field(FIELD *field, const void *argp)
185ae611fdaStholo {
18681d8c4e1Snicm const thisARG *argn = (const thisARG *)argp;
187ae611fdaStholo double low = argn->low;
188ae611fdaStholo double high = argn->high;
189ae611fdaStholo int prec = argn->precision;
190ae611fdaStholo unsigned char *bp = (unsigned char *)field_buffer(field, 0);
191ae611fdaStholo char *s = (char *)bp;
192ae611fdaStholo struct lconv *L = argn->L;
19381d8c4e1Snicm bool result = FALSE;
194ae611fdaStholo
195*c7ef0cfcSnicm while (*bp == ' ')
19681d8c4e1Snicm bp++;
197ae611fdaStholo if (*bp)
198ae611fdaStholo {
199ae611fdaStholo if (*bp == '-' || *bp == '+')
200ae611fdaStholo bp++;
20181d8c4e1Snicm #if USE_WIDEC_SUPPORT
20281d8c4e1Snicm if (*bp)
20381d8c4e1Snicm {
20481d8c4e1Snicm int len;
20581d8c4e1Snicm wchar_t *list = _nc_Widen_String((char *)bp, &len);
20681d8c4e1Snicm
20781d8c4e1Snicm if (list != 0)
20881d8c4e1Snicm {
209*c7ef0cfcSnicm bool blank = FALSE;
210*c7ef0cfcSnicm int state = 0;
211*c7ef0cfcSnicm int n;
212*c7ef0cfcSnicm
21381d8c4e1Snicm result = TRUE;
21481d8c4e1Snicm for (n = 0; n < len; ++n)
21581d8c4e1Snicm {
21681d8c4e1Snicm if (blank)
21781d8c4e1Snicm {
21881d8c4e1Snicm if (list[n] != ' ')
21981d8c4e1Snicm {
22081d8c4e1Snicm result = FALSE;
22181d8c4e1Snicm break;
22281d8c4e1Snicm }
22381d8c4e1Snicm }
22481d8c4e1Snicm else if (list[n] == ' ')
22581d8c4e1Snicm {
22681d8c4e1Snicm blank = TRUE;
22781d8c4e1Snicm }
22881d8c4e1Snicm else if (isDecimalPoint(list[n]))
22981d8c4e1Snicm {
23081d8c4e1Snicm if (++state > 1)
23181d8c4e1Snicm {
23281d8c4e1Snicm result = FALSE;
23381d8c4e1Snicm break;
23481d8c4e1Snicm }
23581d8c4e1Snicm }
23681d8c4e1Snicm else if (!isDigit(list[n]))
23781d8c4e1Snicm {
23881d8c4e1Snicm result = FALSE;
23981d8c4e1Snicm break;
24081d8c4e1Snicm }
24181d8c4e1Snicm }
24281d8c4e1Snicm free(list);
24381d8c4e1Snicm }
24481d8c4e1Snicm }
24581d8c4e1Snicm #else
246ae611fdaStholo while (*bp)
247ae611fdaStholo {
24881d8c4e1Snicm if (!isdigit(UChar(*bp)))
24981d8c4e1Snicm break;
250ae611fdaStholo bp++;
251ae611fdaStholo }
25281d8c4e1Snicm if (isDecimalPoint(*bp))
25381d8c4e1Snicm {
25481d8c4e1Snicm bp++;
25581d8c4e1Snicm while (*bp)
25681d8c4e1Snicm {
25781d8c4e1Snicm if (!isdigit(UChar(*bp)))
25881d8c4e1Snicm break;
25981d8c4e1Snicm bp++;
26081d8c4e1Snicm }
26181d8c4e1Snicm }
26281d8c4e1Snicm while (*bp && *bp == ' ')
26381d8c4e1Snicm bp++;
26481d8c4e1Snicm result = (*bp == '\0');
2656cd90de4Smillert #endif
26681d8c4e1Snicm if (result)
267ae611fdaStholo {
268*c7ef0cfcSnicm double val = atof(s);
269*c7ef0cfcSnicm
270ae611fdaStholo if (low < high)
271ae611fdaStholo {
27281d8c4e1Snicm if (val < low || val > high)
27381d8c4e1Snicm result = FALSE;
274ae611fdaStholo }
27581d8c4e1Snicm if (result)
27681d8c4e1Snicm {
277*c7ef0cfcSnicm char buf[64];
278*c7ef0cfcSnicm
279*c7ef0cfcSnicm _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf))
280*c7ef0cfcSnicm "%.*f", (prec > 0 ? prec : 0), val);
281ae611fdaStholo set_field_buffer(field, 0, buf);
282ae611fdaStholo }
283ae611fdaStholo }
28481d8c4e1Snicm }
28581d8c4e1Snicm return (result);
286ae611fdaStholo }
287ae611fdaStholo
288ae611fdaStholo /*---------------------------------------------------------------------------
289ae611fdaStholo | Facility : libnform
29081d8c4e1Snicm | Function : static bool Check_This_Character(
291ae611fdaStholo | int c,
292ae611fdaStholo | const void * argp)
293ae611fdaStholo |
294ae611fdaStholo | Description : Check a character for the numeric type.
295ae611fdaStholo |
296ae611fdaStholo | Return Values : TRUE - character is valid
297ae611fdaStholo | FALSE - character is invalid
298ae611fdaStholo +--------------------------------------------------------------------------*/
29981d8c4e1Snicm static bool
Check_This_Character(int c,const void * argp)30081d8c4e1Snicm Check_This_Character(int c, const void *argp)
301ae611fdaStholo {
30281d8c4e1Snicm const thisARG *argn = (const thisARG *)argp;
303ae611fdaStholo struct lconv *L = argn->L;
304ae611fdaStholo
30581d8c4e1Snicm return ((isDigit(c) ||
306ae611fdaStholo c == '+' ||
307ae611fdaStholo c == '-' ||
30881d8c4e1Snicm isDecimalPoint(c))
30981d8c4e1Snicm ? TRUE
31081d8c4e1Snicm : FALSE);
311ae611fdaStholo }
312ae611fdaStholo
31381d8c4e1Snicm static FIELDTYPE typeTHIS =
31481d8c4e1Snicm {
315ae611fdaStholo _HAS_ARGS | _RESIDENT,
316ae611fdaStholo 1, /* this is mutable, so we can't be const */
317ae611fdaStholo (FIELDTYPE *)0,
318ae611fdaStholo (FIELDTYPE *)0,
31981d8c4e1Snicm Make_This_Type,
32081d8c4e1Snicm Copy_This_Type,
32181d8c4e1Snicm Free_This_Type,
322*c7ef0cfcSnicm INIT_FT_FUNC(Check_This_Field),
323*c7ef0cfcSnicm INIT_FT_FUNC(Check_This_Character),
324*c7ef0cfcSnicm INIT_FT_FUNC(NULL),
325*c7ef0cfcSnicm INIT_FT_FUNC(NULL),
326*c7ef0cfcSnicm #if NCURSES_INTEROP_FUNCS
327*c7ef0cfcSnicm Generic_This_Type
328*c7ef0cfcSnicm #endif
329ae611fdaStholo };
330ae611fdaStholo
331*c7ef0cfcSnicm FORM_EXPORT_VAR(FIELDTYPE *) TYPE_NUMERIC = &typeTHIS;
332*c7ef0cfcSnicm
333*c7ef0cfcSnicm #if NCURSES_INTEROP_FUNCS
334*c7ef0cfcSnicm /* The next routines are to simplify the use of ncurses from
335*c7ef0cfcSnicm programming languages with restrictions on interop with C level
336*c7ef0cfcSnicm constructs (e.g. variable access or va_list + ellipsis constructs)
337*c7ef0cfcSnicm */
338*c7ef0cfcSnicm FORM_EXPORT(FIELDTYPE *)
_nc_TYPE_NUMERIC(void)339*c7ef0cfcSnicm _nc_TYPE_NUMERIC(void)
340*c7ef0cfcSnicm {
341*c7ef0cfcSnicm return TYPE_NUMERIC;
342*c7ef0cfcSnicm }
343*c7ef0cfcSnicm #endif
344ae611fdaStholo
345ae611fdaStholo /* fty_num.c ends here */
346