mirror of
https://github.com/NikitaIvanovV/ctpv.git
synced 2024-12-01 00:43:08 +01:00
Fixes, improvements, additions
This commit is contained in:
parent
e0505cf094
commit
3e06cea1e4
80
ctpv.c
80
ctpv.c
@ -20,6 +20,7 @@ static struct {
|
|||||||
MODE_PREVIEW,
|
MODE_PREVIEW,
|
||||||
MODE_SERVER,
|
MODE_SERVER,
|
||||||
MODE_LIST,
|
MODE_LIST,
|
||||||
|
MODE_MIME,
|
||||||
} mode;
|
} mode;
|
||||||
} ctpv = { MODE_PREVIEW };
|
} ctpv = { MODE_PREVIEW };
|
||||||
|
|
||||||
@ -29,9 +30,10 @@ static void cleanup(void) {
|
|||||||
magic_close(magic);
|
magic_close(magic);
|
||||||
}
|
}
|
||||||
|
|
||||||
static int init_magic() {
|
static int init_magic()
|
||||||
magic = magic_open(MAGIC_MIME_TYPE);
|
{
|
||||||
ERRCHK_RET(!magic, "magic_open() failed");
|
ERRCHK_RET(!(magic = magic_open(MAGIC_MIME_TYPE)),
|
||||||
|
"magic_open() failed: %s", magic_error(magic));
|
||||||
|
|
||||||
ERRCHK_RET(magic_load(magic, NULL) != 0, "magic_load() failed: %s",
|
ERRCHK_RET(magic_load(magic, NULL) != 0, "magic_load() failed: %s",
|
||||||
magic_error(magic));
|
magic_error(magic));
|
||||||
@ -44,7 +46,8 @@ static void init_previews_v(void)
|
|||||||
init_previews(previews, LEN(previews));
|
init_previews(previews, LEN(previews));
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_mimetype(char const *path) {
|
static const char *get_mimetype(char const *path)
|
||||||
|
{
|
||||||
const char *r = magic_file(magic, path);
|
const char *r = magic_file(magic, path);
|
||||||
if (!r) {
|
if (!r) {
|
||||||
print_errorf("magic_file() failed: %s", magic_error(magic));
|
print_errorf("magic_file() failed: %s", magic_error(magic));
|
||||||
@ -54,12 +57,26 @@ static const char *get_mimetype(char const *path) {
|
|||||||
return r;
|
return r;
|
||||||
}
|
}
|
||||||
|
|
||||||
static const char *get_ext(char const *path) {
|
static const char *get_ext(char const *path)
|
||||||
const char *r = strrchr(path, '.');
|
{
|
||||||
if (!r)
|
const char *dot = strrchr(path, '.');
|
||||||
|
if (!dot)
|
||||||
return NULL;
|
return NULL;
|
||||||
|
|
||||||
return &r[1];
|
const char *slash = strrchr(path, '/');
|
||||||
|
if (slash && dot < slash)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
|
return &dot[1];
|
||||||
|
}
|
||||||
|
|
||||||
|
static int check_file(char const *f)
|
||||||
|
{
|
||||||
|
ERRCHK_RET(!f, "file not given");
|
||||||
|
ERRCHK_RET(access(f, R_OK) != 0, "failed to access '%s': %s", f,
|
||||||
|
strerror(errno));
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define GET_PARG(a, i) (a) = argc > (i) ? argv[i] : NULL
|
#define GET_PARG(a, i) (a) = argc > (i) ? argv[i] : NULL
|
||||||
@ -73,9 +90,7 @@ static int preview(int argc, char *argv[])
|
|||||||
GET_PARG(x, 3);
|
GET_PARG(x, 3);
|
||||||
GET_PARG(y, 4);
|
GET_PARG(y, 4);
|
||||||
|
|
||||||
ERRCHK_RET(!f, "file not given");
|
ERRCHK_RET_OK(check_file(f));
|
||||||
ERRCHK_RET(access(f, R_OK) != 0, "failed to access '%s': %s", f,
|
|
||||||
strerror(errno));
|
|
||||||
|
|
||||||
ERRCHK_RET_OK(init_magic());
|
ERRCHK_RET_OK(init_magic());
|
||||||
|
|
||||||
@ -84,15 +99,9 @@ static int preview(int argc, char *argv[])
|
|||||||
const char *mimetype = get_mimetype(f);
|
const char *mimetype = get_mimetype(f);
|
||||||
ERRCHK_RET(!mimetype);
|
ERRCHK_RET(!mimetype);
|
||||||
|
|
||||||
Preview *p = find_preview(get_ext(f), mimetype);
|
|
||||||
if (!p) {
|
|
||||||
puts("no preview found");
|
|
||||||
return OK;
|
|
||||||
}
|
|
||||||
|
|
||||||
PreviewArgs args = { .f = f, .w = w, .h = h, .x = x, .y = y };
|
PreviewArgs args = { .f = f, .w = w, .h = h, .x = x, .y = y };
|
||||||
|
|
||||||
ERRCHK_RET_OK(run_preview(p, &args));
|
ERRCHK_RET_OK(run_preview(get_ext(f), mimetype, &args));
|
||||||
|
|
||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
@ -132,12 +141,34 @@ static int list(void)
|
|||||||
return OK;
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static int mime(int argc, char *argv[])
|
||||||
|
{
|
||||||
|
char const *f, *mimetype;
|
||||||
|
|
||||||
|
for (int i = 0; i < argc; i++) {
|
||||||
|
f = argv[i];
|
||||||
|
ERRCHK_RET_OK(check_file(f));
|
||||||
|
|
||||||
|
ERRCHK_RET_OK(init_magic());
|
||||||
|
|
||||||
|
mimetype = get_mimetype(f);
|
||||||
|
ERRCHK_RET(!mimetype);
|
||||||
|
|
||||||
|
if (argc > 1)
|
||||||
|
printf("%s: ", f);
|
||||||
|
|
||||||
|
puts(mimetype);
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
int main(int argc, char *argv[])
|
int main(int argc, char *argv[])
|
||||||
{
|
{
|
||||||
program = argc > 0 ? argv[0] : "ctpv";
|
program = argc > 0 ? argv[0] : "ctpv";
|
||||||
|
|
||||||
int c;
|
int c;
|
||||||
while ((c = getopt(argc, argv, "sl")) != -1) {
|
while ((c = getopt(argc, argv, "slm")) != -1) {
|
||||||
switch (c) {
|
switch (c) {
|
||||||
case 's':
|
case 's':
|
||||||
ctpv.mode = MODE_SERVER;
|
ctpv.mode = MODE_SERVER;
|
||||||
@ -145,15 +176,21 @@ int main(int argc, char *argv[])
|
|||||||
case 'l':
|
case 'l':
|
||||||
ctpv.mode = MODE_LIST;
|
ctpv.mode = MODE_LIST;
|
||||||
break;
|
break;
|
||||||
|
case 'm':
|
||||||
|
ctpv.mode = MODE_MIME;
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
return EXIT_FAILURE;
|
return EXIT_FAILURE;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
argc -= optind;
|
||||||
|
argv = &argv[optind];
|
||||||
|
|
||||||
int ret;
|
int ret;
|
||||||
switch (ctpv.mode) {
|
switch (ctpv.mode) {
|
||||||
case MODE_PREVIEW:
|
case MODE_PREVIEW:
|
||||||
ret = preview(argc, &argv[optind]);
|
ret = preview(argc, argv);
|
||||||
break;
|
break;
|
||||||
case MODE_SERVER:
|
case MODE_SERVER:
|
||||||
ret = server();
|
ret = server();
|
||||||
@ -161,6 +198,9 @@ int main(int argc, char *argv[])
|
|||||||
case MODE_LIST:
|
case MODE_LIST:
|
||||||
ret = list();
|
ret = list();
|
||||||
break;
|
break;
|
||||||
|
case MODE_MIME:
|
||||||
|
ret = mime(argc, argv);
|
||||||
|
break;
|
||||||
default:
|
default:
|
||||||
print_errorf("unknowm mode: %d", ctpv.mode);
|
print_errorf("unknowm mode: %d", ctpv.mode);
|
||||||
ret = ERR;
|
ret = ERR;
|
||||||
|
89
preview.c
89
preview.c
@ -1,5 +1,6 @@
|
|||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
#include <unistd.h>
|
||||||
|
|
||||||
#include "utils.h"
|
#include "utils.h"
|
||||||
#include "error.h"
|
#include "error.h"
|
||||||
@ -7,6 +8,8 @@
|
|||||||
|
|
||||||
#define PREVP_SIZE sizeof(Preview *)
|
#define PREVP_SIZE sizeof(Preview *)
|
||||||
|
|
||||||
|
typedef Preview *(*FindFunc)(char const *s, size_t *i);
|
||||||
|
|
||||||
static char shell[] = "sh";
|
static char shell[] = "sh";
|
||||||
|
|
||||||
static Preview **sorted_by_ext,
|
static Preview **sorted_by_ext,
|
||||||
@ -69,9 +72,6 @@ void init_previews(Preview *ps, size_t len)
|
|||||||
|
|
||||||
qsort(sorted_by_ext, len, PREVP_SIZE, cmp_prev_ext);
|
qsort(sorted_by_ext, len, PREVP_SIZE, cmp_prev_ext);
|
||||||
qsort(sorted_by_mimetype, len, PREVP_SIZE, cmp_prev_mimetype);
|
qsort(sorted_by_mimetype, len, PREVP_SIZE, cmp_prev_mimetype);
|
||||||
|
|
||||||
/* for (size_t i = 0; i < len; i++) */
|
|
||||||
/* printf("%s %s\n", sorted_by_mimetype[i]->type, sorted_by_mimetype[i]->subtype); */
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void cleanup_previews(void)
|
void cleanup_previews(void)
|
||||||
@ -89,14 +89,21 @@ void cleanup_previews(void)
|
|||||||
prevs_length = 0;
|
prevs_length = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
static Preview *find_by_ext(char const *ext)
|
static Preview *find_by_ext(char const *ext, size_t *i)
|
||||||
{
|
{
|
||||||
Preview *key = &(Preview){ .ext = (char *)ext };
|
if (!ext)
|
||||||
|
return NULL;
|
||||||
|
|
||||||
void *p =
|
Preview *p;
|
||||||
bsearch(&key, sorted_by_ext, prevs_length, PREVP_SIZE, cmp_prev_ext);
|
|
||||||
|
|
||||||
return p ? *(Preview **)p : NULL;
|
for (; *i < prevs_length; (*i)++) {
|
||||||
|
p = sorted_by_ext[*i];
|
||||||
|
|
||||||
|
if (p->ext && strcmp(ext, p->ext) == 0)
|
||||||
|
return p;
|
||||||
|
}
|
||||||
|
|
||||||
|
return NULL;
|
||||||
}
|
}
|
||||||
|
|
||||||
static void break_mimetype(char *mimetype, char **type, char **subtype)
|
static void break_mimetype(char *mimetype, char **type, char **subtype)
|
||||||
@ -116,7 +123,7 @@ static void break_mimetype(char *mimetype, char **type, char **subtype)
|
|||||||
|
|
||||||
#define MIMETYPE_MAX 64
|
#define MIMETYPE_MAX 64
|
||||||
|
|
||||||
static Preview *find_by_mimetype(char const *mimetype)
|
static Preview *find_by_mimetype(char const *mimetype, size_t *i)
|
||||||
{
|
{
|
||||||
Preview *p;
|
Preview *p;
|
||||||
char mimetype_c[MIMETYPE_MAX], *t, *s;
|
char mimetype_c[MIMETYPE_MAX], *t, *s;
|
||||||
@ -124,8 +131,8 @@ static Preview *find_by_mimetype(char const *mimetype)
|
|||||||
strncpy(mimetype_c, mimetype, MIMETYPE_MAX - 1);
|
strncpy(mimetype_c, mimetype, MIMETYPE_MAX - 1);
|
||||||
break_mimetype(mimetype_c, &t, &s);
|
break_mimetype(mimetype_c, &t, &s);
|
||||||
|
|
||||||
for (size_t i = 0; i < prevs_length; i++) {
|
for (; *i < prevs_length; (*i)++) {
|
||||||
p = sorted_by_mimetype[i];
|
p = sorted_by_mimetype[*i];
|
||||||
|
|
||||||
if (!p->type)
|
if (!p->type)
|
||||||
return p;
|
return p;
|
||||||
@ -151,17 +158,38 @@ static void check_init_previews(void)
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
Preview *find_preview(char const *ext, char const *mimetype)
|
static int run(Preview *p, int *exitcode)
|
||||||
{
|
{
|
||||||
check_init_previews();
|
printf("MIME: .%s %s/%s\n", p->ext, p->type, p->subtype);
|
||||||
|
char *args[] = { shell, "-c", p->script, shell, NULL };
|
||||||
|
|
||||||
Preview *ret = NULL;
|
int *fds[] = { (int[]){ STDOUT_FILENO, STDERR_FILENO }, NULL };
|
||||||
if (mimetype)
|
|
||||||
ret = find_by_mimetype(mimetype);
|
|
||||||
if (!ret)
|
|
||||||
ret = find_by_ext(ext);
|
|
||||||
|
|
||||||
return ret;
|
return spawn(args, NULL, exitcode, fds);
|
||||||
|
}
|
||||||
|
|
||||||
|
static int find_and_run(int *found, FindFunc func, char const *arg)
|
||||||
|
{
|
||||||
|
Preview *p;
|
||||||
|
size_t i = 0;
|
||||||
|
int exitcode;
|
||||||
|
|
||||||
|
*found = 0;
|
||||||
|
|
||||||
|
run:
|
||||||
|
p = func(arg, &i);
|
||||||
|
if (!p)
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
ERRCHK_RET_OK(run(p, &exitcode));
|
||||||
|
if (exitcode == 127) {
|
||||||
|
i++;
|
||||||
|
goto run;
|
||||||
|
}
|
||||||
|
|
||||||
|
*found = 1;
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
#define SET_PENV(n, v) \
|
#define SET_PENV(n, v) \
|
||||||
@ -170,7 +198,7 @@ Preview *find_preview(char const *ext, char const *mimetype)
|
|||||||
ERRCHK_RET(setenv((n), (v), 1) != 0); \
|
ERRCHK_RET(setenv((n), (v), 1) != 0); \
|
||||||
} while (0)
|
} while (0)
|
||||||
|
|
||||||
int run_preview(Preview *p, PreviewArgs *pa)
|
int run_preview(const char *ext, const char *mimetype, PreviewArgs *pa)
|
||||||
{
|
{
|
||||||
SET_PENV("f", pa->f);
|
SET_PENV("f", pa->f);
|
||||||
SET_PENV("w", pa->w);
|
SET_PENV("w", pa->w);
|
||||||
@ -178,15 +206,24 @@ int run_preview(Preview *p, PreviewArgs *pa)
|
|||||||
SET_PENV("x", pa->x);
|
SET_PENV("x", pa->x);
|
||||||
SET_PENV("y", pa->y);
|
SET_PENV("y", pa->y);
|
||||||
|
|
||||||
char *args[] = { shell, "-c", p->script, shell, NULL };
|
SET_PENV("m", mimetype);
|
||||||
int ret, exitcode;
|
SET_PENV("e", ext);
|
||||||
|
|
||||||
ret = spawn(args, NULL, &exitcode);
|
check_init_previews();
|
||||||
|
|
||||||
if (exitcode > 0)
|
int found;
|
||||||
printf("error: preview exited with code: %d\n", exitcode);
|
|
||||||
|
|
||||||
return ret;
|
ERRCHK_RET_OK(find_and_run(&found, find_by_mimetype, mimetype));
|
||||||
|
if (found)
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
ERRCHK_RET_OK(find_and_run(&found, find_by_ext, ext));
|
||||||
|
if (found)
|
||||||
|
return OK;
|
||||||
|
|
||||||
|
puts("ctpv: no previews found");
|
||||||
|
|
||||||
|
return OK;
|
||||||
}
|
}
|
||||||
|
|
||||||
Preview **get_previews_list(size_t *len)
|
Preview **get_previews_list(size_t *len)
|
||||||
|
@ -13,8 +13,7 @@ typedef struct {
|
|||||||
|
|
||||||
void init_previews(Preview *ps, size_t len);
|
void init_previews(Preview *ps, size_t len);
|
||||||
void cleanup_previews(void);
|
void cleanup_previews(void);
|
||||||
Preview *find_preview(char const *ext, char const *mimetype);
|
int run_preview(const char *ext, const char *mimetype, PreviewArgs *pa);
|
||||||
int run_preview(Preview *p, PreviewArgs *pa);
|
|
||||||
Preview **get_previews_list(size_t *len);
|
Preview **get_previews_list(size_t *len);
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
13
utils.c
13
utils.c
@ -14,8 +14,11 @@ char *program;
|
|||||||
*
|
*
|
||||||
* If cpid is NULL, wait for the command to finish executing;
|
* If cpid is NULL, wait for the command to finish executing;
|
||||||
* otherwise store pid in cpid
|
* otherwise store pid in cpid
|
||||||
|
*
|
||||||
|
* fd is a NULL-terminated array of pairs of file descriptors
|
||||||
|
* to pass to dup2()
|
||||||
*/
|
*/
|
||||||
int spawn(char *args[], pid_t *cpid, int *exitcode)
|
int spawn(char *args[], pid_t *cpid, int *exitcode, int *fds[2])
|
||||||
{
|
{
|
||||||
if (exitcode)
|
if (exitcode)
|
||||||
*exitcode = -1;
|
*exitcode = -1;
|
||||||
@ -25,6 +28,14 @@ int spawn(char *args[], pid_t *cpid, int *exitcode)
|
|||||||
|
|
||||||
/* Child process */
|
/* Child process */
|
||||||
if (pid == 0) {
|
if (pid == 0) {
|
||||||
|
while (*fds) {
|
||||||
|
if (dup2((*fds)[0], (*fds)[1]) == -1) {
|
||||||
|
print_errorf("dup2() failed: %s", strerror(errno));
|
||||||
|
exit(EXIT_FAILURE);
|
||||||
|
}
|
||||||
|
fds = &fds[1];
|
||||||
|
}
|
||||||
|
|
||||||
execvp(args[0], args);
|
execvp(args[0], args);
|
||||||
print_errorf("exec() failed: %s", strerror(errno));
|
print_errorf("exec() failed: %s", strerror(errno));
|
||||||
exit(EXIT_FAILURE);
|
exit(EXIT_FAILURE);
|
||||||
|
2
utils.h
2
utils.h
@ -23,7 +23,7 @@ typedef struct {
|
|||||||
|
|
||||||
extern char *program;
|
extern char *program;
|
||||||
|
|
||||||
int spawn(char *args[], pid_t *cpid, int *exitcode);
|
int spawn(char *args[], pid_t *cpid, int *exitcode, int *fds[2]);
|
||||||
|
|
||||||
CharVec char_v_new(size_t cap);
|
CharVec char_v_new(size_t cap);
|
||||||
void char_v_append(CharVec *v, char c);
|
void char_v_append(CharVec *v, char c);
|
||||||
|
Loading…
Reference in New Issue
Block a user