1ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
2ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru**********************************************************************
3b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho*   Copyright (c) 2001-2011, International Business Machines
4ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Corporation and others.  All Rights Reserved.
5ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru**********************************************************************
6ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   Date        Name        Description
7ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*   11/19/2001  aliu        Creation.
8ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru**********************************************************************
9ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
10ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
11ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru#include "unicode/unimatch.h"
1283a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius#include "unicode/utf16.h"
13b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "patternprops.h"
14b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho#include "util.h"
15ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
16ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// Define UChar constants using hex for EBCDIC compatibility
17ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
18ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar BACKSLASH  = 0x005C; /*\*/
19ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar UPPER_U    = 0x0055; /*U*/
20ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar LOWER_U    = 0x0075; /*u*/
21ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar APOSTROPHE = 0x0027; // '\''
22ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar SPACE      = 0x0020; // ' '
23ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
24ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// "0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ"
25ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Querustatic const UChar DIGITS[] = {
26ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    48,49,50,51,52,53,54,55,56,57,
27ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    65,66,67,68,69,70,71,72,73,74,
28ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    75,76,77,78,79,80,81,82,83,84,
29ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    85,86,87,88,89,90
30ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru};
31ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
32ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_BEGIN
33ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
34ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUnicodeString& ICU_Utility::appendNumber(UnicodeString& result, int32_t n,
35ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                     int32_t radix, int32_t minDigits) {
36ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (radix < 2 || radix > 36) {
37ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Bogus radix
38ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return result.append((UChar)63/*?*/);
39ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
40ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Handle negatives
41ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (n < 0) {
42ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        n = -n;
43ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result.append((UChar)45/*-*/);
44ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
45ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // First determine the number of digits
46ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t nn = n;
47ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t r = 1;
48ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (nn >= radix) {
49ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        nn /= radix;
50ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        r *= radix;
51ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        --minDigits;
52ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
53ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Now generate the digits
54ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (--minDigits > 0) {
55ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result.append(DIGITS[0]);
56ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
57ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (r > 0) {
58ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        int32_t digit = n / r;
59ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result.append(DIGITS[digit]);
60ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        n -= digit * r;
61ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        r /= radix;
62ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
63ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return result;
64ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
65ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
66ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
67ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Return true if the character is NOT printable ASCII.
68ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
69ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool ICU_Utility::isUnprintable(UChar32 c) {
70ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return !(c >= 0x20 && c <= 0x7E);
71ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
72ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
73ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
74ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Escape unprintable characters using \uxxxx notation for U+0000 to
75ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * U+FFFF and \Uxxxxxxxx for U+10000 and above.  If the character is
76ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * printable ASCII, then do nothing and return FALSE.  Otherwise,
77ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * append the escaped notation and return TRUE.
78ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
79ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool ICU_Utility::escapeUnprintable(UnicodeString& result, UChar32 c) {
80ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (isUnprintable(c)) {
81ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        result.append(BACKSLASH);
82ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (c & ~0xFFFF) {
83ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            result.append(UPPER_U);
8485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result.append(DIGITS[0xF&(c>>28)]);
8585bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result.append(DIGITS[0xF&(c>>24)]);
8685bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result.append(DIGITS[0xF&(c>>20)]);
8785bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho            result.append(DIGITS[0xF&(c>>16)]);
88ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else {
89ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            result.append(LOWER_U);
90ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
9185bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        result.append(DIGITS[0xF&(c>>12)]);
9285bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        result.append(DIGITS[0xF&(c>>8)]);
9385bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        result.append(DIGITS[0xF&(c>>4)]);
9485bf2e2fbc60a9f938064abc8127d61da7d19882Claire Ho        result.append(DIGITS[0xF&c]);
95ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return TRUE;
96ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
97ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return FALSE;
98ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
99ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
100ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
101ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Returns the index of a character, ignoring quoted text.
102ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * For example, in the string "abc'hide'h", the 'h' in "hide" will not be
103ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * found by a search for 'h'.
104ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
105ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru// FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
106ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/*
107ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t ICU_Utility::quotedIndexOf(const UnicodeString& text,
108ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               int32_t start, int32_t limit,
109ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UChar charToFind) {
110ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (int32_t i=start; i<limit; ++i) {
111ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UChar c = text.charAt(i);
112ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (c == BACKSLASH) {
113ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            ++i;
114ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (c == APOSTROPHE) {
115ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            while (++i < limit
116ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                   && text.charAt(i) != APOSTROPHE) {}
117ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        } else if (c == charToFind) {
118ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return i;
119ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
120ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
121ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return -1;
122ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
123ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru*/
124ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
125ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
126ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Skip over a sequence of zero or more white space characters at pos.
127ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param advance if true, advance pos to the first non-white-space
128ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * character at or after pos, or str.length(), if there is none.
129ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Otherwise leave pos unchanged.
130ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @return the index of the first non-white-space character at or
131ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * after pos, or str.length(), if there is none.
132ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
133ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t ICU_Utility::skipWhitespace(const UnicodeString& str, int32_t& pos,
134ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                    UBool advance) {
135ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t p = pos;
136b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    const UChar* s = str.getBuffer();
137b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho    p = (int32_t)(PatternProps::skipWhiteSpace(s + p, str.length() - p) - s);
138ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (advance) {
139ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        pos = p;
140ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
141ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return p;
142ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
143ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
144ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
145b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Skip over Pattern_White_Space in a Replaceable.
146b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * Skipping may be done in the forward or
147ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * reverse direction.  In either case, the leftmost index will be
148ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * inclusive, and the rightmost index will be exclusive.  That is,
149ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * given a range defined as [start, limit), the call
150ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * skipWhitespace(text, start, limit) will advance start past leading
151ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * whitespace, whereas the call skipWhitespace(text, limit, start),
152ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * will back up limit past trailing whitespace.
153ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param text the text to be analyzed
154ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param pos either the start or limit of a range of 'text', to skip
155ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * leading or trailing whitespace, respectively
156ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param stop either the limit or start of a range of 'text', to skip
157ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * leading or trailing whitespace, respectively
158ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @return the new start or limit, depending on what was passed in to
159ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * 'pos'
160ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
161ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?FOR FUTURE USE.  DISABLE FOR NOW for coverage reasons.
162ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?int32_t ICU_Utility::skipWhitespace(const Replaceable& text,
163ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?                                    int32_t pos, int32_t stop) {
164ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    UChar32 c;
165ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    UBool isForward = (stop >= pos);
166ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?
167ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    if (!isForward) {
168ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?        --pos; // pos is a limit, so back up by one
169ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    }
170ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?
171ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    while (pos != stop &&
172b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho//?           PatternProps::isWhiteSpace(c = text.char32At(pos))) {
173ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?        if (isForward) {
17483a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius//?            pos += U16_LENGTH(c);
175ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?        } else {
17683a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius//?            pos -= U16_LENGTH(c);
177ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?        }
178ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    }
179ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?
180ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    if (!isForward) {
181ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?        ++pos; // make pos back into a limit
182ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    }
183ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?
184ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?    return pos;
185ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru//?}
186ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
187ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
188ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Parse a single non-whitespace character 'ch', optionally
189ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * preceded by whitespace.
190ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param id the string to be parsed
191ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param pos INPUT-OUTPUT parameter.  On input, pos[0] is the
192ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * offset of the first character to be parsed.  On output, pos[0]
193ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * is the index after the last parsed character.  If the parse
194ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * fails, pos[0] will be unchanged.
195ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param ch the non-whitespace character to be parsed.
196ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @return true if 'ch' is seen preceded by zero or more
197ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * whitespace characters.
198ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
199ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruUBool ICU_Utility::parseChar(const UnicodeString& id, int32_t& pos, UChar ch) {
200ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t start = pos;
201ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    skipWhitespace(id, pos, TRUE);
202ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (pos == id.length() ||
203ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        id.charAt(pos) != ch) {
204ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        pos = start;
205ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return FALSE;
206ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
207ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    ++pos;
208ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return TRUE;
209ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
210ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
211ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
212ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Parse a pattern string within the given Replaceable and a parsing
213ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * pattern.  Characters are matched literally and case-sensitively
214ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * except for the following special characters:
215ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
216b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho * ~  zero or more Pattern_White_Space chars
217ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru *
218ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * If end of pattern is reached with all matches along the way,
219ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * pos is advanced to the first unparsed index and returned.
220ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Otherwise -1 is returned.
221ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param pat pattern that controls parsing
222ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param text text to be parsed, starting at index
223ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param index offset to first character to parse
224ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param limit offset after last character to parse
225ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @return index after last parsed character, or -1 on parse failure.
226ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
227ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruint32_t ICU_Utility::parsePattern(const UnicodeString& pat,
228ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                  const Replaceable& text,
229ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                  int32_t index,
230ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                                  int32_t limit) {
231ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    int32_t ipat = 0;
232ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
233ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // empty pattern matches immediately
234ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (ipat == pat.length()) {
235ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        return index;
236ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
237ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
238ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    UChar32 cpat = pat.char32At(ipat);
239ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
240ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    while (index < limit) {
241ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UChar32 c = text.char32At(index);
242ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
243ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // parse \s*
244ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (cpat == 126 /*~*/) {
245b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho            if (PatternProps::isWhiteSpace(c)) {
24683a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius                index += U16_LENGTH(c);
247ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                continue;
248ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else {
249ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (++ipat == pat.length()) {
250ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    return index; // success; c unparsed
251ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
252ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                // fall thru; process c again with next cpat
253ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
254ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
255ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
256ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // parse literal
257ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        else if (c == cpat) {
25883a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius            index += U16_LENGTH(c);
25983a171d1a62abf406f7f44ae671823d5ec20db7dCraig Cornelius            ipat += U16_LENGTH(cpat);
260ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (ipat == pat.length()) {
261ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                return index; // success; c parsed
262ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
263ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // fall thru; get next cpat
264ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
265ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
266ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // match failure of literal
267ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        else {
268ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            return -1;
269ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
270ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
271ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        cpat = pat.char32At(ipat);
272ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
273ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
274ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    return -1; // text ended before end of pat
275ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
276ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
277ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
278ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Append a character to a rule that is being built up.  To flush
279ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * the quoteBuf to rule, make one final call with isLiteral == TRUE.
280ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * If there is no final character, pass in (UChar32)-1 as c.
281ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param rule the string to append the character to
282ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param c the character to append, or (UChar32)-1 if none.
283ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param isLiteral if true, then the given character should not be
284ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * quoted or escaped.  Usually this means it is a syntactic element
285ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * such as > or $
286ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param escapeUnprintable if true, then unprintable characters
287ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * should be escaped using \uxxxx or \Uxxxxxxxx.  These escapes will
288ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * appear outside of quotes.
289ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * @param quoteBuf a buffer which is used to build up quoted
290ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * substrings.  The caller should initially supply an empty buffer,
291ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * and thereafter should not modify the buffer.  The buffer should be
292ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * cleared out by, at the end, calling this method with a literal
293ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * character.
294ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
295ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid ICU_Utility::appendToRule(UnicodeString& rule,
296ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UChar32 c,
297ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UBool isLiteral,
298ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UBool escapeUnprintable,
299ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UnicodeString& quoteBuf) {
300ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // If we are escaping unprintables, then escape them outside
301ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // quotes.  \u and \U are not recognized within quotes.  The same
302ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // logic applies to literals, but literals are never escaped.
303ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (isLiteral ||
304ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        (escapeUnprintable && ICU_Utility::isUnprintable(c))) {
305ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (quoteBuf.length() > 0) {
306ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // We prefer backslash APOSTROPHE to double APOSTROPHE
307ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // (more readable, less similar to ") so if there are
308ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // double APOSTROPHEs at the ends, we pull them outside
309ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // of the quote.
310ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
311ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // If the first thing in the quoteBuf is APOSTROPHE
312ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // (doubled) then pull it out.
313ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            while (quoteBuf.length() >= 2 &&
314ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                   quoteBuf.charAt(0) == APOSTROPHE &&
315ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                   quoteBuf.charAt(1) == APOSTROPHE) {
316ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(BACKSLASH).append(APOSTROPHE);
317ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                quoteBuf.remove(0, 2);
318ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
319ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // If the last thing in the quoteBuf is APOSTROPHE
320ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            // (doubled) then remove and count it and add it after.
321ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            int32_t trailingCount = 0;
322ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            while (quoteBuf.length() >= 2 &&
323ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                   quoteBuf.charAt(quoteBuf.length()-2) == APOSTROPHE &&
324ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                   quoteBuf.charAt(quoteBuf.length()-1) == APOSTROPHE) {
325ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                quoteBuf.truncate(quoteBuf.length()-2);
326ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                ++trailingCount;
327ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
328ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (quoteBuf.length() > 0) {
329ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(APOSTROPHE);
330ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(quoteBuf);
331ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(APOSTROPHE);
332ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                quoteBuf.truncate(0);
333ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
334ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            while (trailingCount-- > 0) {
335ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(BACKSLASH).append(APOSTROPHE);
336ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
337ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
338ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (c != (UChar32)-1) {
339ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            /* Since spaces are ignored during parsing, they are
340ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             * emitted only for readability.  We emit one here
341ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             * only if there isn't already one at the end of the
342ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             * rule.
343ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             */
344ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            if (c == SPACE) {
345ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                int32_t len = rule.length();
346ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                if (len > 0 && rule.charAt(len-1) != c) {
347ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                    rule.append(c);
348ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                }
349ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            } else if (!escapeUnprintable || !ICU_Utility::escapeUnprintable(rule, c)) {
350ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                rule.append(c);
351ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            }
352ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
353ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
354ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
355ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Escape ' and '\' and don't begin a quote just for them
356ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else if (quoteBuf.length() == 0 &&
357ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             (c == APOSTROPHE || c == BACKSLASH)) {
358ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        rule.append(BACKSLASH);
359ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        rule.append(c);
360ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
361ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
362ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Specials (printable ascii that isn't [0-9a-zA-Z]) and
363ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // whitespace need quoting.  Also append stuff to quotes if we are
364ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // building up a quoted substring already.
365ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else if (quoteBuf.length() > 0 ||
366ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru             (c >= 0x0021 && c <= 0x007E &&
367ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru              !((c >= 0x0030/*'0'*/ && c <= 0x0039/*'9'*/) ||
368ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                (c >= 0x0041/*'A'*/ && c <= 0x005A/*'Z'*/) ||
369ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                (c >= 0x0061/*'a'*/ && c <= 0x007A/*'z'*/))) ||
370b26ce3a7367e4ed2ee7ddddcdc3f3d3377a455c2claireho             PatternProps::isWhiteSpace(c)) {
371ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        quoteBuf.append(c);
372ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        // Double ' within a quote
373ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        if (c == APOSTROPHE) {
374ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru            quoteBuf.append(c);
375ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        }
376ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
377ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
378ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    // Otherwise just append
379ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    else {
380ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        rule.append(c);
381ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
382ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
383ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
384ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid ICU_Utility::appendToRule(UnicodeString& rule,
385ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               const UnicodeString& text,
386ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UBool isLiteral,
387ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UBool escapeUnprintable,
388ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UnicodeString& quoteBuf) {
389ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    for (int32_t i=0; i<text.length(); ++i) {
390ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendToRule(rule, text[i], isLiteral, escapeUnprintable, quoteBuf);
391ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
392ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
393ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
394ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru/**
395ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * Given a matcher reference, which may be null, append its
396ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru * pattern as a literal to the given rule.
397ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru */
398ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queruvoid ICU_Utility::appendToRule(UnicodeString& rule,
399ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               const UnicodeMatcher* matcher,
400ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UBool escapeUnprintable,
401ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                               UnicodeString& quoteBuf) {
402ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    if (matcher != NULL) {
403ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        UnicodeString pat;
404ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru        appendToRule(rule, matcher->toPattern(pat, escapeUnprintable),
405ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru                     TRUE, escapeUnprintable, quoteBuf);
406ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru    }
407ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru}
408ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste Queru
409ac04d0bbe12b3ef54518635711412f178cb4d16Jean-Baptiste QueruU_NAMESPACE_END
410