]> git.lizzy.rs Git - plan9front.git/blob - sys/src/libregexp/regexec.c
libregex: fix sed regression (thans spew)
[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                         next = t->next;
73                         t->pc = curinst + 1;
74                         t->next = nil;
75                         *nlist->tail = t;
76                         nlist->tail = &t->next;
77                         if(next == nil)
78                                 break;
79                         t = next;
80                         curinst = t->pc;
81                         goto Again;
82                 case OCLASS:
83                 Class:
84                         if(r < curinst->r)
85                                 goto Done;
86                         if(r > curinst->r1) {
87                                 curinst++;
88                                 goto Class;
89                         }
90                         next = t->next;
91                         t->pc = curinst->a;
92                         t->next = nil;
93                         *nlist->tail = t;
94                         nlist->tail = &t->next;
95                         if(next == nil)
96                                 break;
97                         t = next;
98                         curinst = t->pc;
99                         goto Again;
100                 case ONOTNL:
101                         if(r != L'\n') {
102                                 curinst++;
103                                 goto Again;
104                         }
105                         goto Done;
106                 case OBOL:
107                         if(sp == str || sp[-1] == '\n') {
108                                 curinst++;
109                                 goto Again;
110                         }
111                         goto Done;
112                 case OEOL:
113                         if(r == L'\n' || r == L'\0' && ep == nil) {
114                                 curinst++;
115                                 goto Again;
116                         }
117                         goto Done;
118                 case OJMP:
119                         curinst = curinst->a;
120                         goto Again;
121                 case OSPLIT:
122                         if(avail == nil)
123                                 next = --pooltop;
124                         else {
125                                 next = avail;
126                                 avail = avail->next;
127                         }
128                         next->pc = curinst->b;
129                         if(msize > 0)
130                                 memcpy(next->sem, t->sem, sizeof(Resub)*msize);
131                         next->pri = t->pri;
132                         next->next = t->next;
133                         t->next = next;
134                         curinst = curinst->a;
135                         goto Again;
136                 case OSAVE:
137                         if(curinst->sub < msize)
138                                 t->sem[curinst->sub].sp = sp;
139                         curinst++;
140                         goto Again;
141                 case OUNSAVE:
142                         if(curinst->sub == 0) {
143                                 /* "Highest" priority is the left-most longest. */
144                                 if (t->pri > matchpri)
145                                         goto Done;
146                                 match = 1;
147                                 matchpri = t->pri;
148                                 if(sem != nil && msize > 0) {
149                                         memcpy(sem, t->sem, sizeof(Resub)*msize);
150                                         sem->ep = sp;
151                                 }
152                                 goto Done;
153                         }
154                         if(curinst->sub < msize)
155                                 t->sem[curinst->sub].ep = sp;
156                         curinst++;
157                         goto Again;
158                 Done:
159                         next = t->next;
160                         t->next = avail;
161                         avail = t;
162                         if(next == nil)
163                                 break;
164                         t = next;
165                         curinst = t->pc;
166                         goto Again;
167                 }
168 Start:
169                 /* Start again once if we haven't found anything. */
170                 if(first == 1 && match == 0) {
171                         first = 0;
172                         if(avail == nil)
173                                 t = --pooltop;
174                         else {
175                                 t = avail;
176                                 avail = avail->next;
177                         }
178                         if(msize > 0)
179                                 memset(t->sem, 0, sizeof(Resub)*msize);
180                         /* "Lower" priority thread */
181                         t->pri = matchpri = pri++;
182                         t->next = nil;
183                         curinst = prog->startinst;
184                         goto Again;
185                 }
186                 /* If we have a match and no extant threads, we are done. */
187                 if(match == 1 && nlist->head == nil)
188                         break;
189                 tmp = clist;
190                 clist = nlist;
191                 nlist = tmp;
192                 nlist->head = nil;
193                 nlist->tail = &nlist->head;
194         }
195         if(ep != nil)
196                 *ep = endc;
197         return match;
198 }