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