Fixes, improvements, additions

This commit is contained in:
Nikita Ivanov 2022-05-23 06:32:09 +05:00
parent e0505cf094
commit 3e06cea1e4
No known key found for this signature in database
GPG Key ID: 6E656AC5B97B5133
5 changed files with 137 additions and 50 deletions

80
ctpv.c
View File

@ -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;

View File

@ -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)

View File

@ -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
View File

@ -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);

View File

@ -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);