fty_num.c revision 262685
1/****************************************************************************
2 * Copyright (c) 1998-2010,2012 Free Software Foundation, Inc.              *
3 *                                                                          *
4 * Permission is hereby granted, free of charge, to any person obtaining a  *
5 * copy of this software and associated documentation files (the            *
6 * "Software"), to deal in the Software without restriction, including      *
7 * without limitation the rights to use, copy, modify, merge, publish,      *
8 * distribute, distribute with modifications, sublicense, and/or sell       *
9 * copies of the Software, and to permit persons to whom the Software is    *
10 * furnished to do so, subject to the following conditions:                 *
11 *                                                                          *
12 * The above copyright notice and this permission notice shall be included  *
13 * in all copies or substantial portions of the Software.                   *
14 *                                                                          *
15 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS  *
16 * OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF               *
17 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT.   *
18 * IN NO EVENT SHALL THE ABOVE COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM,   *
19 * DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR    *
20 * OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION WITH THE SOFTWARE OR    *
21 * THE USE OR OTHER DEALINGS IN THE SOFTWARE.                               *
22 *                                                                          *
23 * Except as contained in this notice, the name(s) of the above copyright   *
24 * holders shall not be used in advertising or otherwise to promote the     *
25 * sale, use or other dealings in this Software without prior written       *
26 * authorization.                                                           *
27 ****************************************************************************/
28
29/***************************************************************************
30*                                                                          *
31*  Author : Juergen Pfeifer                                                *
32*                                                                          *
33***************************************************************************/
34
35#include "form.priv.h"
36
37MODULE_ID("$Id: fty_num.c,v 1.29 2012/02/23 10:02:15 tom Exp $")
38
39#if HAVE_LOCALE_H
40#include <locale.h>
41#endif
42
43#if HAVE_LOCALE_H
44#define isDecimalPoint(c) ((c) == ((L && L->decimal_point) ? *(L->decimal_point) : '.'))
45#else
46#define isDecimalPoint(c) ((c) == '.')
47#endif
48
49#if USE_WIDEC_SUPPORT
50#define isDigit(c) (iswdigit((wint_t)(c)) || isdigit(UChar(c)))
51#else
52#define isDigit(c) isdigit(UChar(c))
53#endif
54
55#define thisARG numericARG
56
57typedef struct
58  {
59    int precision;
60    double low;
61    double high;
62    struct lconv *L;
63  }
64thisARG;
65
66typedef struct
67  {
68    int precision;
69    double low;
70    double high;
71  }
72thisPARM;
73
74/*---------------------------------------------------------------------------
75|   Facility      :  libnform
76|   Function      :  static void *Generic_This_Type(void * arg)
77|
78|   Description   :  Allocate structure for numeric type argument.
79|
80|   Return Values :  Pointer to argument structure or NULL on error
81+--------------------------------------------------------------------------*/
82static void *
83Generic_This_Type(void *arg)
84{
85  thisARG *argn = (thisARG *) 0;
86  thisPARM *args = (thisPARM *) arg;
87
88  if (args)
89    {
90      argn = typeMalloc(thisARG, 1);
91
92      if (argn)
93	{
94	  T((T_CREATE("thisARG %p"), (void *)argn));
95	  argn->precision = args->precision;
96	  argn->low = args->low;
97	  argn->high = args->high;
98
99#if HAVE_LOCALE_H
100	  argn->L = localeconv();
101#else
102	  argn->L = NULL;
103#endif
104	}
105    }
106  return (void *)argn;
107}
108
109/*---------------------------------------------------------------------------
110|   Facility      :  libnform
111|   Function      :  static void *Make_This_Type(va_list * ap)
112|
113|   Description   :  Allocate structure for numeric type argument.
114|
115|   Return Values :  Pointer to argument structure or NULL on error
116+--------------------------------------------------------------------------*/
117static void *
118Make_This_Type(va_list *ap)
119{
120  thisPARM arg;
121
122  arg.precision = va_arg(*ap, int);
123  arg.low = va_arg(*ap, double);
124  arg.high = va_arg(*ap, double);
125
126  return Generic_This_Type((void *)&arg);
127}
128
129/*---------------------------------------------------------------------------
130|   Facility      :  libnform
131|   Function      :  static void *Copy_This_Type(const void * argp)
132|
133|   Description   :  Copy structure for numeric type argument.
134|
135|   Return Values :  Pointer to argument structure or NULL on error.
136+--------------------------------------------------------------------------*/
137static void *
138Copy_This_Type(const void *argp)
139{
140  const thisARG *ap = (const thisARG *)argp;
141  thisARG *result = (thisARG *) 0;
142
143  if (argp)
144    {
145      result = typeMalloc(thisARG, 1);
146      if (result)
147	{
148	  T((T_CREATE("thisARG %p"), (void *)result));
149	  *result = *ap;
150	}
151    }
152  return (void *)result;
153}
154
155/*---------------------------------------------------------------------------
156|   Facility      :  libnform
157|   Function      :  static void Free_This_Type(void * argp)
158|
159|   Description   :  Free structure for numeric type argument.
160|
161|   Return Values :  -
162+--------------------------------------------------------------------------*/
163static void
164Free_This_Type(void *argp)
165{
166  if (argp)
167    free(argp);
168}
169
170/*---------------------------------------------------------------------------
171|   Facility      :  libnform
172|   Function      :  static bool Check_This_Field(FIELD * field,
173|                                                 const void * argp)
174|
175|   Description   :  Validate buffer content to be a valid numeric value
176|
177|   Return Values :  TRUE  - field is valid
178|                    FALSE - field is invalid
179+--------------------------------------------------------------------------*/
180static bool
181Check_This_Field(FIELD *field, const void *argp)
182{
183  const thisARG *argn = (const thisARG *)argp;
184  double low = argn->low;
185  double high = argn->high;
186  int prec = argn->precision;
187  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
188  char *s = (char *)bp;
189  double val = 0.0;
190  struct lconv *L = argn->L;
191  char buf[64];
192  bool result = FALSE;
193
194  while (*bp && *bp == ' ')
195    bp++;
196  if (*bp)
197    {
198      if (*bp == '-' || *bp == '+')
199	bp++;
200#if USE_WIDEC_SUPPORT
201      if (*bp)
202	{
203	  bool blank = FALSE;
204	  int state = 0;
205	  int len;
206	  int n;
207	  wchar_t *list = _nc_Widen_String((char *)bp, &len);
208
209	  if (list != 0)
210	    {
211	      result = TRUE;
212	      for (n = 0; n < len; ++n)
213		{
214		  if (blank)
215		    {
216		      if (list[n] != ' ')
217			{
218			  result = FALSE;
219			  break;
220			}
221		    }
222		  else if (list[n] == ' ')
223		    {
224		      blank = TRUE;
225		    }
226		  else if (isDecimalPoint(list[n]))
227		    {
228		      if (++state > 1)
229			{
230			  result = FALSE;
231			  break;
232			}
233		    }
234		  else if (!isDigit(list[n]))
235		    {
236		      result = FALSE;
237		      break;
238		    }
239		}
240	      free(list);
241	    }
242	}
243#else
244      while (*bp)
245	{
246	  if (!isdigit(UChar(*bp)))
247	    break;
248	  bp++;
249	}
250      if (isDecimalPoint(*bp))
251	{
252	  bp++;
253	  while (*bp)
254	    {
255	      if (!isdigit(UChar(*bp)))
256		break;
257	      bp++;
258	    }
259	}
260      while (*bp && *bp == ' ')
261	bp++;
262      result = (*bp == '\0');
263#endif
264      if (result)
265	{
266	  val = atof(s);
267	  if (low < high)
268	    {
269	      if (val < low || val > high)
270		result = FALSE;
271	    }
272	  if (result)
273	    {
274	      _nc_SPRINTF(buf, _nc_SLIMIT(sizeof(buf))
275			  "%.*f", (prec > 0 ? prec : 0), val);
276	      set_field_buffer(field, 0, buf);
277	    }
278	}
279    }
280  return (result);
281}
282
283/*---------------------------------------------------------------------------
284|   Facility      :  libnform
285|   Function      :  static bool Check_This_Character(
286|                                      int c,
287|                                      const void * argp)
288|
289|   Description   :  Check a character for the numeric type.
290|
291|   Return Values :  TRUE  - character is valid
292|                    FALSE - character is invalid
293+--------------------------------------------------------------------------*/
294static bool
295Check_This_Character(int c, const void *argp)
296{
297  const thisARG *argn = (const thisARG *)argp;
298  struct lconv *L = argn->L;
299
300  return ((isDigit(c) ||
301	   c == '+' ||
302	   c == '-' ||
303	   isDecimalPoint(c))
304	  ? TRUE
305	  : FALSE);
306}
307
308static FIELDTYPE typeTHIS =
309{
310  _HAS_ARGS | _RESIDENT,
311  1,				/* this is mutable, so we can't be const */
312  (FIELDTYPE *)0,
313  (FIELDTYPE *)0,
314  Make_This_Type,
315  Copy_This_Type,
316  Free_This_Type,
317  INIT_FT_FUNC(Check_This_Field),
318  INIT_FT_FUNC(Check_This_Character),
319  INIT_FT_FUNC(NULL),
320  INIT_FT_FUNC(NULL),
321#if NCURSES_INTEROP_FUNCS
322  Generic_This_Type
323#endif
324};
325
326NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_NUMERIC = &typeTHIS;
327
328#if NCURSES_INTEROP_FUNCS
329/* The next routines are to simplify the use of ncurses from
330   programming languages with restictions on interop with C level
331   constructs (e.g. variable access or va_list + ellipsis constructs)
332*/
333NCURSES_EXPORT(FIELDTYPE *)
334_nc_TYPE_NUMERIC(void)
335{
336  return TYPE_NUMERIC;
337}
338#endif
339
340/* fty_num.c ends here */
341