1/*
2 * THIS CODE IS SPECIFICALLY EXEMPTED FROM THE NCURSES PACKAGE COPYRIGHT.
3 * You may freely copy it for use as a template for your own field types.
4 * If you develop a field type that might be of general use, please send
5 * it back to the ncurses maintainers for inclusion in the next version.
6 */
7/***************************************************************************
8*                                                                          *
9*  Author : Juergen Pfeifer                                                *
10*                                                                          *
11***************************************************************************/
12
13#include "form.priv.h"
14
15MODULE_ID("$Id: fty_num.c,v 1.22 2005/08/20 18:26:16 tom Exp $")
16
17#if HAVE_LOCALE_H
18#include <locale.h>
19#endif
20
21#if HAVE_LOCALE_H
22#define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.'))
23#else
24#define isDecimalPoint(c) ((c) == '.')
25#endif
26
27#if USE_WIDEC_SUPPORT
28#define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c)))
29#else
30#define isDigit(c) isdigit(UChar(c))
31#endif
32
33#define thisARG numericARG
34
35typedef struct
36  {
37    int precision;
38    double low;
39    double high;
40    struct lconv *L;
41  }
42thisARG;
43
44/*---------------------------------------------------------------------------
45|   Facility      :  libnform
46|   Function      :  static void *Make_This_Type(va_list * ap)
47|
48|   Description   :  Allocate structure for numeric type argument.
49|
50|   Return Values :  Pointer to argument structure or NULL on error
51+--------------------------------------------------------------------------*/
52static void *
53Make_This_Type(va_list *ap)
54{
55  thisARG *argn = (thisARG *) malloc(sizeof(thisARG));
56
57  if (argn)
58    {
59      argn->precision = va_arg(*ap, int);
60      argn->low = va_arg(*ap, double);
61      argn->high = va_arg(*ap, double);
62
63#if HAVE_LOCALE_H
64      argn->L = localeconv();
65#else
66      argn->L = NULL;
67#endif
68    }
69  return (void *)argn;
70}
71
72/*---------------------------------------------------------------------------
73|   Facility      :  libnform
74|   Function      :  static void *Copy_This_Type(const void * argp)
75|
76|   Description   :  Copy structure for numeric type argument.
77|
78|   Return Values :  Pointer to argument structure or NULL on error.
79+--------------------------------------------------------------------------*/
80static void *
81Copy_This_Type(const void *argp)
82{
83  const thisARG *ap = (const thisARG *)argp;
84  thisARG *result = (thisARG *) 0;
85
86  if (argp)
87    {
88      result = (thisARG *) malloc(sizeof(thisARG));
89      if (result)
90	*result = *ap;
91    }
92  return (void *)result;
93}
94
95/*---------------------------------------------------------------------------
96|   Facility      :  libnform
97|   Function      :  static void Free_This_Type(void * argp)
98|
99|   Description   :  Free structure for numeric type argument.
100|
101|   Return Values :  -
102+--------------------------------------------------------------------------*/
103static void
104Free_This_Type(void *argp)
105{
106  if (argp)
107    free(argp);
108}
109
110/*---------------------------------------------------------------------------
111|   Facility      :  libnform
112|   Function      :  static bool Check_This_Field(FIELD * field,
113|                                                 const void * argp)
114|
115|   Description   :  Validate buffer content to be a valid numeric value
116|
117|   Return Values :  TRUE  - field is valid
118|                    FALSE - field is invalid
119+--------------------------------------------------------------------------*/
120static bool
121Check_This_Field(FIELD *field, const void *argp)
122{
123  const thisARG *argn = (const thisARG *)argp;
124  double low = argn->low;
125  double high = argn->high;
126  int prec = argn->precision;
127  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
128  char *s = (char *)bp;
129  double val = 0.0;
130  struct lconv *L = argn->L;
131  char buf[64];
132  bool result = FALSE;
133
134  while (*bp && *bp == ' ')
135    bp++;
136  if (*bp)
137    {
138      if (*bp == '-' || *bp == '+')
139	bp++;
140#if USE_WIDEC_SUPPORT
141      if (*bp)
142	{
143	  bool blank = FALSE;
144	  int state = 0;
145	  int len;
146	  int n;
147	  wchar_t *list = _nc_Widen_String((char *)bp, &len);
148
149	  if (list != 0)
150	    {
151	      result = TRUE;
152	      for (n = 0; n < len; ++n)
153		{
154		  if (blank)
155		    {
156		      if (list[n] != ' ')
157			{
158			  result = FALSE;
159			  break;
160			}
161		    }
162		  else if (list[n] == ' ')
163		    {
164		      blank = TRUE;
165		    }
166		  else if (isDecimalPoint(list[n]))
167		    {
168		      if (++state > 1)
169			{
170			  result = FALSE;
171			  break;
172			}
173		    }
174		  else if (!isDigit(list[n]))
175		    {
176		      result = FALSE;
177		      break;
178		    }
179		}
180	      free(list);
181	    }
182	}
183#else
184      while (*bp)
185	{
186	  if (!isdigit(UChar(*bp)))
187	    break;
188	  bp++;
189	}
190      if (isDecimalPoint(*bp))
191	{
192	  bp++;
193	  while (*bp)
194	    {
195	      if (!isdigit(UChar(*bp)))
196		break;
197	      bp++;
198	    }
199	}
200      while (*bp && *bp == ' ')
201	bp++;
202      result = (*bp == '\0');
203#endif
204      if (result)
205	{
206	  val = atof(s);
207	  if (low < high)
208	    {
209	      if (val < low || val > high)
210		result = FALSE;
211	    }
212	  if (result)
213	    {
214	      sprintf(buf, "%.*f", (prec > 0 ? prec : 0), val);
215	      set_field_buffer(field, 0, buf);
216	    }
217	}
218    }
219  return (result);
220}
221
222/*---------------------------------------------------------------------------
223|   Facility      :  libnform
224|   Function      :  static bool Check_This_Character(
225|                                      int c,
226|                                      const void * argp)
227|
228|   Description   :  Check a character for the numeric type.
229|
230|   Return Values :  TRUE  - character is valid
231|                    FALSE - character is invalid
232+--------------------------------------------------------------------------*/
233static bool
234Check_This_Character(int c, const void *argp)
235{
236  const thisARG *argn = (const thisARG *)argp;
237  struct lconv *L = argn->L;
238
239  return ((isDigit(c) ||
240	   c == '+' ||
241	   c == '-' ||
242	   isDecimalPoint(c))
243	  ? TRUE
244	  : FALSE);
245}
246
247static FIELDTYPE typeTHIS =
248{
249  _HAS_ARGS | _RESIDENT,
250  1,				/* this is mutable, so we can't be const */
251  (FIELDTYPE *)0,
252  (FIELDTYPE *)0,
253  Make_This_Type,
254  Copy_This_Type,
255  Free_This_Type,
256  Check_This_Field,
257  Check_This_Character,
258  NULL,
259  NULL
260};
261
262NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_NUMERIC = &typeTHIS;
263
264/* fty_num.c ends here */
265