00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019
00020
00021
00022
00023
#include <kmacroexpander.h>
00024
00025
#include <qvaluestack.h>
00026
#include <qregexp.h>
00027
00028 KMacroExpanderBase::KMacroExpanderBase(
QChar c )
00029 {
00030 escapechar = c;
00031 }
00032
00033 KMacroExpanderBase::~KMacroExpanderBase()
00034 {
00035 }
00036
00037
void
00038 KMacroExpanderBase::setEscapeChar(
QChar c )
00039 {
00040 escapechar = c;
00041 }
00042
00043
QChar
00044 KMacroExpanderBase::escapeChar()
const
00045
{
00046
return escapechar;
00047 }
00048
00049 void KMacroExpanderBase::expandMacros(
QString &str )
00050 {
00051 uint pos;
00052
int len;
00053
QChar ec( escapechar );
00054
QStringList rst;
00055
QString rsts;
00056
00057
for (pos = 0; pos < str.length(); ) {
00058
if (ec != (
char)0) {
00059
if (str.unicode()[pos] != ec)
00060
goto nohit;
00061
if (!(len =
expandEscapedMacro( str, pos, rst )))
00062
goto nohit;
00063 }
else {
00064
if (!(len =
expandPlainMacro( str, pos, rst )))
00065
goto nohit;
00066 }
00067
if (len < 0) {
00068 pos -= len;
00069
continue;
00070 }
00071 rsts = rst.join(
" " );
00072 rst.clear();
00073 str.replace( pos, len, rsts );
00074 pos += rsts.length();
00075
continue;
00076 nohit:
00077 pos++;
00078 }
00079 }
00080
00081
00082 namespace KMacroExpander {
00083
00084
enum Quoting { noquote, singlequote, doublequote, dollarquote,
00085 paren, subst, group, math };
00086
typedef struct {
00087 Quoting current;
00088
bool dquote;
00089 } State;
00090
typedef struct {
00091
QString str;
00092 uint pos;
00093 } Save;
00094
00095 }
00096
00097
using namespace KMacroExpander;
00098
00099
bool KMacroExpanderBase::expandMacrosShellQuote(
QString &str, uint &pos )
00100 {
00101
int len;
00102 uint pos2;
00103
QChar ec( escapechar );
00104 State state = { noquote,
false };
00105
QValueStack<State> sstack;
00106
QValueStack<Save> ostack;
00107
QStringList rst;
00108
QString rsts;
00109
00110
while (pos < str.length()) {
00111
QChar cc( str.unicode()[pos] );
00112
if (ec != (
char)0) {
00113
if (cc != ec)
00114
goto nohit;
00115
if (!(len =
expandEscapedMacro( str, pos, rst )))
00116
goto nohit;
00117 }
else {
00118
if (!(len =
expandPlainMacro( str, pos, rst )))
00119
goto nohit;
00120 }
00121
if (len < 0) {
00122 pos -= len;
00123
continue;
00124 }
00125
if (state.dquote) {
00126 rsts = rst.join(
" " );
00127 rsts.replace(
QRegExp(
"([$`\"\\\\])"),
"\\\\1" );
00128 }
else if (state.current == dollarquote) {
00129 rsts = rst.join(
" " );
00130 rsts.replace(
QRegExp(
"(['\\\\])"),
"\\\\1" );
00131 }
else if (state.current == singlequote) {
00132 rsts = rst.join(
" " );
00133 rsts.replace(
'\'',
"'\\''");
00134 }
else {
00135
if (rst.isEmpty()) {
00136 str.remove( pos, len );
00137
continue;
00138 }
else {
00139 rsts =
"'";
00140
#if 0 // this could pay off if join() would be cleverer and the strings were long
00141
for (QStringList::Iterator it = rst.begin(); it != rst.end(); ++it)
00142 (*it).replace(
'\'',
"'\\''" );
00143 rsts += rst.join(
"' '" );
00144
#else
00145
for (QStringList::ConstIterator it = rst.begin(); it != rst.end(); ++it) {
00146
if (it != rst.begin())
00147 rsts +=
"' '";
00148
QString trsts( *it );
00149 trsts.replace(
'\'',
"'\\''" );
00150 rsts += trsts;
00151 }
00152
#endif
00153
rsts +=
"'";
00154 }
00155 }
00156 rst.clear();
00157 str.replace( pos, len, rsts );
00158 pos += rsts.length();
00159
continue;
00160 nohit:
00161
if (state.current == singlequote) {
00162
if (cc ==
'\'')
00163 state = sstack.pop();
00164 }
else if (cc ==
'\\') {
00165
00166 pos += 2;
00167
continue;
00168 }
else if (state.current == dollarquote) {
00169
if (cc ==
'\'')
00170 state = sstack.pop();
00171 }
else if (cc ==
'$') {
00172 cc = str[++pos];
00173
if (cc ==
'(') {
00174 sstack.push( state );
00175
if (str[pos + 1] ==
'(') {
00176 Save sav = { str, pos + 2 };
00177 ostack.push( sav );
00178 state.current = math;
00179 pos += 2;
00180
continue;
00181 }
else {
00182 state.current = paren;
00183 state.dquote =
false;
00184 }
00185 }
else if (cc ==
'{') {
00186 sstack.push( state );
00187 state.current = subst;
00188 }
else if (!state.dquote) {
00189
if (cc ==
'\'') {
00190 sstack.push( state );
00191 state.current = dollarquote;
00192 }
else if (cc ==
'"') {
00193 sstack.push( state );
00194 state.current = doublequote;
00195 state.dquote =
true;
00196 }
00197 }
00198
00199 }
else if (cc ==
'`') {
00200 str.replace( pos, 1,
"$( " );
00201 pos2 = pos += 3;
00202
for (;;) {
00203
if (pos2 >= str.length()) {
00204 pos = pos2;
00205
return false;
00206 }
00207 cc = str.unicode()[pos2];
00208
if (cc ==
'`')
00209
break;
00210
if (cc ==
'\\') {
00211 cc = str[++pos2];
00212
if (cc ==
'$' || cc ==
'`' || cc ==
'\\' ||
00213 (cc ==
'"' && state.dquote))
00214 {
00215 str.remove( pos2 - 1, 1 );
00216
continue;
00217 }
00218 }
00219 pos2++;
00220 }
00221 str[pos2] =
')';
00222 sstack.push( state );
00223 state.current = paren;
00224 state.dquote =
false;
00225
continue;
00226 }
else if (state.current == doublequote) {
00227
if (cc ==
'"')
00228 state = sstack.pop();
00229 }
else if (cc ==
'\'') {
00230
if (!state.dquote) {
00231 sstack.push( state );
00232 state.current = singlequote;
00233 }
00234 }
else if (cc ==
'"') {
00235
if (!state.dquote) {
00236 sstack.push( state );
00237 state.current = doublequote;
00238 state.dquote =
true;
00239 }
00240 }
else if (state.current == subst) {
00241
if (cc ==
'}')
00242 state = sstack.pop();
00243 }
else if (cc ==
')') {
00244
if (state.current == math) {
00245
if (str[pos + 1] ==
')') {
00246 state = sstack.pop();
00247 pos += 2;
00248 }
else {
00249
00250
00251 pos = ostack.top().pos;
00252 str = ostack.top().str;
00253 ostack.pop();
00254 state.current = paren;
00255 state.dquote =
false;
00256 sstack.push( state );
00257 }
00258
continue;
00259 }
else if (state.current == paren)
00260 state = sstack.pop();
00261
else
00262
break;
00263 }
else if (cc ==
'}') {
00264
if (state.current == KMacroExpander::group)
00265 state = sstack.pop();
00266
else
00267
break;
00268 }
else if (cc ==
'(') {
00269 sstack.push( state );
00270 state.current = paren;
00271 }
else if (cc ==
'{') {
00272 sstack.push( state );
00273 state.current = KMacroExpander::group;
00274 }
00275 pos++;
00276 }
00277
return sstack.empty();
00278 }
00279
00280 bool KMacroExpanderBase::expandMacrosShellQuote(
QString &str )
00281 {
00282 uint pos = 0;
00283
return expandMacrosShellQuote( str, pos ) && pos == str.length();
00284 }
00285
00286 int KMacroExpanderBase::expandPlainMacro(
const QString &, uint,
QStringList & )
00287 { qFatal(
"KMacroExpanderBase::expandPlainMacro called!" );
return 0; }
00288
00289 int KMacroExpanderBase::expandEscapedMacro(
const QString &, uint,
QStringList & )
00290 { qFatal(
"KMacroExpanderBase::expandEscapedMacro called!" );
return 0; }
00291
00292
00294
00295
template<
class KT,
class VT>
00296
class KMacroMapExpander :
public KMacroExpanderBase {
00297
00298
public:
00299 KMacroMapExpander(
const QMap<KT,VT> &map,
QChar c =
'%' ) :
00300
KMacroExpanderBase( c ), macromap( map ) {}
00301
00302
protected:
00303
virtual int expandPlainMacro(
const QString &str, uint pos,
QStringList &ret );
00304
virtual int expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret );
00305
00306
private:
00307
QMap<KT,VT> macromap;
00308 };
00309
00310
static QStringList &operator+=(
QStringList &s,
const QString &n) { s << n;
return s; }
00311
00313
00314
template<
class VT>
00315
class KMacroMapExpander<QChar,VT> :
public KMacroExpanderBase {
00316
00317
public:
00318 KMacroMapExpander(
const QMap<QChar,VT> &map, QChar c =
'%' ) :
00319
KMacroExpanderBase( c ), macromap( map ) {}
00320
00321
protected:
00322
virtual int expandPlainMacro(
const QString &str, uint pos,
QStringList &ret );
00323
virtual int expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret );
00324
00325
private:
00326
QMap<QChar,VT> macromap;
00327 };
00328
00329
template<
class VT>
00330
int
00331 KMacroMapExpander<QChar,VT>::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00332 {
00333
QMapConstIterator<QChar,VT> it = macromap.find(str[pos]);
00334
if (it != macromap.end()) {
00335 ret += it.data();
00336
return 1;
00337 }
00338
return 0;
00339 }
00340
00341
template<
class VT>
00342
int
00343 KMacroMapExpander<QChar,VT>::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00344 {
00345
if (str[pos + 1] ==
escapeChar()) {
00346 ret +=
QString(
escapeChar() );
00347
return 2;
00348 }
00349
00350
QMapConstIterator<QChar,VT> it = macromap.find(str[pos+1]);
00351
if (it != macromap.end()) {
00352 ret += it.data();
00353
return 2;
00354 }
00355
return false;
00356 }
00357
00358
template<
class VT>
00359
class KMacroMapExpander<QString,VT> :
public KMacroExpanderBase {
00360
00361
public:
00362 KMacroMapExpander(
const QMap<QString,VT> &map, QChar c =
'%' ) :
00363
KMacroExpanderBase( c ), macromap( map ) {}
00364
00365
protected:
00366
virtual int expandPlainMacro(
const QString &str, uint pos,
QStringList &ret );
00367
virtual int expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret );
00368
00369
private:
00370
bool isIdentifier(uint c) {
return c ==
'_' || (c >=
'A' && c <= 'Z') || (c >=
'a' && c <= 'z') || (c >=
'0' && c <=
'9'); }
00371
QMap<QString,VT> macromap;
00372 };
00373
00374
template<
class VT>
00375
int
00376 KMacroMapExpander<QString,VT>::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00377 {
00378
if (isIdentifier( str[pos - 1].unicode() ))
00379
return 0;
00380 uint sl;
00381
for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
00382
if (!sl)
00383
return 0;
00384
QMapConstIterator<QString,VT> it =
00385 macromap.find(
QConstString( str.unicode() + pos, sl ).string() );
00386
if (it != macromap.end()) {
00387 ret += it.data();
00388
return sl;
00389 }
00390
return false;
00391 }
00392
00393
template<
class VT>
00394
int
00395 KMacroMapExpander<QString,VT>::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00396 {
00397
if (str[pos + 1] ==
escapeChar()) {
00398 ret += QString(
escapeChar() );
00399
return 2;
00400 }
00401 uint sl, rsl, rpos;
00402
if (str[pos + 1] ==
'{') {
00403 rpos = pos + 2;
00404
for (sl = 0; str[rpos + sl] !=
'}'; sl++)
00405
if (rpos + sl >= str.length())
00406
return 0;
00407 rsl = sl + 3;
00408 }
else {
00409 rpos = pos + 1;
00410
for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
00411 rsl = sl + 1;
00412 }
00413
if (!sl)
00414
return 0;
00415
QMapConstIterator<QString,VT> it =
00416 macromap.find(
QConstString( str.unicode() + rpos, sl ).string() );
00417
if (it != macromap.end()) {
00418 ret += it.data();
00419
return rsl;
00420 }
00421
return false;
00422 }
00423
00425
00426
template<
class KT,
class VT>
00427
inline QString
00428 TexpandMacros(
const QString &ostr,
const QMap<KT,VT> &map, QChar c )
00429 {
00430 QString str( ostr );
00431 KMacroMapExpander<KT,VT> kmx( map, c );
00432 kmx.expandMacros( str );
00433
return str;
00434 }
00435
00436
template<
class KT,
class VT>
00437
inline QString
00438 TexpandMacrosShellQuote(
const QString &ostr,
const QMap<KT,VT> &map, QChar c )
00439 {
00440 QString str( ostr );
00441 KMacroMapExpander<KT,VT> kmx( map, c );
00442
if (!kmx.expandMacrosShellQuote( str ))
00443
return QString::null;
00444
return str;
00445 }
00446
00447
00448
namespace KMacroExpander {
00449
00450 QString
expandMacros(
const QString &ostr,
const QMap<QChar,QString> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00451 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QChar,QString> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00452 QString
expandMacros(
const QString &ostr,
const QMap<QString,QString> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00453 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QString,QString> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00454 QString
expandMacros(
const QString &ostr,
const QMap<QChar,QStringList> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00455 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QChar,QStringList> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00456 QString
expandMacros(
const QString &ostr,
const QMap<QString,QStringList> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00457 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QString,QStringList> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00458
00459 }