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