#include <stdio.h>
#include <assert.h>
#include <string.h>
#include "include/nfd.h"
#include "nfd_common.h"
#define SIMPLE_EXEC_IMPLEMENTATION
#include "simple_exec.h"
const char NO_ZENITY_MSG[] = "zenity not installed";
static void
AddTypeToFilterName(const char* typebuf, char* filterName, size_t bufsize)
{
size_t len = strlen(filterName);
if (len > 0)
strncat(filterName, " *.", bufsize - len - 1);
else
strncat(filterName, "--file-filter=*.", bufsize - len - 1);
len = strlen(filterName);
strncat(filterName, typebuf, bufsize - len - 1);
}
static void
AddFiltersToCommandArgs(char** commandArgs, int commandArgsLen, const char* filterList)
{
char typebuf[NFD_MAX_STRLEN] = {0};
const char* p_filterList = filterList;
char* p_typebuf = typebuf;
char filterName[NFD_MAX_STRLEN] = {0};
int i;
if (!filterList || strlen(filterList) == 0)
return;
while (1) {
if (NFDi_IsFilterSegmentChar(*p_filterList)) {
char typebufWildcard[NFD_MAX_STRLEN + 3];
assert(strlen(typebuf) > 0);
assert(strlen(typebuf) < NFD_MAX_STRLEN - 1);
snprintf(typebufWildcard, NFD_MAX_STRLEN + 3, "*.%s", typebuf);
AddTypeToFilterName(typebuf, filterName, NFD_MAX_STRLEN);
p_typebuf = typebuf;
memset(typebuf, 0, sizeof(char) * NFD_MAX_STRLEN);
}
if (*p_filterList == ';' || *p_filterList == '\0') {
for (i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++)
;
commandArgs[i] = strdup(filterName);
filterName[0] = '\0';
if (*p_filterList == '\0')
break;
}
if (!NFDi_IsFilterSegmentChar(*p_filterList)) {
*p_typebuf = *p_filterList;
p_typebuf++;
}
p_filterList++;
}
for (i = 0; commandArgs[i] != NULL && i < commandArgsLen; i++)
;
commandArgs[i] = strdup("--file-filter=*.*");
}
static nfdresult_t
ZenityCommon(char** command,
int commandLen,
const char* defaultPath,
const char* filterList,
char** stdOut)
{
if (defaultPath != NULL) {
char* prefix = "--filename=";
int len = strlen(prefix) + strlen(defaultPath) + 1;
char* tmp = (char*)calloc(len, 1);
strcat(tmp, prefix);
strcat(tmp, defaultPath);
int i;
for (i = 0; command[i] != NULL && i < commandLen; i++)
;
command[i] = tmp;
}
AddFiltersToCommandArgs(command, commandLen, filterList);
int byteCount = 0;
int exitCode = 0;
int processInvokeError =
runCommandArray(stdOut, &byteCount, &exitCode, 0, command);
for (int i = 0; command[i] != NULL && i < commandLen; i++) free(command[i]);
nfdresult_t result = NFD_OKAY;
if (processInvokeError == COMMAND_NOT_FOUND) {
NFDi_SetError(NO_ZENITY_MSG);
result = NFD_ERROR;
} else {
if (exitCode == 1)
result = NFD_CANCEL;
}
return result;
}
static nfdresult_t
AllocPathSet(char* zenityList, nfdpathset_t* pathSet)
{
assert(zenityList);
assert(pathSet);
size_t len = strlen(zenityList) + 1;
pathSet->buf = NFDi_Malloc(len);
int numEntries = 1;
for (size_t i = 0; i < len; i++) {
char ch = zenityList[i];
if (ch == '|') {
numEntries++;
ch = '\0';
}
pathSet->buf[i] = ch;
}
pathSet->count = numEntries;
assert(pathSet->count > 0);
pathSet->indices = NFDi_Malloc(sizeof(size_t) * pathSet->count);
int entry = 0;
pathSet->indices[0] = 0;
for (size_t i = 0; i < len; i++) {
char ch = zenityList[i];
if (ch == '|') {
entry++;
pathSet->indices[entry] = i + 1;
}
}
return NFD_OKAY;
}
nfdresult_t
NFD_OpenDialog(const char* filterList, const nfdchar_t* defaultPath, nfdchar_t** outPath)
{
int commandLen = 100;
char* command[commandLen];
memset(command, 0, commandLen * sizeof(char*));
command[0] = strdup("zenity");
command[1] = strdup("--file-selection");
command[2] = strdup("--title=Open File");
char* stdOut = NULL;
nfdresult_t result =
ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
if (stdOut != NULL) {
size_t len = strlen(stdOut);
*outPath = NFDi_Malloc(len);
memcpy(*outPath, stdOut, len);
(*outPath)[len - 1] = '\0'; free(stdOut);
} else {
*outPath = NULL;
}
return result;
}
nfdresult_t
NFD_OpenDialogMultiple(const nfdchar_t* filterList,
const nfdchar_t* defaultPath,
nfdpathset_t* outPaths)
{
int commandLen = 100;
char* command[commandLen];
memset(command, 0, commandLen * sizeof(char*));
command[0] = strdup("zenity");
command[1] = strdup("--file-selection");
command[2] = strdup("--title=Open Files");
command[3] = strdup("--multiple");
char* stdOut = NULL;
nfdresult_t result =
ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
if (stdOut != NULL) {
size_t len = strlen(stdOut);
stdOut[len - 1] = '\0';
if (AllocPathSet(stdOut, outPaths) == NFD_ERROR)
result = NFD_ERROR;
free(stdOut);
} else {
result = NFD_ERROR;
}
return result;
}
nfdresult_t
NFD_SaveDialog(const nfdchar_t* filterList, const nfdchar_t* defaultPath, nfdchar_t** outPath)
{
int commandLen = 100;
char* command[commandLen];
memset(command, 0, commandLen * sizeof(char*));
command[0] = strdup("zenity");
command[1] = strdup("--file-selection");
command[2] = strdup("--title=Save File");
command[3] = strdup("--save");
char* stdOut = NULL;
nfdresult_t result =
ZenityCommon(command, commandLen, defaultPath, filterList, &stdOut);
if (stdOut != NULL) {
size_t len = strlen(stdOut);
*outPath = NFDi_Malloc(len);
memcpy(*outPath, stdOut, len);
(*outPath)[len - 1] = '\0'; free(stdOut);
} else {
*outPath = NULL;
}
return result;
}
nfdresult_t
NFD_PickFolder(const nfdchar_t* defaultPath, nfdchar_t** outPath)
{
int commandLen = 100;
char* command[commandLen];
memset(command, 0, commandLen * sizeof(char*));
command[0] = strdup("zenity");
command[1] = strdup("--file-selection");
command[2] = strdup("--directory");
command[3] = strdup("--title=Select folder");
char* stdOut = NULL;
nfdresult_t result = ZenityCommon(command, commandLen, defaultPath, "", &stdOut);
if (stdOut != NULL) {
size_t len = strlen(stdOut);
*outPath = NFDi_Malloc(len);
memcpy(*outPath, stdOut, len);
(*outPath)[len - 1] = '\0'; free(stdOut);
} else {
*outPath = NULL;
}
return result;
}