]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libregexp/regexec.c
merge default
[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 {
9         Rethread *head;
10         Rethread **tail;
11 };
12
13 int
14 regexec(Reprog *prog, char *str, Resub *sem, int msize)
15 {
16         RethreadQ lists[2], *clist, *nlist, *tmp;
17         Rethread *t, *next, *pooltop, *avail;
18         Reinst *curinst;
19         Rune r;
20         char *sp, *ep, endc;
21         int i, match, first, gen, matchpri, pri;
22
23         if(msize > NSUBEXPM)
24                 msize = NSUBEXPM;
25
26         if(prog->startinst->gen != 0) {
27                 for(curinst = prog->startinst; curinst < prog->startinst + prog->len; curinst++)
28                         curinst->gen = 0;
29         }
30
31         clist = lists;
32         clist->head = nil;
33         clist->tail = &clist->head;
34         nlist = lists + 1;
35         nlist->head = nil;
36         nlist->tail = &nlist->head;
37
38         pooltop = prog->threads + prog->nthr;
39         avail = nil;
40
41         pri = matchpri = gen = match = 0;
42         sp = str;
43         ep = nil;
44         endc = '\0';
45         if(sem != nil && msize > 0) {
46                 if(sem->sp != nil)
47                         sp = sem->sp;
48                 if(sem->ep != nil && *sem->ep != '\0') {
49                         ep = sem->ep;
50                         endc = *sem->ep;
51                         *sem->ep = '\0';
52                 }
53         }
54         r = Runemax + 1; 
55         for(; r != L'\0'; sp += i) {
56                 gen++;
57                 i = chartorune(&r, sp);
58                 first = 1;
59                 t = clist->head;
60                 if(t == nil)
61                         goto Start;
62                 curinst = t->pc;
63 Again:
64                 if(curinst->gen == gen)
65                         goto Done;
66                 curinst->gen = gen;
67                 switch(curinst->op) {
68                 case ORUNE:
69                         if(r != curinst->r)
70                                 goto Done;
71                 case OANY: /* fallthrough */
72                 Any:
73                         next = t->next;
74                         t->pc = curinst + 1;
75                         t->next = nil;
76                         *nlist->tail = t;
77                         nlist->tail = &t->next;
78                         if(next == nil)
79                                 break;
80                         t = next;
81                         curinst = t->pc;
82                         goto Again;
83                 case OCLASS:
84                 Class:
85                         if(r < curinst->r)
86                                 goto Done;
87                         if(r > curinst->r1) {
88                                 curinst++;
89                                 goto Class;
90                         }
91                         next = t->next;
92                         t->pc = curinst->a;
93                         t->next = nil;
94                         *nlist->tail = t;
95                         nlist->tail = &t->next;
96                         if(next == nil)
97                                 break;
98                         t = next;
99                         curinst = t->pc;
100                         goto Again;
101                 case ONOTNL:
102                         if(r != L'\n') {
103                                 curinst++;
104                                 goto Again;
105                         }
106                         goto Done;
107                 case OBOL:
108                         if(sp == str || sp[-1] == '\n') {
109                                 curinst++;
110                                 goto Again;
111                         }
112                         goto Done;
113                 case OEOL:
114                         if(r == L'\0' && ep == nil) {
115                                 curinst++;
116                                 goto Again;
117                         }
118                         if(r == L'\n')
119                                 goto Any;
120                         goto Done;
121                 case OJMP:
122                         curinst = curinst->a;
123                         goto Again;
124                 case OSPLIT:
125                         if(avail == nil)
126                                 next = --pooltop;
127                         else {
128                                 next = avail;
129                                 avail = avail->next;
130                         }
131                         next->pc = curinst->b;
132                         if(msize > 0)
133                                 memcpy(next->sem, t->sem, sizeof(Resub)*msize);
134                         next->pri = t->pri;
135                         next->next = t->next;
136                         t->next = next;
137                         curinst = curinst->a;
138                         goto Again;
139                 case OSAVE:
140                         if(curinst->sub < msize)
141                                 t->sem[curinst->sub].sp = sp;
142                         curinst++;
143                         goto Again;
144                 case OUNSAVE:
145                         if(curinst->sub == 0) {
146                                 /* "Highest" priority is the left-most longest. */
147                                 if (t->pri > matchpri)
148                                         goto Done;
149                                 match = 1;
150                                 matchpri = t->pri;
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(curinst->sub < msize)
158                                 t->sem[curinst->sub].ep = sp;
159                         curinst++;
160                         goto Again;
161                 Done:
162                         next = t->next;
163                         t->next = avail;
164                         avail = t;
165                         if(next == nil)
166                                 break;
167                         t = next;
168                         curinst = t->pc;
169                         goto Again;
170                 }
171 Start:
172                 /* Start again once if we haven't found anything. */
173                 if(first == 1 && match == 0) {
174                         first = 0;
175                         if(avail == nil)
176                                 t = --pooltop;
177                         else {
178                                 t = avail;
179                                 avail = avail->next;
180                         }
181                         if(msize > 0)
182                                 memset(t->sem, 0, sizeof(Resub)*msize);
183                         /* "Lower" priority thread */
184                         t->pri = matchpri = pri++;
185                         t->next = nil;
186                         curinst = prog->startinst;
187                         goto Again;
188                 }
189                 /* If we have a match and no extant threads, we are done. */
190                 if(match == 1 && nlist->head == nil)
191                         break;
192                 tmp = clist;
193                 clist = nlist;
194                 nlist = tmp;
195                 nlist->head = nil;
196                 nlist->tail = &nlist->head;
197         }
198         if(ep != nil)
199                 *ep = endc;
200         return match;
201 }