1// Copyright (C) 2016 and later: Unicode, Inc. and others.
2// License & terms of use: http://www.unicode.org/copyright.html
3/*
4******************************************************************************
5* Copyright (C) 2014-2016, International Business Machines
6* Corporation and others.  All Rights Reserved.
7******************************************************************************
8* simpleformatter.h
9*/
10
11#ifndef __SIMPLEFORMATTER_H__
12#define __SIMPLEFORMATTER_H__
13
14/**
15 * \file
16 * \brief C++ API: Simple formatter, minimal subset of MessageFormat.
17 */
18
19#include "unicode/utypes.h"
20#include "unicode/unistr.h"
21
22#ifndef U_HIDE_DRAFT_API
23
24U_NAMESPACE_BEGIN
25
26/**
27 * Formats simple patterns like "{1} was born in {0}".
28 * Minimal subset of MessageFormat; fast, simple, minimal dependencies.
29 * Supports only numbered arguments with no type nor style parameters,
30 * and formats only string values.
31 * Quoting via ASCII apostrophe compatible with ICU MessageFormat default behavior.
32 *
33 * Factory methods set error codes for syntax errors
34 * and for too few or too many arguments/placeholders.
35 *
36 * SimpleFormatter objects are thread-safe except for assignment and applying new patterns.
37 *
38 * Example:
39 * <pre>
40 * UErrorCode errorCode = U_ZERO_ERROR;
41 * SimpleFormatter fmt("{1} '{born}' in {0}", errorCode);
42 * UnicodeString result;
43 *
44 * // Output: "paul {born} in england"
45 * fmt.format("england", "paul", result, errorCode);
46 * </pre>
47 *
48 * This class is not intended for public subclassing.
49 *
50 * @see MessageFormat
51 * @see UMessagePatternApostropheMode
52 * @draft ICU 57
53 */
54class U_COMMON_API SimpleFormatter U_FINAL : public UMemory {
55public:
56    /**
57     * Default constructor.
58     * @draft ICU 57
59     */
60    SimpleFormatter() : compiledPattern((UChar)0) {}
61
62    /**
63     * Constructs a formatter from the pattern string.
64     *
65     * @param pattern The pattern string.
66     * @param errorCode ICU error code in/out parameter.
67     *                  Must fulfill U_SUCCESS before the function call.
68     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax.
69     * @draft ICU 57
70     */
71    SimpleFormatter(const UnicodeString& pattern, UErrorCode &errorCode) {
72        applyPattern(pattern, errorCode);
73    }
74
75    /**
76     * Constructs a formatter from the pattern string.
77     * The number of arguments checked against the given limits is the
78     * highest argument number plus one, not the number of occurrences of arguments.
79     *
80     * @param pattern The pattern string.
81     * @param min The pattern must have at least this many arguments.
82     * @param max The pattern must have at most this many arguments.
83     * @param errorCode ICU error code in/out parameter.
84     *                  Must fulfill U_SUCCESS before the function call.
85     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax and
86     *                  too few or too many arguments.
87     * @draft ICU 57
88     */
89    SimpleFormatter(const UnicodeString& pattern, int32_t min, int32_t max,
90                    UErrorCode &errorCode) {
91        applyPatternMinMaxArguments(pattern, min, max, errorCode);
92    }
93
94    /**
95     * Copy constructor.
96     * @draft ICU 57
97     */
98    SimpleFormatter(const SimpleFormatter& other)
99            : compiledPattern(other.compiledPattern) {}
100
101    /**
102     * Assignment operator.
103     * @draft ICU 57
104     */
105    SimpleFormatter &operator=(const SimpleFormatter& other);
106
107    /**
108     * Destructor.
109     * @draft ICU 57
110     */
111    ~SimpleFormatter();
112
113    /**
114     * Changes this object according to the new pattern.
115     *
116     * @param pattern The pattern string.
117     * @param errorCode ICU error code in/out parameter.
118     *                  Must fulfill U_SUCCESS before the function call.
119     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax.
120     * @return TRUE if U_SUCCESS(errorCode).
121     * @draft ICU 57
122     */
123    UBool applyPattern(const UnicodeString &pattern, UErrorCode &errorCode) {
124        return applyPatternMinMaxArguments(pattern, 0, INT32_MAX, errorCode);
125    }
126
127    /**
128     * Changes this object according to the new pattern.
129     * The number of arguments checked against the given limits is the
130     * highest argument number plus one, not the number of occurrences of arguments.
131     *
132     * @param pattern The pattern string.
133     * @param min The pattern must have at least this many arguments.
134     * @param max The pattern must have at most this many arguments.
135     * @param errorCode ICU error code in/out parameter.
136     *                  Must fulfill U_SUCCESS before the function call.
137     *                  Set to U_ILLEGAL_ARGUMENT_ERROR for bad argument syntax and
138     *                  too few or too many arguments.
139     * @return TRUE if U_SUCCESS(errorCode).
140     * @draft ICU 57
141     */
142    UBool applyPatternMinMaxArguments(const UnicodeString &pattern,
143                                      int32_t min, int32_t max, UErrorCode &errorCode);
144
145    /**
146     * @return The max argument number + 1.
147     * @draft ICU 57
148     */
149    int32_t getArgumentLimit() const {
150        return getArgumentLimit(compiledPattern.getBuffer(), compiledPattern.length());
151    }
152
153    /**
154     * Formats the given value, appending to the appendTo builder.
155     * The argument value must not be the same object as appendTo.
156     * getArgumentLimit() must be at most 1.
157     *
158     * @param value0 Value for argument {0}.
159     * @param appendTo Gets the formatted pattern and value appended.
160     * @param errorCode ICU error code in/out parameter.
161     *                  Must fulfill U_SUCCESS before the function call.
162     * @return appendTo
163     * @draft ICU 57
164     */
165    UnicodeString &format(
166            const UnicodeString &value0,
167            UnicodeString &appendTo, UErrorCode &errorCode) const;
168
169    /**
170     * Formats the given values, appending to the appendTo builder.
171     * An argument value must not be the same object as appendTo.
172     * getArgumentLimit() must be at most 2.
173     *
174     * @param value0 Value for argument {0}.
175     * @param value1 Value for argument {1}.
176     * @param appendTo Gets the formatted pattern and values appended.
177     * @param errorCode ICU error code in/out parameter.
178     *                  Must fulfill U_SUCCESS before the function call.
179     * @return appendTo
180     * @draft ICU 57
181     */
182    UnicodeString &format(
183            const UnicodeString &value0,
184            const UnicodeString &value1,
185            UnicodeString &appendTo, UErrorCode &errorCode) const;
186
187    /**
188     * Formats the given values, appending to the appendTo builder.
189     * An argument value must not be the same object as appendTo.
190     * getArgumentLimit() must be at most 3.
191     *
192     * @param value0 Value for argument {0}.
193     * @param value1 Value for argument {1}.
194     * @param value2 Value for argument {2}.
195     * @param appendTo Gets the formatted pattern and values appended.
196     * @param errorCode ICU error code in/out parameter.
197     *                  Must fulfill U_SUCCESS before the function call.
198     * @return appendTo
199     * @draft ICU 57
200     */
201    UnicodeString &format(
202            const UnicodeString &value0,
203            const UnicodeString &value1,
204            const UnicodeString &value2,
205            UnicodeString &appendTo, UErrorCode &errorCode) const;
206
207    /**
208     * Formats the given values, appending to the appendTo string.
209     *
210     * @param values The argument values.
211     *               An argument value must not be the same object as appendTo.
212     *               Can be NULL if valuesLength==getArgumentLimit()==0.
213     * @param valuesLength The length of the values array.
214     *                     Must be at least getArgumentLimit().
215     * @param appendTo Gets the formatted pattern and values appended.
216     * @param offsets offsets[i] receives the offset of where
217     *                values[i] replaced pattern argument {i}.
218     *                Can be shorter or longer than values. Can be NULL if offsetsLength==0.
219     *                If there is no {i} in the pattern, then offsets[i] is set to -1.
220     * @param offsetsLength The length of the offsets array.
221     * @param errorCode ICU error code in/out parameter.
222     *                  Must fulfill U_SUCCESS before the function call.
223     * @return appendTo
224     * @draft ICU 57
225     */
226    UnicodeString &formatAndAppend(
227            const UnicodeString *const *values, int32_t valuesLength,
228            UnicodeString &appendTo,
229            int32_t *offsets, int32_t offsetsLength, UErrorCode &errorCode) const;
230
231    /**
232     * Formats the given values, replacing the contents of the result string.
233     * May optimize by actually appending to the result if it is the same object
234     * as the value corresponding to the initial argument in the pattern.
235     *
236     * @param values The argument values.
237     *               An argument value may be the same object as result.
238     *               Can be NULL if valuesLength==getArgumentLimit()==0.
239     * @param valuesLength The length of the values array.
240     *                     Must be at least getArgumentLimit().
241     * @param result Gets its contents replaced by the formatted pattern and values.
242     * @param offsets offsets[i] receives the offset of where
243     *                values[i] replaced pattern argument {i}.
244     *                Can be shorter or longer than values. Can be NULL if offsetsLength==0.
245     *                If there is no {i} in the pattern, then offsets[i] is set to -1.
246     * @param offsetsLength The length of the offsets array.
247     * @param errorCode ICU error code in/out parameter.
248     *                  Must fulfill U_SUCCESS before the function call.
249     * @return result
250     * @draft ICU 57
251     */
252    UnicodeString &formatAndReplace(
253            const UnicodeString *const *values, int32_t valuesLength,
254            UnicodeString &result,
255            int32_t *offsets, int32_t offsetsLength, UErrorCode &errorCode) const;
256
257    /**
258     * Returns the pattern text with none of the arguments.
259     * Like formatting with all-empty string values.
260     * @draft ICU 57
261     */
262    UnicodeString getTextWithNoArguments() const {
263        return getTextWithNoArguments(compiledPattern.getBuffer(), compiledPattern.length());
264    }
265
266private:
267    /**
268     * Binary representation of the compiled pattern.
269     * Index 0: One more than the highest argument number.
270     * Followed by zero or more arguments or literal-text segments.
271     *
272     * An argument is stored as its number, less than ARG_NUM_LIMIT.
273     * A literal-text segment is stored as its length (at least 1) offset by ARG_NUM_LIMIT,
274     * followed by that many chars.
275     */
276    UnicodeString compiledPattern;
277
278    static inline int32_t getArgumentLimit(const UChar *compiledPattern,
279                                              int32_t compiledPatternLength) {
280        return compiledPatternLength == 0 ? 0 : compiledPattern[0];
281    }
282
283    static UnicodeString getTextWithNoArguments(const UChar *compiledPattern, int32_t compiledPatternLength);
284
285    static UnicodeString &format(
286            const UChar *compiledPattern, int32_t compiledPatternLength,
287            const UnicodeString *const *values,
288            UnicodeString &result, const UnicodeString *resultCopy, UBool forbidResultAsValue,
289            int32_t *offsets, int32_t offsetsLength,
290            UErrorCode &errorCode);
291};
292
293U_NAMESPACE_END
294
295#endif /* U_HIDE_DRAFT_API */
296
297#endif  // __SIMPLEFORMATTER_H__
298