File dialog improvements

- Add a globally-accessible function to handle the parsing of filter extensions
- Remove the ability of putting the wildcard ('*') among other patterns; it's either a list of patterns or a single '*' now
- Add a hint to select between portals and Zenity on Unix
This commit is contained in:
Semphris
2024-04-02 16:03:58 -04:00
committed by Sam Lantinga
parent 5fa87e29e7
commit 6ad390fc50
18 changed files with 501 additions and 125 deletions

View File

@@ -19,7 +19,7 @@
3. This notice may not be removed or altered from any source distribution.
*/
#include "SDL_internal.h"
#include "./SDL_dialog.h"
#include "../SDL_dialog_utils.h"
#include <errno.h>
#include <sys/types.h>
@@ -65,6 +65,22 @@ typedef struct
} \
}
char *zenity_clean_name(const char *name)
{
char *newname = SDL_strdup(name);
/* Filter out "|", which Zenity considers a special character. Let's hope
there aren't others. TODO: find something better. */
for (char *c = newname; *c; c++) {
if (*c == '|') {
/* Zenity doesn't support escaping with \ */
*c = '/';
}
}
return newname;
}
/* Exec call format:
*
* /usr/bin/env zenity --file-selection --separator=\n [--multiple]
@@ -147,68 +163,15 @@ static char** generate_args(const zenityArgs* info)
const SDL_DialogFileFilter *filter_ptr = info->filters;
while (filter_ptr->name && filter_ptr->pattern) {
/* *Normally*, no filter arg should exceed 4096 bytes. */
char buffer[4096];
char *filter_str = convert_filter(*filter_ptr, zenity_clean_name,
"--file-filter=", " | ", "",
"*.", " *.", "");
SDL_snprintf(buffer, 4096, "--file-filter=%s | *.", filter_ptr->name);
size_t i_buf = SDL_strlen(buffer);
/* "|" is a special character for Zenity */
for (char *c = buffer; *c; c++) {
if (*c == '|') {
*c = ' ';
}
}
for (size_t i_pat = 0; i_buf < 4095 && filter_ptr->pattern[i_pat]; i_pat++) {
const char *c = filter_ptr->pattern + i_pat;
if (*c == ';') {
/* Disallow empty patterns (might bug Zenity) */
int at_end = (c[1] == '\0');
int at_mid = (c[1] == ';');
int at_beg = (i_pat == 0);
if (at_end || at_mid || at_beg) {
const char *pos_str = "";
if (at_end) {
pos_str = "end";
} else if (at_mid) {
pos_str = "middle";
} else if (at_beg) {
pos_str = "beginning";
}
SDL_SetError("Empty pattern file extension (at %s of list)", pos_str);
CLEAR_AND_RETURN()
}
if (i_buf + 3 >= 4095) {
i_buf += 3;
break;
}
buffer[i_buf++] = ' ';
buffer[i_buf++] = '*';
buffer[i_buf++] = '.';
} else if (*c == '*' && (c[1] == '\0' || c[1] == ';') && (i_pat == 0 || *(c - 1) == ';')) {
buffer[i_buf++] = '*';
} else if (!((*c >= 'a' && *c <= 'z') || (*c >= 'A' && *c <= 'Z') || (*c >= '0' && *c <= '9') || *c == '.' || *c == '_' || *c == '-')) {
SDL_SetError("Illegal character in pattern name: %c (Only alphanumeric characters, periods, underscores and hyphens allowed)", *c);
CLEAR_AND_RETURN()
} else {
buffer[i_buf++] = *c;
}
}
if (i_buf >= 4095) {
SDL_SetError("Filter '%s' wouldn't fit in a 4096 byte buffer; please report your use case if you need filters that long", filter_ptr->name);
if (!filter_str) {
CLEAR_AND_RETURN()
}
buffer[i_buf] = '\0';
argv[nextarg++] = SDL_strdup(buffer);
argv[nextarg++] = filter_str;
CHECK_OOM()
filter_ptr++;