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_SERVER,
MODE_LIST,
MODE_MIME,
} mode;
} ctpv = { MODE_PREVIEW };
@ -29,9 +30,10 @@ static void cleanup(void) {
magic_close(magic);
}
static int init_magic() {
magic = magic_open(MAGIC_MIME_TYPE);
ERRCHK_RET(!magic, "magic_open() failed");
static int init_magic()
{
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",
magic_error(magic));
@ -44,7 +46,8 @@ static void init_previews_v(void)
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);
if (!r) {
print_errorf("magic_file() failed: %s", magic_error(magic));
@ -54,12 +57,26 @@ static const char *get_mimetype(char const *path) {
return r;
}
static const char *get_ext(char const *path) {
const char *r = strrchr(path, '.');
if (!r)
static const char *get_ext(char const *path)
{
const char *dot = strrchr(path, '.');
if (!dot)
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
@ -73,9 +90,7 @@ static int preview(int argc, char *argv[])
GET_PARG(x, 3);
GET_PARG(y, 4);
ERRCHK_RET(!f, "file not given");
ERRCHK_RET(access(f, R_OK) != 0, "failed to access '%s': %s", f,
strerror(errno));
ERRCHK_RET_OK(check_file(f));
ERRCHK_RET_OK(init_magic());
@ -84,15 +99,9 @@ static int preview(int argc, char *argv[])
const char *mimetype = get_mimetype(f);
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 };
ERRCHK_RET_OK(run_preview(p, &args));
ERRCHK_RET_OK(run_preview(get_ext(f), mimetype, &args));
return OK;
}
@ -132,12 +141,34 @@ static int list(void)
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[])
{
program = argc > 0 ? argv[0] : "ctpv";
int c;
while ((c = getopt(argc, argv, "sl")) != -1) {
while ((c = getopt(argc, argv, "slm")) != -1) {
switch (c) {
case 's':
ctpv.mode = MODE_SERVER;
@ -145,15 +176,21 @@ int main(int argc, char *argv[])
case 'l':
ctpv.mode = MODE_LIST;
break;
case 'm':
ctpv.mode = MODE_MIME;
break;
default:
return EXIT_FAILURE;
}
}
argc -= optind;
argv = &argv[optind];
int ret;
switch (ctpv.mode) {
case MODE_PREVIEW:
ret = preview(argc, &argv[optind]);
ret = preview(argc, argv);
break;
case MODE_SERVER:
ret = server();
@ -161,6 +198,9 @@ int main(int argc, char *argv[])
case MODE_LIST:
ret = list();
break;
case MODE_MIME:
ret = mime(argc, argv);
break;
default:
print_errorf("unknowm mode: %d", ctpv.mode);
ret = ERR;

View File

@ -1,5 +1,6 @@
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "utils.h"
#include "error.h"
@ -7,6 +8,8 @@
#define PREVP_SIZE sizeof(Preview *)
typedef Preview *(*FindFunc)(char const *s, size_t *i);
static char shell[] = "sh";
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_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)
@ -89,14 +89,21 @@ void cleanup_previews(void)
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 =
bsearch(&key, sorted_by_ext, prevs_length, PREVP_SIZE, cmp_prev_ext);
Preview *p;
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)
@ -116,7 +123,7 @@ static void break_mimetype(char *mimetype, char **type, char **subtype)
#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;
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);
break_mimetype(mimetype_c, &t, &s);
for (size_t i = 0; i < prevs_length; i++) {
p = sorted_by_mimetype[i];
for (; *i < prevs_length; (*i)++) {
p = sorted_by_mimetype[*i];
if (!p->type)
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;
if (mimetype)
ret = find_by_mimetype(mimetype);
if (!ret)
ret = find_by_ext(ext);
int *fds[] = { (int[]){ STDOUT_FILENO, STDERR_FILENO }, NULL };
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) \
@ -170,7 +198,7 @@ Preview *find_preview(char const *ext, char const *mimetype)
ERRCHK_RET(setenv((n), (v), 1) != 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("w", pa->w);
@ -178,15 +206,24 @@ int run_preview(Preview *p, PreviewArgs *pa)
SET_PENV("x", pa->x);
SET_PENV("y", pa->y);
char *args[] = { shell, "-c", p->script, shell, NULL };
int ret, exitcode;
SET_PENV("m", mimetype);
SET_PENV("e", ext);
ret = spawn(args, NULL, &exitcode);
check_init_previews();
if (exitcode > 0)
printf("error: preview exited with code: %d\n", exitcode);
int found;
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)

View File

@ -13,8 +13,7 @@ typedef struct {
void init_previews(Preview *ps, size_t len);
void cleanup_previews(void);
Preview *find_preview(char const *ext, char const *mimetype);
int run_preview(Preview *p, PreviewArgs *pa);
int run_preview(const char *ext, const char *mimetype, PreviewArgs *pa);
Preview **get_previews_list(size_t *len);
#endif

13
utils.c
View File

@ -14,8 +14,11 @@ char *program;
*
* If cpid is NULL, wait for the command to finish executing;
* 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)
*exitcode = -1;
@ -25,6 +28,14 @@ int spawn(char *args[], pid_t *cpid, int *exitcode)
/* Child process */
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);
print_errorf("exec() failed: %s", strerror(errno));
exit(EXIT_FAILURE);

View File

@ -23,7 +23,7 @@ typedef struct {
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);
void char_v_append(CharVec *v, char c);