]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libregexp/regexec.c
libsec: do proper type checking, fix wrong deduplication check
[plan9front.git] / sys / src / libregexp / regexec.c
1 #include <u.h>
2 #include <libc.h>
3 #include <regexp.h>
4 #include "regimpl.h"
5
6 typedef struct RethreadQ RethreadQ;
7 struct RethreadQ {
8         Rethread *head;
9         Rethread **tail;
10 };
11
12 int
13 regexec(Reprog *p, char *str, Resub *sem, int msize)
14 {
15         RethreadQ lists[2], *clist, *nlist, *tmp;
16         Rethread *t, *next, *pool, *avail;
17         Reinst *ci;
18         Rune r;
19         char *sp, *ep, endc;
20         int i, matchgen, gen;
21
22         memset(p->threads, 0, sizeof(Rethread)*p->nthr);
23         if(msize > NSUBEXPM)
24                 msize = NSUBEXPM;
25         if(p->startinst->gen != 0) {
26                 for(ci = p->startinst; ci < p->startinst + p->len; ci++)
27                         ci->gen = 0;
28         }
29
30         clist = lists;
31         clist->head = nil;
32         clist->tail = &clist->head;
33         nlist = lists + 1;
34         nlist->head = nil;
35         nlist->tail = &nlist->head;
36
37         pool = p->threads;
38         avail = nil;
39         gen = matchgen = 0;
40
41         sp = str;
42         ep = nil;
43         endc = '\0';
44         if(sem != nil && msize > 0) {
45                 if(sem->sp != nil)
46                         sp = sem->sp;
47                 if(sem->ep != nil && *sem->ep != '\0') {
48                         ep = sem->ep;
49                         endc = *sem->ep;
50                         *sem->ep = '\0';
51                 }
52         }
53
54         for(r = L'☺'; r != L'\0'; sp += i) {
55                 i = chartorune(&r, sp);
56                 gen++;
57                 if(matchgen == 0) {
58                         if(avail == nil) {
59                                 assert(pool < p->threads + p->nthr);
60                                 t = pool++;
61                         } else {
62                                 t = avail;
63                                 avail = avail->next;
64                         }
65                         t->i = p->startinst;
66                         if(msize > 0)
67                                 memset(t->sem, 0, sizeof(Resub)*msize);
68                         t->next = nil;
69                         t->gen = gen;
70                         *clist->tail = t;
71                         clist->tail = &t->next;
72                 }
73                 t = clist->head;
74                 if(t == nil)
75                         break;
76                 ci = t->i;
77 Again:
78                 if(ci->gen == gen)
79                         goto Done;
80                 ci->gen = gen;
81                 switch(ci->op) {
82                 case ORUNE:
83                         if(r != ci->r)
84                                 goto Done;
85                 case OANY: /* fallthrough */
86                         next = t->next;
87                         t->i = ci + 1;
88                         t->next = nil;
89                         *nlist->tail = t;
90                         nlist->tail = &t->next;
91                         goto Next;
92                 case OCLASS:
93                 Class:
94                         if(r < ci->r)
95                                 goto Done;
96                         if(r > ci->r1) {
97                                 ci++;
98                                 goto Class;
99                         }
100                         next = t->next;
101                         t->i = ci->a;
102                         t->next = nil;
103                         *nlist->tail = t;
104                         nlist->tail = &t->next;
105                         goto Next;
106                 case ONOTNL:
107                         if(r != L'\n') {
108                                 ci++;
109                                 goto Again;
110                         }
111                         goto Done;
112                 case OBOL:
113                         if(sp == str || sp[-1] == '\n') {
114                                 ci++;
115                                 goto Again;
116                         }
117                         goto Done;
118                 case OEOL:
119                         if(r == L'\n' || r == L'\0' && ep == nil) {
120                                 ci++;
121                                 goto Again;
122                         }
123                         goto Done;
124                 case OJMP:
125                         ci = ci->a;
126                         goto Again;
127                 case OSPLIT:
128                         if(avail == nil) {
129                                 assert(pool < p->threads + p->nthr);
130                                 next = pool++;
131                         } else {
132                                 next = avail;
133                                 avail = avail->next;
134                         }
135                         next->i = ci->b;
136                         if(msize > 0)
137                                 memcpy(next->sem, t->sem, sizeof(Resub)*msize);
138                         next->next = t->next;
139                         next->gen = t->gen;
140                         t->next = next;
141                         ci = ci->a;
142                         goto Again;
143                 case OSAVE:
144                         if(ci->sub < msize)
145                                 t->sem[ci->sub].sp = sp;
146                         ci++;
147                         goto Again;
148                 case OUNSAVE:
149                         if(ci->sub == 0) {
150                                 matchgen = t->gen;
151                                 if(sem != nil && msize > 0) {
152                                         memcpy(sem, t->sem, sizeof(Resub)*msize);
153                                         sem->ep = sp;
154                                 }
155                                 goto Done;
156                         }
157                         if(ci->sub < msize)
158                                 t->sem[ci->sub].ep = sp;
159                         ci++;
160                         goto Again;
161                 Done:
162                         next = t->next;
163                         t->next = avail;
164                         avail = t;
165                 Next:
166                         if(next == nil)
167                                 break;
168                         if(matchgen && next->gen > matchgen) {
169                                 *clist->tail = avail;
170                                 avail = next;
171                                 break;
172                         }
173                         t = next;
174                         ci = t->i;
175                         goto Again;
176                 }
177                 tmp = clist;
178                 clist = nlist;
179                 nlist = tmp;
180                 nlist->head = nil;
181                 nlist->tail = &nlist->head;
182         }
183         if(ep != nil)
184                 *ep = endc;
185         return matchgen > 0 ? 1 : 0;
186 }