diff options
| author | Michele Bini <rev@alienbuntu.local> | 2019-04-18 22:12:22 (GMT) |
|---|---|---|
| committer | Michele Bini <rev@alienbuntu.local> | 2019-04-18 22:13:11 (GMT) |
| commit | 3567ae383ea8d19f054ba138c8250446cc4a8bb1 (patch) | |
| tree | d7d23be597c2ffb7176fbaa511050a067947a62f /nanobox.c | |
| parent | da7ba579a7d9a95457f87bc5389a53b12d6fc9cb (diff) | |
.
Diffstat (limited to 'nanobox.c')
| -rw-r--r-- | nanobox.c | 255 |
1 files changed, 185 insertions, 70 deletions
@@ -17,12 +17,14 @@ * An "ex" line oriented mode- maybe using "cmdedit" */ +#define ENABLE_FEATURE_NANO 1 //config:config NANO //config: bool "nano" //config: default y //config: help //config: 'nano' is a text editor. This is a clone attempt. //config: +#define CONFIG_FEATURE_NANO_MAX_LEN 4096 //config:config FEATURE_NANO_MAX_LEN //config: int "Maximum screen width" //config: range 256 16384 @@ -32,6 +34,7 @@ //config: Contrary to what you may think, this is not eating much. //config: Make it smaller than 4k only if you are very limited on memory. //config: +#define ENABLE_FEATURE_NANO_8BIT 1 //config:config FEATURE_NANO_8BIT //config: bool "Allow to display 8-bit chars (otherwise shows dots)" //config: default n @@ -42,6 +45,7 @@ //config: If your terminal combines several 8-bit bytes into one character //config: (as in Unicode mode), this will not work properly. //config: +#define ENABLE_FEATURE_NANO_UTF8 1 //config:config FEATURE_NANO_UTF8 //config: bool "Allow editing utf-8 files" //config: default y @@ -49,6 +53,7 @@ //config: help //config: Allow input of utf8 characters. (EXPERIMENTAL) //config: +#define ENABLE_FEATURE_NANO_UTF8_MIXED 1 //config:config FEATURE_NANO_UTF8_MIXED //config: bool "Allow editing of utf-8 files containing invalid character sequences" //config: default y @@ -56,14 +61,7 @@ //config: help //config: Allow input of utf8 characters. (EXPERIMENTAL) //config: -//config:config FEATURE_NANO_COLON -//config: bool "Enable \":\" colon commands (no \"ex\" mode)" -//config: default y -//config: depends on NANO -//config: help -//config: Enable a limited set of colon commands. This does not -//config: provide an "ex" mode. -//config: +#define ENABLE_FEATURE_NANO_YANKMARK 1 //config:config FEATURE_NANO_YANKMARK //config: bool "Enable yank/put commands and mark cmds" //config: default y @@ -71,6 +69,8 @@ //config: help //config: This will enable you to use yank and put, as well as mark. //config: +#define ENABLE_FEATURE_NANO_SEARCH 1 +#define IF_FEATURE_NANO_SEARCH(...) __VA_ARGS__ //config:config FEATURE_NANO_SEARCH //config: bool "Enable search and replace cmds" //config: default y @@ -78,6 +78,7 @@ //config: help //config: Select this if you wish to be able to do search and replace. //config: +#define ENABLE_FEATURE_NANO_REGEX_SEARCH 0 //config:config FEATURE_NANO_REGEX_SEARCH //config: bool "Enable regex in search and replace" //config: default n # Uses GNU regex, which may be unavailable. FIXME @@ -85,6 +86,7 @@ //config: help //config: Use extended regex search. //config: +#define ENABLE_FEATURE_NANO_USE_SIGNALS 1 //config:config FEATURE_NANO_USE_SIGNALS //config: bool "Catch signals" //config: default y @@ -93,6 +95,7 @@ //config: Selecting this option will make nano signal aware. This will support //config: SIGWINCH to deal with Window Changes, catch ^Z and ^C and alarms. //config: +#define ENABLE_FEATURE_NANO_READONLY 1 //config:config FEATURE_NANO_READONLY //config: bool "Enable -R option and \"view\" mode" //config: default y @@ -101,6 +104,7 @@ //config: Enable the read-only command line option, which allows the user to //config: open a file in read-only mode. //config: +#define ENABLE_FEATURE_NANO_SETOPTS 1 //config:config FEATURE_NANO_SETOPTS //config: bool "Enable settable options, ai ic showmatch" //config: default y @@ -109,11 +113,7 @@ //config: Enable the editor to set some (ai, ic, showmatch) options. //config: Consider removing this option! FIXME //config: -//config:config FEATURE_NANO_SET -//config: bool "Support :set" -//config: default y -//config: depends on NANO -//config: +#define ENABLE_FEATURE_NANO_WIN_RESIZE 1 //config:config FEATURE_NANO_WIN_RESIZE //config: bool "Handle window resize" //config: default y @@ -121,6 +121,8 @@ //config: help //config: Behave nicely with terminals that get resized. //config: +#define ENABLE_FEATURE_NANO_ASK_TERMINAL 1 +#define IF_FEATURE_NANO_ASK_TERMINAL(...) __VA_ARGS__ //config:config FEATURE_NANO_ASK_TERMINAL //config: bool "Use 'tell me cursor position' ESC sequence to measure window" //config: default y @@ -132,6 +134,7 @@ //config: cursor position using "ESC [ 6 n" escape sequence, then read stdin. //config: This is not clean but helps a lot on serial lines and such. //config: +#define ENABLE_FEATURE_NANO_UNDO 1 //config:config FEATURE_NANO_UNDO //config: bool "Support undo command \"u\"" //config: default y @@ -140,6 +143,7 @@ //config: Support the 'u' command to undo insertion, deletion, and replacement //config: of text. //config: +#define ENABLE_FEATURE_NANO_UNDO_QUEUE 1 //config:config FEATURE_NANO_UNDO_QUEUE //config: bool "Enable undo operation queuing" //config: default y @@ -151,6 +155,7 @@ //config: This increases the size of the undo code and allows some undo //config: operations (especially un-typing/backspacing) to be far more useful. //config: +#define CONFIG_FEATURE_NANO_UNDO_QUEUE_MAX 256 //config:config FEATURE_NANO_UNDO_QUEUE_MAX //config: int "Maximum undo character queue size" //config: default 256 @@ -165,6 +170,7 @@ //config: Unless you want more (or less) frequent "undo points" while typing, //config: you should probably leave this unchanged. //config: +#define ENABLE_FEATURE_NANO_HIGHLIGHT 1 //config:config FEATURE_NANO_HIGHLIGHT //config: bool "Support syntax highlighting" //config: default y @@ -172,6 +178,7 @@ //config: help //config: Support syntax highlighting. //config: +#define ENABLE_FEATURE_NANO_HIGHLIGHT_LANGUAGE_C 1 //config:config FEATURE_NANO_HIGHLIGHT_LANGUAGE_C //config: bool "Support syntax highlighting for C language" //config: default y @@ -180,6 +187,56 @@ //config: Support syntax highlighting for the C language //config: +#define _GNU_SOURCE +#include <setjmp.h> +#include <termios.h> +#include <stdint.h> +#include <stdio.h> +#include <stdlib.h> +#include <unistd.h> +#include <string.h> +#include <signal.h> +#include <ctype.h> +#include <stddef.h> +#include <errno.h> +#include <fcntl.h> +#include <stdarg.h> +#include <sys/stat.h> +#include <sys/poll.h> +#include <sys/ioctl.h> +#if 1 +#include "platform.h" +#define FALSE 0 +#define TRUE 1 +#define smallint int +// #define KEYCODE_BUFFER_SIZE 16 +struct globals *ptr_to_globals; +#define SET_PTR_TO_GLOBALS(x) ptr_to_globals = (x) +#define xzalloc malloc +#define xstrndup strndup +#define xstrdup strdup +#define xmalloc malloc +#define xrealloc realloc +#define xfree free +#define FAST_FUNC +int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height); +int64_t FAST_FUNC read_key(int fd, char *buffer, int timeout); +#include "keycodes.h" +#define NOINLINE +#define ARRAY_SIZE(x) ((unsigned)((sizeof(x)) / (sizeof(x[0])))) +int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags); +#define TERMIOS_RAW_CRNL (1 << 1) +#define TERMIOS_CLEAR_ISIG (1 << 0) +#define TERMIOS_RAW_INPUT (1 << 2) +int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp); +int safe_poll(struct pollfd *ufds, nfds_t nfds, int timeout_ms) FAST_FUNC; +void FAST_FUNC bb_error_msg_and_die(const char *s, ...); +#define bb_putchar putchar +ssize_t FAST_FUNC full_read(int fd, void *buf, size_t len); +ssize_t FAST_FUNC full_write(int fd, const void *buf, size_t len); +static int wh_helper(int value, int def_val, const char *env_name, int *err); +#endif + //applet:IF_NANO(APPLET(nano, BB_DIR_BIN, BB_SUID_DROP)) //kbuild:lib-$(CONFIG_NANO) += nano.o @@ -188,9 +245,6 @@ //usage: "[OPTIONS] [FILE]..." //usage:#define nano_full_usage "\n\n" //usage: "Edit FILE\n" -//usage: IF_FEATURE_NANO_COLON( -//usage: "\n -c CMD Initial command to run ($EXINIT also available)" -//usage: ) //usage: IF_FEATURE_NANO_READONLY( //usage: "\n -R Read-only" //usage: ) @@ -262,13 +316,6 @@ enum { //#define ESC_CURSOR_UP "\033[A" //#define ESC_CURSOR_DOWN "\n" -#if ENABLE_FEATURE_NANO_YANKMARK -// cmds modifying text[] -// vda: removed "aAiIs" as they switch us into insert mode -// and remembering input for replay after them makes no sense -static const char modifying_cmds[] ALIGN1 = "cCdDJoOpPrRxX<>~"; -#endif - enum { YANKONLY = FALSE, YANKDEL = TRUE, @@ -358,9 +405,6 @@ struct globals { sigjmp_buf restart; // catch_sig() #endif struct termios term_orig; // remember what the cooked mode was -#if ENABLE_FEATURE_NANO_COLON - char *initial_cmds[3]; // currently 2 entries, NULL terminated -#endif // Should be just enough to hold a key sequence, // but CRASHME mode uses it as generated command buffer too #if ENABLE_FEATURE_NANO_CRASHME @@ -561,7 +605,7 @@ static void catch_sig(int); // catch ctrl-C and alarm time-outs #if ENABLE_FEATURE_NANO_SETOPTS static void showmatching(char *); // show the matching pair () [] {} #endif -#if ENABLE_FEATURE_NANO_YANKMARK || (ENABLE_FEATURE_NANO_COLON && ENABLE_FEATURE_NANO_SEARCH) || ENABLE_FEATURE_NANO_CRASHME +#if ENABLE_FEATURE_NANO_YANKMARK || ENABLE_FEATURE_NANO_SEARCH || ENABLE_FEATURE_NANO_CRASHME // might reallocate text[]! use p += string_insert(p, ...), // and be careful to not use pointers into potentially freed text[]! # if !ENABLE_FEATURE_NANO_UNDO @@ -603,8 +647,7 @@ static void write1(const char *out) fputs(out, stdout); } -int nano_main(int argc, char **argv) MAIN_EXTERNALLY_VISIBLE; -int nano_main(int argc, char **argv) +int main(int argc, char **argv) { int c; @@ -636,14 +679,7 @@ int nano_main(int argc, char **argv) // 1- process $HOME/.exrc file (not inplemented yet) // 2- process EXINIT variable from environment // 3- process command line args -#if ENABLE_FEATURE_NANO_COLON - { - char *p = getenv("EXINIT"); - if (p && *p) - initial_cmds[0] = xstrndup(p, MAX_INPUT_LEN); - } -#endif - while ((c = getopt(argc, argv, "hCRH" IF_FEATURE_NANO_COLON("c:"))) != -1) { + while ((c = getopt(argc, argv, "hCRH")) != -1) { switch (c) { #if ENABLE_FEATURE_NANO_CRASHME case 'C': @@ -655,17 +691,11 @@ int nano_main(int argc, char **argv) SET_READONLY_MODE(readonly_mode); break; #endif -#if ENABLE_FEATURE_NANO_COLON - case 'c': // cmd line nano command - if (*optarg) - initial_cmds[initial_cmds[0] != NULL] = xstrndup(optarg, MAX_INPUT_LEN); - break; -#endif case 'H': show_help(); /* fall through */ default: - bb_show_usage(); + // bb_show_usage(); return 1; } } @@ -755,7 +785,7 @@ static void edit_file(char *fn) if (G.get_rowcol_error /* TODO? && no input on stdin */) { uint64_t k; write1("\033[999;999H" "\033[6n"); - fflush_all(); + fflush(NULL); k = read_key(STDIN_FILENO, readbuffer, /*timeout_ms:*/ 100); if ((int32_t)k == KEYCODE_CURSOR_POS) { uint32_t rc = (k >> 32); @@ -1778,7 +1808,7 @@ static void show_help(void) } #if ENABLE_FEATURE_NANO_YANKMARK \ - || (ENABLE_FEATURE_NANO_COLON && ENABLE_FEATURE_NANO_SEARCH) \ + || ENABLE_FEATURE_NANO_SEARCH \ || ENABLE_FEATURE_NANO_CRASHME // might reallocate text[]! use p += string_insert(p, ...), // and be careful to not use pointers into potentially freed text[]! @@ -1835,23 +1865,6 @@ static char *text_yank(char *p, char *q) // copy text into a register return p; } -static void check_context(char cmd) -{ - // A context is defined to be "modifying text" - // Any modifying command establishes a new context. - - if (dot < context_start || dot > context_end) { - if (strchr(modifying_cmds, cmd) != NULL) { - // we are trying to modify text[]- make this the current context - mark[27] = mark[26]; // move cur to prev - mark[26] = dot; // move local to cur - context_start = prev_line(prev_line(dot)); - context_end = next_line(next_line(dot)); - //loiter= start_loiter= now; - } - } -} - #endif /* FEATURE_NANO_YANKMARK */ //----- Set terminal attributes -------------------------------- @@ -1864,7 +1877,7 @@ static void rawmode(void) static void cookmode(void) { - fflush_all(); + fflush(NULL); tcsetattr_stdin_TCSANOW(&term_orig); } @@ -1921,7 +1934,7 @@ static int mysleep(int hund) // sleep for 'hund' 1/100 seconds or stdin ready struct pollfd pfd[1]; if (hund != 0) - fflush_all(); + fflush(NULL); pfd[0].fd = STDIN_FILENO; pfd[0].events = POLLIN; @@ -1932,7 +1945,7 @@ static int get_one_char(void) // read (maybe cursor) key from stdin { int c; - fflush_all(); + fflush(NULL); // Wait for input. TIMEOUT = -1 makes read_key wait even // on nonblocking stdin. @@ -2215,7 +2228,7 @@ static void show_status_line(void) } place_cursor(crow, ccol); // put cursor back in correct place } - fflush_all(); + fflush(NULL); } //----- format the status buffer, the bottom line of screen ------ @@ -2861,9 +2874,6 @@ static void do_cmd(int c) if (dot != end) { dot = bound_dot(dot); // make sure "dot" is valid } -#if ENABLE_FEATURE_NANO_YANKMARK - check_context(c); // update the current context -#endif } /* NB! the CRASHME code is unmaintained, and doesn't currently build */ @@ -3071,3 +3081,108 @@ static void crash_test() } } #endif + +int FAST_FUNC get_terminal_width_height(int fd, unsigned *width, unsigned *height) +{ + struct winsize win; + int err; + int close_me = -1; + + if (fd == -1) { + if (isatty(STDOUT_FILENO)) + fd = STDOUT_FILENO; + else + if (isatty(STDERR_FILENO)) + fd = STDERR_FILENO; + else + if (isatty(STDIN_FILENO)) + fd = STDIN_FILENO; + else + close_me = fd = open("/dev/tty", O_RDONLY); + } + + win.ws_row = 0; + win.ws_col = 0; + /* I've seen ioctl returning 0, but row/col is (still?) 0. + * We treat that as an error too. */ + err = ioctl(fd, TIOCGWINSZ, &win) != 0 || win.ws_row == 0; + if (height) + *height = wh_helper(win.ws_row, 24, "LINES", &err); + if (width) + *width = wh_helper(win.ws_col, 80, "COLUMNS", &err); + + if (close_me >= 0) + close(close_me); + + return err; +} + +int FAST_FUNC set_termios_to_raw(int fd, struct termios *oldterm, int flags) +{ +//TODO: lineedit, microcom and less might be adapted to use this too: +// grep for "tcsetattr" + + struct termios newterm; + + tcgetattr(fd, oldterm); + newterm = *oldterm; + + /* Turn off buffered input (ICANON) + * Turn off echoing (ECHO) + * and separate echoing of newline (ECHONL, normally off anyway) + */ + newterm.c_lflag &= ~(ICANON | ECHO | ECHONL); + if (flags & TERMIOS_CLEAR_ISIG) { + /* dont recognize INT/QUIT/SUSP chars */ + newterm.c_lflag &= ~ISIG; + } + /* reads will block only if < 1 char is available */ + newterm.c_cc[VMIN] = 1; + /* no timeout (reads block forever) */ + newterm.c_cc[VTIME] = 0; + if (flags & TERMIOS_RAW_CRNL) { + /* dont convert CR to NL on input */ + newterm.c_iflag &= ~(IXON | ICRNL); + /* dont convert NL to CR on output */ + newterm.c_oflag &= ~(ONLCR); + } + if (flags & TERMIOS_RAW_INPUT) { + /* dont convert anything on input */ + newterm.c_iflag &= ~(BRKINT|INLCR|ICRNL|IXON|IXOFF|IUCLC|IXANY|IMAXBEL); + } + + return tcsetattr(fd, TCSANOW, &newterm); +} + +int FAST_FUNC tcsetattr_stdin_TCSANOW(const struct termios *tp) +{ + return tcsetattr(STDIN_FILENO, TCSANOW, tp); +} + +static int wh_helper(int value, int def_val, const char *env_name, int *err) +{ + /* Envvars override even if "value" from ioctl is valid (>0). + * Rationale: it's impossible to guess what user wants. + * For example: "man CMD | ...": should "man" format output + * to stdout's width? stdin's width? /dev/tty's width? 80 chars? + * We _cant_ know it. If "..." saves text for e.g. email, + * then it's probably 80 chars. + * If "..." is, say, "grep -v DISCARD | $PAGER", then user + * would prefer his tty's width to be used! + * + * Since we don't know, at least allow user to do this: + * "COLUMNS=80 man CMD | ..." + */ + char *s = getenv(env_name); + if (s) { + value = atoi(s); + /* If LINES/COLUMNS are set, pretend that there is + * no error getting w/h, this prevents some ugly + * cursor tricks by our callers */ + *err = 0; + } + + if (value <= 1 || value >= 30000) + value = def_val; + return value; +} |
