1
(* $Id: netglob_lex.mll 1514 2010-12-17 18:24:59Z gerd $ *)
4
exception Bracket_Unsupported
9
| Bracket_range of (char * char)
10
| Bracket_code of int (* see Netglob.reparse_bracket_expr *)
14
Brace_literal of string
16
| Brace_braces of brace_token list (* inner braces *)
22
enable_brackets : bool;
26
mutable escaped : bool; (* after a backslash *)
30
Glob_literal of string
33
| Glob_brackets of (bool * bracket_token list)
34
| Glob_braces of brace_token list
35
| Glob_tilde of string * bool (* whether there is a slash *)
39
C of char (* An unescaped character *)
40
| E of char (* An escaped character *)
41
| Delim of char (* delimiter *)
45
let rec collect_until end_token parse_fun lexbuf =
46
let tok = parse_fun lexbuf in
47
if tok = end_token then
50
tok :: (collect_until end_token parse_fun lexbuf)
53
let string_of_exploded l =
57
| C c -> String.make 1 c
58
| E c -> String.make 1 c
65
List.exists (function Delim _ -> true | _ -> false) l
69
(* bracket_rest: Scans a bracket expression beginning at the second
70
* character (where ']' is always the terminating character)
73
rule bracket_rest = parse
74
"[:" [^ ':' ] ":]" { raise Bracket_Unsupported }
75
| "[." [^ '.' ] ".]" { raise Bracket_Unsupported }
76
| "[=" [^ '=' ] "=]" { raise Bracket_Unsupported }
78
| [ ^ ']' ] "-" [^ ']' ]
79
{ let c0 = Lexing.lexeme_char lexbuf 0 in
80
let c1 = Lexing.lexeme_char lexbuf 2 in
81
if c0 > '\127' || c1 > '\127' then raise Lexing_Error;
82
if c0 > c1 then raise Lexing_Error;
85
| eof { raise Lexing_Error }
86
| [ ^ ']' ] { Bracket_char (Lexing.lexeme_char lexbuf 0) }
88
(* bracket_first: Scans the first token of a bracket expression
89
* (after "[", "[^", or "[!").
90
* Here, ']' is not recognized as terminating character.
93
and bracket_first = parse
94
"[:" [^ ':' ] ":]" { raise Bracket_Unsupported }
95
| "[." [^ '.' ] ".]" { raise Bracket_Unsupported }
96
| "[=" [^ '=' ] "=]" { raise Bracket_Unsupported }
97
| _ "-" [^ ']' ] { let c0 = Lexing.lexeme_char lexbuf 0 in
98
let c1 = Lexing.lexeme_char lexbuf 2 in
99
if c0 > '\127' || c1 > '\127' then raise Lexing_Error;
100
if c0 > c1 then raise Lexing_Error;
103
| eof { raise Lexing_Error }
104
| _ { Bracket_char (Lexing.lexeme_char lexbuf 0) }
107
(* brace: Collects material within brace expressions (case: backslash
108
* is escape character
113
| "," { Brace_comma }
114
| "{" { let l = collect_until Brace_end brace lexbuf in
116
| '\\' _ { Brace_literal (Lexing.lexeme lexbuf) }
117
| [^ '}' ',' '\\' '{' ] { Brace_literal (Lexing.lexeme lexbuf) }
118
| eof { raise Lexing_Error }
119
| _ { raise Lexing_Error }
121
(* brace_noescape: Used for the case that backslash is not an escape
125
and brace_noescape = parse
127
| "," { Brace_comma }
128
| "{" { let l = collect_until Brace_end brace_noescape lexbuf in
130
| [^ '}' ',' '{'] { Brace_literal (Lexing.lexeme lexbuf) }
131
| eof { raise Lexing_Error }
132
| _ { raise Lexing_Error }
134
and glob_expr feat = parse
135
"*" { if feat.enable_star && not feat.escaped then
138
feat.escaped <- false;
142
| "?" { if feat.enable_qmark && not feat.escaped then
145
feat.escaped <- false;
149
| "[" [ '!' '^' ]? { if feat.enable_brackets && not feat.escaped then (
151
String.length(Lexing.lexeme lexbuf) > 1 in
152
let t0 = bracket_first lexbuf in
153
let l = collect_until
154
Bracket_end bracket_rest lexbuf in
155
Glob_brackets (negated, t0 :: l)
158
feat.escaped <- false;
159
Glob_literal (Lexing.lexeme lexbuf)
162
| "{" { if feat.enable_braces && not feat.escaped then (
164
if feat.enable_escape then
168
let l = collect_until Brace_end p lexbuf in
172
feat.escaped <- false;
176
| "~" { if (feat.enable_tilde && not feat.escaped &&
177
Lexing.lexeme_start lexbuf = 0) then (
179
if feat.enable_escape then
180
generic_lex_until '/'
182
generic_lex_noescape_until '/' in
184
let s = string_of_exploded l in
185
let slash = have_delim l in
188
feat.escaped <- false;
192
| "\\" { if feat.enable_escape && not feat.escaped then (
193
feat.escaped <- true;
197
feat.escaped <- false;
201
| [ ^ '*' '?' '[' '{' '\\' '~' ]+
202
{ feat.escaped <- false;
203
Glob_literal (Lexing.lexeme lexbuf)
205
| eof { if feat.escaped then raise Lexing_Error;
209
and generic_lex_until c = parse
210
'\\' _ { let char = E (Lexing.lexeme_char lexbuf 1) in
211
char :: generic_lex_until c lexbuf }
212
| _ { let lc = Lexing.lexeme_char lexbuf 0 in
213
if c = lc then [ Delim c ] else (
215
char :: generic_lex_until c lexbuf
219
and generic_lex_noescape_until c = parse
220
| _ { let lc = Lexing.lexeme_char lexbuf 0 in
221
if c = lc then [ Delim c ] else (
223
char :: generic_lex_noescape_until c lexbuf