ncurses 5.5
[ncurses.git] / form / fty_regex.c
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 *                                                                          *
10 *  Author : Juergen Pfeifer                                                *
11 *                                                                          *
12 ***************************************************************************/
13
14 #include "form.priv.h"
15
16 MODULE_ID("$Id: fty_regex.c,v 1.18 2004/05/29 19:19:09 tom Exp $")
17
18 #if HAVE_REGEX_H_FUNCS          /* We prefer POSIX regex */
19 #include <regex.h>
20
21 typedef struct
22   {
23     regex_t *pRegExp;
24     unsigned long *refCount;
25   }
26 RegExp_Arg;
27
28 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
29 #undef RETURN
30 static int reg_errno;
31
32 static char *
33 RegEx_Init(char *instring)
34 {
35   reg_errno = 0;
36   return instring;
37 }
38
39 static char *
40 RegEx_Error(int code)
41 {
42   reg_errno = code;
43   return 0;
44 }
45
46 #define INIT            register char *sp = RegEx_Init(instring);
47 #define GETC()          (*sp++)
48 #define PEEKC()         (*sp)
49 #define UNGETC(c)       (--sp)
50 #define RETURN(c)       return(c)
51 #define ERROR(c)        return RegEx_Error(c)
52
53 #if HAVE_REGEXP_H_FUNCS
54 #include <regexp.h>
55 #else
56 #include <regexpr.h>
57 #endif
58
59 typedef struct
60 {
61   char *compiled_expression;
62   unsigned long *refCount;
63 }
64 RegExp_Arg;
65
66 /* Maximum Length we allow for a compiled regular expression */
67 #define MAX_RX_LEN   (2048)
68 #define RX_INCREMENT (256)
69
70 #endif
71
72 /*---------------------------------------------------------------------------
73 |   Facility      :  libnform
74 |   Function      :  static void *Make_RegularExpression_Type(va_list * ap)
75 |
76 |   Description   :  Allocate structure for regex type argument.
77 |
78 |   Return Values :  Pointer to argument structure or NULL on error
79 +--------------------------------------------------------------------------*/
80 static void *
81 Make_RegularExpression_Type(va_list *ap)
82 {
83 #if HAVE_REGEX_H_FUNCS
84   char *rx = va_arg(*ap, char *);
85   RegExp_Arg *preg;
86
87   preg = (RegExp_Arg *)malloc(sizeof(RegExp_Arg));
88
89   if (preg)
90     {
91       if (((preg->pRegExp = (regex_t *) malloc(sizeof(regex_t))) != 0)
92           && !regcomp(preg->pRegExp, rx,
93                       (REG_EXTENDED | REG_NOSUB | REG_NEWLINE)))
94         {
95           preg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
96
97           *(preg->refCount) = 1;
98         }
99       else
100         {
101           if (preg->pRegExp)
102             free(preg->pRegExp);
103           free(preg);
104           preg = (RegExp_Arg *)0;
105         }
106     }
107   return ((void *)preg);
108 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
109   char *rx = va_arg(*ap, char *);
110   RegExp_Arg *pArg;
111
112   pArg = (RegExp_Arg *)malloc(sizeof(RegExp_Arg));
113
114   if (pArg)
115     {
116       int blen = RX_INCREMENT;
117
118       pArg->compiled_expression = NULL;
119       pArg->refCount = (unsigned long *)malloc(sizeof(unsigned long));
120
121       *(pArg->refCount) = 1;
122
123       do
124         {
125           char *buf = (char *)malloc(blen);
126
127           if (buf)
128             {
129 #if HAVE_REGEXP_H_FUNCS
130               char *last_pos = compile(rx, buf, &buf[blen], '\0');
131
132 #else /* HAVE_REGEXPR_H_FUNCS */
133               char *last_pos = compile(rx, buf, &buf[blen]);
134 #endif
135               if (reg_errno)
136                 {
137                   free(buf);
138                   if (reg_errno == 50)
139                     blen += RX_INCREMENT;
140                   else
141                     {
142                       free(pArg);
143                       pArg = NULL;
144                       break;
145                     }
146                 }
147               else
148                 {
149                   pArg->compiled_expression = buf;
150                   break;
151                 }
152             }
153         }
154       while (blen <= MAX_RX_LEN);
155     }
156   if (pArg && !pArg->compiled_expression)
157     {
158       free(pArg);
159       pArg = NULL;
160     }
161   return (void *)pArg;
162 #else
163   return 0;
164 #endif
165 }
166
167 /*---------------------------------------------------------------------------
168 |   Facility      :  libnform
169 |   Function      :  static void *Copy_RegularExpression_Type(
170 |                                      const void * argp)
171 |
172 |   Description   :  Copy structure for regex type argument.
173 |
174 |   Return Values :  Pointer to argument structure or NULL on error.
175 +--------------------------------------------------------------------------*/
176 static void *
177 Copy_RegularExpression_Type(const void *argp)
178 {
179 #if (HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS)
180   const RegExp_Arg *ap = (const RegExp_Arg *)argp;
181   const RegExp_Arg *result = (const RegExp_Arg *)0;
182
183   if (ap)
184     {
185       *(ap->refCount) += 1;
186       result = ap;
187     }
188   return (void *)result;
189 #else
190   return 0;
191 #endif
192 }
193
194 /*---------------------------------------------------------------------------
195 |   Facility      :  libnform
196 |   Function      :  static void Free_RegularExpression_Type(void * argp)
197 |
198 |   Description   :  Free structure for regex type argument.
199 |
200 |   Return Values :  -
201 +--------------------------------------------------------------------------*/
202 static void
203 Free_RegularExpression_Type(void *argp)
204 {
205 #if HAVE_REGEX_H_FUNCS | HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
206   RegExp_Arg *ap = (RegExp_Arg *)argp;
207
208   if (ap)
209     {
210       if (--(*(ap->refCount)) == 0)
211         {
212 #if HAVE_REGEX_H_FUNCS
213           if (ap->pRegExp)
214             {
215               free(ap->refCount);
216               regfree(ap->pRegExp);
217             }
218 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
219           if (ap->compiled_expression)
220             {
221               free(ap->refCount);
222               free(ap->compiled_expression);
223             }
224 #endif
225           free(ap);
226         }
227     }
228 #endif
229 }
230
231 /*---------------------------------------------------------------------------
232 |   Facility      :  libnform
233 |   Function      :  static bool Check_RegularExpression_Field(
234 |                                      FIELD * field,
235 |                                      const void  * argp)
236 |
237 |   Description   :  Validate buffer content to be a valid regular expression
238 |
239 |   Return Values :  TRUE  - field is valid
240 |                    FALSE - field is invalid
241 +--------------------------------------------------------------------------*/
242 static bool
243 Check_RegularExpression_Field(FIELD *field, const void *argp)
244 {
245   bool match = FALSE;
246
247 #if HAVE_REGEX_H_FUNCS
248   const RegExp_Arg *ap = (const RegExp_Arg *)argp;
249
250   if (ap && ap->pRegExp)
251     match = (regexec(ap->pRegExp, field_buffer(field, 0), 0, NULL, 0)
252              ? FALSE
253              : TRUE);
254 #elif HAVE_REGEXP_H_FUNCS | HAVE_REGEXPR_H_FUNCS
255   RegExp_Arg *ap = (RegExp_Arg *)argp;
256
257   if (ap && ap->compiled_expression)
258     match = (step(field_buffer(field, 0), ap->compiled_expression)
259              ? TRUE
260              : FALSE);
261 #endif
262   return match;
263 }
264
265 static FIELDTYPE typeREGEXP =
266 {
267   _HAS_ARGS | _RESIDENT,
268   1,                            /* this is mutable, so we can't be const */
269   (FIELDTYPE *)0,
270   (FIELDTYPE *)0,
271   Make_RegularExpression_Type,
272   Copy_RegularExpression_Type,
273   Free_RegularExpression_Type,
274   Check_RegularExpression_Field,
275   NULL,
276   NULL,
277   NULL
278 };
279
280 NCURSES_EXPORT_VAR(FIELDTYPE*) TYPE_REGEXP = &typeREGEXP;
281
282 /* fty_regex.c ends here */