• 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 
28 KMacroExpanderBase::KMacroExpanderBase( TQChar c )
29 {
30  escapechar = c;
31 }
32 
33 KMacroExpanderBase::~KMacroExpanderBase()
34 {
35 }
36 
37 void
38 KMacroExpanderBase::setEscapeChar( TQChar c )
39 {
40  escapechar = c;
41 }
42 
43 TQChar
44 KMacroExpanderBase::escapeChar() const
45 {
46  return escapechar;
47 }
48 
49 void 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 != (QChar)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 
82 namespace 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 
98 using namespace KMacroExpander;
99 
100 bool 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 != (QChar)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 == (QChar)'\'')
164  state = sstack.pop();
165  } else if (cc == (QChar)'\\') {
166  // always swallow the char -> prevent anomalies due to expansion
167  pos += 2;
168  continue;
169  } else if (state.current == dollarquote) {
170  if (cc == (QChar)'\'')
171  state = sstack.pop();
172  } else if (cc == (QChar)'$') {
173  cc = str[++pos];
174  if (cc == (QChar)'(') {
175  sstack.push( state );
176  if (str[pos + 1] == (QChar)'(') {
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 == (QChar)'{') {
187  sstack.push( state );
188  state.current = subst;
189  } else if (!state.dquote) {
190  if (cc == (QChar)'\'') {
191  sstack.push( state );
192  state.current = dollarquote;
193  } else if (cc == (QChar)'"') {
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 == (QChar)'`') {
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 == (QChar)'`')
210  break;
211  if (cc == (QChar)'\\') {
212  cc = str[++pos2];
213  if (cc == (QChar)'$' || cc == (QChar)'`' || cc == (QChar)'\\' ||
214  (cc == (QChar)'"' && 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 == (QChar)'"')
229  state = sstack.pop();
230  } else if (cc == (QChar)'\'') {
231  if (!state.dquote) {
232  sstack.push( state );
233  state.current = singlequote;
234  }
235  } else if (cc == (QChar)'"') {
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 == (QChar)'}')
243  state = sstack.pop();
244  } else if (cc == (QChar)')') {
245  if (state.current == math) {
246  if (str[pos + 1] == (QChar)')') {
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 == (QChar)'}') {
265  if (state.current == KMacroExpander::group)
266  state = sstack.pop();
267  else
268  break;
269  } else if (cc == (QChar)'(') {
270  sstack.push( state );
271  state.current = paren;
272  } else if (cc == (QChar)'{') {
273  sstack.push( state );
274  state.current = KMacroExpander::group;
275  }
276  pos++;
277  }
278  return sstack.empty();
279 }
280 
281 bool KMacroExpanderBase::expandMacrosShellQuote( TQString &str )
282 {
283  uint pos = 0;
284  return expandMacrosShellQuote( str, pos ) && pos == str.length();
285 }
286 
287 int KMacroExpanderBase::expandPlainMacro( const TQString &, uint, TQStringList & )
288 { tqFatal( "KMacroExpanderBase::expandPlainMacro called!" ); return 0; }
289 
290 int KMacroExpanderBase::expandEscapedMacro( const TQString &, uint, TQStringList & )
291 { tqFatal( "KMacroExpanderBase::expandEscapedMacro called!" ); return 0; }
292 
293 
295 
296 template<class KT,class VT>
297 class KMacroMapExpander : public KMacroExpanderBase {
298 
299 public:
300  KMacroMapExpander( const TQMap<KT,VT> &map, TQChar c = '%' ) :
301  KMacroExpanderBase( c ), macromap( map ) {}
302 
303 protected:
304  virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
305  virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
306 
307 private:
308  TQMap<KT,VT> macromap;
309 };
310 
311 static TQStringList &operator+=( TQStringList &s, const TQString &n) { s << n; return s; }
312 
314 
315 static bool
316 isIdentifier( uint c )
317 {
318  return c == '_' || (c >= 'A' && c <= 'Z') || (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
319 }
320 
322 
323 template<class VT>
324 class KMacroMapExpander<TQChar,VT> : public KMacroExpanderBase {
325 
326 public:
327  KMacroMapExpander( const TQMap<TQChar,VT> &map, TQChar c = '%' ) :
328  KMacroExpanderBase( c ), macromap( map ) {}
329 
330 protected:
331  virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
332  virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
333 
334 private:
335  TQMap<TQChar,VT> macromap;
336 };
337 
338 template<class VT>
339 int
340 KMacroMapExpander<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 
350 template<class VT>
351 int
352 KMacroMapExpander<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 
367 template<class VT>
368 class KMacroMapExpander<TQString,VT> : public KMacroExpanderBase {
369 
370 public:
371  KMacroMapExpander( const TQMap<TQString,VT> &map, TQChar c = '%' ) :
372  KMacroExpanderBase( c ), macromap( map ) {}
373 
374 protected:
375  virtual int expandPlainMacro( const TQString &str, uint pos, TQStringList &ret );
376  virtual int expandEscapedMacro( const TQString &str, uint pos, TQStringList &ret );
377 
378 private:
379  TQMap<TQString,VT> macromap;
380 };
381 
382 template<class VT>
383 int
384 KMacroMapExpander<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 
401 template<class VT>
402 int
403 KMacroMapExpander<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] == (QChar)'{') {
411  rpos = pos + 2;
412  for (sl = 0; str[rpos + sl] != (QChar)'}'; 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 
434 int
435 KCharMacroExpander::expandPlainMacro( const TQString &str, uint pos, TQStringList &ret )
436 {
437  if (expandMacro( str[pos], ret ))
438  return 1;
439  return 0;
440 }
441 
442 int
443 KCharMacroExpander::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 
454 int
455 KWordMacroExpander::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 
468 int
469 KWordMacroExpander::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] == (QChar)'{') {
477  rpos = pos + 2;
478  for (sl = 0; str[rpos + sl] != (QChar)'}'; 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 
496 template<class KT,class VT>
497 inline QString
498 TexpandMacros( 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 
506 template<class KT,class VT>
507 inline QString
508 TexpandMacrosShellQuote( 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
518 namespace 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
KMacroExpanderBase
Abstract base class for the worker classes behind the KMacroExpander namespace and the KCharMacroExpa...
Definition: kmacroexpander.h:37
KMacroExpanderBase::escapeChar
TQChar escapeChar() const
Obtain the macro escape character.
Definition: kmacroexpander.cpp:44
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::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
KMacroExpanderBase::~KMacroExpanderBase
virtual ~KMacroExpanderBase()
Destructor.
Definition: kmacroexpander.cpp:33
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
KMacroExpander::Quoting
Quoting
Definition: kmacroexpander.cpp:85
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
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::expandMacros
void expandMacros(TQString &str)
Perform safe macro expansion (substitution) on a string.
Definition: kmacroexpander.cpp:49
KMacroExpander
A group of functions providing macro expansion (substitution) in strings, optionally with quoting app...
Definition: kmacroexpander.cpp:82
KMacroExpanderBase::KMacroExpanderBase
KMacroExpanderBase(TQChar c= '%')
Constructor.
Definition: kmacroexpander.cpp:28
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
KMacroExpanderBase::setEscapeChar
void setEscapeChar(TQChar c)
Set the macro escape character.
Definition: kmacroexpander.cpp:38
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
  •     tdecore
  • tdeabc
  • tdecmshell
  • tdecore
  • tdefx
  • tdehtml
  • tdeinit
  • tdeio
  •   bookmarks
  •   httpfilter
  •   kpasswdserver
  •   kssl
  • tdeioslave
  •   http
  •   tdefile
  •   tdeio
  •   tdeioexec
  • tdemdi
  •   tdemdi
  • tdenewstuff
  • tdeparts
  • tdeprint
  • tderandr
  • tderesources
  • tdespell2
  • tdesu
  • tdeui
  • tdeunittest
  • tdeutils
  • tdewallet
Generated for tdecore by doxygen 1.8.8
This website is maintained by Timothy Pearson.