option.c: fixed warnings
[k8jam.git] / src / rexp.c
blobbd4b2fe2d320d2ed3564e6f4fb6b285172cc9a4c
1 /* coded by Ketmar // Vampire Avalon (psyc://ketmar.no-ip.org/~Ketmar)
2 * Understanding is not required. Only obedience.
4 * This program is free software: you can redistribute it and/or modify
5 * it under the terms of the GNU General Public License as published by
6 * the Free Software Foundation, version 3 of the License ONLY.
8 * This program is distributed in the hope that it will be useful,
9 * but WITHOUT ANY WARRANTY; without even the implied warranty of
10 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
11 * GNU General Public License for more details.
13 * You should have received a copy of the GNU General Public License
14 * along with this program. If not, see <http://www.gnu.org/licenses/>.
16 #include "jam.h"
17 #include "hash.h"
18 #include "newstr.h"
21 typedef struct recache_item_s {
22 regexp_t re; /* this MUST be here! */
23 struct recache_item_s *next; /* for 'same string, different flags' */
24 } recache_item_t;
27 static struct hash *recache = NULL;
30 /* return 0 if not found (created new ci) */
31 static int find_re (regexp_t **ci, const char *str, int flags) {
32 int r = 1;
33 recache_item_t fnd, *res = &fnd;
34 if (recache == NULL) recache = hashinit(sizeof(recache_item_t), "recache");
35 fnd.re.restr = newstr(str);
36 if (hashenter(recache, (HASHDATA **)&res)) {
37 /* want new one */
38 res->re.flags = flags;
39 res->re.maxmem = 0;
40 res->next = NULL;
41 r = 0;
42 //fprintf(stderr, "NEW RE: '%s'\n", str);
43 } else {
44 /* hit; check if we have regexp with this set of flags */
45 recache_item_t *c;
46 for (c = res; c != NULL; c = c->next) if (c->re.flags == flags) break;
47 if (c == NULL) {
48 /* not found; create new item */
49 recache_item_t *last;
50 for (last = res; last->next != NULL; last = last->next) ;
51 if ((c = malloc(sizeof(*c))) == NULL) { printf("FATAL: out of memory!\n"); exit(EXITBAD); }
52 c->re.restr = res->re.restr;
53 c->re.flags = res->re.flags;
54 c->re.maxmem = 0;
55 c->next = NULL;
56 last->next = c;
57 res = c;
58 r = 0;
59 //fprintf(stderr, "NEW RE(1): '%s'\n", str);
60 } else {
61 res = c;
62 //fprintf(stderr, "RE HIT: '%s'\n", str);
65 *ci = &res->re;
66 return r;
71 * regexp options:
72 * i: ignore case
73 * u: this is utf-8 string
74 * m: '.' matches newline
75 * default mode: non-utf-8 (it can be only reset with /.../u)
77 regexp_t *regexp_compile (const char *str, int flags) {
78 regexp_t *cre;
79 const char *s = str, *e = NULL, *errmsg;
80 flags |= RE9_FLAG_NONUTF8;
81 if (str == NULL) str = "";
82 if (str[0] == '/' && (e = strrchr(str+1, '/')) != NULL) {
83 /* this must be regexp with options */
84 for (const char *t = e+1; *t; ++t) {
85 switch (*t) {
86 case 'i': flags |= RE9_FLAG_CASEINSENS; break;
87 case 'u': flags &= ~RE9_FLAG_NONUTF8; break;
88 case 'm': flags |= RE9_FLAG_ANYDOT; break;
89 default:
90 printf("FATAL: invalid regexp option: '%c'!\n", *t);
91 exit(EXITBAD); /* oops */
94 ++str;
96 if (find_re(&cre, s, flags) == 0) {
97 if ((cre->re = re9_compile_ex(str, e, flags, &errmsg)) == NULL) {
98 printf("FATAL: regexp error: '%s'!\n", errmsg);
99 exit(EXITBAD); /* oops */
101 flags &= ~RE9_FLAG_ANYDOT; /* don't need that */
102 /* RE9_FLAG_CASEINSENS left only for caller checks; re9_execute() will ignore it */
103 cre->flags = flags;
105 return cre;
109 void regexp_free (regexp_t *re) {
110 /* do nothing, yeah! */
114 int regexp_execute (regexp_t *re, const char *bol, re9_sub_t *mp, int ms) {
115 if (re != NULL) {
116 #ifdef REGEXP9_DEBUG_MEMSIZE
117 int res = re9_execute(re->re, re->flags, bol, mp, ms);
118 if (re9_memused > re->maxmem) re->maxmem = re9_memused;
119 return res;
120 #else
121 return re9_execute(re->re, re->flags, bol, mp, ms);
122 #endif
124 return -1;
128 void regexp_done (void) {
129 #ifdef REGEXP9_DEBUG_MEMSIZE
130 int count = 0;
131 regexp_t *rarray;
132 hashiterate(recache, ({ int lmb (const void *hdata, void *udata) { ++count; return 0; } lmb; }), NULL);
133 rarray = malloc(sizeof(rarray[0])*count);
134 count = 0;
135 hashiterate(recache, ({ int lmb (const void *hdata, void *udata) { rarray[count++] = *((regexp_t *)hdata); return 0; } lmb; }), NULL);
136 printf("regexps, sorted by used memory:\n");
137 qsort(rarray, count, sizeof(rarray[0]), ({
138 int cmp (const void *p0, const void *p1) {
139 regexp_t *r0 = (regexp_t *)p0;
140 regexp_t *r1 = (regexp_t *)p1;
141 if (r0->maxmem != r1->maxmem) return r1->maxmem-r0->maxmem;
142 if (strlen(r0->restr) != strlen(r1->restr)) return strlen(r0->restr)-strlen(r1->restr);
143 return strcmp(r0->restr, r1->restr);
145 cmp;
146 }));
147 for (int f = 0; f < count; ++f) printf("%10d: /%s/\n", rarray[f].maxmem, rarray[f].restr);
148 free(rarray);
149 #endif