File indexing completed on 2024-04-28 03:53:48

0001 /*
0002     This file is part of the KDE libraries
0003 
0004     SPDX-FileCopyrightText: 2008 Oswald Buddenhagen <ossi@kde.org>
0005 
0006     SPDX-License-Identifier: LGPL-2.0-or-later
0007 */
0008 
0009 #include "kmacroexpander_p.h"
0010 #include "kshell_p.h"
0011 
0012 #include "kshell.h"
0013 
0014 #include <QString>
0015 #include <QStringList>
0016 
0017 bool KMacroExpanderBase::expandMacrosShellQuote(QString &str, int &pos)
0018 {
0019     int len;
0020     int pos2;
0021     ushort uc;
0022     ushort ec = d->escapechar.unicode();
0023     bool shellQuote = false; // shell is in quoted state
0024     bool crtQuote = false; // c runtime is in quoted state
0025     bool escaped = false; // previous char was a circumflex
0026     int bslashes = 0; // previous chars were backslashes
0027     int parens = 0; // parentheses nesting level
0028     QStringList rst;
0029     QString rsts;
0030 
0031     while (pos < str.length()) {
0032         ushort cc = str.unicode()[pos].unicode();
0033         if (escaped) { // prevent anomalies due to expansion
0034             goto notcf;
0035         }
0036         if (ec != 0) {
0037             if (cc != ec) {
0038                 goto nohit;
0039             }
0040             if (!(len = expandEscapedMacro(str, pos, rst))) {
0041                 goto nohit;
0042             }
0043         } else {
0044             if (!(len = expandPlainMacro(str, pos, rst))) {
0045                 goto nohit;
0046             }
0047         }
0048         if (len < 0) {
0049             pos -= len;
0050             continue;
0051         }
0052         if (shellQuote != crtQuote) { // Silly, isn't it? Ahoy to Redmond.
0053             return false;
0054         }
0055         if (shellQuote) {
0056             rsts = KShell::quoteArgInternal(rst.join(QLatin1Char(' ')), true);
0057         } else {
0058             if (rst.isEmpty()) {
0059                 str.remove(pos, len);
0060                 continue;
0061             }
0062             rsts = KShell::joinArgs(rst);
0063         }
0064         pos2 = 0;
0065         while (pos2 < rsts.length() && ((uc = rsts.unicode()[pos2].unicode()) == '\\' || uc == '^')) {
0066             pos2++;
0067         }
0068         if (pos2 < rsts.length() && rsts.unicode()[pos2].unicode() == '"') {
0069             QString bsl;
0070             bsl.reserve(bslashes);
0071             for (; bslashes; bslashes--) {
0072                 bsl.append(QLatin1String("\\"));
0073             }
0074             rsts.prepend(bsl);
0075         }
0076         bslashes = 0;
0077         rst.clear();
0078         str.replace(pos, len, rsts);
0079         pos += rsts.length();
0080         continue;
0081     nohit:
0082         if (!escaped && !shellQuote && cc == '^') {
0083             escaped = true;
0084         } else {
0085         notcf:
0086             if (cc == '\\') {
0087                 bslashes++;
0088             } else {
0089                 if (cc == '"') {
0090                     if (!escaped) {
0091                         shellQuote = !shellQuote;
0092                     }
0093                     if (!(bslashes & 1)) {
0094                         crtQuote = !crtQuote;
0095                     }
0096                 } else if (!shellQuote) {
0097                     if (cc == '(') {
0098                         parens++;
0099                     } else if (cc == ')')
0100                         if (--parens < 0) {
0101                             break;
0102                         }
0103                 }
0104                 bslashes = 0;
0105             }
0106             escaped = false;
0107         }
0108         pos++;
0109     }
0110     return true;
0111 }