1/****************************************************************************
2 * Copyright (c) 1998-2006,2007 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.25 2007/10/13 19:32:54 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
66/*---------------------------------------------------------------------------
67|   Facility      :  libnform
68|   Function      :  static void *Make_This_Type(va_list * ap)
69|
70|   Description   :  Allocate structure for numeric type argument.
71|
72|   Return Values :  Pointer to argument structure or NULL on error
73+--------------------------------------------------------------------------*/
74static void *
75Make_This_Type(va_list *ap)
76{
77  thisARG *argn = typeMalloc(thisARG, 1);
78
79  if (argn)
80    {
81      T((T_CREATE("thisARG %p"), argn));
82      argn->precision = va_arg(*ap, int);
83      argn->low = va_arg(*ap, double);
84      argn->high = va_arg(*ap, double);
85
86#if HAVE_LOCALE_H
87      argn->L = localeconv();
88#else
89      argn->L = NULL;
90#endif
91    }
92  return (void *)argn;
93}
94
95/*---------------------------------------------------------------------------
96|   Facility      :  libnform
97|   Function      :  static void *Copy_This_Type(const void * argp)
98|
99|   Description   :  Copy structure for numeric type argument.
100|
101|   Return Values :  Pointer to argument structure or NULL on error.
102+--------------------------------------------------------------------------*/
103static void *
104Copy_This_Type(const void *argp)
105{
106  const thisARG *ap = (const thisARG *)argp;
107  thisARG *result = (thisARG *) 0;
108
109  if (argp)
110    {
111      result = typeMalloc(thisARG, 1);
112      if (result)
113	{
114	  T((T_CREATE("thisARG %p"), result));
115	  *result = *ap;
116	}
117    }
118  return (void *)result;
119}
120
121/*---------------------------------------------------------------------------
122|   Facility      :  libnform
123|   Function      :  static void Free_This_Type(void * argp)
124|
125|   Description   :  Free structure for numeric type argument.
126|
127|   Return Values :  -
128+--------------------------------------------------------------------------*/
129static void
130Free_This_Type(void *argp)
131{
132  if (argp)
133    free(argp);
134}
135
136/*---------------------------------------------------------------------------
137|   Facility      :  libnform
138|   Function      :  static bool Check_This_Field(FIELD * field,
139|                                                 const void * argp)
140|
141|   Description   :  Validate buffer content to be a valid numeric value
142|
143|   Return Values :  TRUE  - field is valid
144|                    FALSE - field is invalid
145+--------------------------------------------------------------------------*/
146static bool
147Check_This_Field(FIELD *field, const void *argp)
148{
149  const thisARG *argn = (const thisARG *)argp;
150  double low = argn->low;
151  double high = argn->high;
152  int prec = argn->precision;
153  unsigned char *bp = (unsigned char *)field_buffer(field, 0);
154  char *s = (char *)bp;
155  double val = 0.0;
156  struct lconv *L = argn->L;
157  char buf[64];
158  bool result = FALSE;
159
160  while (*bp && *bp == ' ')
161    bp++;
162  if (*bp)
163    {
164      if (*bp == '-' || *bp == '+')
165	bp++;
166#if USE_WIDEC_SUPPORT
167      if (*bp)
168	{
169	  bool blank = FALSE;
170	  int state = 0;
171	  int len;
172	  int n;
173	  wchar_t *list = _nc_Widen_String((char *)bp, &len);
174
175	  if (list != 0)
176	    {
177	      result = TRUE;
178	      for (n = 0; n < len; ++n)
179		{
180		  if (blank)
181		    {
182		      if (list[n] != ' ')
183			{
184			  result = FALSE;
185			  break;
186			}
187		    }
188		  else if (list[n] == ' ')
189		    {
190		      blank = TRUE;
191		    }
192		  else if (isDecimalPoint(list[n]))
193		    {
194		      if (++state > 1)
195			{
196			  result = FALSE;
197			  break;
198			}
199		    }
200		  else if (!isDigit(list[n]))
201		    {
202		      result = FALSE;
203		      break;
204		    }
205		}
206	      free(list);
207	    }
208	}
209#else
210      while (*bp)
211	{
212	  if (!isdigit(UChar(*bp)))
213	    break;
214	  bp++;
215	}
216      if (isDecimalPoint(*bp))
217	{
218	  bp++;
219	  while (*bp)
220	    {
221	      if (!isdigit(UChar(*bp)))
222		break;
223	      bp++;
224	    }
225	}
226      while (*bp && *bp == ' ')
227	bp++;
228      result = (*bp == '\0');
229#endif
230      if (result)
231	{
232	  val = atof(s);
233	  if (low < high)
234	    {
235	      if (val < low || val > high)
236		result = FALSE;
237	    }
238	  if (result)
239	    {
240	      sprintf(buf, "%.*f", (prec > 0 ? prec : 0), val);
241	      set_field_buffer(field, 0, buf);
242	    }
243	}
244    }
245  return (result);
246}
247
248/*---------------------------------------------------------------------------
249|   Facility      :  libnform
250|   Function      :  static bool Check_This_Character(
251|                                      int c,
252|                                      const void * argp)
253|
254|   Description   :  Check a character for the numeric type.
255|
256|   Return Values :  TRUE  - character is valid
257|                    FALSE - character is invalid
258+--------------------------------------------------------------------------*/
259static bool
260Check_This_Character(int c, const void *argp)
261{
262  const thisARG *argn = (const thisARG *)argp;
263  struct lconv *L = argn->L;
264
265  return ((isDigit(c) ||
266	   c == '+' ||
267	   c == '-' ||
268	   isDecimalPoint(c))
269	  ? TRUE
270	  : FALSE);
271}
272
273static FIELDTYPE typeTHIS =
274{
275  _HAS_ARGS | _RESIDENT,
276  1,				/* this is mutable, so we can't be const */
277  (FIELDTYPE *)0,
278  (FIELDTYPE *)0,
279  Make_This_Type,
280  Copy_This_Type,
281  Free_This_Type,
282  Check_This_Field,
283  Check_This_Character,
284  NULL,
285  NULL
286};
287
288NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_NUMERIC = &typeTHIS;
289
290/* fty_num.c ends here */
291