1 /*
2 *
3 ***** BEGIN LICENSE BLOCK *****
4
5 Copyright (C) 2009-2019 Olof Hagsand and Benny Holmgren
6
7 This file is part of CLIXON.
8
9 Licensed under the Apache License, Version 2.0 (the "License");
10 you may not use this file except in compliance with the License.
11 You may obtain a copy of the License at
12
13 http://www.apache.org/licenses/LICENSE-2.0
14
15 Unless required by applicable law or agreed to in writing, software
16 distributed under the License is distributed on an "AS IS" BASIS,
17 WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
18 See the License for the specific language governing permissions and
19 limitations under the License.
20
21 Alternatively, the contents of this file may be used under the terms of
22 the GNU General Public License Version 3 or later (the "GPL"),
23 in which case the provisions of the GPL are applicable instead
24 of those above. If you wish to allow use of your version of this file only
25 under the terms of the GPL, and not to allow others to
26 use your version of this file under the terms of Apache License version 2,
27 indicate your decision by deleting the provisions above and replace them with
28 the notice and other provisions required by the GPL. If you do not delete
29 the provisions above, a recipient may use your version of this file under
30 the terms of any one of the Apache License version 2 or the GPL.
31
32 ***** END LICENSE BLOCK *****
33
34 * Utility for compiling regexp and checking validity
35 * gcc -I /usr/include/libxml2 regex.c -o regex -lxml2
36 * @see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028
37 */
38 #ifdef HAVE_CONFIG_H
39 #include "clixon_config.h" /* generated by config & autoconf */
40 #endif
41
42 #include <unistd.h> /* unistd */
43 #include <string.h>
44 #include <regex.h> /* posix regex */
45 #include <syslog.h>
46 #include <stdlib.h>
47 #include <limits.h>
48
49 #ifdef HAVE_LIBXML2 /* Actually it should check for a header file */
50 #include <libxml/xmlregexp.h>
51 #endif
52
53 /* cligen */
54 #include <cligen/cligen.h>
55
56 /* clixon */
57 #include "clixon/clixon.h"
58
59 /*! libxml2 regex implementation
60 * @see http://www.w3.org/TR/2004/REC-xmlschema-2-20041028
61 * @retval -1 Error
62 * @retval 0 Not match
63 * @retval 1 Match
64 */
65 static int
regex_libxml2(char * regexp0,char * content0,int nr,int debug)66 regex_libxml2(char *regexp0,
67 char *content0,
68 int nr,
69 int debug)
70
71 {
72 int retval = -1;
73 #ifdef HAVE_LIBXML2
74 xmlChar *regexp = (xmlChar*)regexp0;
75 xmlChar *content = (xmlChar*)content0;
76 xmlRegexp *xrp = NULL;
77 int ret;
78 int i;
79
80 if ((xrp = xmlRegexpCompile(regexp)) == NULL)
81 goto done;
82 if (nr==0)
83 return 1;
84 for (i=0; i<nr; i++)
85 if ((ret = xmlRegexpExec(xrp, content)) < 0)
86 goto done;
87 return ret;
88 done:
89 #endif
90 return retval;
91 }
92
93 static int
regex_posix(char * regexp,char * content,int nr,int debug)94 regex_posix(char *regexp,
95 char *content,
96 int nr,
97 int debug)
98 {
99 int retval = -1;
100 char *posix = NULL;
101 char pattern[1024];
102 int status = 0;
103 regex_t re;
104 char errbuf[1024];
105 int len0;
106 int i;
107
108 if (regexp_xsd2posix(regexp, &posix) < 0)
109 goto done;
110 clicon_debug(1, "posix: %s", posix);
111 len0 = strlen(posix);
112 if (len0 > sizeof(pattern)-5){
113 fprintf(stderr, "pattern too long\n");
114 return -1;
115 }
116 strncpy(pattern, "^(", 2);
117 strncpy(pattern+2, posix, sizeof(pattern)-2);
118 strncat(pattern, ")$", sizeof(pattern)-len0-1);
119 if (regcomp(&re, pattern, REG_NOSUB|REG_EXTENDED) != 0)
120 return(0); /* report error */
121 if (nr==0)
122 return 1;
123 for (i=0; i<nr; i++)
124 status = regexec(&re, content, (size_t) 0, NULL, 0);
125 regfree(&re);
126 if (status != 0) {
127 regerror(status, &re, errbuf, sizeof(errbuf)); /* XXX error is ignored */
128 return(0); /* report error */
129 }
130 return(1);
131 done:
132 if (posix)
133 free(posix);
134 return retval;
135 }
136
137 static int
usage(char * argv0)138 usage(char *argv0)
139 {
140 fprintf(stderr, "usage:%s [options]\n"
141 "where options are\n"
142 "\t-h \t\tHelp\n"
143 "\t-D <level>\tDebug\n"
144 "\t-p \txsd->posix translation regexp (default)\n"
145 "\t-x \tlibxml2 regexp (alternative to -p)\n"
146 "\t-n <nr> \tIterate content match (default: 1, 0: no match only compile)\n"
147 "\t-r <regexp> \tregexp (mandatory)\n"
148 "\t-c <string> \tValue content string(mandatory if -n > 0)\n",
149 argv0
150 );
151 exit(0);
152 }
153
154 int
main(int argc,char ** argv)155 main(int argc,
156 char **argv)
157 {
158 int retval = -1;
159 char *argv0 = argv[0];
160 int c;
161 char *regexp = NULL;
162 char *content = NULL;
163 int ret = 0;
164 int nr = 1;
165 int mode = 0; /* 0 is posix, 1 is libxml */
166 int dbg = 0;
167
168 optind = 1;
169 opterr = 0;
170 while ((c = getopt(argc, argv, "hD:pxn:r:c:")) != -1)
171 switch (c) {
172 case 'h':
173 usage(argv0);
174 break;
175 case 'D':
176 if (sscanf(optarg, "%d", &dbg) != 1)
177 usage(argv0);
178 break;
179 case 'p': /* xsd->posix */
180 mode = 0;
181 break;
182 case 'n': /* Number of iterations */
183 if ((nr = atoi(optarg)) < 0)
184 usage(argv0);
185 break;
186 case 'x': /* libxml2 */
187 mode = 1;
188 break;
189 case 'r': /* regexp */
190 regexp = optarg;
191 break;
192 case 'c': /* value content string */
193 content = optarg;
194 break;
195 default:
196 usage(argv[0]);
197 break;
198 }
199 clicon_log_init(__FILE__, dbg?LOG_DEBUG:LOG_INFO, CLICON_LOG_STDERR);
200 clicon_debug_init(dbg, NULL);
201
202 if (regexp == NULL){
203 fprintf(stderr, "-r mandatory\n");
204 usage(argv0);
205 }
206 if (nr > 0 && content == NULL){
207 fprintf(stderr, "-c mandatory (if -n > 0)\n");
208 usage(argv0);
209 }
210 if (mode != 0 && mode != 1){
211 fprintf(stderr, "Neither posix or libxml2 set\n");
212 usage(argv0);
213 }
214 clicon_debug(1, "regexp:%s", regexp);
215 clicon_debug(1, "content:%s", content);
216 if (mode == 0){
217 if ((ret = regex_posix(regexp, content, nr, dbg)) < 0)
218 goto done;
219
220 }
221 else if (mode == 1){
222 if ((ret = regex_libxml2(regexp, content, nr, dbg)) < 0)
223 goto done;
224 }
225 else
226 usage(argv0);
227 fprintf(stdout, "%d\n", ret);
228 exit(ret);
229 retval = 0;
230 done:
231 return retval;
232 }
233