2022-05-22 09:55:04 +02:00
|
|
|
#include <stdio.h>
|
2022-05-23 03:32:09 +02:00
|
|
|
#include <unistd.h>
|
2022-05-22 09:55:04 +02:00
|
|
|
|
|
|
|
#include "utils.h"
|
|
|
|
#include "error.h"
|
2022-05-25 23:57:50 +02:00
|
|
|
#include "shell.h"
|
2022-05-22 09:55:04 +02:00
|
|
|
#include "preview.h"
|
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
#define FAILED_PREVIEW_EC NOTEXIST_EC
|
2022-05-24 02:46:34 +02:00
|
|
|
|
2022-05-22 09:55:04 +02:00
|
|
|
#define PREVP_SIZE sizeof(Preview *)
|
|
|
|
|
2022-05-24 03:26:02 +02:00
|
|
|
static struct {
|
|
|
|
size_t len;
|
|
|
|
Preview **list;
|
|
|
|
} previews;
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-23 04:45:06 +02:00
|
|
|
static int cmp_previews(const void *p1, const void *p2)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
|
|
|
Preview *pr1 = *(Preview **)p1;
|
|
|
|
Preview *pr2 = *(Preview **)p2;
|
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
int i;
|
|
|
|
|
|
|
|
if ((i = pr2->priority - pr1->priority) != 0)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
if ((i = strcmpnull(pr1->ext, pr2->ext)) != 0)
|
|
|
|
return -i;
|
|
|
|
|
|
|
|
if ((i = strcmpnull(pr1->type, pr2->type)) != 0)
|
|
|
|
return -i;
|
|
|
|
|
|
|
|
if ((i = strcmpnull(pr1->subtype, pr2->subtype)) != 0)
|
|
|
|
return i;
|
|
|
|
|
|
|
|
return i;
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void init_previews(Preview *ps, size_t len)
|
|
|
|
{
|
2022-05-24 03:26:02 +02:00
|
|
|
previews.len = len;
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-24 03:26:02 +02:00
|
|
|
previews.list = malloc(len * PREVP_SIZE);
|
|
|
|
if (!previews.list) {
|
2022-05-24 02:27:07 +02:00
|
|
|
PRINTINTERR(FUNCFAILED("malloc"), ERRNOS);
|
2022-05-22 09:55:04 +02:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
for (size_t i = 0; i < len; i++)
|
2022-05-24 03:26:02 +02:00
|
|
|
previews.list[i] = &ps[i];
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-24 03:26:02 +02:00
|
|
|
qsort(previews.list, previews.len, PREVP_SIZE, cmp_previews);
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
void cleanup_previews(void)
|
|
|
|
{
|
2022-05-24 03:26:02 +02:00
|
|
|
if (!previews.list)
|
|
|
|
return;
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-24 03:26:02 +02:00
|
|
|
free(previews.list);
|
|
|
|
previews.list = NULL;
|
|
|
|
previews.len = 0;
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
static void break_mimetype(char *mimetype, char **type, char **subtype)
|
|
|
|
{
|
|
|
|
*type = mimetype[0] == '\0' ? NULL : mimetype;
|
|
|
|
*subtype = NULL;
|
|
|
|
|
|
|
|
char *s = strchr(mimetype, '/');
|
|
|
|
if (!s) {
|
2022-05-24 02:27:07 +02:00
|
|
|
PRINTINTERR("invalid mimetype: '%s'", mimetype);
|
2022-05-22 09:55:04 +02:00
|
|
|
abort();
|
|
|
|
}
|
|
|
|
|
|
|
|
*s = '\0';
|
|
|
|
*subtype = &s[1];
|
|
|
|
}
|
|
|
|
|
|
|
|
#define MIMETYPE_MAX 64
|
|
|
|
|
2022-05-23 04:45:06 +02:00
|
|
|
static Preview *find_preview(char const *mimetype, char const *ext, size_t *i)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
|
|
|
Preview *p;
|
|
|
|
char mimetype_c[MIMETYPE_MAX], *t, *s;
|
|
|
|
|
|
|
|
strncpy(mimetype_c, mimetype, MIMETYPE_MAX - 1);
|
|
|
|
break_mimetype(mimetype_c, &t, &s);
|
|
|
|
|
2022-05-24 03:26:02 +02:00
|
|
|
for (; *i < previews.len; (*i)++) {
|
|
|
|
p = previews.list[*i];
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
if (p->ext && strcmpnull(p->ext, ext) != 0)
|
2022-05-22 11:56:44 +02:00
|
|
|
continue;
|
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
if (p->type && strcmpnull(p->type, t) != 0)
|
2022-05-23 04:45:06 +02:00
|
|
|
continue;
|
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
if (p->subtype && strcmpnull(p->subtype, s) != 0)
|
|
|
|
continue;
|
2022-05-23 04:45:06 +02:00
|
|
|
|
2022-05-23 20:45:35 +02:00
|
|
|
return p;
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
|
|
|
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2022-05-22 22:07:08 +02:00
|
|
|
static void check_init_previews(void)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
2022-05-24 03:26:02 +02:00
|
|
|
if (!previews.list) {
|
2022-05-24 02:27:07 +02:00
|
|
|
PRINTINTERR("init_previews() not called");
|
2022-05-22 09:55:04 +02:00
|
|
|
abort();
|
|
|
|
}
|
2022-05-22 22:07:08 +02:00
|
|
|
}
|
|
|
|
|
2022-05-24 02:46:34 +02:00
|
|
|
#define CMD_ERR_BUF 256
|
|
|
|
|
2022-05-23 03:32:09 +02:00
|
|
|
static int run(Preview *p, int *exitcode)
|
2022-05-22 22:07:08 +02:00
|
|
|
{
|
2022-05-25 23:57:50 +02:00
|
|
|
int pipe_fds[2];
|
|
|
|
ERRCHK_RET(pipe(pipe_fds) == -1, FUNCFAILED("pipe"), ERRNOS);
|
2022-05-24 02:46:34 +02:00
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
int sp_arg[] = { pipe_fds[0], pipe_fds[1], STDERR_FILENO };
|
2022-05-24 02:46:34 +02:00
|
|
|
|
2022-05-28 19:33:18 +02:00
|
|
|
char *script = prepend_helpers(p->script, p->script_len - 1);
|
|
|
|
char *args[] = SHELL_ARGS(script);
|
2022-05-24 02:46:34 +02:00
|
|
|
int ret = spawn(args, NULL, exitcode, spawn_redirect, sp_arg);
|
|
|
|
|
2022-05-28 19:33:18 +02:00
|
|
|
free(script);
|
2022-05-25 23:57:50 +02:00
|
|
|
close(pipe_fds[1]);
|
2022-05-24 02:46:34 +02:00
|
|
|
|
|
|
|
if (*exitcode != FAILED_PREVIEW_EC) {
|
|
|
|
char buf[CMD_ERR_BUF];
|
|
|
|
int len;
|
2022-05-25 23:57:50 +02:00
|
|
|
while ((len = read(pipe_fds[0], buf, CMD_ERR_BUF)) > 0) {
|
2022-05-24 02:46:34 +02:00
|
|
|
write(STDOUT_FILENO, buf, len);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (len == -1) {
|
|
|
|
PRINTINTERR(FUNCFAILED("read"), ERRNOS);
|
|
|
|
ret = ERR;
|
|
|
|
}
|
|
|
|
}
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
close(pipe_fds[0]);
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-24 02:46:34 +02:00
|
|
|
return ret;
|
2022-05-23 03:32:09 +02:00
|
|
|
}
|
|
|
|
|
2022-05-24 02:27:07 +02:00
|
|
|
#define SET_PENV(n, v) \
|
|
|
|
do { \
|
|
|
|
if (v) \
|
|
|
|
ERRCHK_RET(setenv((n), (v), 1) != 0, FUNCFAILED("setenv"), \
|
|
|
|
ERRNOS); \
|
2022-05-22 09:55:04 +02:00
|
|
|
} while (0)
|
|
|
|
|
2022-05-23 03:32:09 +02:00
|
|
|
int run_preview(const char *ext, const char *mimetype, PreviewArgs *pa)
|
2022-05-22 09:55:04 +02:00
|
|
|
{
|
2022-05-28 16:07:59 +02:00
|
|
|
SET_PENV("ctpv", pa->ctpv);
|
2022-05-22 09:55:04 +02:00
|
|
|
SET_PENV("f", pa->f);
|
|
|
|
SET_PENV("w", pa->w);
|
|
|
|
SET_PENV("h", pa->h);
|
|
|
|
SET_PENV("x", pa->x);
|
|
|
|
SET_PENV("y", pa->y);
|
|
|
|
|
2022-05-23 03:32:09 +02:00
|
|
|
SET_PENV("m", mimetype);
|
|
|
|
SET_PENV("e", ext);
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-23 03:32:09 +02:00
|
|
|
check_init_previews();
|
2022-05-22 09:55:04 +02:00
|
|
|
|
2022-05-23 04:45:06 +02:00
|
|
|
Preview *p;
|
|
|
|
size_t i = 0;
|
|
|
|
int exitcode;
|
2022-05-23 03:32:09 +02:00
|
|
|
|
2022-05-23 04:45:06 +02:00
|
|
|
run:
|
|
|
|
p = find_preview(mimetype, ext, &i);
|
|
|
|
if (!p) {
|
|
|
|
puts("ctpv: no previews found");
|
2022-05-25 23:57:50 +02:00
|
|
|
return ERR;
|
2022-05-23 04:45:06 +02:00
|
|
|
}
|
2022-05-23 03:32:09 +02:00
|
|
|
|
2022-05-23 04:45:06 +02:00
|
|
|
ERRCHK_RET_OK(run(p, &exitcode));
|
2022-05-24 02:46:34 +02:00
|
|
|
if (exitcode == FAILED_PREVIEW_EC) {
|
2022-05-23 04:45:06 +02:00
|
|
|
i++;
|
|
|
|
goto run;
|
|
|
|
}
|
2022-05-23 03:32:09 +02:00
|
|
|
|
2022-05-25 23:57:50 +02:00
|
|
|
return exitcode == 0 ? OK : ERR;
|
2022-05-22 09:55:04 +02:00
|
|
|
}
|
2022-05-22 22:07:08 +02:00
|
|
|
|
|
|
|
Preview **get_previews_list(size_t *len)
|
|
|
|
{
|
|
|
|
check_init_previews();
|
2022-05-24 03:26:02 +02:00
|
|
|
*len = previews.len;
|
|
|
|
return previews.list;
|
2022-05-22 22:07:08 +02:00
|
|
|
}
|