summaryrefslogtreecommitdiffstats
path: root/tdecore/kmacroexpander.h
blob: 73537a11a479eb8240d5abae6e91cebb6546b4da (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
335
336
337
338
339
340
341
342
343
344
345
346
347
348
349
350
351
352
353
354
355
356
357
358
359
360
361
362
363
364
365
366
367
368
369
370
371
372
373
374
375
376
377
378
379
380
/*
    This file is part of the KDE libraries

    Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
    Copyright (c) 2003 Waldo Bastian <bastian@kde.org>

    This library is free software; you can redistribute it and/or
    modify it under the terms of the GNU Library General Public
    License as published by the Free Software Foundation; either
    version 2 of the License, or (at your option) any later version.

    This library is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
    Library General Public License for more details.

    You should have received a copy of the GNU Library General Public License
    along with this library; see the file COPYING.LIB.  If not, write to
    the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
    Boston, MA 02110-1301, USA.
*/
#ifndef _KMACROEXPANDER_H
#define _KMACROEXPANDER_H

#include <tqstringlist.h>
#include <tqstring.h>
#include <tqmap.h>
#include "tdelibs_export.h"

/**
 * Abstract base class for the worker classes behind the KMacroExpander namespace
 * and the KCharMacroExpander and KWordMacroExpander classes.
 *
 * @since 3.1.3
 * @author Oswald Buddenhagen <ossi@kde.org>
 */
class TDECORE_EXPORT KMacroExpanderBase {

public:
    /**
     * Constructor.
     * @param c escape char indicating start of macros, or TQChar::null for none
     */
    KMacroExpanderBase( TQChar c = '%' );

    /**
     * Destructor.
     */
    virtual ~KMacroExpanderBase();

    /**
     * Perform safe macro expansion (substitution) on a string.
     *
     * @param str the string in which macros are expanded in-place
     */
    void expandMacros( TQString &str );

    /*
     * Perform safe macro expansion (substitution) on a string for use
     * in shell commands.
     *
     * Explicitly supported shell constructs:
     *   \ '' "" $'' $"" {} () $(()) ${} $() ``
     *
     * Implicitly supported shell constructs:
     *   (())
     *
     * Unsupported shell constructs that will cause problems:
     *  @li Shortened "case $v in pat)" syntax. Use "case $v in (pat)" instead.
     *
     * The rest of the shell (incl. bash) syntax is simply ignored,
     * as it is not expected to cause problems.
     *
     * Note that bash contains a bug which makes macro expansion within 
     * double quoted substitutions ("${VAR:-%macro}") inherently insecure.
     *
     * @param str the string in which macros are expanded in-place
     * @param pos the position inside the string at which parsing/substitution
     *  should start, and upon exit where processing stopped
     * @return false if the string could not be parsed and therefore no safe
     *  substitution was possible. Note that macros will have been processed
     *  up to the point where the error occurred. An unmatched closing paren
     *  or brace outside any shell construct is @em not an error (unlike in
     *  the function below), but still prematurely terminates processing.
     */
    bool expandMacrosShellQuote( TQString &str, uint &pos );

    /**
     * Same as above, but always starts at position 0, and unmatched closing
     * parens and braces are treated as errors.
     */
    bool expandMacrosShellQuote( TQString &str );

    /**
     * Set the macro escape character.
     * @param c escape char indicating start of macros, or TQChar::null if none
     */
    void setEscapeChar( TQChar c );

    /**
     * Obtain the macro escape character.
     * @return escape char indicating start of macros, or TQChar::null if none
     */
    TQChar escapeChar() const;

protected:
    /**
     * This function is called for every single char within the string if
     * the escape char is TQChar::null. It should determine whether the
     * string starting at @p pos within @p str is a valid macro and return
     * the substitution value for it if so.
     * @param str the input string
     * @param pos the offset within @p str
     * @param ret return value: the string to substitute for the macro
     * @return if greater than zero, the number of chars at @p pos in @p str
     *  to substitute with @p ret (i.e., a valid macro was found). if less
     *  than zero, subtract this value from @p pos (to skip a macro, i.e.,
     *  substitute it with itself). zero requests no special action.
     */
    virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );

    /**
     * This function is called every time the escape char is found if it is
     * not TQChar::null. It should determine whether the
     * string starting at @p pos witin @p str is a valid macro and return
     * the substitution value for it if so.
     * @param str the input string
     * @param pos the offset within @p str. Note that this is the position of
     *  the occurrence of the escape char
     * @param ret return value: the string to substitute for the macro
     * @return if greater than zero, the number of chars at @p pos in @p str
     *  to substitute with @p ret (i.e., a valid macro was found). if less
     *  than zero, subtract this value from @p pos (to skip a macro, i.e.,
     *  substitute it with itself). zero requests no special action.
     */
    virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );

private:
    TQChar escapechar;
};

/**
 * Abstract base class for simple word macro substitutors. Use this instead of
 * the functions in the KMacroExpander namespace if speculatively pre-filling
 * the substitution map would be too expensive.
 *
 * A typical application:
 *
 * \code
 * class MyClass {
 * ...
 *   private:
 *     TQString m_str;
 * ...
 *   friend class MyExpander;
 * };
 *
 * class MyExpander : public KWordMacroExpander {
 *   public:
 *     MyExpander( MyClass *_that ) : KWordMacroExpander(), that( _that ) {}
 *   protected:
 *     virtual bool expandMacro( const TQString &str, TQStringList &ret );
 *   private:
 *     MyClass *that;
 * };
 *
 * bool MyExpander::expandMacro( const TQString &str, TQStringList &ret )
 * {
 *   if (str == "macro") {
 *     ret += complexOperation( that->m_str );
 *     return true;
 *   }
 *   return false;
 * }
 *
 * ... MyClass::...(...)
 * {
 *   TQString str;
 *   ...
 *   MyExpander mx( this );
 *   mx.expandMacrosShellQuote( str );
 *   ...
 * }
 * \endcode
 *
 * Alternatively MyClass could inherit from KWordMacroExpander directly.
 *
 * @since 3.3
 * @author Oswald Buddenhagen <ossi@kde.org>
 */
class TDECORE_EXPORT KWordMacroExpander : public KMacroExpanderBase {

public:
    /**
     * Constructor.
     * @param c escape char indicating start of macros, or TQChar::null for none
     */
    KWordMacroExpander( TQChar c = '%' ) : KMacroExpanderBase( c ) {}

protected:
    virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
    virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );

    /**
     * Return substitution list @p ret for string macro @p str.
     * @param str the macro to expand
     * @param ret return variable reference. It is guaranteed to be empty
     *  when expandMacro is entered.
     * @return @c true iff @p chr was a recognized macro name
     */
    virtual bool expandMacro( const TQString &str, TQStringList &ret ) = 0;
};

/**
 * Abstract base class for single char macro substitutors. Use this instead of
 * the functions in the KMacroExpander namespace if speculatively pre-filling
 * the substitution map would be too expensive.
 *
 * See KWordMacroExpander for a sample application.
 *
 * @since 3.3
 * @author Oswald Buddenhagen <ossi@kde.org>
 */
class TDECORE_EXPORT KCharMacroExpander : public KMacroExpanderBase {

public:
    /**
     * Constructor.
     * @param c escape char indicating start of macros, or TQChar::null for none
     */
    KCharMacroExpander( TQChar c = '%' ) : KMacroExpanderBase( c ) {}

protected:
    virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
    virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );

    /**
     * Return substitution list @p ret for single-character macro @p chr.
     * @param chr the macro to expand
     * @param ret return variable reference. It is guaranteed to be empty
     *  when expandMacro is entered.
     * @return @c true iff @p chr was a recognized macro name
     */
    virtual bool expandMacro( TQChar chr, TQStringList &ret ) = 0;
};

/**
 * A group of functions providing macro expansion (substitution) in strings,
 * optionally with quoting appropriate for shell execution.
 * @since 3.1.3
 */
namespace KMacroExpander {
    /**
     * Perform safe macro expansion (substitution) on a string.
     * The escape char must be quoted with itself to obtain its literal
     * representation in the resulting string.
     *
     * @param str The string to expand
     * @param map map with substitutions
     * @param c escape char indicating start of macro, or TQChar::null if none
     * @return the string with all valid macros expanded
     *
     * \code
     * // Code example
     * TQMap<TQChar,TQString> map;
     * map.insert('u', "/tmp/myfile.txt");
     * map.insert('n', "My File");
     * TQString s = "%% Title: %u:%n";
     * s = KMacroExpander::expandMacros(s, map);
     * // s is now "% Title: /tmp/myfile.txt:My File";
     * \endcode
     */
    TDECORE_EXPORT TQString expandMacros( const TQString &str, const TQMap<TQChar,TQString> &map, TQChar c = '%' );

    /**
     * Perform safe macro expansion (substitution) on a string for use
     * in shell commands.
     * The escape char must be quoted with itself to obtain its literal
     * representation in the resulting string.
     *
     * @param str The string to expand
     * @param map map with substitutions
     * @param c escape char indicating start of macro, or TQChar::null if none
     * @return the string with all valid macros expanded, or a null string
     *  if a shell syntax error was detected in the command
     *
     * \code
     * // Code example
     * TQMap<TQChar,TQString> map;
     * map.insert('u', "/tmp/myfile.txt");
     * map.insert('n', "My File");
     * TQString s = "kedit --caption %n %u";
     * s = KMacroExpander::expandMacrosShellQuote(s, map);
     * // s is now "kedit --caption 'My File' '/tmp/myfile.txt'";
     * system(TQFile::encodeName(s));
     * \endcode
     */
    TDECORE_EXPORT TQString expandMacrosShellQuote( const TQString &str, const TQMap<TQChar,TQString> &map, TQChar c = '%' );

    /**
     * Perform safe macro expansion (substitution) on a string.
     * The escape char must be quoted with itself to obtain its literal
     * representation in the resulting string.
     * Macro names can consist of chars in the range [A-Za-z0-9_];
     * use braces to delimit macros from following words starting
     * with these chars, or to use other chars for macro names.
     *
     * @param str The string to expand
     * @param map map with substitutions
     * @param c escape char indicating start of macro, or TQChar::null if none
     * @return the string with all valid macros expanded
     *
     * \code
     * // Code example
     * TQMap<TQString,TQString> map;
     * map.insert("url", "/tmp/myfile.txt");
     * map.insert("name", "My File");
     * TQString s = "Title: %{url}-%name";
     * s = KMacroExpander::expandMacros(s, map);
     * // s is now "Title: /tmp/myfile.txt-My File";
     * \endcode
     */
    TDECORE_EXPORT TQString expandMacros( const TQString &str, const TQMap<TQString,TQString> &map, TQChar c = '%' );

    /**
     * Perform safe macro expansion (substitution) on a string for use
     * in shell commands.
     * The escape char must be quoted with itself to obtain its literal
     * representation in the resulting string.
     * Macro names can consist of chars in the range [A-Za-z0-9_];
     * use braces to delimit macros from following words starting
     * with these chars, or to use other chars for macro names.
     *
     * @param str The string to expand
     * @param map map with substitutions
     * @param c escape char indicating start of macro, or TQChar::null if none
     * @return the string with all valid macros expanded, or a null string
     *  if a shell syntax error was detected in the command
     *
     * \code
     * // Code example
     * TQMap<TQString,TQString> map;
     * map.insert("url", "/tmp/myfile.txt");
     * map.insert("name", "My File");
     * TQString s = "kedit --caption %name %{url}";
     * s = KMacroExpander::expandMacrosShellQuote(s, map);
     * // s is now "kedit --caption 'My File' '/tmp/myfile.txt'";
     * system(TQFile::encodeName(s));
     * \endcode
     */
    TDECORE_EXPORT TQString expandMacrosShellQuote( const TQString &str, const TQMap<TQString,TQString> &map, TQChar c = '%' );

    /**
     * Same as above, except that the macros expand to string lists that
     * are simply join(" ")ed together.
     */
    TDECORE_EXPORT TQString expandMacros( const TQString &str, const TQMap<TQChar,TQStringList> &map, TQChar c = '%' );
    /**
     * Same as above, except that the macros expand to string lists that
     * are simply join(" ")ed together.
     */
    TDECORE_EXPORT TQString expandMacros( const TQString &str, const TQMap<TQString,TQStringList> &map, TQChar c = '%' );

    /**
     * Same as above, except that the macros expand to string lists.
     * If the macro appears inside a quoted string, the list is simply
     * join(" ")ed together; otherwise every element expands to a separate
     * quoted string.
     */
    TDECORE_EXPORT TQString expandMacrosShellQuote( const TQString &str, const TQMap<TQChar,TQStringList> &map, TQChar c = '%' );
    /**
     * Same as above, except that the macros expand to string lists.
     * If the macro appears inside a quoted string, the list is simply
     * join(" ")ed together; otherwise every element expands to a separate
     * quoted string.
     */
    TDECORE_EXPORT TQString expandMacrosShellQuote( const TQString &str, const TQMap<TQString,TQStringList> &map, TQChar c = '%' );
}

#endif /* _KMACROEXPANDER_H */