| 123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196 |
- /*
- * Copyright © 2025 Pierre Le Marre <dev@wismill.eu>
- * SPDX-License-Identifier: MIT
- */
- #pragma once
- #include "config.h"
- #include <stdlib.h>
- #include <limits.h>
- #include <stdio.h>
- #include <spawn.h>
- #include <unistd.h>
- #include <assert.h>
- #include <signal.h>
- #include <sys/types.h>
- #include <sys/wait.h>
- #include <getopt.h>
- #include "utils.h"
- #include "darray.h"
- #define PIPE_WRITE 1
- #define PIPE_READ 0
- #define SETUP_FAILURE 99
- int
- compile_with(const char* compiler_name, const char* const *compiler_argv,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out);
- int
- compile_with(const char* compiler_name, const char* const *compiler_argv,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out)
- {
- int ret = EXIT_FAILURE;
- assert(keymap_in);
- /* Prepare parameters */
- char *envp[] = { NULL };
- /* Prepare input */
- int stdin_pipe[2] = {0};
- int stdout_pipe[2] = {0};
- posix_spawn_file_actions_t action;
- if (pipe(stdin_pipe) == -1) {
- perror("stdin pipe");
- ret = SETUP_FAILURE;
- goto pipe_error;
- }
- if (posix_spawn_file_actions_init(&action)) {
- perror("spawn_file_actions_init error");
- goto posix_spawn_file_actions_init_error;
- }
- /* Make spawned process close unused write-end of pipe, else it will not
- * receive EOF when write-end of the pipe is closed below and it will result
- * in a deadlock. */
- if (posix_spawn_file_actions_addclose(&action, stdin_pipe[PIPE_WRITE]))
- goto posix_spawn_file_actions_error;
- /* Make spawned process replace stdin with read end of the pipe */
- if (posix_spawn_file_actions_adddup2(&action, stdin_pipe[PIPE_READ], STDIN_FILENO))
- goto posix_spawn_file_actions_error;
- /* Prepare stdout */
- if (pipe(stdout_pipe) == -1) {
- perror("stdout pipe");
- ret = SETUP_FAILURE;
- goto pipe_error;
- }
- if (posix_spawn_file_actions_addclose(&action, stdout_pipe[PIPE_READ]))
- goto posix_spawn_file_actions_error;
- if (posix_spawn_file_actions_adddup2(&action, stdout_pipe[PIPE_WRITE], STDOUT_FILENO))
- goto posix_spawn_file_actions_error;
- /* Launch compiler */
- pid_t compiler_pid;
- ret = posix_spawnp(&compiler_pid, compiler_name, &action, NULL,
- (char* const*)compiler_argv, envp);
- if (ret != 0) {
- errno = ret;
- perror("posix_spawnp XKB compiler failed");
- goto posix_spawn_file_actions_init_error;
- }
- /* Close unused read-end of pipe */
- close(stdin_pipe[PIPE_READ]);
- close(stdout_pipe[PIPE_WRITE]);
- ssize_t ret2 = write(stdin_pipe[PIPE_WRITE], keymap_in, keymap_size_in);
- /* Close write-end of the pipe, to emit EOF */
- close(stdin_pipe[PIPE_WRITE]);
- if (ret2 == -1) {
- perror("Cannot write keymap to stdin");
- kill(compiler_pid, SIGTERM);
- }
- /* Capture stdout */
- const size_t buffer_size = 1024;
- darray_char stdout = darray_new();
- darray_resize0(stdout, buffer_size);
- size_t size = 0;
- ssize_t count;
- while ((count = read(stdout_pipe[PIPE_READ], darray_items(stdout) + size,
- buffer_size)) > 0) {
- size += (size_t) count;
- darray_resize0(stdout, size + buffer_size);
- }
- close(stdout_pipe[PIPE_READ]);
- /* Ensure we get a NULL-terminated string */
- if (size > 0 && darray_item(stdout, size - 1) != '\0')
- darray_resize0(stdout, size + 1);
- darray_steal(stdout, keymap_out, NULL);
- *keymap_size_out = size;
- /* Wait for compiler to complete */
- int status;
- ret = waitpid(compiler_pid, &status, 0);
- ret = (ret < 0 || !WIFEXITED(status) || WEXITSTATUS(status) != 0)
- ? SETUP_FAILURE
- : EXIT_SUCCESS;
- goto cleanup;
- posix_spawn_file_actions_error:
- perror("posix_spawn_file_actions_* error");
- posix_spawn_file_actions_init_error:
- close(stdin_pipe[PIPE_WRITE]);
- close(stdin_pipe[PIPE_READ]);
- close(stdout_pipe[PIPE_READ]);
- close(stdout_pipe[PIPE_WRITE]);
- ret = SETUP_FAILURE;
- cleanup:
- posix_spawn_file_actions_destroy(&action);
- pipe_error:
- return ret;
- }
- int
- compile_with_xkbcomp(const char* display, const char *include_path,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out);
- int
- compile_with_xkbcomp(const char* display, const char *include_path,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out)
- {
- const bool has_display = !isempty(display);
- const char* const out = (has_display) ? display : "-";
- /* Prepare xkbcomp parameters */
- char include_path_arg[PATH_MAX+2] = "-I";
- const char *xkbcomp_argv[] = {
- "xkbcomp", "-I" /* reset include path*/, include_path_arg,
- "-opt", "g", "-w", "10", "-xkb", "-" /* stdin */, out, NULL
- };
- if (include_path) {
- int ret = snprintf(include_path_arg, ARRAY_SIZE(include_path_arg),
- "-I%s", include_path);
- if (ret < 0 || ret >= (int)ARRAY_SIZE(include_path_arg)) {
- return SETUP_FAILURE;
- }
- }
- return compile_with("xkbcomp", xkbcomp_argv,
- keymap_in, keymap_size_in,
- keymap_out, keymap_size_out);
- }
- int
- compile_with_kbvm(const char *include_path,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out);
- int
- compile_with_kbvm(const char *include_path,
- const char *keymap_in, size_t keymap_size_in,
- char **keymap_out, size_t *keymap_size_out)
- {
- /* Prepare xkbcomp parameters */
- const char *kbvm_argv[] = {
- "kbvm", "compile-xkb", "-", NULL, NULL, NULL, NULL
- };
- if (include_path) {
- kbvm_argv[3] = "--no-default-includes";
- kbvm_argv[4] = "--append-include";
- kbvm_argv[5] = include_path;
- }
- return compile_with("kbvm", kbvm_argv,
- keymap_in, keymap_size_in,
- keymap_out, keymap_size_out);
- }
|