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
static bool
00315 isIdentifier( uint c )
00316 {
00317
return c ==
'_' || (c >=
'A' && c <= 'Z') || (c >=
'a' && c <= 'z') || (c >=
'0' && c <=
'9');
00318 }
00319
00321
00322
template<
class VT>
00323
class KMacroMapExpander<QChar,VT> :
public KMacroExpanderBase {
00324
00325
public:
00326 KMacroMapExpander(
const QMap<QChar,VT> &map, QChar c =
'%' ) :
00327
KMacroExpanderBase( c ), macromap( map ) {}
00328
00329
protected:
00330
virtual int expandPlainMacro(
const QString &str, uint pos,
QStringList &ret );
00331
virtual int expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret );
00332
00333
private:
00334
QMap<QChar,VT> macromap;
00335 };
00336
00337
template<
class VT>
00338
int
00339 KMacroMapExpander<QChar,VT>::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00340 {
00341
QMapConstIterator<QChar,VT> it = macromap.find(str[pos]);
00342
if (it != macromap.end()) {
00343 ret += it.
data();
00344
return 1;
00345 }
00346
return 0;
00347 }
00348
00349
template<
class VT>
00350
int
00351 KMacroMapExpander<QChar,VT>::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00352 {
00353
if (str[pos + 1] ==
escapeChar()) {
00354 ret +=
QString(
escapeChar() );
00355
return 2;
00356 }
00357
QMapConstIterator<QChar,VT> it = macromap.find(str[pos+1]);
00358
if (it != macromap.end()) {
00359 ret += it.
data();
00360
return 2;
00361 }
00362
00363
return 0;
00364 }
00365
00366
template<
class VT>
00367
class KMacroMapExpander<QString,VT> :
public KMacroExpanderBase {
00368
00369
public:
00370 KMacroMapExpander(
const QMap<QString,VT> &map, QChar c =
'%' ) :
00371
KMacroExpanderBase( c ), macromap( map ) {}
00372
00373
protected:
00374
virtual int expandPlainMacro(
const QString &str, uint pos,
QStringList &ret );
00375
virtual int expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret );
00376
00377
private:
00378
QMap<QString,VT> macromap;
00379 };
00380
00381
template<
class VT>
00382
int
00383 KMacroMapExpander<QString,VT>::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00384 {
00385
if (isIdentifier( str[pos - 1].unicode() ))
00386
return 0;
00387 uint sl;
00388
for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
00389
if (!sl)
00390
return 0;
00391
QMapConstIterator<QString,VT> it =
00392 macromap.find(
QConstString( str.
unicode() + pos, sl ).string() );
00393
if (it != macromap.end()) {
00394 ret += it.
data();
00395
return sl;
00396 }
00397
return 0;
00398 }
00399
00400
template<
class VT>
00401
int
00402 KMacroMapExpander<QString,VT>::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00403 {
00404
if (str[pos + 1] ==
escapeChar()) {
00405 ret += QString(
escapeChar() );
00406
return 2;
00407 }
00408 uint sl, rsl, rpos;
00409
if (str[pos + 1] ==
'{') {
00410 rpos = pos + 2;
00411
for (sl = 0; str[rpos + sl] !=
'}'; sl++)
00412
if (rpos + sl >= str.
length())
00413
return 0;
00414 rsl = sl + 3;
00415 }
else {
00416 rpos = pos + 1;
00417
for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
00418 rsl = sl + 1;
00419 }
00420
if (!sl)
00421
return 0;
00422
QMapConstIterator<QString,VT> it =
00423 macromap.find(
QConstString( str.
unicode() + rpos, sl ).string() );
00424
if (it != macromap.end()) {
00425 ret += it.
data();
00426
return rsl;
00427 }
00428
return 0;
00429 }
00430
00432
00433
int
00434 KCharMacroExpander::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00435 {
00436
if (
expandMacro( str[pos], ret ))
00437
return 1;
00438
return 0;
00439 }
00440
00441
int
00442 KCharMacroExpander::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00443 {
00444
if (str[pos + 1] ==
escapeChar()) {
00445 ret += QString(
escapeChar() );
00446
return 2;
00447 }
00448
if (
expandMacro( str[pos+1], ret ))
00449
return 2;
00450
return 0;
00451 }
00452
00453
int
00454 KWordMacroExpander::expandPlainMacro(
const QString &str, uint pos,
QStringList &ret )
00455 {
00456
if (isIdentifier( str[pos - 1].unicode() ))
00457
return 0;
00458 uint sl;
00459
for (sl = 0; isIdentifier( str[pos + sl].unicode() ); sl++);
00460
if (!sl)
00461
return 0;
00462
if (
expandMacro(
QConstString( str.
unicode() + pos, sl ).string(), ret ))
00463
return sl;
00464
return 0;
00465 }
00466
00467
int
00468 KWordMacroExpander::expandEscapedMacro(
const QString &str, uint pos,
QStringList &ret )
00469 {
00470
if (str[pos + 1] ==
escapeChar()) {
00471 ret += QString(
escapeChar() );
00472
return 2;
00473 }
00474 uint sl, rsl, rpos;
00475
if (str[pos + 1] ==
'{') {
00476 rpos = pos + 2;
00477
for (sl = 0; str[rpos + sl] !=
'}'; sl++)
00478
if (rpos + sl >= str.
length())
00479
return 0;
00480 rsl = sl + 3;
00481 }
else {
00482 rpos = pos + 1;
00483
for (sl = 0; isIdentifier( str[rpos + sl].unicode() ); sl++);
00484 rsl = sl + 1;
00485 }
00486
if (!sl)
00487
return 0;
00488
if (
expandMacro(
QConstString( str.
unicode() + rpos, sl ).string(), ret ))
00489
return rsl;
00490
return 0;
00491 }
00492
00494
00495
template<
class KT,
class VT>
00496
inline QString
00497 TexpandMacros(
const QString &ostr,
const QMap<KT,VT> &map, QChar c )
00498 {
00499 QString str( ostr );
00500 KMacroMapExpander<KT,VT> kmx( map, c );
00501 kmx.expandMacros( str );
00502
return str;
00503 }
00504
00505
template<
class KT,
class VT>
00506
inline QString
00507 TexpandMacrosShellQuote(
const QString &ostr,
const QMap<KT,VT> &map, QChar c )
00508 {
00509 QString str( ostr );
00510 KMacroMapExpander<KT,VT> kmx( map, c );
00511
if (!kmx.expandMacrosShellQuote( str ))
00512
return QString::null;
00513
return str;
00514 }
00515
00516
00517
namespace KMacroExpander {
00518
00519 QString
expandMacros(
const QString &ostr,
const QMap<QChar,QString> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00520 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QChar,QString> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00521 QString
expandMacros(
const QString &ostr,
const QMap<QString,QString> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00522 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QString,QString> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00523 QString
expandMacros(
const QString &ostr,
const QMap<QChar,QStringList> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00524 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QChar,QStringList> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00525 QString
expandMacros(
const QString &ostr,
const QMap<QString,QStringList> &map, QChar c ) {
return TexpandMacros( ostr, map, c ); }
00526 QString
expandMacrosShellQuote(
const QString &ostr,
const QMap<QString,QStringList> &map, QChar c ) {
return TexpandMacrosShellQuote( ostr, map, c ); }
00527
00528 }