/* * ke - kyle's editor * * ke started off following along with the kilo walkthrough at * https://viewsourcecode.org/snaptoken/kilo/ * * It is inspired heavily by mg(1) and VDE. This is a single file and * can be built with * $(CC) -D_DEFAULT_SOURCE -D_XOPEN_SOURCE -Wall -Wextra -pedantic \ * -Wshadow -Werror -std=c99 -g -o ke main.c * * It builds and runs on Linux and Darwin. I can't confirm BSD compatibility. * * commit 59d3fa1dab68e8683d5f5a9341f5f42ef3308876 * Author: Kyle Isom * Date: Fri Feb 7 20:46:43 2020 -0800 * * Initial import, starting with kyle's editor. */ #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include #include "abuf.h" #include "buffer.h" #include "editor.h" #include "editing.h" #include "process.h" #include "term.h" void loop(void); void enable_debugging(void); void deathknell(void); static void signal_handler(int sig); static void install_signal_handlers(void); int kbhit(void) { int bytes_waiting = 0; ioctl(STDIN_FILENO, FIONREAD, &bytes_waiting); if (bytes_waiting < 0) { editor_set_status("kbhit: FIONREAD failed: %s", strerror(errno)); /* if FIONREAD fails, we need to assume we should read. this * will default to a much slower input sequence, but it'll work. */ return 1; } return bytes_waiting > 0; } void loop(void) { int up = 1; /* update on the first runthrough */ while (1) { if (up) { display_refresh(); } /* * ke should only refresh the display if it has received keyboard * input; if it has, drain all the inputs. This is useful for * handling pastes without massive screen flicker. * */ up = process_keypress(); if (up != 0) { while (kbhit()) { process_keypress(); } } } } void enable_debugging(void) { dump_pidfile(); } void deathknell(void) { fflush(stderr); if (editor.killring != NULL) { ab_free(editor.killring); free(editor.killring); editor.killring = NULL; } reset_editor(); disable_termraw(); } static void signal_handler(int sig) { signal(sig, SIG_DFL); fprintf(stderr, "caught signal %d\n", sig); deathknell(); raise(sig); _exit(127 + sig); } static void install_signal_handlers(void) { /* Block all these signals while inside any of them */ const int fatal_signals[] = { SIGABRT, SIGFPE, SIGILL, SIGSEGV, #ifdef SIGBUS SIGBUS, #endif #ifdef SIGQUIT SIGQUIT, #endif #ifdef SIGSYS SIGSYS, #endif -1 /* sentinel */ }; int i = 0; for (i = 0; fatal_signals[i] != -1; i++) { signal(fatal_signals[i], signal_handler); } atexit(deathknell); } int main(int argc, char *argv[]) { const char *arg = NULL; const char *path = NULL; int i = 0; int v = 0; int nb = 0; int opt = 0; int debug = 0; int pending_line = 0; /* line number for the next filename */ int first_loaded = 0; /* has a filed been loaded already? */ install_signal_handlers(); while ((opt = getopt(argc, argv, "df:")) != -1) { if (opt == 'd') { debug = 1; } else { fprintf(stderr, "Usage: ke [-d] [-f logfile] [ +N ] [file ...]\n"); exit(EXIT_FAILURE); } } argc -= optind; argv += optind; setlocale(LC_ALL, ""); if (debug) { enable_debugging(); } setup_terminal(); init_editor(); /* start processing file names. if an arg starts with a '+', * interpret it as the line to jump to. */ for (i = 0; i < argc; i++) { arg = argv[i]; if (arg[0] == '+') { path = arg + 1; v = 0; if (*path != '\0') { v = atoi(path); if (v < 1) v = 0; } pending_line = v; continue; } if (!first_loaded) { open_file(arg); if (pending_line > 0) { jump_to_position(0, pending_line - 1); pending_line = 0; } first_loaded = 1; } else { nb = buffer_add_empty(); buffer_switch(nb); open_file(arg); if (pending_line > 0) { jump_to_position(0, pending_line - 1); pending_line = 0; } } } editor_set_status("C-k q to exit / C-k d to dump core"); display_clear(NULL); loop(); return 0; }