1 /**
2  * qsre.c: pcre expression match test tool
3  *
4  * See http://mod-qos.sourceforge.net/ for further
5  * details.
6  *
7  * Copyright (C) 2020 Pascal Buchbinder
8  *
9  * Licensed to the Apache Software Foundation (ASF) under one or more
10  * contributor license agreements.  See the NOTICE file distributed with
11  * this work for additional information regarding copyright ownership.
12  * The ASF licenses this file to You under the Apache License, Version 2.0
13  * (the "License"); you may not use this file except in compliance with
14  * the License.  You may obtain a copy of the License at
15  *
16  *     http://www.apache.org/licenses/LICENSE-2.0
17  *
18  * Unless required by applicable law or agreed to in writing, software
19  * distributed under the License is distributed on an "AS IS" BASIS,
20  * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
21  * See the License for the specific language governing permissions and
22  * limitations under the License.
23  *
24  */
25 
26 static const char revision[] = "$Id: qsre.c 2595 2020-01-03 06:19:53Z pbuchbinder $";
27 
28 /* system */
29 #include <stdio.h>
30 #include <string.h>
31 
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <time.h>
35 
36 /* apr */
37 #include <pcre.h>
38 #include <apr.h>
39 #include <apr_strings.h>
40 #include <apr_time.h>
41 #include <apr_general.h>
42 #include <apr_lib.h>
43 #include <apr_portable.h>
44 #include <apr_support.h>
45 
46 #include "qs_util.h"
47 
48 #define QS_OVECCOUNT 100
49 
50 
usage(const char * cmd,int man)51 static void usage(const char *cmd, int man) {
52   if(man) {
53     //.TH [name of program] [section number] [center footer] [left footer] [center header]
54     printf(".TH %s 1 \"%s\" \"mod_qos utilities %s\" \"%s man page\"\n", qs_CMD(cmd), man_date,
55 	   man_version, cmd);
56   }
57   printf("\n");
58 
59   if(man) {
60     printf(".SH NAME\n");
61   }
62   qs_man_print(man, "%s matches a regular expression against test strings.\n", cmd);
63   printf("\n");
64 
65   if(man) {
66     printf(".SH SYNOPSIS\n");
67   }
68   qs_man_print(man, "%s%s <string>|<path> <pcre>|<path>\n", man ? "" : "Usage: ", cmd);
69   printf("\n");
70 
71   if(man) {
72     printf(".SH DESCRIPTION\n");
73   } else {
74     printf("Summary\n");
75   }
76   qs_man_print(man, "Regular expression test tool.\n");
77   qs_man_print(man, "The provided regular expression (pcre, caseless matching, \".\" matches anything\n");
78   qs_man_print(man, "incl. newline) is appplied against the provided test strings to verify if the\n");
79   qs_man_print(man, "pattern matches.\n");
80   printf("\n");
81 
82   if(man) {
83     printf(".SH OPTIONS\n");
84   } else {
85     printf("Options\n");
86   }
87   if(man) printf(".TP\n");
88   qs_man_print(man, "  <string>|<path>\n");
89   if(man) printf("\n");
90   qs_man_print(man, "     The first argument either defines a sinlge test string of a path to\n");
91   qs_man_print(man, "     a file containing either multiple test strings or a test pattern with\n");
92   qs_man_print(man, "     newline characters (text).\n");
93   if(man) printf("\n.TP\n");
94   qs_man_print(man, "  <pcre>|<path>\n");
95   if(man) printf("\n");
96   qs_man_print(man, "     The second argument either defines a regular expression or a path to\n");
97   qs_man_print(man, "     a file containing the expression.\n");
98   printf("\n");
99 
100   if(man) {
101     printf(".SH SEE ALSO\n");
102     printf("qsdt(1), qsexec(1), qsfilter2(1), qsgeo(1), qsgrep(1), qshead(1), qslog(1), qslogger(1), qspng(1), qsrespeed(1), qsrotate(1), qssign(1), qstail(1)\n");
103     printf(".SH AUTHOR\n");
104     printf("Pascal Buchbinder, http://mod-qos.sourceforge.net/\n");
105   } else {
106     printf("See http://mod-qos.sourceforge.net/ for further details.\n");
107   }
108   if(man) {
109     exit(0);
110   } else {
111     exit(1);
112   }
113 }
114 
rmatch(const char * line,pcre * pcre)115 static int rmatch(const char *line, pcre *pcre) {
116   int ovector[QS_OVECCOUNT];
117   int rc_c = -1;
118   do {
119     int rc = pcre_exec(pcre, NULL, line, strlen(line), 0, 0, ovector, QS_OVECCOUNT);
120     if(rc >= 0) {
121       int ix;
122       rc_c = 0;
123       printf("[%.*s]", ovector[1] - ovector[0], &line[ovector[0]]);
124       for(ix = 1; ix < rc; ix++) {
125 	printf(" $%d=%.*s", ix, ovector[ix*2+1] - ovector[ix*2], &line[ovector[ix*2]]);
126       }
127       line = &line[ovector[1]];
128       if(ovector[1] - ovector[0] == 0) {
129 	line++;
130       }
131     } else {
132       line = NULL;
133     }
134   } while(line && line[0]);
135   return rc_c;
136 }
137 
main(int argc,const char * const argv[])138 int main(int argc, const char *const argv[]) {
139   const char *errptr = NULL;
140   int erroffset;
141   pcre *pcre;
142   int rc_c = -1;
143   const char *line;
144   const char *in;
145   const char *pattern;
146   FILE *file;
147   apr_pool_t *pool;
148   char *raw = "";
149   int linenr = 0;
150 
151   const char *cmd = strrchr(argv[0], '/');
152 
153   apr_app_initialize(&argc, &argv, NULL);
154   apr_pool_create(&pool, NULL);
155 
156   if(cmd == NULL) {
157     cmd = (char *)argv[0];
158   } else {
159     cmd++;
160   }
161 
162   argc--;
163   argv++;
164   if(argc != 2) {
165     if(argc  == 1 && strcmp(argv[0], "--man") == 0) {
166       usage(cmd, 1);
167     } else {
168       usage(cmd, 0);
169     }
170   }
171   in = argv[0];
172   pattern = argv[1];
173 
174   file = fopen(pattern, "r");
175   if(file) {
176     char readline[MAX_LINE];
177     if(fgets(readline, MAX_LINE-1, file) != NULL) {
178       int len = strlen(readline);
179       while(len > 0 && readline[len] < 32) {
180 	readline[len] = '\0';
181 	len--;
182       }
183       pattern = apr_pstrdup(pool, readline);
184     }
185     fclose(file);
186   }
187   printf("expression: %s\n", pattern);
188 
189   pcre = pcre_compile(pattern, PCRE_DOTALL|PCRE_CASELESS, &errptr, &erroffset, NULL);
190   if(pcre == NULL) {
191     fprintf(stderr, "ERROR, rule <%s> could not compile pcre at position %d,"
192 	    " reason: %s\n", pattern, erroffset, errptr);
193     exit(1);
194   }
195 
196   file = fopen(in, "r");
197   if(file) {
198     char readline[MAX_LINE];
199     while(fgets(readline, MAX_LINE-1, file) != NULL) {
200       int len = strlen(readline);
201       linenr++;
202       printf("line %.3d: ", linenr);
203       raw = apr_pstrcat(pool, raw, readline, NULL);
204       while(len > 0 && readline[len] < 32) {
205 	readline[len] = '\0';
206 	len--;
207       }
208       if(readline[0] >= 32 && strlen(readline) > 0) {
209 	line = readline;
210 	rc_c = rmatch(line, pcre);
211       }
212       printf("\n");
213     }
214     fclose(file);
215     printf("entire content match:\n");
216     rc_c = rmatch(raw, pcre);
217     printf("\n");
218   } else {
219     line = in;
220     rc_c = rmatch(line, pcre);
221     printf("\n");
222   }
223   if(rc_c < 0) {
224     printf("no match\n");
225     return 2;
226   }
227   return 0;
228 }
229