• Skip to content
  • Skip to link menu
Trinity API Reference
  • Trinity API Reference
  • tdecore
 

tdecore

  • tdecore
kmacroexpander.cpp
1/*
2 This file is part of the KDE libraries
3
4 Copyright (c) 2002-2003 Oswald Buddenhagen <ossi@kde.org>
5 Copyright (c) 2003 Waldo Bastian <bastian@kde.org>
6
7 This library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public
9 License as published by the Free Software Foundation; either
10 version 2 of the License, or (at your option) any later version.
11
12 This library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public License
18 along with this library; see the file COPYING.LIB. If not, write to
19 the Free Software Foundation, Inc., 51 Franklin Street, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21*/
22
23#include <kmacroexpander.h>
24
25#include <tqvaluestack.h>
26#include <tqregexp.h>
27
28KMacroExpanderBase::KMacroExpanderBase( TQChar c )
29{
30 escapechar = c;
31}
32
33KMacroExpanderBase::~KMacroExpanderBase()
34{
35}
36
37void
38KMacroExpanderBase::setEscapeChar( TQChar c )
39{
40 escapechar = c;
41}
42
43TQChar
44KMacroExpanderBase::escapeChar() const
45{
46 return escapechar;
47}
48
49void KMacroExpanderBase::expandMacros( TQString &str )
50{
51 uint pos;
52 int len;
53 TQChar ec( escapechar );
54 TQStringList rst;
55 TQString rsts;
56
57 for (pos = 0; pos < str.length(); ) {
58 if (ec != (TQChar)0) {
59 if (str.unicode()[pos] != ec)
60 goto nohit;
61 if (!(len = expandEscapedMacro( str, pos, rst )))
62 goto nohit;
63 } else {
64 if (!(len = expandPlainMacro( str, pos, rst )))
65 goto nohit;
66 }
67 if (len < 0) {
68 pos -= len;
69 continue;
70 }
71 rsts = rst.join( " " );
72 rst.clear();
73 str.replace( pos, len, rsts );
74 pos += rsts.length();
75 continue;
76 nohit:
77 pos++;
78 }
79}
80
81
82namespace KMacroExpander {
83
85 enum Quoting { noquote, singlequote, doublequote, dollarquote,
86 paren, subst, group, math };
87 typedef struct {
88 Quoting current;
89 bool dquote;
90 } State;
91 typedef struct {
92 TQString str;
93 uint pos;
94 } Save;
95
96}
97
98using namespace KMacroExpander;
99
100bool KMacroExpanderBase::expandMacrosShellQuote( TQString &str, uint &pos )
101{
102 int len;
103 uint pos2;
104 TQChar ec( escapechar );
105 State state = { noquote, false };
106 TQValueStack<State> sstack;
107 TQValueStack<Save> ostack;
108 TQStringList rst;
109 TQString rsts;
110
111 while (pos < str.length()) {
112 TQChar cc( str.unicode()[pos] );
113 if (ec != (TQChar)0) {
114 if (cc != ec)
115 goto nohit;
116 if (!(len = expandEscapedMacro( str, pos, rst )))
117 goto nohit;
118 } else {
119 if (!(len = expandPlainMacro( str, pos, rst )))
120 goto nohit;
121 }
122 if (len < 0) {
123 pos -= len;
124 continue;
125 }
126 if (state.dquote) {
127 rsts = rst.join( " " );
128 rsts.replace( TQRegExp("([$`\"\\\\])"), "\\\\1" );
129 } else if (state.current == dollarquote) {
130 rsts = rst.join( " " );
131 rsts.replace( TQRegExp("(['\\\\])"), "\\\\1" );
132 } else if (state.current == singlequote) {
133 rsts = rst.join( " " );
134 rsts.replace( '\'', "'\\''");
135 } else {
136 if (rst.isEmpty()) {
137 str.remove( pos, len );
138 continue;
139 } else {
140 rsts = "'";
141#if 0 // this could pay off if join() would be cleverer and the strings were long
142 for (TQStringList::Iterator it = rst.begin(); it != rst.end(); ++it)
143 (*it).replace( '\'', "'\\''" );
144 rsts += rst.join( "' '" );
145#else
146 for (TQStringList::ConstIterator it = rst.begin(); it != rst.end(); ++it) {
147 if (it != rst.begin())
148 rsts += "' '";
149 TQString trsts( *it );
150 trsts.replace( '\'', "'\\''" );
151 rsts += trsts;
152 }
153#endif
154 rsts += "'";
155 }
156 }
157 rst.clear();
158 str.replace( pos, len, rsts );
159 pos += rsts.length();
160 continue;
161 nohit:
162 if (state.current == singlequote) {
163 if (cc == (TQChar)'\'')
164 state = sstack.pop();
165 } else if (cc == (TQChar)'\\') {
166 // always swallow the char -> prevent anomalies due to expansion
167 pos += 2;
168 continue;
169 } else if (state.current == dollarquote) {
170 if (cc == (TQChar)'\'')
171 state = sstack.pop();
172 } else if (cc == (TQChar)'$') {
173 cc = str[++pos];
174 if (cc == (TQChar)'(') {
175 sstack.push( state );
176 if (str[pos + 1] == (TQChar)'(') {
177 Save sav = { str, pos + 2 };
178 ostack.push( sav );
179 state.current = math;
180 pos += 2;
181 continue;
182 } else {
183 state.current = paren;
184 state.dquote = false;
185 }
186 } else if (cc == (TQChar)'{') {
187 sstack.push( state );
188 state.current = subst;
189 } else if (!state.dquote) {
190 if (cc == (TQChar)'\'') {
191 sstack.push( state );
192 state.current = dollarquote;
193 } else if (cc == (TQChar)'"') {
194 sstack.push( state );
195 state.current = doublequote;
196 state.dquote = true;
197 }
198 }
199 // always swallow the char -> prevent anomalies due to expansion
200 } else if (cc == (TQChar)'`') {
201 str.replace( pos, 1, "$( " ); // add space -> avoid creating $((
202 pos2 = pos += 3;
203 for (;;) {
204 if (pos2 >= str.length()) {
205 pos = pos2;
206 return false;
207 }
208 cc = str.unicode()[pos2];
209 if (cc == (TQChar)'`')
210 break;
211 if (cc == (TQChar)'\\') {
212 cc = str[++pos2];
213 if (cc == (TQChar)'$' || cc == (TQChar)'`' || cc == (TQChar)'\\' ||
214 (cc == (TQChar)'"' && state.dquote))
215 {
216 str.remove( pos2 - 1, 1 );
217 continue;
218 }
219 }
220 pos2++;
221 }
222 str[pos2] = ')';
223 sstack.push( state );
224 state.current = paren;
225 state.dquote = false;
226 continue;
227 } else if (state.current == doublequote) {
228 if (cc == (TQChar)'"')
229 state = sstack.pop();
230 } else if (cc == (TQChar)'\'') {
231 if (!state.dquote) {
232 sstack.push( state );
233 state.current = singlequote;
234 }
235 } else if (cc == (TQChar)'"') {
236 if (!state.dquote) {
237 sstack.push( state );
238 state.current = doublequote;
239 state.dquote = true;
240 }
241 } else if (state.current == subst) {
242 if (cc == (TQChar)'}')
243 state = sstack.pop();
244 } else if (cc == (TQChar)')') {
245 if (state.current == math) {
246 if (str[pos + 1] == (TQChar)')') {
247 state = sstack.pop();
248 pos += 2;
249 } else {
250 // false hit: the $(( was a $( ( in fact
251 // ash does not care, but bash does
252 pos = ostack.top().pos;
253 str = ostack.top().str;
254 ostack.pop();
255 state.current = paren;
256 state.dquote = false;
257 sstack.push( state );
258 }
259 continue;
260 } else if (state.current == paren)
261 state = sstack.pop();
262 else
263 break;
264 } else if (cc == (TQChar)'}') {
265 if (state.current == KMacroExpander::group)
266 state = sstack.pop();
267 else
268 break;
269 } else if (cc == (TQChar)'(') {
270 sstack.push( state );
271 state.current = paren;
272 } else if (cc == (TQChar)'{') {
273 sstack.push( state );
274 state.current = KMacroExpander::group;
275 }
276 pos++;
277 }
278 return sstack.empty();
279}
280
281bool KMacroExpanderBase::expandMacrosShellQuote( TQString &str )
282{
283 uint pos = 0;
284 return expandMacrosShellQuote( str, pos ) && pos == str.length();
285}
286
287int KMacroExpanderBase::expandPlainMacro( const TQString &, uint, TQStringList & )
288{ tqFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; }
289
290int KMacroExpanderBase::expandEscapedMacro( const TQString &, uint, TQStringList & )
291{ tqFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; }
292
293
295
296template<class KT,class VT>
297class KMacroMapExpander : public KMacroExpanderBase {
298
299public:
300 KMacroMapExpander( const TQMap<KT,VT> &map, TQChar c = '%' ) :
301 KMacroExpanderBase( c ), macromap( map ) {}
302
303protected:
304 virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
305 virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
306
307private:
308 TQMap<KT,VT> macromap;
309};
310
311static TQStringList &operator+=( TQStringList &s, const TQString &n) { s << n; return s; }
312
314
315static bool
316isIdentifier( uint c )
317{
318 return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
319}
320
322
323template<class VT>
324class KMacroMapExpander<TQChar,VT> : public KMacroExpanderBase {
325
326public:
327 KMacroMapExpander( const TQMap<TQChar,VT> &map, TQChar c = '%' ) :
328 KMacroExpanderBase( c ), macromap( map ) {}
329
330protected:
331 virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
332 virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
333
334private:
335 TQMap<TQChar,VT> macromap;
336};
337
338template<class VT>
339int
340KMacroMapExpander<TQChar,VT>::expandPlainMacro( const TQString &str, uint pos, TQStringList &ret )
341{
342 TQMapConstIterator<TQChar,VT> it = macromap.find(str[pos]);
343 if (it != macromap.end()) {
344 ret += it.data();
345 return 1;
346 }
347 return 0;
348}
349
350template<class VT>
351int
352KMacroMapExpander<TQChar,VT>::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
353{
354 if (str[pos + 1] == escapeChar()) {
355 ret += TQString( escapeChar() );
356 return 2;
357 }
358 TQMapConstIterator<TQChar,VT> it = macromap.find(str[pos+1]);
359 if (it != macromap.end()) {
360 ret += it.data();
361 return 2;
362 }
363
364 return 0;
365}
366
367template<class VT>
368class KMacroMapExpander<TQString,VT> : public KMacroExpanderBase {
369
370public:
371 KMacroMapExpander( const TQMap<TQString,VT> &map, TQChar c = '%' ) :
372 KMacroExpanderBase( c ), macromap( map ) {}
373
374protected:
375 virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
376 virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
377
378private:
379 TQMap<TQString,VT> macromap;
380};
381
382template<class VT>
383int
384KMacroMapExpander<TQString,VT>::expandPlainMacro( const TQString &str, uint pos, TQStringList &ret )
385{
386 if (isIdentifier( str[pos - 1].unicode() ))
387 return 0;
388 uint sl;
389 for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
390 if (!sl)
391 return 0;
392 TQMapConstIterator<TQString,VT> it =
393 macromap.find( TQConstString( str.unicode() + pos, sl ).string() );
394 if (it != macromap.end()) {
395 ret += it.data();
396 return sl;
397 }
398 return 0;
399}
400
401template<class VT>
402int
403KMacroMapExpander<TQString,VT>::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
404{
405 if (str[pos + 1] == escapeChar()) {
406 ret += TQString( escapeChar() );
407 return 2;
408 }
409 uint sl, rsl, rpos;
410 if (str[pos + 1] == (TQChar)'{') {
411 rpos = pos + 2;
412 for (sl = 0; str[rpos + sl] != (TQChar)'}'; sl++)
413 if (rpos + sl >= str.length())
414 return 0;
415 rsl = sl + 3;
416 } else {
417 rpos = pos + 1;
418 for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
419 rsl = sl + 1;
420 }
421 if (!sl)
422 return 0;
423 TQMapConstIterator<TQString,VT> it =
424 macromap.find( TQConstString( str.unicode() + rpos, sl ).string() );
425 if (it != macromap.end()) {
426 ret += it.data();
427 return rsl;
428 }
429 return 0;
430}
431
433
434int
435KCharMacroExpander::expandPlainMacro( const TQString &str, uint pos, TQStringList &ret )
436{
437 if (expandMacro( str[pos], ret ))
438 return 1;
439 return 0;
440}
441
442int
443KCharMacroExpander::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
444{
445 if (str[pos + 1] == escapeChar()) {
446 ret += TQString( escapeChar() );
447 return 2;
448 }
449 if (expandMacro( str[pos+1], ret ))
450 return 2;
451 return 0;
452}
453
454int
455KWordMacroExpander::expandPlainMacro( const TQString &str, uint pos, TQStringList &ret )
456{
457 if (isIdentifier( str[pos - 1].unicode() ))
458 return 0;
459 uint sl;
460 for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
461 if (!sl)
462 return 0;
463 if (expandMacro( TQConstString( str.unicode() + pos, sl ).string(), ret ))
464 return sl;
465 return 0;
466}
467
468int
469KWordMacroExpander::expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret )
470{
471 if (str[pos + 1] == escapeChar()) {
472 ret += TQString( escapeChar() );
473 return 2;
474 }
475 uint sl, rsl, rpos;
476 if (str[pos + 1] == (TQChar)'{') {
477 rpos = pos + 2;
478 for (sl = 0; str[rpos + sl] != (TQChar)'}'; sl++)
479 if (rpos + sl >= str.length())
480 return 0;
481 rsl = sl + 3;
482 } else {
483 rpos = pos + 1;
484 for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
485 rsl = sl + 1;
486 }
487 if (!sl)
488 return 0;
489 if (expandMacro( TQConstString( str.unicode() + rpos, sl ).string(), ret ))
490 return rsl;
491 return 0;
492}
493
495
496template<class KT,class VT>
497inline TQString
498TexpandMacros( const TQString &ostr, const TQMap<KT,VT> &map, TQChar c )
499{
500 TQString str( ostr );
501 KMacroMapExpander<KT,VT> kmx( map, c );
502 kmx.expandMacros( str );
503 return str;
504}
505
506template<class KT,class VT>
507inline TQString
508TexpandMacrosShellQuote( const TQString &ostr, const TQMap<KT,VT> &map, TQChar c )
509{
510 TQString str( ostr );
511 KMacroMapExpander<KT,VT> kmx( map, c );
512 if (!kmx.expandMacrosShellQuote( str ))
513 return TQString();
514 return str;
515}
516
517// public API
518namespace KMacroExpander {
519
520 TQString expandMacros( const TQString &ostr, const TQMap<TQChar,TQString> &map, TQChar c ) { return TexpandMacros( ostr, map, c ); }
521 TQString expandMacrosShellQuote( const TQString &ostr, const TQMap<TQChar,TQString> &map, TQChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
522 TQString expandMacros( const TQString &ostr, const TQMap<TQString,TQString> &map, TQChar c ) { return TexpandMacros( ostr, map, c ); }
523 TQString expandMacrosShellQuote( const TQString &ostr, const TQMap<TQString,TQString> &map, TQChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
524 TQString expandMacros( const TQString &ostr, const TQMap<TQChar,TQStringList> &map, TQChar c ) { return TexpandMacros( ostr, map, c ); }
525 TQString expandMacrosShellQuote( const TQString &ostr, const TQMap<TQChar,TQStringList> &map, TQChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
526 TQString expandMacros( const TQString &ostr, const TQMap<TQString,TQStringList> &map, TQChar c ) { return TexpandMacros( ostr, map, c ); }
527 TQString expandMacrosShellQuote( const TQString &ostr, const TQMap<TQString,TQStringList> &map, TQChar c ) { return TexpandMacrosShellQuote( ostr, map, c ); }
528
529} // namespace
KCharMacroExpander::expandEscapedMacro
virtual int expandEscapedMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called every time the escape char is found if it is not TQChar::null.
Definition: kmacroexpander.cpp:443
KCharMacroExpander::expandPlainMacro
virtual int expandPlainMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called for every single char within the string if the escape char is TQChar::null.
Definition: kmacroexpander.cpp:435
KCharMacroExpander::expandMacro
virtual bool expandMacro(TQChar chr, TQStringList &ret)=0
Return substitution list ret for single-character macro chr.
KMacroExpanderBase
Abstract base class for the worker classes behind the KMacroExpander namespace and the KCharMacroExpa...
Definition: kmacroexpander.h:37
KMacroExpanderBase::setEscapeChar
void setEscapeChar(TQChar c)
Set the macro escape character.
Definition: kmacroexpander.cpp:38
KMacroExpanderBase::expandPlainMacro
virtual int expandPlainMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called for every single char within the string if the escape char is TQChar::null.
Definition: kmacroexpander.cpp:287
KMacroExpanderBase::expandEscapedMacro
virtual int expandEscapedMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called every time the escape char is found if it is not TQChar::null.
Definition: kmacroexpander.cpp:290
KMacroExpanderBase::expandMacros
void expandMacros(TQString &str)
Perform safe macro expansion (substitution) on a string.
Definition: kmacroexpander.cpp:49
KMacroExpanderBase::~KMacroExpanderBase
virtual ~KMacroExpanderBase()
Destructor.
Definition: kmacroexpander.cpp:33
KMacroExpanderBase::KMacroExpanderBase
KMacroExpanderBase(TQChar c='%')
Constructor.
Definition: kmacroexpander.cpp:28
KMacroExpanderBase::escapeChar
TQChar escapeChar() const
Obtain the macro escape character.
Definition: kmacroexpander.cpp:44
KWordMacroExpander::expandMacro
virtual bool expandMacro(const TQString &str, TQStringList &ret)=0
Return substitution list ret for string macro str.
KWordMacroExpander::expandPlainMacro
virtual int expandPlainMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called for every single char within the string if the escape char is TQChar::null.
Definition: kmacroexpander.cpp:455
KWordMacroExpander::expandEscapedMacro
virtual int expandEscapedMacro(const TQString &str, uint pos, TQStringList &ret)
This function is called every time the escape char is found if it is not TQChar::null.
Definition: kmacroexpander.cpp:469
KMacroExpander
A group of functions providing macro expansion (substitution) in strings, optionally with quoting app...
Definition: kmacroexpander.cpp:82
KMacroExpander::expandMacros
TQString expandMacros(const TQString &ostr, const TQMap< TQChar, TQString > &map, TQChar c)
Perform safe macro expansion (substitution) on a string.
Definition: kmacroexpander.cpp:520
KMacroExpander::Quoting
Quoting
Definition: kmacroexpander.cpp:85
KMacroExpander::expandMacrosShellQuote
TQString expandMacrosShellQuote(const TQString &ostr, const TQMap< TQChar, TQString > &map, TQChar c)
Perform safe macro expansion (substitution) on a string for use in shell commands.
Definition: kmacroexpander.cpp:521

tdecore

Skip menu "tdecore"
  • Main Page
  • Modules
  • Namespace List
  • Class Hierarchy
  • Alphabetical List
  • Class List
  • File List
  • Namespace Members
  • Class Members
  • Related Pages

tdecore

Skip menu "tdecore"
  • arts
  • dcop
  • dnssd
  • interfaces
  •   kspeech
  •     interface
  •     library
  •   tdetexteditor
  • kate
  • kded
  • kdoctools
  • kimgio
  • kjs
  • libtdemid
  • libtdescreensaver
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdeioslave
  •   http
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.9.4
This website is maintained by Timothy Pearson.