blob: 6aac716919988cf8c4a6a0ffc777813087889a01 [file] [log] [blame]
Rashed Abdel-Tawab4db47f42019-09-06 10:38:22 -07001package re;
2
3# pragma for controlling the regexp engine
4use strict;
5use warnings;
6
7our $VERSION = "0.34";
8our @ISA = qw(Exporter);
9our @EXPORT_OK = ('regmust',
10 qw(is_regexp regexp_pattern
11 regname regnames regnames_count));
12our %EXPORT_OK = map { $_ => 1 } @EXPORT_OK;
13
14my %bitmask = (
15 taint => 0x00100000, # HINT_RE_TAINT
16 eval => 0x00200000, # HINT_RE_EVAL
17);
18
19my $flags_hint = 0x02000000; # HINT_RE_FLAGS
20my $PMMOD_SHIFT = 0;
21my %reflags = (
22 m => 1 << ($PMMOD_SHIFT + 0),
23 s => 1 << ($PMMOD_SHIFT + 1),
24 i => 1 << ($PMMOD_SHIFT + 2),
25 x => 1 << ($PMMOD_SHIFT + 3),
26 xx => 1 << ($PMMOD_SHIFT + 4),
27 n => 1 << ($PMMOD_SHIFT + 5),
28 p => 1 << ($PMMOD_SHIFT + 6),
29 strict => 1 << ($PMMOD_SHIFT + 10),
30# special cases:
31 d => 0,
32 l => 1,
33 u => 2,
34 a => 3,
35 aa => 4,
36);
37
38sub setcolor {
39 eval { # Ignore errors
40 require Term::Cap;
41
42 my $terminal = Tgetent Term::Cap ({OSPEED => 9600}); # Avoid warning.
43 my $props = $ENV{PERL_RE_TC} || 'md,me,so,se,us,ue';
44 my @props = split /,/, $props;
45 my $colors = join "\t", map {$terminal->Tputs($_,1)} @props;
46
47 $colors =~ s/\0//g;
48 $ENV{PERL_RE_COLORS} = $colors;
49 };
50 if ($@) {
51 $ENV{PERL_RE_COLORS} ||= qq'\t\t> <\t> <\t\t';
52 }
53
54}
55
56my %flags = (
57 COMPILE => 0x0000FF,
58 PARSE => 0x000001,
59 OPTIMISE => 0x000002,
60 TRIEC => 0x000004,
61 DUMP => 0x000008,
62 FLAGS => 0x000010,
63 TEST => 0x000020,
64
65 EXECUTE => 0x00FF00,
66 INTUIT => 0x000100,
67 MATCH => 0x000200,
68 TRIEE => 0x000400,
69
70 EXTRA => 0xFF0000,
71 TRIEM => 0x010000,
72 OFFSETS => 0x020000,
73 OFFSETSDBG => 0x040000,
74 STATE => 0x080000,
75 OPTIMISEM => 0x100000,
76 STACK => 0x280000,
77 BUFFERS => 0x400000,
78 GPOS => 0x800000,
79);
80$flags{ALL} = -1 & ~($flags{OFFSETS}|$flags{OFFSETSDBG}|$flags{BUFFERS});
81$flags{All} = $flags{all} = $flags{DUMP} | $flags{EXECUTE};
82$flags{Extra} = $flags{EXECUTE} | $flags{COMPILE} | $flags{GPOS};
83$flags{More} = $flags{MORE} = $flags{All} | $flags{TRIEC} | $flags{TRIEM} | $flags{STATE};
84$flags{State} = $flags{DUMP} | $flags{EXECUTE} | $flags{STATE};
85$flags{TRIE} = $flags{DUMP} | $flags{EXECUTE} | $flags{TRIEC};
86
87if (defined &DynaLoader::boot_DynaLoader) {
88 require XSLoader;
89 XSLoader::load();
90}
91# else we're miniperl
92# We need to work for miniperl, because the XS toolchain uses Text::Wrap, which
93# uses re 'taint'.
94
95sub _load_unload {
96 my ($on)= @_;
97 if ($on) {
98 # We call install() every time, as if we didn't, we wouldn't
99 # "see" any changes to the color environment var since
100 # the last time it was called.
101
102 # install() returns an integer, which if casted properly
103 # in C resolves to a structure containing the regexp
104 # hooks. Setting it to a random integer will guarantee
105 # segfaults.
106 $^H{regcomp} = install();
107 } else {
108 delete $^H{regcomp};
109 }
110}
111
112sub bits {
113 my $on = shift;
114 my $bits = 0;
115 my $turning_all_off = ! @_ && ! $on;
116 if ($turning_all_off) {
117
118 # Pretend were called with certain parameters, which are best dealt
119 # with that way.
120 push @_, keys %bitmask; # taint and eval
121 push @_, 'strict';
122 }
123
124 # Process each subpragma parameter
125 ARG:
126 foreach my $idx (0..$#_){
127 my $s=$_[$idx];
128 if ($s eq 'Debug' or $s eq 'Debugcolor') {
129 setcolor() if $s =~/color/i;
130 ${^RE_DEBUG_FLAGS} = 0 unless defined ${^RE_DEBUG_FLAGS};
131 for my $idx ($idx+1..$#_) {
132 if ($flags{$_[$idx]}) {
133 if ($on) {
134 ${^RE_DEBUG_FLAGS} |= $flags{$_[$idx]};
135 } else {
136 ${^RE_DEBUG_FLAGS} &= ~ $flags{$_[$idx]};
137 }
138 } else {
139 require Carp;
140 Carp::carp("Unknown \"re\" Debug flag '$_[$idx]', possible flags: ",
141 join(", ",sort keys %flags ) );
142 }
143 }
144 _load_unload($on ? 1 : ${^RE_DEBUG_FLAGS});
145 last;
146 } elsif ($s eq 'debug' or $s eq 'debugcolor') {
147 setcolor() if $s =~/color/i;
148 _load_unload($on);
149 last;
150 } elsif (exists $bitmask{$s}) {
151 $bits |= $bitmask{$s};
152 } elsif ($EXPORT_OK{$s}) {
153 require Exporter;
154 re->export_to_level(2, 're', $s);
155 } elsif ($s eq 'strict') {
156 if ($on) {
157 $^H{reflags} |= $reflags{$s};
158 warnings::warnif('experimental::re_strict',
159 "\"use re 'strict'\" is experimental");
160
161 # Turn on warnings if not already done.
162 if (! warnings::enabled('regexp')) {
163 require warnings;
164 warnings->import('regexp');
165 $^H{re_strict} = 1;
166 }
167 }
168 else {
169 $^H{reflags} &= ~$reflags{$s} if $^H{reflags};
170
171 # Turn off warnings if we turned them on.
172 warnings->unimport('regexp') if $^H{re_strict};
173 }
174 if ($^H{reflags}) {
175 $^H |= $flags_hint;
176 }
177 else {
178 $^H &= ~$flags_hint;
179 }
180 } elsif ($s =~ s/^\///) {
181 my $reflags = $^H{reflags} || 0;
182 my $seen_charset;
183 my $x_count = 0;
184 while ($s =~ m/( . )/gx) {
185 local $_ = $1;
186 if (/[adul]/) {
187 # The 'a' may be repeated; hide this from the rest of the
188 # code by counting and getting rid of all of them, then
189 # changing to 'aa' if there is a repeat.
190 if ($_ eq 'a') {
191 my $sav_pos = pos $s;
192 my $a_count = $s =~ s/a//g;
193 pos $s = $sav_pos - 1; # -1 because got rid of the 'a'
194 if ($a_count > 2) {
195 require Carp;
196 Carp::carp(
197 qq 'The "a" flag may only appear a maximum of twice'
198 );
199 }
200 elsif ($a_count == 2) {
201 $_ = 'aa';
202 }
203 }
204 if ($on) {
205 if ($seen_charset) {
206 require Carp;
207 if ($seen_charset ne $_) {
208 Carp::carp(
209 qq 'The "$seen_charset" and "$_" flags '
210 .qq 'are exclusive'
211 );
212 }
213 else {
214 Carp::carp(
215 qq 'The "$seen_charset" flag may not appear '
216 .qq 'twice'
217 );
218 }
219 }
220 $^H{reflags_charset} = $reflags{$_};
221 $seen_charset = $_;
222 }
223 else {
224 delete $^H{reflags_charset}
225 if defined $^H{reflags_charset}
226 && $^H{reflags_charset} == $reflags{$_};
227 }
228 } elsif (exists $reflags{$_}) {
229 if ($_ eq 'x') {
230 $x_count++;
231 if ($x_count > 2) {
232 require Carp;
233 Carp::carp(
234 qq 'The "x" flag may only appear a maximum of twice'
235 );
236 }
237 elsif ($x_count == 2) {
238 $_ = 'xx'; # First time through got the /x
239 }
240 }
241
242 $on
243 ? $reflags |= $reflags{$_}
244 : ($reflags &= ~$reflags{$_});
245 } else {
246 require Carp;
247 Carp::carp(
248 qq'Unknown regular expression flag "$_"'
249 );
250 next ARG;
251 }
252 }
253 ($^H{reflags} = $reflags or defined $^H{reflags_charset})
254 ? $^H |= $flags_hint
255 : ($^H &= ~$flags_hint);
256 } else {
257 require Carp;
258 Carp::carp("Unknown \"re\" subpragma '$s' (known ones are: ",
259 join(', ', map {qq('$_')} 'debug', 'debugcolor', sort keys %bitmask),
260 ")");
261 }
262 }
263
264 if ($turning_all_off) {
265 _load_unload(0);
266 $^H{reflags} = 0;
267 $^H{reflags_charset} = 0;
268 $^H &= ~$flags_hint;
269 }
270
271 $bits;
272}
273
274sub import {
275 shift;
276 $^H |= bits(1, @_);
277}
278
279sub unimport {
280 shift;
281 $^H &= ~ bits(0, @_);
282}
283
2841;
285
286__END__
287