• Home
  • Line#
  • Scopes#
  • Navigate#
  • Raw
  • Download
1# Copyright 2001, 2002 Dave Abrahams
2# Copyright 2003 Douglas Gregor
3# Copyright 2003 Rene Rivera
4# Copyright 2002, 2003, 2004, 2005 Vladimir Prus
5# Distributed under the Boost Software License, Version 1.0.
6# (See accompanying file LICENSE_1_0.txt or copy at
7# http://www.boost.org/LICENSE_1_0.txt)
8
9#
10#   Returns a list of the following substrings:
11#   1) from beginning till the first occurrence of 'separator' or till the end,
12#   2) between each occurrence of 'separator' and the next occurrence,
13#   3) from the last occurrence of 'separator' till the end.
14#   If no separator is present, the result will contain only one element.
15#
16
17rule split ( string separator )
18{
19    local result ;
20    local s = $(string) ;
21
22    # Break pieaces off 's' until it has no separators left.
23    local match = 1 ;
24    while $(match)
25    {
26        match = [ MATCH ^(.*)($(separator))(.*) : $(s) ] ;
27        if $(match)
28        {
29            match += "" ;  # in case 3rd item was empty - works around MATCH bug
30            result = $(match[3]) $(result) ;
31            s = $(match[1]) ;
32        }
33    }
34    # Combine the remaining part at the beginning, which does not have
35    # separators, with the pieces broken off. Note that the rule's signature
36    # does not allow the initial s to be empty.
37    return $(s) $(result) ;
38}
39
40if [ HAS_NATIVE_RULE regex : split : 1 ]
41{
42    NATIVE_RULE regex : split ;
43}
44
45# Returns the concatenated results of Applying regex.split to every element of
46# the list using the separator pattern.
47#
48rule split-list ( list * : separator )
49{
50    local result ;
51    for s in $(list)
52    {
53        result += [ split $(s) $(separator) ] ;
54    }
55    return $(result) ;
56}
57
58
59# Match string against pattern, and return the elements indicated by indices.
60#
61rule match ( pattern : string : indices * )
62{
63    indices ?= 1 2 3 4 5 6 7 8 9 ;
64    local x = [ MATCH $(pattern) : $(string) ] ;
65    return $(x[$(indices)]) ;
66}
67
68
69# Matches all elements of 'list' against the 'pattern' and returns a list of
70# elements indicated by indices of all successful matches. If 'indices' is
71# omitted returns a list of first parenthesised groups of all successful
72# matches.
73#
74rule transform ( list * : pattern : indices * )
75{
76    indices ?= 1 ;
77    local result ;
78    for local e in $(list)
79    {
80        local m = [ MATCH $(pattern) : $(e) ] ;
81        if $(m)
82        {
83            result += $(m[$(indices)]) ;
84        }
85    }
86    return $(result) ;
87}
88
89NATIVE_RULE regex : transform ;
90
91
92# Escapes all of the characters in symbols using the escape symbol escape-symbol
93# for the given string, and returns the escaped string.
94#
95rule escape ( string : symbols : escape-symbol )
96{
97    local result = "" ;
98    local m = 1 ;
99    while $(m)
100    {
101        m = [ MATCH "^([^$(symbols)]*)([$(symbols)])(.*)" : $(string) ] ;
102        if $(m)
103        {
104            m += "" ;  # Supposedly a bug fix; borrowed from regex.split
105            result = "$(result)$(m[1])$(escape-symbol)$(m[2])" ;
106            string = $(m[3]) ;
107        }
108    }
109    string ?= "" ;
110    result = "$(result)$(string)" ;
111    return $(result) ;
112}
113
114
115# Replaces occurrences of a match string in a given string and returns the new
116# string. The match string can be a regex expression.
117#
118rule replace (
119    string  # The string to modify.
120    match  # The characters to replace.
121    replacement  # The string to replace with.
122    )
123{
124    local result = "" ;
125    local parts = 1 ;
126    while $(parts)
127    {
128        parts = [ MATCH ^(.*)($(match))(.*) : $(string) ] ;
129        if $(parts)
130        {
131            parts += "" ;
132            result = "$(replacement)$(parts[3])$(result)" ;
133            string = $(parts[1]) ;
134        }
135    }
136    string ?= "" ;
137    result = "$(string)$(result)" ;
138    return $(result) ;
139}
140
141if [ HAS_NATIVE_RULE regex : replace : 1 ]
142{
143    NATIVE_RULE regex : replace ;
144}
145
146
147# Replaces occurrences of a match string in a given list of strings and returns
148# a list of new strings. The match string can be a regex expression.
149#
150# list        - the list of strings to modify.
151# match       - the search expression.
152# replacement - the string to replace with.
153#
154rule replace-list ( list * : match : replacement )
155{
156    local result ;
157    for local e in $(list)
158    {
159        result += [ replace $(e) $(match) $(replacement) ] ;
160    }
161    return $(result) ;
162}
163
164
165rule __test__ ( )
166{
167    import assert ;
168
169    assert.result a b c : split "a/b/c" / ;
170    assert.result "" a b c : split "/a/b/c" / ;
171    assert.result "" "" a b c : split "//a/b/c" / ;
172    assert.result "" a "" b c : split "/a//b/c" / ;
173    assert.result "" a "" b c "" : split "/a//b/c/" / ;
174    assert.result "" a "" b c "" "" : split "/a//b/c//" / ;
175    assert.result "" a b c "" : split "abc" "" ;
176    assert.result "" "" : split "" "" ;
177
178    assert.result a c b d
179        : match (.)(.)(.)(.) : abcd : 1 3 2 4 ;
180
181    assert.result a b c d
182        : match (.)(.)(.)(.) : abcd ;
183
184    assert.result ababab cddc
185        : match "((ab)*)([cd]+)" : abababcddc : 1 3 ;
186
187    assert.result a.h c.h
188        : transform <a.h> \"b.h\" <c.h> : <(.*)> ;
189
190    assert.result a.h b.h c.h
191        : transform <a.h> \"b.h\" <c.h> : "<([^>]*)>|\"([^\"]*)\"" : 1 2 ;
192
193    assert.result "^<?xml version=\"1.0\"^>"
194        : escape "<?xml version=\"1.0\">" : "&|()<>^" : "^" ;
195
196    assert.result "<?xml version=\\\"1.0\\\">"
197        : escape "<?xml version=\"1.0\">" : "\\\"" : "\\" ;
198
199    assert.result "string&nbsp;string&nbsp;" : replace "string string " " " "&nbsp;" ;
200    assert.result "&nbsp;string&nbsp;string" : replace " string string" " " "&nbsp;" ;
201    assert.result "string&nbsp;&nbsp;string" : replace "string  string" " " "&nbsp;" ;
202    assert.result "-" : replace "&" "&" "-" ;
203    assert.result "x" : replace "" "" "x" ;
204    assert.result "xax" : replace "a" "" "x" ;
205    assert.result "xaxbx" : replace "ab" "" "x" ;
206
207    assert.result "-" "a-b" : replace-list "&" "a&b" : "&" : "-" ;
208}
209