Solves issue #884: single quote zenity/kdialog

This commit is contained in:
Greg Ercolano 2024-01-11 07:50:09 -08:00
parent a237743c8b
commit d9125d76cb
4 changed files with 106 additions and 75 deletions

View File

@ -24,6 +24,7 @@
*/
#include <FL/Fl_Native_File_Chooser.H>
#include "Fl_String.H"
class Fl_Kdialog_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_FLTK_Driver {
friend class Fl_Native_File_Chooser;
@ -45,7 +46,7 @@ class Fl_Kdialog_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_FLTK
int count() const FL_OVERRIDE;
const char *filename() const FL_OVERRIDE;
const char *filename(int i) const FL_OVERRIDE;
virtual char *build_command();
virtual void build_command(Fl_String& command);
int show() FL_OVERRIDE;
char *parse_filter(const char *f);
const char *filter() const FL_OVERRIDE;
@ -57,6 +58,7 @@ class Fl_Kdialog_Native_File_Chooser_Driver : public Fl_Native_File_Chooser_FLTK
const char *directory() const FL_OVERRIDE;
void title(const char *val) FL_OVERRIDE;
const char *title() const FL_OVERRIDE;
void shell_quote(Fl_String& s);
};
/**

View File

@ -30,7 +30,6 @@
#include <string.h>
#include <unistd.h>
/* Fl_Kdialog_Native_File_Chooser_Driver : file chooser based on the "kdialog" command */
bool Fl_Kdialog_Native_File_Chooser_Driver::did_find_kdialog = false;
@ -73,7 +72,7 @@ static int fnfc_dispatch(int /*event*/, Fl_Window* /*win*/) {
}
char *Fl_Kdialog_Native_File_Chooser_Driver::build_command() {
void Fl_Kdialog_Native_File_Chooser_Driver::build_command(Fl_String& command) {
const char *option;
switch (_btype) {
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
@ -92,25 +91,30 @@ char *Fl_Kdialog_Native_File_Chooser_Driver::build_command() {
default:
option = "--getopenfilename";
}
// Build preset
const char *preset = ".";
if (_preset_file) preset = _preset_file;
if (_preset_file) preset = _preset_file;
else if (_directory) preset = _directory;
const int com_size = strlen(option) + strlen(preset) +
(_title?strlen(_title)+11:0) + (_parsedfilt?strlen(_parsedfilt):0) + 50;
char *command = new char[com_size];
strcpy(command, "kdialog ");
// Build command
command = "kdialog";
if (_title) {
snprintf(command+strlen(command), com_size - strlen(command),
" --title '%s'", _title);
Fl_String quoted_title = _title; shell_quote(quoted_title);
command += " --title ";
command += quoted_title;
}
snprintf(command+strlen(command), com_size - strlen(command),
" %s %s ", option, preset);
command += " ";
command += option;
command += " ";
command += preset;
if (_parsedfilt) {
snprintf(command+strlen(command), com_size - strlen(command),
" \"%s\" ", _parsedfilt);
Fl_String quoted_filt = _parsedfilt; shell_quote(quoted_filt); // NOTE: orig code used double quoting -erco 1/10/24
command += " ";
command += quoted_filt;
}
strcat(command, "2> /dev/null"); // get rid of stderr output
return command;
command += " 2> /dev/null"; // get rid of stderr
//printf("command = %s\n", command.c_str());
}
@ -137,9 +141,10 @@ int Fl_Kdialog_Native_File_Chooser_Driver::show() {
return retval;
}
char *command = build_command();
//puts(command);
FILE *pipe = popen(command, "r");
Fl_String command;
build_command(command);
fprintf(stderr, "DEBUG: POPEN: %s\n", command.c_str());
FILE *pipe = popen(command.c_str(), "r");
fnfc_pipe_struct data;
data.all_files = NULL;
if (pipe) {
@ -175,7 +180,6 @@ int Fl_Kdialog_Native_File_Chooser_Driver::show() {
}
}
}
delete[] command;
if (!pipe) return -1;
return (data.all_files == NULL ? 1 : 0);
}
@ -298,6 +302,19 @@ const char *Fl_Kdialog_Native_File_Chooser_Driver::title() const {
return _title;
}
// Add shell quotes around string 's'.
// Handles quoting embedded quotes.
//
void Fl_Kdialog_Native_File_Chooser_Driver::shell_quote(Fl_String& s) {
Fl_String out = "'"; // leading quote
for (int t=0; t<s.size(); t++) {
if (s[t] == '\'') out += "'\"'\"'"; // quote any quotes
else out += s[t];
}
out += "'"; // trailing quote
s = out;
}
/**
\}
\endcond

View File

@ -30,7 +30,8 @@ class Fl_Zenity_Native_File_Chooser_Driver : public Fl_Kdialog_Native_File_Choos
static bool did_find_zenity;
static bool have_looked_for_zenity;
Fl_Zenity_Native_File_Chooser_Driver(int val);
char *build_command() FL_OVERRIDE;
void append_filter(Fl_String& command);
void build_command(Fl_String& command) FL_OVERRIDE;
};
/**

View File

@ -36,10 +36,48 @@ bool Fl_Zenity_Native_File_Chooser_Driver::have_looked_for_zenity = false;
Fl_Zenity_Native_File_Chooser_Driver::Fl_Zenity_Native_File_Chooser_Driver(int val) : Fl_Kdialog_Native_File_Chooser_Driver(val) {
}
char *Fl_Zenity_Native_File_Chooser_Driver::build_command() {
const char *option;
void Fl_Zenity_Native_File_Chooser_Driver::append_filter(Fl_String& ret_command) {
// TODO: This could probably be simplified + toughened with Fl_String -erco 1/10/24
int l;
int lcommand = 10000;
char *command = new char[lcommand];
command[0] = 0;
char *parsed_filter_copy = strdup(_parsedfilt); // keep _parsedfilt unchanged for re-use
char *p = strtok(parsed_filter_copy, "\n");
while (p) {
char *op = strchr(p, '(');
l = strlen(command);
snprintf(command+l, lcommand-l, " --file-filter='%s|", p);
char *cp = strchr(p, ')');
*cp = 0;
char *ob = strchr(op+1, '[');
if (ob) { // process [xyz] patterns
*ob = 0;
char *cb = strchr(ob+1, ']');
char aux[100];
for (char *q = ob+1; q < cb; q++) {
strcpy(aux, op+1);
int la = strlen(aux);
aux[la++] = *q;
if (cb < cp-1) { strcpy(aux+la, cb+1); la += strlen(cb+1); }
aux[la] = 0;
l = strlen(command);
snprintf(command+l, lcommand-l, " %s", aux);
}
strcat(command, "'");
} else {
l = strlen(command);
snprintf(command+l, lcommand-l, "%s'", op+1);
}
p = strtok(NULL, "\n");
}
free(parsed_filter_copy);
ret_command += command; // append to parent's Fl_String
delete [] command;
}
void Fl_Zenity_Native_File_Chooser_Driver::build_command(Fl_String& command) {
const char *option;
switch (_btype) {
case Fl_Native_File_Chooser::BROWSE_DIRECTORY:
case Fl_Native_File_Chooser::BROWSE_SAVE_DIRECTORY:
@ -60,63 +98,36 @@ char *Fl_Zenity_Native_File_Chooser_Driver::build_command() {
default:
option = "--file-selection";
}
char *preset = NULL;
// Build preset
Fl_String preset;
if (_preset_file) {
l = strlen(_preset_file) + 15;
preset = new char[l];
snprintf(preset, l, "--filename='%s'", _preset_file);
}
else if (_directory) {
Fl_String quoted_filename = _preset_file; shell_quote(quoted_filename);
preset = "--filename=";
preset += quoted_filename;
} else if (_directory) {
// This doesn't actually seem to do anything, but supply it anyway.
l = strlen(_directory) + 15;
preset = new char[l];
snprintf(preset, l, "--filename '%s'", _directory);
Fl_String quoted_dir = _directory; shell_quote(quoted_dir);
preset = "--filename=";
preset += quoted_dir;
}
int lcommand = 10000;
char *command = new char[lcommand];
strcpy(command, "zenity ");
// Build command
command = "zenity";
if (_title) {
l = strlen(command);
snprintf(command+l, lcommand-l, " --title '%s'", _title);
Fl_String quoted_title = _title; shell_quote(quoted_title);
command += " --title ";
command += quoted_title;
}
l = strlen(command);
snprintf(command+l, lcommand-l, " %s %s ", option, preset ? preset : "");
delete[] preset;
if (_parsedfilt) {
char *parsed_filter_copy = strdup(_parsedfilt); // keep _parsedfilt unchanged for re-use
char *p = strtok(parsed_filter_copy, "\n");
while (p) {
char *op = strchr(p, '(');
l = strlen(command);
snprintf(command+l, lcommand-l, " --file-filter='%s|", p);
char *cp = strchr(p, ')');
*cp = 0;
char *ob = strchr(op+1, '[');
if (ob) { // process [xyz] patterns
*ob = 0;
char *cb = strchr(ob+1, ']');
char aux[100];
for (char *q = ob+1; q < cb; q++) {
strcpy(aux, op+1);
int la = strlen(aux);
aux[la++] = *q;
if (cb < cp-1) { strcpy(aux+la, cb+1); la += strlen(cb+1); }
aux[la] = 0;
l = strlen(command);
snprintf(command+l, lcommand-l, " %s", aux);
}
strcat(command, "'");
} else {
l = strlen(command);
snprintf(command+l, lcommand-l, "%s'", op+1);
}
p = strtok(NULL, "\n");
}
free(parsed_filter_copy);
command += " ";
command += option;
if (preset != "") {
command += " ";
command += preset;
}
strcat(command, " 2> /dev/null"); // get rid of stderr output
//puts(command);
return command;
if (_parsedfilt) append_filter(command);
command += " 2> /dev/null"; // get rid of stderr
//printf("command = %s\n", command.c_str());
}
/**