mirror of
https://github.com/kovidgoyal/kitty.git
synced 2026-07-03 11:12:30 +08:00
Agent-Logs-Url: https://github.com/kovidgoyal/kitty/sessions/2cdc7e8f-5b64-4c97-bd65-dec508155313 Co-authored-by: kovidgoyal <1308621+kovidgoyal@users.noreply.github.com>
111 lines
3.1 KiB
C
111 lines
3.1 KiB
C
/*
|
|
* cmdline.c
|
|
* Copyright (C) 2025 Kovid Goyal <kovid at kovidgoyal.net>
|
|
*
|
|
* Distributed under terms of the GPL3 license.
|
|
*/
|
|
|
|
#define _POSIX_C_SOURCE 200809L
|
|
#include "shlex.h"
|
|
#include "utils.h"
|
|
#include "launcher.h"
|
|
#ifdef __APPLE__
|
|
#include <os/log.h>
|
|
#endif
|
|
|
|
bool
|
|
append_arg_to_argv_array(argv_array *a, const char *arg) {
|
|
if (a->count + 2 > a->capacity) {
|
|
size_t cap = a->capacity * 2;
|
|
if (!cap) cap = 256;
|
|
void *m = realloc(a->argv, cap * sizeof(a->argv[0]));
|
|
if (!m) return false;
|
|
a->argv = m;
|
|
a->capacity = cap;
|
|
a->needs_free = true;
|
|
}
|
|
// arg points into the process's original argv which persists for the lifetime
|
|
// of the process and is never modified through this pointer.
|
|
a->argv[a->count++] = (char*)arg;
|
|
a->argv[a->count] = 0;
|
|
return true;
|
|
}
|
|
|
|
void
|
|
free_argv_array(argv_array *a) {
|
|
if (a && a->needs_free) {
|
|
free(a->buf); free(a->argv);
|
|
*a = (argv_array){0};
|
|
}
|
|
}
|
|
|
|
static bool
|
|
add_to_argv(argv_array *a, const char* arg, size_t sz) {
|
|
if (a->count + 2 > a->capacity) {
|
|
size_t cap = a->capacity * 2;
|
|
if (!cap) cap = 256;
|
|
void *m = realloc(a->argv, cap * sizeof(a->argv[0]));
|
|
if (!m) return false;
|
|
a->argv = m;
|
|
a->argv[a->count] = 0;
|
|
a->capacity = cap;
|
|
a->needs_free = true;
|
|
}
|
|
memcpy(a->buf + a->pos, arg, sz);
|
|
a->argv[a->count++] = a->buf + a->pos;
|
|
a->argv[a->count] = 0;
|
|
a->pos += sz;
|
|
a->buf[a->pos++] = 0;
|
|
return true;
|
|
}
|
|
|
|
bool
|
|
get_argv_from(const char *filename, const char *argv0, argv_array *final_ans) {
|
|
(void)get_config_dir;
|
|
if (!filename || !filename[0]) return true;
|
|
size_t src_sz;
|
|
char* src = read_full_file(filename, &src_sz);
|
|
if (!src) {
|
|
if (errno == ENOENT || errno == ENOTDIR) return true;
|
|
#ifdef __APPLE__
|
|
int saved = errno;
|
|
os_log_error(OS_LOG_DEFAULT, "Failed to read from %{public}s with error: %{darwin.errno}d", filename, errno);
|
|
errno = saved;
|
|
#endif
|
|
fprintf(stderr, "Failed to read from %s ", filename); perror("with error");
|
|
return true;
|
|
}
|
|
ShlexState s = {0};
|
|
argv_array ans = {0};
|
|
bool ok = false;
|
|
ans.buf = malloc(src_sz + strlen(argv0) + 64);
|
|
if (!ans.buf) goto oom;
|
|
ans.needs_free = true;
|
|
if (!add_to_argv(&ans, argv0, strlen(argv0))) goto oom;
|
|
if (!alloc_shlex_state(&s, src, src_sz, false)) goto oom;
|
|
bool keep_going = true;
|
|
while (keep_going) {
|
|
ssize_t q = next_word(&s);
|
|
switch(q) {
|
|
case -1: fprintf(stderr, "Failed to parse %s with error: %s\n", filename, s.err); goto end;
|
|
case -2: keep_going = false; break;
|
|
default:
|
|
if (ans.count == 1 && strcmp(s.buf, "kitty") == 0) continue;
|
|
if (!add_to_argv(&ans, s.buf, q)) goto oom;
|
|
break;
|
|
}
|
|
}
|
|
ok = true;
|
|
oom:
|
|
if (!ok) {
|
|
errno = ENOMEM;
|
|
fprintf(stderr, "Failed to read from %s ", filename); perror("with error");
|
|
}
|
|
end:
|
|
free(src); dealloc_shlex_state(&s);
|
|
if (ok) *final_ans = ans;
|
|
else free_argv_array(final_ans);
|
|
return ok;
|
|
}
|
|
|