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