KCoreAddons

kmacroexpander.h
1 /*
2  This file is part of the KDE libraries
3 
4  SPDX-FileCopyrightText: 2002-2003 Oswald Buddenhagen <[email protected]>
5  SPDX-FileCopyrightText: 2003 Waldo Bastian <[email protected]>
6 
7  SPDX-License-Identifier: LGPL-2.0-or-later
8 */
9 #ifndef KMACROEXPANDER_H
10 #define KMACROEXPANDER_H
11 
12 #include <QChar>
13 #include <QStringList>
14 
15 #include <kcoreaddons_export.h>
16 #include <memory>
17 
18 class QString;
19 template<typename KT, typename VT>
20 class QHash;
21 class KMacroExpanderBasePrivate;
22 
23 /**
24  * \class KMacroExpanderBase kmacroexpander.h <KMacroExpander>
25  *
26  * Abstract base class for the worker classes behind the KMacroExpander namespace
27  * and the KCharMacroExpander and KWordMacroExpander classes.
28  *
29  * @author Oswald Buddenhagen <[email protected]>
30  */
31 class KCOREADDONS_EXPORT KMacroExpanderBase
32 {
33 public:
34  /**
35  * Constructor.
36  * @param c escape char indicating start of macros, or QChar::null for none
37  */
38  explicit KMacroExpanderBase(QChar c = QLatin1Char('%'));
39 
40  /**
41  * Destructor.
42  */
43  virtual ~KMacroExpanderBase();
44 
45  /**
46  * Perform safe macro expansion (substitution) on a string.
47  *
48  * @param str the string in which macros are expanded in-place
49  */
50  void expandMacros(QString &str);
51 
52  // TODO: This documentation is relevant for end-users. Where to put it?
53  /**
54  * Perform safe macro expansion (substitution) on a string for use
55  * in shell commands.
56  *
57  * <h3>*NIX notes</h3>
58  *
59  * Explicitly supported shell constructs:
60  * \ '' "" $'' $"" {} () $(()) ${} $() ``
61  *
62  * Implicitly supported shell constructs:
63  * (())
64  *
65  * Unsupported shell constructs that will cause problems:
66  * Shortened &quot;<tt>case $v in pat)</tt>&quot; syntax. Use
67  * &quot;<tt>case $v in (pat)</tt>&quot; instead.
68  *
69  * The rest of the shell (incl. bash) syntax is simply ignored,
70  * as it is not expected to cause problems.
71  *
72  * Note that bash contains a bug which makes macro expansion within
73  * double quoted substitutions (<tt>"${VAR:-%macro}"</tt>) inherently
74  * insecure.
75  *
76  * For security reasons, @em never put expandos in command line arguments
77  * that are shell commands by themselves -
78  * &quot;<tt>sh -c 'foo \%f'</tt>&quot; is taboo.
79  * &quot;<tt>file=\%f sh -c 'foo "$file"'</tt>&quot; is OK.
80  *
81  * <h3>Windows notes</h3>
82  *
83  * All quoting syntax supported by KShell is supported here as well.
84  * Additionally, command grouping via parentheses is recognized - note
85  * however, that the parser is much stricter about unquoted parentheses
86  * than cmd itself.
87  * The rest of the cmd syntax is simply ignored, as it is not expected
88  * to cause problems - do not use commands that embed other commands,
89  * though - &quot;<tt>for /f ...</tt>&quot; is taboo.
90  *
91  * @param str the string in which macros are expanded in-place
92  * @param pos the position inside the string at which parsing/substitution
93  * should start, and upon exit where processing stopped
94  * @return false if the string could not be parsed and therefore no safe
95  * substitution was possible. Note that macros will have been processed
96  * up to the point where the error occurred. An unmatched closing paren
97  * or brace outside any shell construct is @em not an error (unlike in
98  * the function below), but still prematurely terminates processing.
99  */
100  bool expandMacrosShellQuote(QString &str, int &pos);
101 
102  /**
103  * Same as above, but always starts at position 0, and unmatched closing
104  * parens and braces are treated as errors.
105  */
106  bool expandMacrosShellQuote(QString &str);
107 
108  /**
109  * Set the macro escape character.
110  * @param c escape char indicating start of macros, or QChar::null if none
111  */
112  void setEscapeChar(QChar c);
113 
114  /**
115  * Obtain the macro escape character.
116  * @return escape char indicating start of macros, or QChar::null if none
117  */
118  QChar escapeChar() const;
119 
120 protected:
121  /**
122  * This function is called for every single char within the string if
123  * the escape char is QChar::null. It should determine whether the
124  * string starting at @p pos within @p str is a valid macro and return
125  * the substitution value for it if so.
126  * @param str the input string
127  * @param pos the offset within @p str
128  * @param ret return value: the string to substitute for the macro
129  * @return If greater than zero, the number of chars at @p pos in @p str
130  * to substitute with @p ret (i.e., a valid macro was found). If less
131  * than zero, subtract this value from @p pos (to skip a macro, i.e.,
132  * substitute it with itself). If zero, no macro starts at @p pos.
133  */
134  virtual int expandPlainMacro(const QString &str, int pos, QStringList &ret);
135 
136  /**
137  * This function is called every time the escape char is found if it is
138  * not QChar::null. It should determine whether the
139  * string starting at @p pos witin @p str is a valid macro and return
140  * the substitution value for it if so.
141  * @param str the input string
142  * @param pos the offset within @p str. Note that this is the position of
143  * the occurrence of the escape char
144  * @param ret return value: the string to substitute for the macro
145  * @return If greater than zero, the number of chars at @p pos in @p str
146  * to substitute with @p ret (i.e., a valid macro was found). If less
147  * than zero, subtract this value from @p pos (to skip a macro, i.e.,
148  * substitute it with itself). If zero, scanning continues as if no
149  * escape char was encountered at all.
150  */
151  virtual int expandEscapedMacro(const QString &str, int pos, QStringList &ret);
152 
153 private:
154  std::unique_ptr<KMacroExpanderBasePrivate> const d;
155 };
156 
157 /**
158  * \class KWordMacroExpander kmacroexpander.h <KMacroExpanderBase>
159  *
160  * Abstract base class for simple word macro substitutors. Use this instead of
161  * the functions in the KMacroExpander namespace if speculatively pre-filling
162  * the substitution map would be too expensive.
163  *
164  * A typical application:
165  *
166  * \code
167  * class MyClass {
168  * ...
169  * private:
170  * QString m_str;
171  * ...
172  * friend class MyExpander;
173  * };
174  *
175  * class MyExpander : public KWordMacroExpander {
176  * public:
177  * MyExpander( MyClass *_that ) : KWordMacroExpander(), that( _that ) {}
178  * protected:
179  * virtual bool expandMacro( const QString &str, QStringList &ret );
180  * private:
181  * MyClass *that;
182  * };
183  *
184  * bool MyExpander::expandMacro( const QString &str, QStringList &ret )
185  * {
186  * if (str == "macro") {
187  * ret += complexOperation( that->m_str );
188  * return true;
189  * }
190  * return false;
191  * }
192  *
193  * ... MyClass::...(...)
194  * {
195  * QString str;
196  * ...
197  * MyExpander mx( this );
198  * mx.expandMacrosShellQuote( str );
199  * ...
200  * }
201  * \endcode
202  *
203  * Alternatively MyClass could inherit from KWordMacroExpander directly.
204  *
205  * @author Oswald Buddenhagen <[email protected]>
206  */
207 class KCOREADDONS_EXPORT KWordMacroExpander : public KMacroExpanderBase
208 {
209 public:
210  /**
211  * Constructor.
212  * @param c escape char indicating start of macros, or QChar::null for none
213  */
215  : KMacroExpanderBase(c)
216  {
217  }
218 
219 protected:
220  /** \internal Not to be called or reimplemented. */
221  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
222  /** \internal Not to be called or reimplemented. */
223  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
224 
225  /**
226  * Return substitution list @p ret for string macro @p str.
227  * @param str the macro to expand
228  * @param ret return variable reference. It is guaranteed to be empty
229  * when expandMacro is entered.
230  * @return @c true iff @p str was a recognized macro name
231  */
232  virtual bool expandMacro(const QString &str, QStringList &ret) = 0;
233 };
234 
235 /**
236  * \class KCharMacroExpander kmacroexpander.h <KMacroExpanderBase>
237  *
238  * Abstract base class for single char macro substitutors. Use this instead of
239  * the functions in the KMacroExpander namespace if speculatively pre-filling
240  * the substitution map would be too expensive.
241  *
242  * See KWordMacroExpander for a sample application.
243  *
244  * @author Oswald Buddenhagen <[email protected]>
245  */
246 class KCOREADDONS_EXPORT KCharMacroExpander : public KMacroExpanderBase
247 {
248 public:
249  /**
250  * Constructor.
251  * @param c escape char indicating start of macros, or QChar::null for none
252  */
254  : KMacroExpanderBase(c)
255  {
256  }
257 
258 protected:
259  /** \internal Not to be called or reimplemented. */
260  int expandPlainMacro(const QString &str, int pos, QStringList &ret) override;
261  /** \internal Not to be called or reimplemented. */
262  int expandEscapedMacro(const QString &str, int pos, QStringList &ret) override;
263 
264  /**
265  * Return substitution list @p ret for single-character macro @p chr.
266  * @param chr the macro to expand
267  * @param ret return variable reference. It is guaranteed to be empty
268  * when expandMacro is entered.
269  * @return @c true iff @p chr was a recognized macro name
270  */
271  virtual bool expandMacro(QChar chr, QStringList &ret) = 0;
272 };
273 
274 /**
275  * A group of functions providing macro expansion (substitution) in strings,
276  * optionally with quoting appropriate for shell execution.
277  */
278 namespace KMacroExpander
279 {
280 /**
281  * Perform safe macro expansion (substitution) on a string.
282  * The escape char must be quoted with itself to obtain its literal
283  * representation in the resulting string.
284  *
285  * @param str The string to expand
286  * @param map map with substitutions
287  * @param c escape char indicating start of macro, or QChar::null if none
288  * @return the string with all valid macros expanded
289  *
290  * \code
291  * // Code example
292  * QHash<QChar,QString> map;
293  * map.insert('u', "/tmp/myfile.txt");
294  * map.insert('n', "My File");
295  * QString s = "%% Title: %u:%n";
296  * s = KMacroExpander::expandMacros(s, map);
297  * // s is now "% Title: /tmp/myfile.txt:My File";
298  * \endcode
299  */
300 KCOREADDONS_EXPORT QString expandMacros(const QString &str, const QHash<QChar, QString> &map, QChar c = QLatin1Char('%'));
301 
302 /**
303  * Perform safe macro expansion (substitution) on a string for use
304  * in shell commands.
305  * The escape char must be quoted with itself to obtain its literal
306  * representation in the resulting string.
307  *
308  * @param str The string to expand
309  * @param map map with substitutions
310  * @param c escape char indicating start of macro, or QChar::null if none
311  * @return the string with all valid macros expanded, or a null string
312  * if a shell syntax error was detected in the command
313  *
314  * \code
315  * // Code example
316  * QHash<QChar,QString> map;
317  * map.insert('u', "/tmp/myfile.txt");
318  * map.insert('n', "My File");
319  * QString s = "kwrite --qwindowtitle %n %u";
320  * s = KMacroExpander::expandMacrosShellQuote(s, map);
321  * // s is now "kwrite --qwindowtitle 'My File' '/tmp/myfile.txt'";
322  * system(QFile::encodeName(s));
323  * \endcode
324  */
325 KCOREADDONS_EXPORT QString expandMacrosShellQuote(const QString &str, const QHash<QChar, QString> &map, QChar c = QLatin1Char('%'));
326 
327 /**
328  * Perform safe macro expansion (substitution) on a string.
329  * The escape char must be quoted with itself to obtain its literal
330  * representation in the resulting string.
331  * Macro names can consist of chars in the range [A-Za-z0-9_];
332  * use braces to delimit macros from following words starting
333  * with these chars, or to use other chars for macro names.
334  *
335  * @param str The string to expand
336  * @param map map with substitutions
337  * @param c escape char indicating start of macro, or QChar::null if none
338  * @return the string with all valid macros expanded
339  *
340  * \code
341  * // Code example
342  * QHash<QString,QString> map;
343  * map.insert("url", "/tmp/myfile.txt");
344  * map.insert("name", "My File");
345  * QString s = "Title: %{url}-%name";
346  * s = KMacroExpander::expandMacros(s, map);
347  * // s is now "Title: /tmp/myfile.txt-My File";
348  * \endcode
349  */
350 KCOREADDONS_EXPORT QString expandMacros(const QString &str, const QHash<QString, QString> &map, QChar c = QLatin1Char('%'));
351 
352 /**
353  * Perform safe macro expansion (substitution) on a string for use
354  * in shell commands. See KMacroExpanderBase::expandMacrosShellQuote()
355  * for the exact semantics.
356  * The escape char must be quoted with itself to obtain its literal
357  * representation in the resulting string.
358  * Macro names can consist of chars in the range [A-Za-z0-9_];
359  * use braces to delimit macros from following words starting
360  * with these chars, or to use other chars for macro names.
361  *
362  * @param str The string to expand
363  * @param map map with substitutions
364  * @param c escape char indicating start of macro, or QChar::null if none
365  * @return the string with all valid macros expanded, or a null string
366  * if a shell syntax error was detected in the command
367  *
368  * \code
369  * // Code example
370  * QHash<QString,QString> map;
371  * map.insert("url", "/tmp/myfile.txt");
372  * map.insert("name", "My File");
373  * QString s = "kwrite --qwindowtitle %name %{url}";
374  * s = KMacroExpander::expandMacrosShellQuote(s, map);
375  * // s is now "kwrite --qwindowtitle 'My File' '/tmp/myfile.txt'";
376  * system(QFile::encodeName(s));
377  * \endcode
378  */
379 KCOREADDONS_EXPORT QString expandMacrosShellQuote(const QString &str, const QHash<QString, QString> &map, QChar c = QLatin1Char('%'));
380 
381 /**
382  * Same as above, except that the macros expand to string lists that
383  * are simply join(" ")ed together.
384  */
385 KCOREADDONS_EXPORT QString expandMacros(const QString &str, const QHash<QChar, QStringList> &map, QChar c = QLatin1Char('%'));
386 KCOREADDONS_EXPORT QString expandMacros(const QString &str, const QHash<QString, QStringList> &map, QChar c = QLatin1Char('%'));
387 
388 /**
389  * Same as above, except that the macros expand to string lists.
390  * If the macro appears inside a quoted string, the list is simply
391  * join(" ")ed together; otherwise every element expands to a separate
392  * quoted string.
393  */
394 KCOREADDONS_EXPORT QString expandMacrosShellQuote(const QString &str, const QHash<QChar, QStringList> &map, QChar c = QLatin1Char('%'));
395 KCOREADDONS_EXPORT QString expandMacrosShellQuote(const QString &str, const QHash<QString, QStringList> &map, QChar c = QLatin1Char('%'));
396 }
397 
398 #endif /* KMACROEXPANDER_H */
A group of functions providing macro expansion (substitution) in strings, optionally with quoting app...
QString expandMacros(const QString &ostr, const QHash< QChar, QString > &map, QChar c)
Perform safe macro expansion (substitution) on a string.
QString expandMacrosShellQuote(const QString &ostr, const QHash< QChar, QString > &map, QChar c)
Perform safe macro expansion (substitution) on a string for use in shell commands.
KCharMacroExpander(QChar c=QLatin1Char('%'))
Constructor.
virtual int expandEscapedMacro(const QString &str, int pos, QStringList &ret)
This function is called every time the escape char is found if it is not QChar::null.
KWordMacroExpander(QChar c=QLatin1Char('%'))
Constructor.
virtual int expandPlainMacro(const QString &str, int pos, QStringList &ret)
This function is called for every single char within the string if the escape char is QChar::null.
This file is part of the KDE documentation.
Documentation copyright © 1996-2023 The KDE developers.
Generated on Mon May 8 2023 04:04:52 by doxygen 1.8.17 written by Dimitri van Heesch, © 1997-2006

KDE's Doxygen guidelines are available online.