xref: /openbsd/lib/libform/fty_num.c (revision c7ef0cfc)
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