Skip to content

Commit

Permalink
Move from command line to argv array (#216)
Browse files Browse the repository at this point in the history
* command line -> argv array

* update function names

* update directory structure

---------

Co-authored-by: Roy Qu <[email protected]>
  • Loading branch information
CyanoHao and royqh1979 authored Feb 28, 2024
1 parent 85efc86 commit 1831865
Show file tree
Hide file tree
Showing 31 changed files with 1,632 additions and 701 deletions.
30 changes: 30 additions & 0 deletions .github/workflows/unit.yml
Original file line number Diff line number Diff line change
@@ -0,0 +1,30 @@
name: Unit

on: [push, pull_request]

jobs:
ubuntu_makefile_escape:
name: Unix makefile escape
runs-on: ubuntu-22.04
steps:
- uses: actions/checkout@v2

- name: Setup xmake
uses: xmake-io/github-action-setup-xmake@v1
with:
xmake-version: '2.8.6'

- name: Setup Qt
uses: ConorMacBride/install-package@v1
with:
apt: libqt5svg5-dev qtbase5-dev qtbase5-dev-tools qttools5-dev-tools

- name: Build
run: |
xmake f --qt=/usr
xmake b test-escape
- name: Test
run: |
export QT_ASSUME_STDERR_HAS_CONSOLE=1
xmake r test-escape
3 changes: 3 additions & 0 deletions NEWS.md
Original file line number Diff line number Diff line change
Expand Up @@ -13,6 +13,9 @@ Red Panda C++ Version 2.27
- enhancement: Display ascii control chars.
- fix: Parser: invalidating file may lost class inheritance infos.
- fix: Function argument infos are not correctly parsed.
- enhancement: Migrate external calls from command string to argv array to improve safety and security.
- enhancement: Support POSIX shell-like escaping in user inputs for compiler arguments.
- fix: (Hopefully) properly escape filenames and arguments in makefile generation.

Red Panda C++ Version 2.26
- enhancement: Code suggestion for embedded std::vectors.
Expand Down
4 changes: 4 additions & 0 deletions RedPandaIDE/RedPandaIDE.pro
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,8 @@ SOURCES += \
settingsdialog/settingswidget.cpp \
systemconsts.cpp \
utils.cpp \
utils/escape.cpp \
utils/parsearg.cpp \
widgets/coloredit.cpp \
widgets/compileargumentswidget.cpp \
widgets/consolewidget.cpp \
Expand Down Expand Up @@ -324,6 +326,8 @@ HEADERS += \
settingsdialog/settingswidget.h \
systemconsts.h \
utils.h \
utils/escape.h \
utils/parsearg.h \
common.h \
widgets/coloredit.h \
widgets/compileargumentswidget.h \
Expand Down
135 changes: 66 additions & 69 deletions RedPandaIDE/compiler/compiler.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -16,6 +16,8 @@
*/
#include "compiler.h"
#include "utils.h"
#include "utils/escape.h"
#include "utils/parsearg.h"
#include "compilermanager.h"
#include "../systemconsts.h"

Expand Down Expand Up @@ -68,10 +70,11 @@ void Compiler::run()
for(int i=0;i<mExtraArgumentsList.count();i++) {
if (!beforeRunExtraCommand(i))
break;
QString command = escapeCommandForLog(mExtraCompilersList[i], mExtraArgumentsList[i]);
if (mExtraOutputFilesList[i].isEmpty()) {
log(tr(" - Command: %1 %2").arg(extractFileName(mExtraCompilersList[i]),mExtraArgumentsList[i]));
log(tr(" - Command: %1").arg(command));
} else {
log(tr(" - Command: %1 %2 > \"%3\"").arg(extractFileName(mExtraCompilersList[i]), mExtraArgumentsList[i], mExtraOutputFilesList[i]));
log(tr(" - Command: %1 > %2").arg(command, escapeArgumentForPlatformShell(mExtraOutputFilesList[i], false)));
}
runCommand(mExtraCompilersList[i],mExtraArgumentsList[i],mDirectory, pipedText(),mExtraOutputFilesList[i]);
}
Expand Down Expand Up @@ -331,9 +334,9 @@ void Compiler::stopCompile()
mStop = true;
}

QString Compiler::getCharsetArgument(const QByteArray& encoding,FileType fileType, bool checkSyntax)
QStringList Compiler::getCharsetArgument(const QByteArray& encoding,FileType fileType, bool checkSyntax)
{
QString result;
QStringList result;
bool forceExecUTF8=false;
// test if force utf8 from autolink infos
if ((fileType == FileType::CSource ||
Expand Down Expand Up @@ -383,21 +386,22 @@ QString Compiler::getCharsetArgument(const QByteArray& encoding,FileType fileTyp
}
//qDebug()<<encodingName<<execEncodingName;
if (checkSyntax) {
result += QString(" -finput-charset=%1")
.arg(encodingName);
result << "-finput-charset=" + encodingName;
} else if (encodingName!=execEncodingName) {
result += QString(" -finput-charset=%1 -fexec-charset=%2")
.arg(encodingName, execEncodingName);
result += {
"-finput-charset=" + encodingName,
"-fexec-charset=" + execEncodingName,
};
}
}
return result;
}

QString Compiler::getCCompileArguments(bool checkSyntax)
QStringList Compiler::getCCompileArguments(bool checkSyntax)
{
QString result;
QStringList result;
if (checkSyntax) {
result += " -fsyntax-only";
result << "-fsyntax-only";
}

QMap<QString, QString> compileOptions;
Expand All @@ -412,38 +416,36 @@ QString Compiler::getCCompileArguments(bool checkSyntax)
PCompilerOption pOption = CompilerInfoManager::getCompilerOption(compilerSet()->compilerType(), key);
if (pOption && pOption->isC && !pOption->isLinker) {
if (pOption->type == CompilerOptionType::Checkbox)
result += " " + pOption->setting;
result << pOption->setting;
else if (pOption->type == CompilerOptionType::Input)
result += " " + pOption->setting + " " + compileOptions[key];
result += {pOption->setting, compileOptions[key]};
else {
result += " " + pOption->setting + compileOptions[key];
result << pOption->setting + compileOptions[key];
}
}
}

QMap<QString, QString> macros = devCppMacroVariables();

if (compilerSet()->useCustomCompileParams() && !compilerSet()->customCompileParams().isEmpty()) {
QStringList params = textToLines(compilerSet()->customCompileParams());
foreach(const QString& param, params)
result += " "+ parseMacros(param);
result << parseArguments(compilerSet()->customCompileParams(), macros, true);
}

if (mProject) {
QString s = mProject->options().compilerCmd;
if (!s.isEmpty()) {
s.replace("_@@_", " ");
QStringList params = textToLines(s);
foreach(const QString& param, params)
result += " "+ parseMacros(param);
result << parseArguments(s, macros, true);
}
}
return result;
}

QString Compiler::getCppCompileArguments(bool checkSyntax)
QStringList Compiler::getCppCompileArguments(bool checkSyntax)
{
QString result;
QStringList result;
if (checkSyntax) {
result += " -fsyntax-only";
result << "-fsyntax-only";
}
QMap<QString, QString> compileOptions;
if (mProject && !mProject->options().compilerOptions.isEmpty()) {
Expand All @@ -457,75 +459,73 @@ QString Compiler::getCppCompileArguments(bool checkSyntax)
PCompilerOption pOption = CompilerInfoManager::getCompilerOption(compilerSet()->compilerType(), key);
if (pOption && pOption->isCpp && !pOption->isLinker) {
if (pOption->type == CompilerOptionType::Checkbox)
result += " " + pOption->setting;
result << pOption->setting;
else if (pOption->type == CompilerOptionType::Input)
result += " " + pOption->setting + " " + compileOptions[key];
result += {pOption->setting, compileOptions[key]};
else {
result += " " + pOption->setting + compileOptions[key];
result << pOption->setting + compileOptions[key];
}
}
}

QMap<QString, QString> macros = devCppMacroVariables();
if (compilerSet()->useCustomCompileParams() && !compilerSet()->customCompileParams().isEmpty()) {
QStringList params = textToLines(compilerSet()->customCompileParams());
foreach(const QString& param, params)
result += " "+ parseMacros(param);
result << parseArguments(compilerSet()->customCompileParams(), macros, true);
}
if (mProject) {
QString s = mProject->options().cppCompilerCmd;
if (!s.isEmpty()) {
s.replace("_@@_", " ");
QStringList params = textToLines(s);
foreach(const QString& param, params)
result += " "+ parseMacros(param);
result << parseArguments(s, macros, true);
}
}
return result;
}


QString Compiler::getCIncludeArguments()
QStringList Compiler::getCIncludeArguments()
{
QString result;
QStringList result;
foreach (const QString& folder,compilerSet()->CIncludeDirs()) {
result += QString(" -I\"%1\"").arg(folder);
result << "-I" + folder;
}
return result;
}

QString Compiler::getProjectIncludeArguments()
QStringList Compiler::getProjectIncludeArguments()
{
QString result;
QStringList result;
if (mProject) {
foreach (const QString& folder,mProject->options().includeDirs) {
result += QString(" -I\"%1\"").arg(folder);
result << "-I" + folder;
}
// result += QString(" -I\"%1\"").arg(extractFilePath(mProject->filename()));
}
return result;
}

QString Compiler::getCppIncludeArguments()
QStringList Compiler::getCppIncludeArguments()
{
QString result;
QStringList result;
foreach (const QString& folder,compilerSet()->CppIncludeDirs()) {
result += QString(" -I\"%1\"").arg(folder);
result << "-I" + folder;
}
return result;
}

QString Compiler::getLibraryArguments(FileType fileType)
QStringList Compiler::getLibraryArguments(FileType fileType)
{
QString result;
QStringList result;

//Add libraries
foreach (const QString& folder, compilerSet()->libDirs()) {
result += QString(" -L\"%1\"").arg(folder);
result << "-L" + folder;
}

//add libs added via project
if (mProject) {
foreach (const QString& folder, mProject->options().libDirs){
result += QString(" -L\"%1\"").arg(folder);
result << "-L" + folder;
}
}

Expand All @@ -547,9 +547,7 @@ QString Compiler::getLibraryArguments(FileType fileType)
}
if (waitCount<=10) {
QSet<QString> parsedFiles;
result += parseFileIncludesForAutolink(
mFilename,
parsedFiles);
result += parseFileIncludesForAutolink(mFilename, parsedFiles);
}
}

Expand All @@ -567,11 +565,11 @@ QString Compiler::getLibraryArguments(FileType fileType)
PCompilerOption pOption = CompilerInfoManager::getCompilerOption(compilerSet()->compilerType(), key);
if (pOption && pOption->isLinker) {
if (pOption->type == CompilerOptionType::Checkbox)
result += " " + pOption->setting;
result << pOption->setting;
else if (pOption->type == CompilerOptionType::Input)
result += " " + pOption->setting + " " + compileOptions[key];
result += {pOption->setting, compileOptions[key]};
else {
result += " " + pOption->setting + compileOptions[key];
result << pOption->setting + compileOptions[key];
}
}
}
Expand All @@ -581,47 +579,43 @@ QString Compiler::getLibraryArguments(FileType fileType)
QStringList params = textToLines(compilerSet()->customLinkParams());
if (!params.isEmpty()) {
foreach(const QString& param, params)
result += " " + param;
result << param;
}
}

if (mProject) {
if (mProject->options().type == ProjectType::GUI) {
result += " -mwindows";
result << "-mwindows";
}

if (!mProject->options().linkerCmd.isEmpty()) {
QString s = mProject->options().linkerCmd;
if (!s.isEmpty()) {
s.replace("_@@_", " ");
QStringList params = textToLines(s);
if (!params.isEmpty()) {
foreach(const QString& param, params)
result += " " + param;
}
s.replace("_@@_", " "); // historical reason
result += parseArguments(s, {}, true);
}
}
if (mProject->options().staticLink)
result += " -static";
result << "-static";
} else {
if (compilerSet()->staticLink()) {
result += " -static";
result << "-static";
}
}
return result;
}

QString Compiler::parseFileIncludesForAutolink(
QStringList Compiler::parseFileIncludesForAutolink(
const QString &filename,
QSet<QString>& parsedFiles)
{
QString result;
QStringList result;
if (parsedFiles.contains(filename))
return result;
parsedFiles.insert(filename);
PAutolink autolink = pAutolinkManager->getLink(filename);
if (autolink) {
result += ' '+autolink->linkOption;
result += parseArgumentsWithoutVariables(autolink->linkOption);
}
QStringList includedFiles = mParserForFile->getFileDirectIncludes(filename);
// log(QString("File %1 included:").arg(filename));
Expand All @@ -632,9 +626,7 @@ QString Compiler::parseFileIncludesForAutolink(

for (int i=includedFiles.size()-1;i>=0;i--) {
QString includeFilename = includedFiles[i];
result += parseFileIncludesForAutolink(
includeFilename,
parsedFiles);
result += parseFileIncludesForAutolink(includeFilename, parsedFiles);
}
return result;
}
Expand Down Expand Up @@ -667,7 +659,7 @@ bool Compiler::parseForceUTF8ForAutolink(const QString &filename, QSet<QString>
return false;
}

void Compiler::runCommand(const QString &cmd, const QString &arguments, const QString &workingDir, const QByteArray& inputText, const QString& outputFile)
void Compiler::runCommand(const QString &cmd, const QStringList &arguments, const QString &workingDir, const QByteArray& inputText, const QString& outputFile)
{
QProcess process;
mStop = false;
Expand All @@ -692,7 +684,7 @@ void Compiler::runCommand(const QString &cmd, const QString &arguments, const Q
env.insert("CFLAGS","");
env.insert("CXXFLAGS","");
process.setProcessEnvironment(env);
process.setArguments(splitProcessCommand(arguments));
process.setArguments(arguments);
process.setWorkingDirectory(workingDir);
QFile output;
if (!outputFile.isEmpty()) {
Expand Down Expand Up @@ -773,6 +765,11 @@ void Compiler::runCommand(const QString &cmd, const QString &arguments, const Q
output.close();
}

QString Compiler::escapeCommandForLog(const QString &cmd, const QStringList &arguments)
{
return escapeCommandForPlatformShell(extractFileName(cmd), arguments);
}

PCppParser Compiler::parser() const
{
return mParserForFile;
Expand Down
Loading

0 comments on commit 1831865

Please sign in to comment.