xref: /openbsd-src/lib/libform/fty_num.c (revision a4afd6dad3fba28f80e70208181c06c482259988)
1 
2 /*
3  * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
4  * You may freely copy it for use as a template for your own field types.
5  * If you develop a field type that might be of general use, please send
6  * it back to the ncurses maintainers for inclusion in the next version.
7  */
8 
9 #include "form.priv.h"
10 #include <locale.h>
11 
12 typedef struct {
13   int    precision;
14   double low;
15   double high;
16   struct lconv* L;
17 } numericARG;
18 
19 /*---------------------------------------------------------------------------
20 |   Facility      :  libnform
21 |   Function      :  static void *Make_Numeric_Type(va_list * ap)
22 |
23 |   Description   :  Allocate structure for numeric type argument.
24 |
25 |   Return Values :  Pointer to argument structure or NULL on error
26 +--------------------------------------------------------------------------*/
27 static void *Make_Numeric_Type(va_list * ap)
28 {
29   numericARG *argn = (numericARG *)malloc(sizeof(numericARG));
30 
31   if (argn)
32     {
33       argn->precision = va_arg(*ap,int);
34       argn->low       = va_arg(*ap,double);
35       argn->high      = va_arg(*ap,double);
36       argn->L         = localeconv();
37     }
38   return (void *)argn;
39 }
40 
41 /*---------------------------------------------------------------------------
42 |   Facility      :  libnform
43 |   Function      :  static void *Copy_Numeric_Type(const void * argp)
44 |
45 |   Description   :  Copy structure for numeric type argument.
46 |
47 |   Return Values :  Pointer to argument structure or NULL on error.
48 +--------------------------------------------------------------------------*/
49 static void *Copy_Numeric_Type(const void * argp)
50 {
51   numericARG *ap  = (numericARG *)argp;
52   numericARG *new = (numericARG *)0;
53 
54   if (argp)
55     {
56       new = (numericARG *)malloc(sizeof(numericARG));
57       if (new)
58 	*new  = *ap;
59     }
60   return (void *)new;
61 }
62 
63 /*---------------------------------------------------------------------------
64 |   Facility      :  libnform
65 |   Function      :  static void Free_Numeric_Type(void * argp)
66 |
67 |   Description   :  Free structure for numeric type argument.
68 |
69 |   Return Values :  -
70 +--------------------------------------------------------------------------*/
71 static void Free_Numeric_Type(void * argp)
72 {
73   if (argp)
74     free(argp);
75 }
76 
77 /*---------------------------------------------------------------------------
78 |   Facility      :  libnform
79 |   Function      :  static bool Check_Numeric_Field(FIELD * field,
80 |                                                    const void * argp)
81 |
82 |   Description   :  Validate buffer content to be a valid numeric value
83 |
84 |   Return Values :  TRUE  - field is valid
85 |                    FALSE - field is invalid
86 +--------------------------------------------------------------------------*/
87 static bool Check_Numeric_Field(FIELD * field, const void * argp)
88 {
89   numericARG *argn    = (numericARG *)argp;
90   double low          = argn->low;
91   double high         = argn->high;
92   int prec            = argn->precision;
93   unsigned char *bp   = (unsigned char *)field_buffer(field,0);
94   char *s             = (char *)bp;
95   double val          = 0.0;
96   struct lconv* L     = argn->L;
97   char buf[64];
98 
99   while(*bp && *bp==' ') bp++;
100   if (*bp)
101     {
102       if (*bp=='-' || *bp=='+')
103 	bp++;
104       while(*bp)
105 	{
106 	  if (!isdigit(*bp)) break;
107 	  bp++;
108 	}
109       if (*bp==((L && L->decimal_point) ? *(L->decimal_point) : '.'))
110 	{
111 	  bp++;
112 	  while(*bp)
113 	    {
114 	      if (!isdigit(*bp)) break;
115 	      bp++;
116 	    }
117 	}
118       while(*bp && *bp==' ') bp++;
119       if (*bp=='\0')
120 	{
121 	  val = atof(s);
122 	  if (low<high)
123 	    {
124 	      if (val<low || val>high) return FALSE;
125 	    }
126 	  sprintf(buf,"%.*f",prec,val);
127 	  set_field_buffer(field,0,buf);
128 	  return TRUE;
129 	}
130     }
131   return FALSE;
132 }
133 
134 /*---------------------------------------------------------------------------
135 |   Facility      :  libnform
136 |   Function      :  static bool Check_Numeric_Character(
137 |                                      int c,
138 |                                      const void * argp)
139 |
140 |   Description   :  Check a character for the numeric type.
141 |
142 |   Return Values :  TRUE  - character is valid
143 |                    FALSE - character is invalid
144 +--------------------------------------------------------------------------*/
145 static bool Check_Numeric_Character(int c, const void * argp)
146 {
147   numericARG *argn = (numericARG *)argp;
148   struct lconv* L  = argn->L;
149 
150   return (isdigit(c)  ||
151 	  c == '+'    ||
152 	  c == '-'    ||
153 	  c == ((L && L->decimal_point) ? *(L->decimal_point) : '.')
154 	 ) ? TRUE : FALSE;
155 }
156 
157 static FIELDTYPE typeNUMERIC = {
158   _HAS_ARGS | _RESIDENT,
159   1,                           /* this is mutable, so we can't be const */
160   (FIELDTYPE *)0,
161   (FIELDTYPE *)0,
162   Make_Numeric_Type,
163   Copy_Numeric_Type,
164   Free_Numeric_Type,
165   Check_Numeric_Field,
166   Check_Numeric_Character,
167   NULL,
168   NULL
169 };
170 
171 FIELDTYPE* TYPE_NUMERIC = &typeNUMERIC;
172 
173 /* fty_num.c ends here */
174