Arcane  4.1.12.0
Developer documentation
Loading...
Searching...
No Matches
StringVariableReplace.cc
1// -*- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature -*-
2//-----------------------------------------------------------------------------
3// Copyright 2000-2026 CEA (www.cea.fr) IFPEN (www.ifpenergiesnouvelles.com)
4// See the top-level COPYRIGHT file for details.
5// SPDX-License-Identifier: Apache-2.0
6//-----------------------------------------------------------------------------
7/*---------------------------------------------------------------------------*/
8/* StringVariableReplace.cc (C) 2000-2025 */
9/* */
10/* Class allowing symbols in a character string to be replaced by another */
11/* character string defined in the launch arguments. */
12/* A symbol is defined by a character string surrounded by @. */
13/* Example: @mon_symbole@ */
14/*---------------------------------------------------------------------------*/
15/*---------------------------------------------------------------------------*/
16
17#include "arcane/core/internal/StringVariableReplace.h"
18
19#include "arcane/utils/CommandLineArguments.h"
20#include "arcane/utils/PlatformUtils.h"
21#include "arcane/utils/SmallArray.h"
22#include "arcane/utils/StringBuilder.h"
23#include "arcane/utils/String.h"
24#include "arcane/utils/FatalErrorException.h"
25#include "arcane/utils/List.h"
26
27/*---------------------------------------------------------------------------*/
28/*---------------------------------------------------------------------------*/
29
30namespace Arcane
31{
32
33/*---------------------------------------------------------------------------*/
34/*---------------------------------------------------------------------------*/
35
36String StringVariableReplace::
37replaceWithCmdLineArgs(StringView string_with_symbols, bool fatal_if_not_found, bool fatal_if_invalid)
38{
39 StringList args;
41 const CommandLineArguments cla{ args };
42 ParameterListWithCaseOption parameters;
43 parameters.addParameters(cla.parameters());
44 return replaceWithCmdLineArgs(parameters, string_with_symbols, fatal_if_not_found, fatal_if_invalid);
45}
46
97String StringVariableReplace::
98replaceWithCmdLineArgs(const ParameterListWithCaseOption& parameter_list, StringView string_with_symbols,
99 bool fatal_if_not_found, bool fatal_if_invalid)
100{
101 // If the environment variable ARCANE_REPLACE_SYMBOLS_IN_DATASET is not
102 // defined, we do not modify the character string.
103 if (platform::getEnvironmentVariable("ARCANE_REPLACE_SYMBOLS_IN_DATASET").null() &&
104 parameter_list.getParameterOrNull("ARCANE_REPLACE_SYMBOLS_IN_DATASET").null()) {
105 return string_with_symbols;
106 }
107
108 if (string_with_symbols.empty())
109 return string_with_symbols;
110
111 Integer nb_at = 0;
112 Integer nb_at_with_escape = 0;
113
114 // At signs can be escaped. It is necessary to differentiate them to get
115 // the size of the segments array and to check the validity of the character string.
116 _countChar(string_with_symbols, '@', nb_at, nb_at_with_escape);
117 if (nb_at == 0 && nb_at_with_escape == 0)
118 return string_with_symbols;
119
120 // If the number of at signs is odd, there is necessarily an inconsistency.
121 if (fatal_if_invalid && nb_at % 2 == 1) {
122 ARCANE_FATAL("Invalid nb of @");
123 }
124
125 // An at sign separates the string into two segments. So the number of segments will
126 // be "nb_at + 1".
127 // We add the escaped at signs. These at signs are considered a special symbol and
128 // generate two segments (so "nb_at_with_escape * 2").
129 const Integer size_array_w_splits = (nb_at + 1) + (nb_at_with_escape * 2);
130
131 // In a valid case, the number of segments must be odd.
132 // In the case where the user disables fatal_if_invalid and the number of segments is even,
133 // the final segment should not be considered a symbol (see the loop below to understand).
134 const Integer max_index = size_array_w_splits % 2 == 0 ? size_array_w_splits - 1 : size_array_w_splits;
135
136 SmallArray<StringView> string_splited(size_array_w_splits);
137 _splitString(string_with_symbols, string_splited, '@');
138
139 StringBuilder combined{};
140
141 // In the array, segments with an odd position are the elements between at signs
142 // and thus symbols.
143 for (Integer i = 0; i < max_index; ++i) {
144 StringView part{ string_splited[i] };
145 if (part.empty())
146 continue;
147
148 // Segments with an even position are not symbols.
149 // We also handle the special case of escaped at signs.
150 if (i % 2 == 0 || part.bytes()[0] == '@') {
151 combined.append(part);
152 }
153 else {
154 String reference_input = parameter_list.getParameterOrNull(part);
155 if (reference_input.null()) {
156 if (fatal_if_not_found) {
157 ARCANE_FATAL("Symbol @{0}@ not found in the parameter list", part);
158 }
159 }
160 else {
161 combined.append(reference_input);
162 }
163 }
164 }
165
166 // In the case where the user disables fatal_if_invalid, the last segment
167 // is at an odd position but is not a symbol, so we add it here.
168 if (size_array_w_splits % 2 == 0) {
169 combined.append(string_splited[string_splited.size() - 1]);
170 }
171
172 return combined.toString();
173}
174
175/*---------------------------------------------------------------------------*/
176/*---------------------------------------------------------------------------*/
177
193_splitString(StringView str_view, ArrayView<StringView> str_view_array, char c)
194{
195 /*
196 aa@aa -> "aa", "aa" 2 (fatal_if_invalid)
197 @aa@aa@aa@ -> "", "aa", "aa", "aa", "" 5
198 @aa@@aa@ -> "", "aa", "", "aa", "" 5
199 @ -> "", "" 2 (fatal_if_invalid)
200 @aa@ -> "", "aa", "" 3
201 @aa@aa\@aa -> "", "aa", "aa", "@", "aa" 5
202 @aa@\@@aa@ -> "", "aa", "", "@", "", "aa", "" 7
203 @aa@@aa@ -> "", "aa", "", "aa", "" 5
204 \@aa -> "", "@", "aa" 3
205 @aa@aa@aa -> "", "aa", "aa", "aa" 4 (fatal_if_invalid)
206 @aa@aa -> "", "aa", "aa" 3
207 */
208
209 Span<const Byte> str_span = str_view.bytes();
210
211 Int64 offset = 0;
212 Int64 len = str_view.length();
213 Integer index = 0;
214 bool previous_backslash = false;
215
216 for (Int64 i = 0; i < len; ++i) {
217 // If we find an at sign.
218 if (str_span[i] == c) {
219 // If this at sign is preceded by a backslash.
220 if (previous_backslash) {
221 // We record the segment we were traversing, without the backslash.
222 str_view_array[index++] = str_view.subView(offset, i - 1 - offset);
223 // We add the at sign.
224 str_view_array[index++] = str_view.subView(i, 1);
225
226 offset = i + 1;
227 previous_backslash = false;
228 }
229 else {
230 // We record the segment we were traversing, without the at sign.
231 str_view_array[index++] = str_view.subView(offset, i - offset);
232
233 offset = i + 1;
234 }
235 }
236 // If we find a backslash.
237 else if (str_span[i] == '\\') {
238 // And if we had already found a backslash, we do nothing.
239 if (previous_backslash)
240 previous_backslash = false;
241 else
242 previous_backslash = true;
243 }
244 else {
245 previous_backslash = false;
246 }
247 }
248 // We add the last segment.
249 str_view_array[index] = str_view.subView(offset, len - offset);
250}
251
252/*---------------------------------------------------------------------------*/
253/*---------------------------------------------------------------------------*/
254
265_countChar(StringView str_view, char c, Integer& count_c, Integer& count_c_with_escape)
266{
267 count_c = 0;
268 count_c_with_escape = 0;
269 bool previous_backslash = false;
270
271 for (const Byte byte : str_view.bytes()) {
272 if (byte == c) {
273 if (previous_backslash) {
274 count_c_with_escape++;
275 previous_backslash = false;
276 }
277 else {
278 count_c++;
279 }
280 }
281 else if (byte == '\\') {
282 // If we had already found a backslash, we do nothing.
283 if (previous_backslash)
284 previous_backslash = false;
285 else
286 previous_backslash = true;
287 }
288 else {
289 previous_backslash = false;
290 }
291 }
292}
293
294/*---------------------------------------------------------------------------*/
295/*---------------------------------------------------------------------------*/
296
297} // namespace Arcane
298
299/*---------------------------------------------------------------------------*/
300/*---------------------------------------------------------------------------*/
#define ARCANE_FATAL(...)
Macro throwing a FatalErrorException.
Integer size() const
Number of elements in the vector.
Modifiable view of an array of type T.
Parameter list with information to override dataset options.
String getParameterOrNull(const String &param_name) const
Retrieves the parameter with name param_name.
1D data array with pre-allocated stack buffer.
View of an array of elements of type T.
Definition Span.h:635
Unicode character string constructor.
StringBuilder & append(const String &str)
Appends str.
String toString() const
Returns the constructed character string.
static void _countChar(StringView str_view, char c, Integer &count_c, Integer &count_c_with_escape)
Method allowing counting the number of separator characters in a character string.
static void _splitString(StringView str_view, ArrayView< StringView > str_view_array, char c)
Method allowing the string "str_view" to be split into multiple segments. The splits will occur betwe...
View of a UTF-8 character string.
Definition StringView.h:44
constexpr Span< const Byte > bytes() const ARCCORE_NOEXCEPT
Returns the conversion of the instance in UTF-8 encoding.
Definition StringView.h:93
constexpr Int64 length() const ARCCORE_NOEXCEPT
Length in bytes of the character string.
Definition StringView.h:96
StringView subView(Int64 pos) const
Substring starting at position pos.
Definition StringView.cc:37
constexpr bool empty() const ARCCORE_NOEXCEPT
True if the string is null or empty.
Definition StringView.h:102
bool null() const
Returns true if the string is null.
Definition String.cc:306
void fillCommandLineArguments(StringList &arg_list)
Fills arg_list with command line arguments.
String getEnvironmentVariable(const String &name)
Environment variable named name.
-- tab-width: 2; indent-tabs-mode: nil; coding: utf-8-with-signature --
std::int64_t Int64
Signed integer type of 64 bits.
Int32 Integer
Type representing an integer.
List< String > StringList
Unicode string list.
Definition UtilsTypes.h:509
unsigned char Byte
Type of a byte.
Definition BaseTypes.h:43