diff options
| author | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
|---|---|---|
| committer | Mitja Felicijan <mitja.felicijan@gmail.com> | 2026-01-21 22:52:54 +0100 |
| commit | dcacc00e3750300617ba6e16eb346713f91a783a (patch) | |
| tree | 38e2d4fb5ed9d119711d4295c6eda4b014af73fd /examples/dte/main.c | |
| parent | 58dac10aeb8f5a041c46bddbeaf4c7966a99b998 (diff) | |
| download | crep-dcacc00e3750300617ba6e16eb346713f91a783a.tar.gz | |
Remove testing data
Diffstat (limited to 'examples/dte/main.c')
| -rw-r--r-- | examples/dte/main.c | 575 |
1 files changed, 0 insertions, 575 deletions
diff --git a/examples/dte/main.c b/examples/dte/main.c deleted file mode 100644 index 11025af..0000000 --- a/examples/dte/main.c +++ /dev/null @@ -1,575 +0,0 @@ -#include <errno.h> -#include <fcntl.h> -#include <stdbool.h> -#include <stdio.h> -#include <stdlib.h> -#include <string.h> -#include <sys/stat.h> -#include <sys/utsname.h> -#include <unistd.h> -#include "block.h" -#include "commands.h" -#include "compiler.h" -#include "config.h" -#include "editor.h" -#include "error.h" -#include "file-history.h" -#include "frame.h" -#include "history.h" -#include "load-save.h" -#include "move.h" -#include "screen.h" -#include "search.h" -#include "signals.h" -#include "syntax/state.h" -#include "syntax/syntax.h" -#include "tag.h" -#include "terminal/input.h" -#include "terminal/key.h" -#include "terminal/mode.h" -#include "terminal/output.h" -#include "terminal/terminal.h" -#include "util/debug.h" -#include "util/exitcode.h" -#include "util/fd.h" -#include "util/log.h" -#include "util/macros.h" -#include "util/path.h" -#include "util/ptr-array.h" -#include "util/strtonum.h" -#include "util/xmalloc.h" -#include "util/xreadwrite.h" -#include "util/xsnprintf.h" -#include "view.h" -#include "window.h" -#include "../build/version.h" - -static void term_cleanup(EditorState *e) -{ - set_fatal_error_cleanup_handler(NULL, NULL); - if (!e->child_controls_terminal) { - ui_end(e); - } -} - -static void cleanup_handler(void *userdata) -{ - term_cleanup(userdata); -} - -static ExitCode write_stdout(const char *str, size_t len) -{ - if (xwrite_all(STDOUT_FILENO, str, len) < 0) { - perror("write"); - return EX_IOERR; - } - return EX_OK; -} - -static ExitCode list_builtin_configs(void) -{ - String str = dump_builtin_configs(); - BUG_ON(!str.buffer); - ExitCode e = write_stdout(str.buffer, str.len); - string_free(&str); - return e; -} - -static ExitCode dump_builtin_config(const char *name) -{ - const BuiltinConfig *cfg = get_builtin_config(name); - if (!cfg) { - fprintf(stderr, "Error: no built-in config with name '%s'\n", name); - return EX_USAGE; - } - return write_stdout(cfg->text.data, cfg->text.length); -} - -static ExitCode lint_syntax(const char *filename) -{ - EditorState *e = init_editor_state(); - int err; - BUG_ON(e->status != EDITOR_INITIALIZING); - const Syntax *s = load_syntax_file(e, filename, CFG_MUST_EXIST, &err); - if (s) { - const size_t n = s->states.count; - const char *plural = (n == 1) ? "" : "s"; - printf("OK: loaded syntax '%s' with %zu state%s\n", s->name, n, plural); - } else if (err == EINVAL) { - error_msg("%s: no default syntax found", filename); - } - free_editor_state(e); - return get_nr_errors() ? EX_DATAERR : EX_OK; -} - -static ExitCode showkey_loop(const char *term_name, const char *colorterm) -{ - if (unlikely(!term_raw())) { - perror("tcsetattr"); - return EX_IOERR; - } - - Terminal term; - TermOutputBuffer *obuf = &term.obuf; - TermInputBuffer *ibuf = &term.ibuf; - term_init(&term, term_name, colorterm); - term_input_init(ibuf); - term_output_init(obuf); - term_enable_private_modes(&term); - term_add_literal(obuf, "Press any key combination, or use Ctrl+D to exit\r\n"); - term_output_flush(obuf); - - char keystr[KEYCODE_STR_MAX]; - for (bool loop = true; loop; ) { - KeyCode key = term_read_key(&term, 100); - switch (key) { - case KEY_NONE: - case KEY_IGNORE: - continue; - case KEY_BRACKETED_PASTE: - case KEY_DETECTED_PASTE: - term_discard_paste(ibuf, key == KEY_BRACKETED_PASTE); - continue; - case MOD_CTRL | 'd': - loop = false; - } - size_t keylen = keycode_to_string(key, keystr); - term_add_literal(obuf, " "); - term_add_bytes(obuf, keystr, keylen); - term_add_literal(obuf, "\r\n"); - term_output_flush(obuf); - } - - term_restore_private_modes(&term); - term_output_flush(obuf); - term_cooked(); - term_input_free(ibuf); - term_output_free(obuf); - return EX_OK; -} - -static ExitCode init_std_fds(int std_fds[2]) -{ - FILE *streams[3] = {stdin, stdout, stderr}; - for (int i = 0; i < ARRAYLEN(streams); i++) { - if (is_controlling_tty(i)) { - continue; - } - - if (i < STDERR_FILENO) { - // Try to create a duplicate fd for redirected stdin/stdout; to - // allow reading/writing after freopen(3) closes the original - int fd = fcntl(i, F_DUPFD_CLOEXEC, 3); - if (fd == -1 && errno != EBADF) { - perror("fcntl"); - return EX_OSERR; - } - std_fds[i] = fd; - } - - // Ensure standard streams are connected to the terminal during - // editor operation, regardless of how they were redirected - if (unlikely(!freopen("/dev/tty", i ? "w" : "r", streams[i]))) { - const char *err = strerror(errno); - fprintf(stderr, "Failed to open tty for fd %d: %s\n", i, err); - return EX_IOERR; - } - - int new_fd = fileno(streams[i]); - if (unlikely(new_fd != i)) { - // This should never happen in a single-threaded program. - // freopen() should call fclose() followed by open() and - // POSIX requires a successful call to open() to return the - // lowest available file descriptor. - fprintf(stderr, "freopen() changed fd from %d to %d\n", i, new_fd); - return EX_OSERR; - } - - if (unlikely(!is_controlling_tty(new_fd))) { - perror("tcgetpgrp"); - return EX_OSERR; - } - } - - return EX_OK; -} - -static Buffer *init_std_buffer(EditorState *e, int fds[2]) -{ - const char *name = NULL; - Buffer *buffer = NULL; - - if (fds[STDIN_FILENO] >= 3) { - Encoding enc = encoding_from_type(UTF8); - buffer = buffer_new(&e->buffers, &e->options, &enc); - if (read_blocks(buffer, fds[STDIN_FILENO], false)) { - name = "(stdin)"; - buffer->temporary = true; - } else { - error_msg("Unable to read redirected stdin"); - remove_and_free_buffer(&e->buffers, buffer); - buffer = NULL; - } - } - - if (fds[STDOUT_FILENO] >= 3) { - if (!buffer) { - buffer = open_empty_buffer(&e->buffers, &e->options); - name = "(stdout)"; - } else { - name = "(stdin|stdout)"; - } - buffer->stdout_buffer = true; - buffer->temporary = true; - } - - BUG_ON(!buffer != !name); - if (name) { - set_display_filename(buffer, xstrdup(name)); - } - - return buffer; -} - -static ExitCode init_logging(const char *filename, const char *req_level_str) -{ - if (!filename || filename[0] == '\0') { - return EX_OK; - } - - LogLevel req_level = log_level_from_str(req_level_str); - if (req_level == LOG_LEVEL_NONE) { - return EX_OK; - } - if (req_level == LOG_LEVEL_INVALID) { - fprintf(stderr, "Invalid $DTE_LOG_LEVEL value: '%s'\n", req_level_str); - return EX_USAGE; - } - - // https://no-color.org/ - const char *no_color = xgetenv("NO_COLOR"); - - LogLevel got_level = log_open(filename, req_level, !no_color); - if (got_level == LOG_LEVEL_NONE) { - const char *err = strerror(errno); - fprintf(stderr, "Failed to open $DTE_LOG (%s): %s\n", filename, err); - return EX_IOERR; - } - - const char *got_level_str = log_level_to_str(got_level); - if (got_level != req_level) { - const char *r = req_level_str; - const char *g = got_level_str; - LOG_WARNING("log level '%s' unavailable; falling back to '%s'", r, g); - } - - LOG_INFO("logging to '%s' (level: %s)", filename, got_level_str); - - if (no_color) { - LOG_INFO("log colors disabled ($NO_COLOR)"); - } - - struct utsname u; - if (likely(uname(&u) >= 0)) { - LOG_INFO("system: %s/%s %s", u.sysname, u.machine, u.release); - } else { - LOG_ERRNO("uname"); - } - return EX_OK; -} - -static void log_config_counts(const EditorState *e) -{ - if (!log_level_enabled(LOG_LEVEL_INFO)) { - return; - } - - size_t nbinds = 0; - for (size_t i = 0; i < ARRAYLEN(e->modes); i++) { - nbinds += e->modes[i].key_bindings.count; - } - - size_t nerrorfmts = 0; - for (HashMapIter it = hashmap_iter(&e->compilers); hashmap_next(&it); ) { - const Compiler *compiler = it.entry->value; - nerrorfmts += compiler->error_formats.count; - } - - LOG_INFO ( - "binds=%zu aliases=%zu hi=%zu ft=%zu option=%zu errorfmt=%zu(%zu)", - nbinds, - e->aliases.count, - e->colors.other.count + NR_BC, - e->filetypes.count, - e->file_options.count, - e->compilers.count, - nerrorfmts - ); -} - -static const char copyright[] = - "dte " VERSION "\n" - "(C) 2013-2023 Craig Barnes\n" - "(C) 2010-2015 Timo Hirvonen\n" - "This program is free software; you can redistribute and/or modify\n" - "it under the terms of the GNU General Public License version 2\n" - "<https://www.gnu.org/licenses/old-licenses/gpl-2.0.html>.\n" - "There is NO WARRANTY, to the extent permitted by law.\n"; - -static const char usage[] = - "Usage: %s [OPTIONS] [[+LINE] FILE]...\n\n" - "Options:\n" - " -c COMMAND Run COMMAND after editor starts\n" - " -t CTAG Jump to source location of CTAG\n" - " -r RCFILE Read user config from RCFILE instead of ~/.dte/rc\n" - " -s FILE Validate dte-syntax commands in FILE and exit\n" - " -b NAME Print built-in config matching NAME and exit\n" - " -B Print list of built-in config names and exit\n" - " -H Don't load or save history files\n" - " -R Don't read user config file\n" - " -K Start editor in \"showkey\" mode\n" - " -h Display help summary and exit\n" - " -V Display version number and exit\n" - "\n"; - -int main(int argc, char *argv[]) -{ - static const char optstring[] = "hBHKRVb:c:t:r:s:"; - const char *tag = NULL; - const char *rc = NULL; - const char *commands[8]; - size_t nr_commands = 0; - bool read_rc = true; - bool use_showkey = false; - bool load_and_save_history = true; - set_print_errors_to_stderr(true); - - for (int ch; (ch = getopt(argc, argv, optstring)) != -1; ) { - switch (ch) { - case 'c': - if (unlikely(nr_commands >= ARRAYLEN(commands))) { - fputs("Error: too many -c options used\n", stderr); - return EX_USAGE; - } - commands[nr_commands++] = optarg; - break; - case 't': - tag = optarg; - break; - case 'r': - rc = optarg; - break; - case 's': - return lint_syntax(optarg); - case 'R': - read_rc = false; - break; - case 'b': - return dump_builtin_config(optarg); - case 'B': - return list_builtin_configs(); - case 'H': - load_and_save_history = false; - break; - case 'K': - use_showkey = true; - goto loop_break; - case 'V': - return write_stdout(copyright, sizeof(copyright)); - case 'h': - printf(usage, (argv[0] && argv[0][0]) ? argv[0] : "dte"); - return EX_OK; - default: - return EX_USAGE; - } - } - -loop_break:; - - const char *term_name = xgetenv("TERM"); - if (!term_name) { - fputs("Error: $TERM not set\n", stderr); - // This is considered a "usage" error, because the program - // must be started from a properly configured terminal - return EX_USAGE; - } - - // This must be done before calling init_logging(), otherwise an - // invocation like e.g. `DTE_LOG=/dev/pts/2 dte 0<&-` could - // cause the logging fd to be opened as STDIN_FILENO - int std_fds[2] = {-1, -1}; - ExitCode r = init_std_fds(std_fds); - if (unlikely(r != EX_OK)) { - return r; - } - - r = init_logging(getenv("DTE_LOG"), getenv("DTE_LOG_LEVEL")); - if (unlikely(r != EX_OK)) { - return r; - } - - if (!term_mode_init()) { - perror("tcgetattr"); - return EX_IOERR; - } - - const char *colorterm = getenv("COLORTERM"); - if (use_showkey) { - return showkey_loop(term_name, colorterm); - } - - EditorState *e = init_editor_state(); - Terminal *term = &e->terminal; - term_init(term, term_name, colorterm); - - Buffer *std_buffer = init_std_buffer(e, std_fds); - bool have_stdout_buffer = std_buffer && std_buffer->stdout_buffer; - - // Create this early (needed if "lock-files" is true) - const char *cfgdir = e->user_config_dir; - BUG_ON(!cfgdir); - if (mkdir(cfgdir, 0755) != 0 && errno != EEXIST) { - error_msg("Error creating %s: %s", cfgdir, strerror(errno)); - load_and_save_history = false; - e->options.lock_files = false; - } - - term_save_title(term); - exec_builtin_rc(e); - - if (read_rc) { - ConfigFlags flags = CFG_NOFLAGS; - char buf[4096]; - if (rc) { - flags |= CFG_MUST_EXIST; - } else { - xsnprintf(buf, sizeof buf, "%s/%s", cfgdir, "rc"); - rc = buf; - } - LOG_INFO("loading configuration from %s", rc); - read_normal_config(e, rc, flags); - } - - log_config_counts(e); - update_all_syntax_colors(&e->syntaxes, &e->colors); - - Window *window = new_window(e); - e->window = window; - e->root_frame = new_root_frame(window); - - set_signal_handlers(); - set_fatal_error_cleanup_handler(cleanup_handler, e); - - if (load_and_save_history) { - file_history_load(&e->file_history, path_join(cfgdir, "file-history")); - history_load(&e->command_history, path_join(cfgdir, "command-history")); - history_load(&e->search_history, path_join(cfgdir, "search-history")); - if (e->search_history.last) { - search_set_regexp(&e->search, e->search_history.last->text); - } - } - - set_print_errors_to_stderr(false); - - // Initialize terminal but don't update screen yet. Also display - // "Press any key to continue" prompt if there were any errors - // during reading configuration files. - if (!term_raw()) { - perror("tcsetattr"); - return EX_IOERR; - } - if (get_nr_errors()) { - any_key(term, e->options.esc_timeout); - clear_error(); - } - - e->status = EDITOR_RUNNING; - - for (size_t i = optind, line = 0, col = 0; i < argc; i++) { - const char *str = argv[i]; - if (line == 0 && *str == '+' && str_to_filepos(str + 1, &line, &col)) { - continue; - } - View *view = window_open_buffer(window, str, false, NULL); - if (line == 0) { - continue; - } - set_view(view); - move_to_filepos(view, line, col); - line = 0; - } - - if (std_buffer) { - window_add_buffer(window, std_buffer); - } - - View *dview = NULL; - if (window->views.count == 0) { - // Open a default buffer, if none were opened for arguments - dview = window_open_empty_buffer(window); - BUG_ON(!dview); - BUG_ON(window->views.count != 1); - BUG_ON(dview != window->views.ptrs[0]); - } - - set_view(window->views.ptrs[0]); - ui_start(e); - - for (size_t i = 0; i < nr_commands; i++) { - handle_normal_command(e, commands[i], false); - } - - if (tag) { - StringView tag_sv = strview_from_cstring(tag); - if (tag_lookup(&e->tagfile, &tag_sv, NULL, &e->messages)) { - activate_current_message(e); - if (dview && nr_commands == 0 && window->views.count > 1) { - // Close default/empty buffer, if `-t` jumped to a tag - // and no commands were executed via `-c` - remove_view(dview); - dview = NULL; - } - } - } - - if (nr_commands > 0 || tag) { - normal_update(e); - } - - int exit_code = main_loop(e); - - term_restore_title(term); - ui_end(e); - term_output_flush(&term->obuf); - set_print_errors_to_stderr(true); - - // Unlock files and add to file history - remove_frame(e, e->root_frame); - - if (load_and_save_history) { - history_save(&e->command_history); - history_save(&e->search_history); - file_history_save(&e->file_history); - } - - if (have_stdout_buffer) { - int fd = std_fds[STDOUT_FILENO]; - Block *blk; - block_for_each(blk, &std_buffer->blocks) { - if (xwrite_all(fd, blk->data, blk->size) < 0) { - error_msg_errno("failed to write (stdout) buffer"); - if (exit_code == EDITOR_EXIT_OK) { - exit_code = EX_IOERR; - } - break; - } - } - free_blocks(std_buffer); - free(std_buffer); - } - - free_editor_state(e); - LOG_INFO("exiting with status %d", exit_code); - log_close(); - return exit_code; -} |
