fty_regex.c revision 262629
1/****************************************************************************
2 * Copyright (c) 1998-2009,2010 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_regex.c,v 1.24 2010/01/23 21:14:37 tom Exp $")
38
39#if HAVE_REGEX_H_FUNCS		/* We prefer POSIX regex */
40#include <regex.h>
41
42typedef struct
43  {
44    regex_t *pRegExp;
45    unsigned long *refCount;
46  }
47RegExp_Arg;
48
49#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
50#undef RETURN
51static int reg_errno;
52
53static char *
54RegEx_Init(char *instring)
55{
56  reg_errno = 0;
57  return instring;
58}
59
60static char *
61RegEx_Error(int code)
62{
63  reg_errno = code;
64  return 0;
65}
66
67#define INIT 		register char *sp = RegEx_Init(instring);
68#define GETC()		(*sp++)
69#define PEEKC()		(*sp)
70#define UNGETC(c)	(--sp)
71#define RETURN(c)	return(c)
72#define ERROR(c)	return RegEx_Error(c)
73
74#if HAVE_REGEXP_H_FUNCS
75#include <regexp.h>
76#else
77#include <regexpr.h>
78#endif
79
80typedef struct
81{
82  char *compiled_expression;
83  unsigned long *refCount;
84}
85RegExp_Arg;
86
87/* Maximum Length we allow for a compiled regular expression */
88#define MAX_RX_LEN   (2048)
89#define RX_INCREMENT (256)
90
91#endif
92
93#if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
94# define MAYBE_UNUSED
95#else
96# define MAYBE_UNUSED GCC_UNUSED
97#endif
98
99/*---------------------------------------------------------------------------
100|   Facility      :  libnform
101|   Function      :  static void *Generic_RegularExpression_Type(void * arg)
102|
103|   Description   :  Allocate structure for regex type argument.
104|
105|   Return Values :  Pointer to argument structure or NULL on error
106+--------------------------------------------------------------------------*/
107static void *
108Generic_RegularExpression_Type(void *arg MAYBE_UNUSED)
109{
110#if HAVE_REGEX_H_FUNCS
111  char *rx = (char *)arg;
112  RegExp_Arg *preg = (RegExp_Arg *)0;
113
114  if (rx)
115    {
116      preg = typeMalloc(RegExp_Arg, 1);
117
118      if (preg)
119	{
120	  T((T_CREATE("RegExp_Arg %p"), (void *)preg));
121	  if (((preg->pRegExp = typeMalloc(regex_t, 1)) != 0)
122	      && !regcomp(preg->pRegExp, rx,
123			  (REG_EXTENDED | REG_NOSUB | REG_NEWLINE)))
124	    {
125	      T((T_CREATE("regex_t %p"), (void *)preg->pRegExp));
126	      preg->refCount = typeMalloc(unsigned long, 1);
127
128	      *(preg->refCount) = 1;
129	    }
130	  else
131	    {
132	      if (preg->pRegExp)
133		free(preg->pRegExp);
134	      free(preg);
135	      preg = (RegExp_Arg *)0;
136	    }
137	}
138    }
139  return ((void *)preg);
140#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
141  char *rx = (char *)arg;
142  RegExp_Arg *pArg = (RegExp_Arg *)0;
143
144  if (rx)
145    {
146      pArg = typeMalloc(RegExp_Arg, 1);
147
148      if (pArg)
149	{
150	  int blen = RX_INCREMENT;
151
152	  T((T_CREATE("RegExp_Arg %p"), pArg));
153	  pArg->compiled_expression = NULL;
154	  pArg->refCount = typeMalloc(unsigned long, 1);
155
156	  *(pArg->refCount) = 1;
157
158	  do
159	    {
160	      char *buf = typeMalloc(char, blen);
161
162	      if (buf)
163		{
164#if HAVE_REGEXP_H_FUNCS
165		  char *last_pos = compile(rx, buf, &buf[blen], '\0');
166
167#else /* HAVE_REGEXPR_H_FUNCS */
168		  char *last_pos = compile(rx, buf, &buf[blen]);
169#endif
170		  if (reg_errno)
171		    {
172		      free(buf);
173		      if (reg_errno == 50)
174			blen += RX_INCREMENT;
175		      else
176			{
177			  free(pArg);
178			  pArg = NULL;
179			  break;
180			}
181		    }
182		  else
183		    {
184		      pArg->compiled_expression = buf;
185		      break;
186		    }
187		}
188	    }
189	  while (blen <= MAX_RX_LEN);
190	}
191      if (pArg && !pArg->compiled_expression)
192	{
193	  free(pArg);
194	  pArg = NULL;
195	}
196    }
197  return (void *)pArg;
198#else
199  return 0;
200#endif
201}
202
203/*---------------------------------------------------------------------------
204|   Facility      :  libnform
205|   Function      :  static void *Make_RegularExpression_Type(va_list * ap)
206|
207|   Description   :  Allocate structure for regex type argument.
208|
209|   Return Values :  Pointer to argument structure or NULL on error
210+--------------------------------------------------------------------------*/
211static void *
212Make_RegularExpression_Type(va_list *ap)
213{
214  char *rx = va_arg(*ap, char *);
215
216  return Generic_RegularExpression_Type((void *)rx);
217}
218
219/*---------------------------------------------------------------------------
220|   Facility      :  libnform
221|   Function      :  static void *Copy_RegularExpression_Type(
222|                                      const void * argp)
223|
224|   Description   :  Copy structure for regex type argument.
225|
226|   Return Values :  Pointer to argument structure or NULL on error.
227+--------------------------------------------------------------------------*/
228static void *
229Copy_RegularExpression_Type(const void *argp MAYBE_UNUSED)
230{
231#if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS)
232  const RegExp_Arg *ap = (const RegExp_Arg *)argp;
233  const RegExp_Arg *result = (const RegExp_Arg *)0;
234
235  if (ap)
236    {
237      *(ap->refCount) += 1;
238      result = ap;
239    }
240  return (void *)result;
241#else
242  return 0;
243#endif
244}
245
246/*---------------------------------------------------------------------------
247|   Facility      :  libnform
248|   Function      :  static void Free_RegularExpression_Type(void * argp)
249|
250|   Description   :  Free structure for regex type argument.
251|
252|   Return Values :  -
253+--------------------------------------------------------------------------*/
254static void
255Free_RegularExpression_Type(void *argp MAYBE_UNUSED)
256{
257#if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
258  RegExp_Arg *ap = (RegExp_Arg *)argp;
259
260  if (ap)
261    {
262      if (--(*(ap->refCount)) == 0)
263	{
264#if HAVE_REGEX_H_FUNCS
265	  if (ap->pRegExp)
266	    {
267	      free(ap->refCount);
268	      regfree(ap->pRegExp);
269	    }
270#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
271	  if (ap->compiled_expression)
272	    {
273	      free(ap->refCount);
274	      free(ap->compiled_expression);
275	    }
276#endif
277	  free(ap);
278	}
279    }
280#endif
281}
282
283/*---------------------------------------------------------------------------
284|   Facility      :  libnform
285|   Function      :  static bool Check_RegularExpression_Field(
286|                                      FIELD * field,
287|                                      const void  * argp)
288|
289|   Description   :  Validate buffer content to be a valid regular expression
290|
291|   Return Values :  TRUE  - field is valid
292|                    FALSE - field is invalid
293+--------------------------------------------------------------------------*/
294static bool
295Check_RegularExpression_Field(FIELD *field MAYBE_UNUSED,
296			      const void *argp MAYBE_UNUSED)
297{
298  bool match = FALSE;
299
300#if HAVE_REGEX_H_FUNCS
301  const RegExp_Arg *ap = (const RegExp_Arg *)argp;
302
303  if (ap && ap->pRegExp)
304    match = (regexec(ap->pRegExp, field_buffer(field, 0), 0, NULL, 0)
305	     ? FALSE
306	     : TRUE);
307#elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
308  RegExp_Arg *ap = (RegExp_Arg *)argp;
309
310  if (ap && ap->compiled_expression)
311    match = (step(field_buffer(field, 0), ap->compiled_expression)
312	     ? TRUE
313	     : FALSE);
314#endif
315  return match;
316}
317
318static FIELDTYPE typeREGEXP =
319{
320  _HAS_ARGS | _RESIDENT,
321  1,				/* this is mutable, so we can't be const */
322  (FIELDTYPE *)0,
323  (FIELDTYPE *)0,
324  Make_RegularExpression_Type,
325  Copy_RegularExpression_Type,
326  Free_RegularExpression_Type,
327  INIT_FT_FUNC(Check_RegularExpression_Field),
328  INIT_FT_FUNC(NULL),
329  INIT_FT_FUNC(NULL),
330  INIT_FT_FUNC(NULL),
331#if NCURSES_INTEROP_FUNCS
332  Generic_RegularExpression_Type
333#endif
334};
335
336NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_REGEXP = &typeREGEXP;
337
338#if NCURSES_INTEROP_FUNCS
339/* The next routines are to simplify the use of ncurses from
340   programming languages with restictions on interop with C level
341   constructs (e.g. variable access or va_list + ellipsis constructs)
342*/
343NCURSES_EXPORT(FIELDTYPE *)
344_nc_TYPE_REGEXP(void)
345{
346  return TYPE_REGEXP;
347}
348#endif
349
350/* fty_regex.c ends here */
351