Update isocline, fix t011, use timegm
This commit is contained in:
Vendored
+58
-50
@@ -23,7 +23,7 @@ Isocline C API reference.
|
||||
|
||||
Isocline is a pure C library that can be used as an alternative to the GNU readline library.
|
||||
|
||||
See the [Github repository](https://github.com/daanx/isocline#readme)
|
||||
See the [Github repository](https://github.com/daanx/isocline#readme)
|
||||
for general information and building the library.
|
||||
|
||||
Contents:
|
||||
@@ -44,24 +44,24 @@ Contents:
|
||||
/// The basic readline interface.
|
||||
/// \{
|
||||
|
||||
/// Isocline version: 102 = 1.0.2.
|
||||
#define IC_VERSION (104)
|
||||
/// Isocline version: 110 = 1.1.0.
|
||||
#define IC_VERSION (110)
|
||||
|
||||
|
||||
/// Read input from the user using rich editing abilities.
|
||||
/// @param prompt_text The prompt text, can be NULL for the default ("").
|
||||
/// The displayed prompt becomes `prompt_text` followed by the `prompt_marker` ("> ").
|
||||
/// @returns the heap allocated input on succes, which should be `free`d by the caller.
|
||||
/// @param prompt_text The prompt text, can be NULL for the default ("").
|
||||
/// The displayed prompt becomes `prompt_text` followed by the `prompt_marker` ("> ").
|
||||
/// @returns the heap allocated input on succes, which should be `free`d by the caller.
|
||||
/// Returns NULL on error, or if the user typed ctrl+d or ctrl+c.
|
||||
///
|
||||
/// If the standard input (`stdin`) has no editing capability
|
||||
/// If the standard input (`stdin`) has no editing capability
|
||||
/// (like a dumb terminal (e.g. `TERM`=`dumb`), running in a debuggen, a pipe or redirected file, etc.)
|
||||
/// the input is read directly from the input stream up to the
|
||||
/// the input is read directly from the input stream up to the
|
||||
/// next line without editing capability.
|
||||
/// See also \a ic_set_prompt_marker(), \a ic_style_def()
|
||||
///
|
||||
/// @see ic_set_prompt_marker(), ic_style_def()
|
||||
char* ic_readline(const char* prompt_text);
|
||||
char* ic_readline(const char* prompt_text);
|
||||
|
||||
/// \}
|
||||
|
||||
@@ -71,7 +71,7 @@ char* ic_readline(const char* prompt_text);
|
||||
/// Formatted text using [bbcode markup](https://github.com/daanx/isocline#bbcode-format).
|
||||
/// \{
|
||||
|
||||
/// Print to the terminal while respection bbcode markup.
|
||||
/// Print to the terminal while respection bbcode markup.
|
||||
/// Any unclosed tags are closed automatically at the end of the print.
|
||||
/// For example:
|
||||
/// ```
|
||||
@@ -83,11 +83,11 @@ char* ic_readline(const char* prompt_text);
|
||||
/// Properties that can be assigned are:
|
||||
/// * `color=` _clr_, `bgcolor=` _clr_: where _clr_ is either a hex value `#`RRGGBB or `#`RGB, a
|
||||
/// standard HTML color name, or an ANSI palette name, like `ansi-maroon`, `ansi-default`, etc.
|
||||
/// * `bold`,`italic`,`reverse`,`underline`: can be `on` or `off`.
|
||||
/// * `bold`,`italic`,`reverse`,`underline`: can be `on` or `off`.
|
||||
/// * everything else is a style; all HTML and ANSI color names are also a style (so we can just use `red`
|
||||
/// instead of `color=red`, or `on red` instead of `bgcolor=red`), and there are
|
||||
/// the `b`, `i`, `u`, and `r` styles for bold, italic, underline, and reverse.
|
||||
///
|
||||
///
|
||||
/// See [here](https://github.com/daanx/isocline#bbcode-format) for a description of the full bbcode format.
|
||||
void ic_print( const char* s );
|
||||
|
||||
@@ -104,7 +104,7 @@ void ic_printf(const char* fmt, ...);
|
||||
void ic_vprintf(const char* fmt, va_list args);
|
||||
|
||||
/// Define or redefine a style.
|
||||
/// @param style_name The name of the style.
|
||||
/// @param style_name The name of the style.
|
||||
/// @param fmt The `fmt` string is the content of a tag and can contain
|
||||
/// other styles. This is very useful to theme the output of a program
|
||||
/// by assigning standard styles like `em` or `warning` etc.
|
||||
@@ -126,11 +126,11 @@ void ic_style_close(void);
|
||||
/// Readline input history.
|
||||
/// \{
|
||||
|
||||
/// Enable history.
|
||||
/// Enable history.
|
||||
/// Use a \a NULL filename to not persist the history. Use -1 for max_entries to get the default (200).
|
||||
void ic_set_history(const char* fname, long max_entries );
|
||||
|
||||
/// Remove the last entry in the history.
|
||||
/// Remove the last entry in the history.
|
||||
/// The last returned input from ic_readline() is automatically added to the history; this function removes it.
|
||||
void ic_history_remove_last(void);
|
||||
|
||||
@@ -157,7 +157,7 @@ struct ic_completion_env_s;
|
||||
typedef struct ic_completion_env_s ic_completion_env_t;
|
||||
|
||||
/// A completion callback that is called by isocline when tab is pressed.
|
||||
/// It is passed a completion environment (containing the current input and the current cursor position),
|
||||
/// It is passed a completion environment (containing the current input and the current cursor position),
|
||||
/// the current input up-to the cursor (`prefix`)
|
||||
/// and the user given argument when the callback was set.
|
||||
/// When using completion transformers, like `ic_complete_quoted_word` the `prefix` contains the
|
||||
@@ -197,9 +197,9 @@ bool ic_add_completion_ex( ic_completion_env_t* cenv, const char* completion, co
|
||||
bool ic_add_completions(ic_completion_env_t* cenv, const char* prefix, const char** completions);
|
||||
|
||||
/// Complete a filename.
|
||||
/// Complete a filename given a semi-colon separated list of root directories `roots` and
|
||||
/// semi-colon separated list of possible extensions (excluding directories).
|
||||
/// If `roots` is NULL, the current directory is the root (".").
|
||||
/// Complete a filename given a semi-colon separated list of root directories `roots` and
|
||||
/// semi-colon separated list of possible extensions (excluding directories).
|
||||
/// If `roots` is NULL, the current directory is the root (".").
|
||||
/// If `extensions` is NULL, any extension will match.
|
||||
/// Each root directory should _not_ end with a directory separator.
|
||||
/// If a directory is completed, the `dir_separator` is added at the end if it is not `0`.
|
||||
@@ -219,11 +219,11 @@ void ic_complete_filename( ic_completion_env_t* cenv, const char* prefix, char d
|
||||
typedef bool (ic_is_char_class_fun_t)(const char* s, long len);
|
||||
|
||||
|
||||
/// Complete a _word_ (i.e. _token_).
|
||||
/// Complete a _word_ (i.e. _token_).
|
||||
/// Calls the user provided function `fun` to complete on the
|
||||
/// current _word_. Almost all user provided completers should use this function.
|
||||
/// If `is_word_char` is NULL, the default `&ic_char_is_nonseparator` is used.
|
||||
/// The `prefix` passed to `fun` is modified to only contain the current word, and
|
||||
/// current _word_. Almost all user provided completers should use this function.
|
||||
/// If `is_word_char` is NULL, the default `&ic_char_is_nonseparator` is used.
|
||||
/// The `prefix` passed to `fun` is modified to only contain the current word, and
|
||||
/// any results from `ic_add_completion` are automatically adjusted to replace that part.
|
||||
/// For example, on the input "hello w", a the user `fun` only gets `w` and can just complete
|
||||
/// with "world" resulting in "hello world" without needing to consider `delete_before` etc.
|
||||
@@ -231,35 +231,35 @@ typedef bool (ic_is_char_class_fun_t)(const char* s, long len);
|
||||
void ic_complete_word(ic_completion_env_t* cenv, const char* prefix, ic_completer_fun_t* fun, ic_is_char_class_fun_t* is_word_char);
|
||||
|
||||
|
||||
/// Complete a quoted _word_.
|
||||
/// Complete a quoted _word_.
|
||||
/// Calls the user provided function `fun` to complete while taking
|
||||
/// care of quotes and escape characters. Almost all user provided completers should use
|
||||
/// this function. The `prefix` passed to `fun` is modified to be unquoted and unescaped, and
|
||||
/// this function. The `prefix` passed to `fun` is modified to be unquoted and unescaped, and
|
||||
/// any results from `ic_add_completion` are automatically quoted and escaped again.
|
||||
/// For example, completing `hello world`, the `fun` always just completes `hel` or `hello w` to `hello world`,
|
||||
/// For example, completing `hello world`, the `fun` always just completes `hel` or `hello w` to `hello world`,
|
||||
/// but depending on user input, it will complete as:
|
||||
/// ```
|
||||
/// hel --> hello\ world
|
||||
/// hello\ w --> hello\ world
|
||||
/// hello w --> # no completion, the word is just 'w'>
|
||||
/// "hel --> "hello world"
|
||||
/// "hel --> "hello world"
|
||||
/// "hello w --> "hello world"
|
||||
/// ```
|
||||
/// with proper quotes and escapes.
|
||||
/// If `is_word_char` is NULL, the default `&ic_char_is_nonseparator` is used.
|
||||
/// If `is_word_char` is NULL, the default `&ic_char_is_nonseparator` is used.
|
||||
/// @see ic_complete_quoted_word() to customize the word boundary, quotes etc.
|
||||
void ic_complete_qword( ic_completion_env_t* cenv, const char* prefix, ic_completer_fun_t* fun, ic_is_char_class_fun_t* is_word_char );
|
||||
|
||||
|
||||
|
||||
/// Complete a _word_.
|
||||
/// Complete a _word_.
|
||||
/// Calls the user provided function `fun` to complete while taking
|
||||
/// care of quotes and escape characters. Almost all user provided completers should use this function.
|
||||
/// care of quotes and escape characters. Almost all user provided completers should use this function.
|
||||
/// The `is_word_char` is a set of characters that are part of a "word". Use NULL for the default (`&ic_char_is_nonseparator`).
|
||||
/// The `escape_char` is the escaping character, usually `\` but use 0 to not have escape characters.
|
||||
/// The `quote_chars` define the quotes, use NULL for the default `"\'\""` quotes.
|
||||
/// @see ic_complete_word() which uses the default values for `non_word_chars`, `quote_chars` and `\` for escape characters.
|
||||
void ic_complete_qword_ex( ic_completion_env_t* cenv, const char* prefix, ic_completer_fun_t fun,
|
||||
void ic_complete_qword_ex( ic_completion_env_t* cenv, const char* prefix, ic_completer_fun_t fun,
|
||||
ic_is_char_class_fun_t* is_word_char, char escape_char, const char* quote_chars );
|
||||
|
||||
/// \}
|
||||
@@ -288,8 +288,8 @@ void ic_highlight(ic_highlight_env_t* henv, long pos, long count, const char* st
|
||||
typedef char* (ic_highlight_format_fun_t)(const char* s, void* arg);
|
||||
|
||||
/// Experimental: Convenience function for highlighting with bbcodes.
|
||||
/// Can be called in a `ic_highlight_fun_t` callback to colorize the `input` using the
|
||||
/// the provided `formatted` input that is the styled `input` with bbcodes. The
|
||||
/// Can be called in a `ic_highlight_fun_t` callback to colorize the `input` using the
|
||||
/// the provided `formatted` input that is the styled `input` with bbcodes. The
|
||||
/// content of `formatted` without bbcode tags should match `input` exactly.
|
||||
void ic_highlight_formatted(ic_highlight_env_t* henv, const char* input, const char* formatted);
|
||||
|
||||
@@ -302,7 +302,7 @@ void ic_highlight_formatted(ic_highlight_env_t* henv, const char* input, const c
|
||||
/// \defgroup readline
|
||||
/// \{
|
||||
|
||||
/// Read input from the user using rich editing abilities,
|
||||
/// Read input from the user using rich editing abilities,
|
||||
/// using a particular completion function and highlighter for this call only.
|
||||
/// both can be NULL in which case the defaults are used.
|
||||
/// @see ic_readline(), ic_set_prompt_marker(), ic_set_default_completer(), ic_set_default_highlighter().
|
||||
@@ -319,7 +319,7 @@ char* ic_readline_ex(const char* prompt_text, ic_completer_fun_t* completer, voi
|
||||
/// \defgroup options Options
|
||||
/// \{
|
||||
|
||||
/// Set a prompt marker and a potential marker for extra lines with multiline input.
|
||||
/// Set a prompt marker and a potential marker for extra lines with multiline input.
|
||||
/// Pass \a NULL for the `prompt_marker` for the default marker (`"> "`).
|
||||
/// Pass \a NULL for continuation prompt marker to make it equal to the `prompt_marker`.
|
||||
void ic_set_prompt_marker( const char* prompt_marker, const char* continuation_prompt_marker );
|
||||
@@ -347,7 +347,7 @@ bool ic_enable_color( bool enable );
|
||||
/// Returns the previous setting.
|
||||
bool ic_enable_history_duplicates( bool enable );
|
||||
|
||||
/// Disable or enable automatic tab completion after a completion
|
||||
/// Disable or enable automatic tab completion after a completion
|
||||
/// to expand as far as possible if the completions are unique. (disabled by default).
|
||||
/// Returns the previous setting.
|
||||
bool ic_enable_auto_tab( bool enable );
|
||||
@@ -381,7 +381,7 @@ bool ic_enable_highlight(bool enable);
|
||||
|
||||
|
||||
/// Set millisecond delay for reading escape sequences in order to distinguish
|
||||
/// a lone ESC from the start of a escape sequence. The defaults are 100ms and 10ms,
|
||||
/// a lone ESC from the start of a escape sequence. The defaults are 100ms and 10ms,
|
||||
/// but it may be increased if working with very slow terminals.
|
||||
void ic_set_tty_esc_delay(long initial_delay_ms, long followup_delay_ms);
|
||||
|
||||
@@ -433,8 +433,8 @@ bool ic_stop_completing( const ic_completion_env_t* cenv);
|
||||
///
|
||||
/// Returns `true` if the callback should continue trying to find more possible completions.
|
||||
/// If `false` is returned, the callback should try to return and not add more completions (for improved latency).
|
||||
bool ic_add_completion_prim( ic_completion_env_t* cenv, const char* completion,
|
||||
const char* display, const char* help,
|
||||
bool ic_add_completion_prim( ic_completion_env_t* cenv, const char* completion,
|
||||
const char* display, const char* help,
|
||||
long delete_before, long delete_after);
|
||||
|
||||
/// \}
|
||||
@@ -492,14 +492,14 @@ bool ic_char_is_filename_letter(const char* s, long len);
|
||||
/// Convenience: If this is a token start, return the length. Otherwise return 0.
|
||||
long ic_is_token(const char* s, long pos, ic_is_char_class_fun_t* is_token_char);
|
||||
|
||||
/// Convenience: Does this match the specified token?
|
||||
/// Convenience: Does this match the specified token?
|
||||
/// Ensures not to match prefixes or suffixes, and returns the length of the match (in bytes).
|
||||
/// E.g. `ic_match_token("function",0,&ic_char_is_letter,"fun")` returns 0.
|
||||
/// while `ic_match_token("fun x",0,&ic_char_is_letter,"fun"})` returns 3.
|
||||
long ic_match_token(const char* s, long pos, ic_is_char_class_fun_t* is_token_char, const char* token);
|
||||
|
||||
|
||||
/// Convenience: Do any of the specified tokens match?
|
||||
/// Convenience: Do any of the specified tokens match?
|
||||
/// Ensures not to match prefixes or suffixes, and returns the length of the match (in bytes).
|
||||
/// E.g. `ic_match_any_token("function",0,&ic_char_is_letter,{"fun","func",NULL})` returns 0.
|
||||
/// while `ic_match_any_token("func x",0,&ic_char_is_letter,{"fun","func",NULL})` returns 4.
|
||||
@@ -511,27 +511,27 @@ long ic_match_any_token(const char* s, long pos, ic_is_char_class_fun_t* is_toke
|
||||
/// \defgroup term Terminal
|
||||
///
|
||||
/// Experimental: Low level terminal output.
|
||||
/// Ensures basic ANSI SGR escape sequences are processed
|
||||
/// Ensures basic ANSI SGR escape sequences are processed
|
||||
/// in a portable way (e.g. on Windows)
|
||||
/// \{
|
||||
|
||||
/// Initialize for terminal output.
|
||||
/// Call this before using the terminal write functions (`ic_term_write`)
|
||||
/// Does nothing on most platforms but on Windows it sets the console to UTF8 output and possible
|
||||
/// Does nothing on most platforms but on Windows it sets the console to UTF8 output and possible
|
||||
/// enables virtual terminal processing.
|
||||
void ic_term_init(void);
|
||||
|
||||
/// Call this when done with the terminal functions.
|
||||
void ic_term_done(void);
|
||||
|
||||
/// Flush the terminal output.
|
||||
/// Flush the terminal output.
|
||||
/// (happens automatically on newline characters ('\n') as well).
|
||||
void ic_term_flush(void);
|
||||
|
||||
/// Write a string to the console (and process CSI escape sequences).
|
||||
void ic_term_write(const char* s);
|
||||
|
||||
/// Write a string to the console and end with a newline
|
||||
/// Write a string to the console and end with a newline
|
||||
/// (and process CSI escape sequences).
|
||||
void ic_term_writeln(const char* s);
|
||||
|
||||
@@ -569,7 +569,7 @@ void ic_term_color_rgb(bool foreground, uint32_t color );
|
||||
void ic_term_reset( void );
|
||||
|
||||
/// Get the palette used by the terminal:
|
||||
/// This is usually initialized from the COLORTERM environment variable. The
|
||||
/// This is usually initialized from the COLORTERM environment variable. The
|
||||
/// possible values of COLORTERM for each palette are given in parenthesis.
|
||||
///
|
||||
/// - 1: monochrome (`monochrome`)
|
||||
@@ -597,17 +597,25 @@ bool ic_async_stop(void);
|
||||
/// \}
|
||||
|
||||
//--------------------------------------------------------------
|
||||
/// \defgroup alloc Custom Allocation
|
||||
/// Register allocation functions for custom allocators
|
||||
/// \defgroup alloc Initialization and Custom Allocation
|
||||
/// Initialized and register allocation functions for custom allocators
|
||||
/// \{
|
||||
|
||||
typedef void* (ic_malloc_fun_t)( size_t size );
|
||||
typedef void* (ic_realloc_fun_t)( void* p, size_t newsize );
|
||||
typedef void (ic_free_fun_t)( void* p );
|
||||
|
||||
/// Initialize with using stderr as output.
|
||||
/// This must be called as early as possible in a program!
|
||||
void ic_init( bool use_std_err );
|
||||
|
||||
/// Initialize with custom allocation functions.
|
||||
/// This must be called as the first function in a program!
|
||||
void ic_init_custom_malloc( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free );
|
||||
/// This must be called as early as possible in a program!
|
||||
void ic_init_custom_alloc( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free );
|
||||
|
||||
/// Initialize with custom allocation functions and potentially use stderr as output.
|
||||
/// This must be called as early as possible in a program!
|
||||
void ic_init_custom_alloc_ex( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free, bool use_std_err );
|
||||
|
||||
/// Free a potentially custom alloc'd pointer (in particular, the result returned from `ic_readline`)
|
||||
void ic_free( void* p );
|
||||
|
||||
Vendored
+3
-3
@@ -231,11 +231,11 @@ ic_private unicode_t unicode_from_qutf8(const uint8_t* s, ssize_t len, ssize_t*
|
||||
if (count != NULL) *count = 2;
|
||||
return (((c0 & 0x1F) << 6) | (s[1] & 0x3F));
|
||||
}
|
||||
// 3 bytes: reject overlong and surrogate halves
|
||||
// 3 byte encoding; reject overlong and utf-16 surrogate halves (0xD800 - 0xDFFF)
|
||||
else if (len >= 3 &&
|
||||
((c0 == 0xE0 && s[1] >= 0xA0 && s[1] <= 0xBF && utf8_is_cont(s[2])) ||
|
||||
(c0 >= 0xE1 && c0 <= 0xEC && utf8_is_cont(s[1]) && utf8_is_cont(s[2]))
|
||||
))
|
||||
(c0 >= 0xE1 && c0 <= 0xEF && c0 != 0xED && utf8_is_cont(s[1]) && utf8_is_cont(s[2])) ||
|
||||
(c0 == 0xED && s[1] > 0x80 && s[1] <= 0x9F && utf8_is_cont(s[2]))))
|
||||
{
|
||||
if (count != NULL) *count = 3;
|
||||
return (((c0 & 0x0F) << 12) | ((unicode_t)(s[1] & 0x3F) << 6) | (s[2] & 0x3F));
|
||||
|
||||
Vendored
+11
-3
@@ -23,6 +23,7 @@
|
||||
typedef struct word_closure_s {
|
||||
long delete_before_adjust;
|
||||
void* prev_env;
|
||||
const char* postfix; // content after the cursor
|
||||
ic_completion_fun_t* prev_complete;
|
||||
} word_closure_t;
|
||||
|
||||
@@ -31,7 +32,8 @@ typedef struct word_closure_s {
|
||||
static bool token_add_completion_ex(ic_env_t* env, void* closure, const char* replacement, const char* display, const char* help, long delete_before, long delete_after) {
|
||||
word_closure_t* wenv = (word_closure_t*)(closure);
|
||||
// call the previous completer with an adjusted delete-before
|
||||
return (*wenv->prev_complete)(env, wenv->prev_env, replacement, display, help, wenv->delete_before_adjust + delete_before, delete_after);
|
||||
const long delete_after_adjust = (long)ic_count_end_overlap(replacement, wenv->postfix);
|
||||
return (*wenv->prev_complete)(env, wenv->prev_env, replacement, display, help, wenv->delete_before_adjust + delete_before, delete_after_adjust + delete_after);
|
||||
}
|
||||
|
||||
|
||||
@@ -61,6 +63,7 @@ ic_public void ic_complete_word(ic_completion_env_t* cenv, const char* prefix, i
|
||||
wenv.delete_before_adjust = (long)(len - pos);
|
||||
wenv.prev_complete = cenv->complete;
|
||||
wenv.prev_env = cenv->env;
|
||||
wenv.postfix = cenv->input + cenv->cursor;
|
||||
cenv->complete = &token_add_completion_ex;
|
||||
cenv->closure = &wenv;
|
||||
|
||||
@@ -77,6 +80,8 @@ ic_public void ic_complete_word(ic_completion_env_t* cenv, const char* prefix, i
|
||||
// Quoted word completion (with escape characters)
|
||||
//-------------------------------------------------------------
|
||||
|
||||
|
||||
|
||||
// free variables for word completion
|
||||
typedef struct qword_closure_s {
|
||||
char escape_char;
|
||||
@@ -84,6 +89,7 @@ typedef struct qword_closure_s {
|
||||
long delete_before_adjust;
|
||||
stringbuf_t* sbuf;
|
||||
void* prev_env;
|
||||
const char* postfix; // follows the current input position
|
||||
ic_is_char_class_fun_t* is_word_char;
|
||||
ic_completion_fun_t* prev_complete;
|
||||
} qword_closure_t;
|
||||
@@ -112,7 +118,8 @@ static bool qword_add_completion_ex(ic_env_t* env, void* closure, const char* re
|
||||
}
|
||||
}
|
||||
// and call the previous completion function
|
||||
return (*wenv->prev_complete)( env, wenv->prev_env, sbuf_string(wenv->sbuf), display, help, wenv->delete_before_adjust + delete_before, delete_after );
|
||||
const long delete_after_adjust = (long)ic_count_end_overlap(sbuf_string(wenv->sbuf), wenv->postfix);
|
||||
return (*wenv->prev_complete)( env, wenv->prev_env, sbuf_string(wenv->sbuf), display, help, wenv->delete_before_adjust + delete_before, delete_after_adjust + delete_after );
|
||||
}
|
||||
|
||||
|
||||
@@ -236,7 +243,8 @@ ic_public void ic_complete_qword_ex( ic_completion_env_t* cenv, const char* pref
|
||||
wenv.escape_char = escape_char;
|
||||
wenv.delete_before_adjust = (long)(len - pos);
|
||||
wenv.prev_complete = cenv->complete;
|
||||
wenv.prev_env = cenv->env;
|
||||
wenv.prev_env = cenv->env;
|
||||
wenv.postfix = cenv->input + cenv->cursor;
|
||||
wenv.sbuf = sbuf_new(cenv->env->mem);
|
||||
if (wenv.sbuf == NULL) { mem_free(cenv->env->mem, word); return; }
|
||||
cenv->complete = &qword_add_completion_ex;
|
||||
|
||||
Vendored
+11
-5
@@ -168,14 +168,19 @@ ic_public bool ic_stop_completing( const ic_completion_env_t* cenv) {
|
||||
|
||||
|
||||
static ssize_t completion_apply( completion_t* cm, stringbuf_t* sbuf, ssize_t pos ) {
|
||||
if (cm == NULL) return -1;
|
||||
if (cm == NULL) return IC_COMP_APPLY_FAIL;
|
||||
debug_msg( "completion: apply: %s at %zd\n", cm->replacement, pos);
|
||||
ssize_t start = pos - cm->delete_before;
|
||||
if (start < 0) start = 0;
|
||||
ssize_t n = cm->delete_before + cm->delete_after;
|
||||
if (ic_strlen(cm->replacement) == n && strncmp(sbuf_string_at(sbuf,start), cm->replacement, to_size_t(n)) == 0) {
|
||||
// no changes
|
||||
return -1;
|
||||
// if delete_after > 0, we performed a completion while inside of the word,
|
||||
// so return the actual new cursor position, because eb->pos needs updating
|
||||
if (cm->delete_after > 0)
|
||||
return start + n;
|
||||
// otherwise we can just say nothing happened at all
|
||||
else
|
||||
return IC_COMP_APPLY_NOOP;
|
||||
}
|
||||
else {
|
||||
sbuf_delete_from_to( sbuf, start, pos + cm->delete_after );
|
||||
@@ -211,7 +216,7 @@ ic_private ssize_t completions_apply_longest_prefix(completions_t* cms, stringbu
|
||||
|
||||
// set initial prefix to the first entry
|
||||
completion_t* cm = completions_get(cms, 0);
|
||||
if (cm == NULL) return -1;
|
||||
if (cm == NULL) return IC_COMP_APPLY_FAIL;
|
||||
|
||||
char prefix[IC_MAX_PREFIX+1];
|
||||
ssize_t delete_before = cm->delete_before;
|
||||
@@ -237,13 +242,14 @@ ic_private ssize_t completions_apply_longest_prefix(completions_t* cms, stringbu
|
||||
|
||||
// check the length
|
||||
ssize_t len = ic_strlen(prefix);
|
||||
if (len <= 0 || len < delete_before) return -1;
|
||||
if (len <= 0 || len < delete_before) return IC_COMP_APPLY_NOOP;
|
||||
|
||||
// we found a prefix :-)
|
||||
completion_t cprefix;
|
||||
memset(&cprefix,0,sizeof(cprefix));
|
||||
cprefix.delete_before = delete_before;
|
||||
cprefix.replacement = prefix;
|
||||
cprefix.delete_after = ic_count_end_overlap(prefix, sbuf_string_at(sbuf, pos));
|
||||
ssize_t newpos = completion_apply( &cprefix, sbuf, pos);
|
||||
if (newpos < 0) return newpos;
|
||||
|
||||
|
||||
Vendored
+8
@@ -18,6 +18,14 @@
|
||||
#define IC_MAX_COMPLETIONS_TO_SHOW (1000)
|
||||
#define IC_MAX_COMPLETIONS_TO_TRY (IC_MAX_COMPLETIONS_TO_SHOW/4)
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Magic return values for completion application functions
|
||||
//-------------------------------------------------------------
|
||||
// completion couldn't complete
|
||||
#define IC_COMP_APPLY_FAIL -1
|
||||
// completion didn't end up modifying the buffer or cursor position
|
||||
#define IC_COMP_APPLY_NOOP -2
|
||||
|
||||
typedef struct completions_s completions_t;
|
||||
|
||||
ic_private completions_t* completions_new(alloc_t* mem);
|
||||
|
||||
Vendored
+5
-5
@@ -938,17 +938,17 @@ static char* edit_line( ic_env_t* env, const char* prompt_text )
|
||||
if (eb.pos == 0 && editor_pos_is_at_end(&eb)) break; // ctrl+D on empty quits with NULL
|
||||
edit_delete_char(env,&eb); // otherwise it is like delete
|
||||
}
|
||||
else if (c == KEY_CTRL_C || c == KEY_EVENT_STOP) {
|
||||
break; // ctrl+C or STOP event quits with NULL
|
||||
else if (c == KEY_EVENT_STOP) {
|
||||
break; // STOP event quits with NULL
|
||||
}
|
||||
else if (c == KEY_ESC) {
|
||||
if (eb.pos == 0 && editor_pos_is_at_end(&eb)) break; // ESC on empty input returns with empty input
|
||||
edit_delete_all(env,&eb); // otherwise delete the current input
|
||||
// edit_delete_line(env,&eb); // otherwise delete the current line
|
||||
}
|
||||
else if (c == KEY_BELL /* ^G */) {
|
||||
else if (c == KEY_BELL /* ^G */ || c == KEY_CTRL_C) {
|
||||
edit_delete_all(env,&eb);
|
||||
break; // ctrl+G cancels (and returns empty input)
|
||||
break; // ctrl+G or ctrl+c cancels (and returns empty input)
|
||||
}
|
||||
|
||||
// Editing Operations
|
||||
@@ -1112,7 +1112,7 @@ static char* edit_line( ic_env_t* env, const char* prompt_text )
|
||||
|
||||
// save result
|
||||
char* res;
|
||||
if ((c == KEY_CTRL_D && sbuf_len(eb.input) == 0) || c == KEY_CTRL_C || c == KEY_EVENT_STOP) {
|
||||
if ((c == KEY_CTRL_D && sbuf_len(eb.input) == 0) || c == KEY_EVENT_STOP) {
|
||||
res = NULL;
|
||||
}
|
||||
else if (!tty_is_utf8(env->tty)) {
|
||||
|
||||
+32
-19
@@ -9,29 +9,43 @@
|
||||
// Completion menu: this file is included in editline.c
|
||||
//-------------------------------------------------------------
|
||||
|
||||
// return true iff the buffer or cursor position was actually changed;
|
||||
// clean up any dirtiness in the undo stack. update eb->pos if appropriate
|
||||
static bool edit_completion_commit(editor_t* eb, ssize_t newpos) {
|
||||
if (newpos == IC_COMP_APPLY_FAIL) {
|
||||
editor_undo_restore(eb, false);
|
||||
return false;
|
||||
}
|
||||
if (newpos == IC_COMP_APPLY_NOOP) {
|
||||
editor_undo_forget(eb);
|
||||
return false;
|
||||
}
|
||||
|
||||
eb->pos = newpos;
|
||||
return true;
|
||||
}
|
||||
|
||||
// return true if anything changed
|
||||
static bool edit_complete(ic_env_t* env, editor_t* eb, ssize_t idx) {
|
||||
editor_start_modify(eb);
|
||||
ssize_t newpos = completions_apply(env->completions, idx, eb->input, eb->pos);
|
||||
if (newpos < 0) {
|
||||
editor_undo_restore(eb,false);
|
||||
return false;
|
||||
}
|
||||
eb->pos = newpos;
|
||||
edit_refresh(env,eb);
|
||||
return true;
|
||||
bool buf_or_pos_changed = edit_completion_commit(eb, newpos);
|
||||
|
||||
// trigger a refresh if the buffer or cursor position changed
|
||||
if (buf_or_pos_changed)
|
||||
edit_refresh(env, eb);
|
||||
// or when choosing between menu items, even if the current item is the same
|
||||
// as the buffer, because we need to highlight that item
|
||||
else if (newpos == IC_COMP_APPLY_NOOP && completions_count(env->completions) > 1)
|
||||
edit_refresh(env, eb);
|
||||
|
||||
return buf_or_pos_changed;
|
||||
}
|
||||
|
||||
static bool edit_complete_longest_prefix(ic_env_t* env, editor_t* eb ) {
|
||||
static void edit_complete_longest_prefix(ic_env_t* env, editor_t* eb ) {
|
||||
editor_start_modify(eb);
|
||||
ssize_t newpos = completions_apply_longest_prefix( env->completions, eb->input, eb->pos );
|
||||
if (newpos < 0) {
|
||||
editor_undo_restore(eb,false);
|
||||
return false;
|
||||
}
|
||||
eb->pos = newpos;
|
||||
edit_refresh(env,eb);
|
||||
return true;
|
||||
edit_completion_commit(eb, newpos);
|
||||
}
|
||||
|
||||
ic_private void sbuf_append_tagged( stringbuf_t* sb, const char* tag, const char* content ) {
|
||||
@@ -150,8 +164,8 @@ again:
|
||||
}
|
||||
}
|
||||
if (!env->complete_nopreview && selected >= 0 && selected <= count_displayed) {
|
||||
edit_complete(env,eb,selected);
|
||||
editor_undo_restore(eb,false);
|
||||
if (edit_complete(env,eb,selected))
|
||||
editor_undo_restore(eb,false);
|
||||
}
|
||||
else {
|
||||
edit_refresh(env, eb);
|
||||
@@ -203,8 +217,7 @@ again:
|
||||
// select the current entry
|
||||
assert(selected < count);
|
||||
c = 0;
|
||||
edit_complete(env, eb, selected);
|
||||
if (env->complete_autotab) {
|
||||
if (edit_complete(env, eb, selected) && env->complete_autotab) {
|
||||
tty_code_pushback(env->tty,KEY_EVENT_AUTOTAB); // immediately try to complete again
|
||||
}
|
||||
}
|
||||
|
||||
Vendored
+1
-1
@@ -95,7 +95,7 @@ static const char* help[] = {
|
||||
|
||||
static const char* help_initial =
|
||||
"[ic-info]"
|
||||
"Isocline v1.0, copyright (c) 2021 Daan Leijen.\n"
|
||||
"Isocline v1.1, copyright (c) 2021-2026 Daan Leijen.\n"
|
||||
"This is free software; you can redistribute it and/or\n"
|
||||
"modify it under the terms of the MIT License.\n"
|
||||
"See <[url]https://github.com/daanx/isocline[/url]> for further information.\n"
|
||||
|
||||
Vendored
+15
-12
@@ -5,7 +5,7 @@
|
||||
found in the "LICENSE" file at the root of this distribution.
|
||||
-----------------------------------------------------------------------------*/
|
||||
#include <stdio.h>
|
||||
#include <string.h>
|
||||
#include <string.h>
|
||||
#include <sys/stat.h>
|
||||
|
||||
#include "../include/isocline.h"
|
||||
@@ -17,7 +17,7 @@
|
||||
|
||||
struct history_s {
|
||||
ssize_t count; // current number of entries in use
|
||||
ssize_t len; // size of elems
|
||||
ssize_t len; // size of elems
|
||||
const char** elems; // history items (up to count)
|
||||
const char* fname; // history file
|
||||
alloc_t* mem;
|
||||
@@ -87,7 +87,7 @@ ic_private bool history_push( history_t* h, const char* entry ) {
|
||||
// insert at front
|
||||
if (h->count == h->len) {
|
||||
// delete oldest entry
|
||||
history_delete_at(h,0);
|
||||
history_delete_at(h,0);
|
||||
}
|
||||
assert(h->count < h->len);
|
||||
h->elems[h->count] = mem_strdup(h->mem,entry);
|
||||
@@ -103,7 +103,7 @@ static void history_remove_last_n( history_t* h, ssize_t n ) {
|
||||
mem_free( h->mem, h->elems[i] );
|
||||
}
|
||||
h->count -= n;
|
||||
assert(h->count >= 0);
|
||||
assert(h->count >= 0);
|
||||
}
|
||||
|
||||
ic_private void history_remove_last(history_t* h) {
|
||||
@@ -141,7 +141,7 @@ ic_private bool history_search( const history_t* h, ssize_t from /*including*/,
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
//
|
||||
//
|
||||
//-------------------------------------------------------------
|
||||
|
||||
ic_private void history_load_from(history_t* h, const char* fname, long max_entries ) {
|
||||
@@ -194,7 +194,7 @@ static bool history_read_entry( history_t* h, FILE* f, stringbuf_t* sbuf ) {
|
||||
else if (c == 't') { sbuf_append(sbuf,"\t"); }
|
||||
else if (c == '\\') { sbuf_append(sbuf,"\\"); }
|
||||
else if (c == 'x') {
|
||||
int c1 = fgetc(f);
|
||||
int c1 = fgetc(f);
|
||||
int c2 = fgetc(f);
|
||||
if (ic_isxdigit(c1) && ic_isxdigit(c2)) {
|
||||
char chr = from_xdigit(c1)*16 + from_xdigit(c2);
|
||||
@@ -204,7 +204,10 @@ static bool history_read_entry( history_t* h, FILE* f, stringbuf_t* sbuf ) {
|
||||
}
|
||||
else return false;
|
||||
}
|
||||
else sbuf_append_char(sbuf,(char)c);
|
||||
else if (c == '\r') { /* ignore */ }
|
||||
else {
|
||||
sbuf_append_char(sbuf,(char)c);
|
||||
}
|
||||
}
|
||||
if (sbuf_len(sbuf)==0 || sbuf_string(sbuf)[0] == '#') return true;
|
||||
return history_push(h, sbuf_string(sbuf));
|
||||
@@ -222,14 +225,14 @@ static bool history_write_entry( const char* entry, FILE* f, stringbuf_t* sbuf )
|
||||
else if (c < ' ' || c > '~' || c == '#') {
|
||||
char c1 = to_xdigit( (uint8_t)c / 16 );
|
||||
char c2 = to_xdigit( (uint8_t)c % 16 );
|
||||
sbuf_append(sbuf,"\\x");
|
||||
sbuf_append_char(sbuf,c1);
|
||||
sbuf_append_char(sbuf,c2);
|
||||
sbuf_append(sbuf,"\\x");
|
||||
sbuf_append_char(sbuf,c1);
|
||||
sbuf_append_char(sbuf,c2);
|
||||
}
|
||||
else sbuf_append_char(sbuf,c);
|
||||
}
|
||||
//debug_msg("history: write buf: %s\n", sbuf_string(sbuf));
|
||||
|
||||
|
||||
if (sbuf_len(sbuf) > 0) {
|
||||
sbuf_append(sbuf,"\n");
|
||||
fputs(sbuf_string(sbuf),f);
|
||||
@@ -265,5 +268,5 @@ ic_private void history_save( const history_t* h ) {
|
||||
}
|
||||
sbuf_free(sbuf);
|
||||
}
|
||||
fclose(f);
|
||||
fclose(f);
|
||||
}
|
||||
|
||||
Vendored
+48
-28
@@ -6,11 +6,11 @@
|
||||
-----------------------------------------------------------------------------*/
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Usually we include all sources one file so no internal
|
||||
// Usually we include all sources one file so no internal
|
||||
// symbols are public in the libray.
|
||||
//
|
||||
// You can compile the entire library just as:
|
||||
// $ gcc -c src/isocline.c
|
||||
//
|
||||
// You can compile the entire library just as:
|
||||
// $ gcc -c src/isocline.c
|
||||
//-------------------------------------------------------------
|
||||
#if !defined(IC_SEPARATE_OBJS)
|
||||
# ifndef _CRT_NONSTDC_NO_WARNINGS
|
||||
@@ -55,14 +55,14 @@
|
||||
|
||||
static char* ic_getline( alloc_t* mem );
|
||||
|
||||
ic_public char* ic_readline(const char* prompt_text)
|
||||
ic_public char* ic_readline(const char* prompt_text)
|
||||
{
|
||||
ic_env_t* env = ic_get_env();
|
||||
if (env == NULL) return NULL;
|
||||
if (!env->noedit) {
|
||||
// terminal editing enabled
|
||||
return ic_editline(env, prompt_text); // in editline.c
|
||||
}
|
||||
}
|
||||
else {
|
||||
// no editing capability (pipe, dumb terminal, etc)
|
||||
if (env->tty != NULL && env->term != NULL) {
|
||||
@@ -71,7 +71,7 @@ ic_public char* ic_readline(const char* prompt_text)
|
||||
if (prompt_text != NULL) {
|
||||
term_write(env->term, prompt_text);
|
||||
}
|
||||
term_write(env->term, env->prompt_marker);
|
||||
term_write(env->term, env->prompt_marker);
|
||||
term_end_raw(env->term, false);
|
||||
}
|
||||
// read directly from stdin
|
||||
@@ -81,12 +81,12 @@ ic_public char* ic_readline(const char* prompt_text)
|
||||
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Read a line from the stdin stream if there is no editing
|
||||
// Read a line from the stdin stream if there is no editing
|
||||
// support (like from a pipe, file, or dumb terminal).
|
||||
//-------------------------------------------------------------
|
||||
|
||||
static char* ic_getline(alloc_t* mem)
|
||||
{
|
||||
{
|
||||
// read until eof or newline
|
||||
stringbuf_t* sb = sbuf_new(mem);
|
||||
int c;
|
||||
@@ -310,7 +310,7 @@ ic_public void ic_set_insertion_braces(const char* brace_pairs) {
|
||||
env->auto_braces = NULL;
|
||||
if (brace_pairs != NULL) {
|
||||
ssize_t len = ic_strlen(brace_pairs);
|
||||
if (len > 0 && (len % 2) == 0) {
|
||||
if (len > 0 && (len % 2) == 0) {
|
||||
env->auto_braces = mem_strdup(env->mem, brace_pairs);
|
||||
}
|
||||
}
|
||||
@@ -356,12 +356,17 @@ ic_public const char* ic_strdup( const char* s ) {
|
||||
// Terminal
|
||||
//-------------------------------------------------------------
|
||||
|
||||
ic_public void ic_term_init(void) {
|
||||
ic_public void ic_term_init_ex(bool use_std_err) {
|
||||
ic_init(use_std_err);
|
||||
ic_env_t* env = ic_get_env(); if (env==NULL) return;
|
||||
if (env->term==NULL) return;
|
||||
term_start_raw(env->term);
|
||||
}
|
||||
|
||||
ic_public void ic_term_init(void) {
|
||||
ic_term_init_ex(false);
|
||||
}
|
||||
|
||||
ic_public void ic_term_done(void) {
|
||||
ic_env_t* env = ic_get_env(); if (env==NULL) return;
|
||||
if (env->term==NULL) return;
|
||||
@@ -412,8 +417,8 @@ ic_public void ic_term_style( const char* style ) {
|
||||
}
|
||||
|
||||
ic_public int ic_term_get_color_bits(void) {
|
||||
ic_env_t* env = ic_get_env();
|
||||
if (env==NULL || env->term==NULL) return 4;
|
||||
ic_env_t* env = ic_get_env();
|
||||
if (env==NULL || env->term==NULL) return 4;
|
||||
return term_get_color_bits(env->term);
|
||||
}
|
||||
|
||||
@@ -497,9 +502,9 @@ static void ic_env_free(ic_env_t* env) {
|
||||
mem_free(env->mem, env->match_braces);
|
||||
mem_free(env->mem, env->auto_braces);
|
||||
env->prompt_marker = NULL;
|
||||
|
||||
|
||||
// and deallocate ourselves
|
||||
alloc_t* mem = env->mem;
|
||||
alloc_t* mem = env->mem;
|
||||
mem_free(mem, env);
|
||||
|
||||
// and finally the custom memory allocation structure
|
||||
@@ -507,7 +512,7 @@ static void ic_env_free(ic_env_t* env) {
|
||||
}
|
||||
|
||||
|
||||
static ic_env_t* ic_env_create( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free )
|
||||
static ic_env_t* ic_env_create( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free, int fd_in, int fd_out )
|
||||
{
|
||||
if (_malloc == NULL) _malloc = &malloc;
|
||||
if (_realloc == NULL) _realloc = &realloc;
|
||||
@@ -526,21 +531,21 @@ static ic_env_t* ic_env_create( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _rea
|
||||
env->mem = mem;
|
||||
|
||||
// Initialize
|
||||
env->tty = tty_new(env->mem, -1); // can return NULL
|
||||
env->term = term_new(env->mem, env->tty, false, false, -1 );
|
||||
env->tty = tty_new(env->mem, fd_in); // can return NULL
|
||||
env->term = term_new(env->mem, env->tty, false, false, fd_out );
|
||||
env->history = history_new(env->mem);
|
||||
env->completions = completions_new(env->mem);
|
||||
env->bbcode = bbcode_new(env->mem, env->term);
|
||||
env->hint_delay = 400;
|
||||
|
||||
env->hint_delay = 400;
|
||||
|
||||
if (env->tty == NULL || env->term==NULL ||
|
||||
env->completions == NULL || env->history == NULL || env->bbcode == NULL ||
|
||||
!term_is_interactive(env->term))
|
||||
!term_is_interactive(env->term))
|
||||
{
|
||||
env->noedit = true;
|
||||
}
|
||||
env->multiline_eol = '\\';
|
||||
|
||||
|
||||
bbcode_style_def(env->bbcode, "ic-prompt", "ansi-green" );
|
||||
bbcode_style_def(env->bbcode, "ic-info", "ansi-darkgray" );
|
||||
bbcode_style_def(env->bbcode, "ic-diminish", "ansi-lightgray" );
|
||||
@@ -570,25 +575,40 @@ static void ic_atexit(void) {
|
||||
}
|
||||
}
|
||||
|
||||
ic_private ic_env_t* ic_get_env(void) {
|
||||
ic_private ic_env_t* ic_get_env(void) {
|
||||
if (rpenv==NULL) {
|
||||
rpenv = ic_env_create( NULL, NULL, NULL );
|
||||
rpenv = ic_env_create( NULL, NULL, NULL, -1, -1 );
|
||||
if (rpenv != NULL) { atexit( &ic_atexit ); }
|
||||
}
|
||||
return rpenv;
|
||||
}
|
||||
|
||||
ic_public void ic_init_custom_malloc( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free ) {
|
||||
#ifndef STDERR_FILENO
|
||||
#define STDERR_FILENO 2
|
||||
#endif
|
||||
|
||||
ic_public void ic_init_custom_alloc_ex( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free, bool use_std_err ) {
|
||||
assert(rpenv == NULL);
|
||||
const int fd_out = (use_std_err ? STDERR_FILENO : -1 /* default = stdout */ );
|
||||
if (rpenv != NULL) {
|
||||
ic_env_free(rpenv);
|
||||
rpenv = ic_env_create( _malloc, _realloc, _free );
|
||||
ic_env_free(rpenv);
|
||||
rpenv = ic_env_create( _malloc, _realloc, _free, -1, fd_out );
|
||||
}
|
||||
else {
|
||||
rpenv = ic_env_create( _malloc, _realloc, _free );
|
||||
rpenv = ic_env_create( _malloc, _realloc, _free, -1, fd_out );
|
||||
if (rpenv != NULL) {
|
||||
atexit( &ic_atexit );
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ic_public void ic_init_custom_alloc( ic_malloc_fun_t* _malloc, ic_realloc_fun_t* _realloc, ic_free_fun_t* _free ) {
|
||||
assert(rpenv == NULL);
|
||||
ic_init_custom_alloc_ex(_malloc,_realloc,_free,false);
|
||||
}
|
||||
|
||||
ic_public void ic_init( bool use_std_err ) {
|
||||
assert(rpenv == NULL);
|
||||
ic_init_custom_alloc_ex(NULL,NULL,NULL,use_std_err);
|
||||
}
|
||||
|
||||
|
||||
Vendored
+23
-6
@@ -679,8 +679,9 @@ ic_private ssize_t sbuf_insert_at_n(stringbuf_t* sbuf, const char* s, ssize_t n,
|
||||
}
|
||||
|
||||
ic_private stringbuf_t* sbuf_split_at( stringbuf_t* sb, ssize_t pos ) {
|
||||
if (pos < 0) return NULL;
|
||||
stringbuf_t* res = sbuf_new(sb->mem);
|
||||
if (res==NULL || pos < 0) return NULL;
|
||||
if (res==NULL) return NULL;
|
||||
if (pos < sb->count) {
|
||||
sbuf_append_n(res, sb->buf + pos, sb->count - pos);
|
||||
sb->count = pos;
|
||||
@@ -889,6 +890,27 @@ ic_private char* sbuf_strdup_from_utf8(stringbuf_t* sbuf) {
|
||||
return s;
|
||||
}
|
||||
|
||||
|
||||
|
||||
static int ic_strncmp(const char* s1, const char* s2, ssize_t n) {
|
||||
return strncmp(s1, s2, to_size_t(n));
|
||||
}
|
||||
|
||||
ic_private ssize_t ic_count_end_overlap(const char* s, const char* postfix) {
|
||||
if (s==NULL || postfix==NULL) return 0;
|
||||
const ssize_t slen = ic_strlen(s);
|
||||
for (ssize_t count = ic_strlen(postfix); count > 0; count--) {
|
||||
if (count <= slen) {
|
||||
if (ic_strncmp(&s[slen - count], postfix, count) == 0) {
|
||||
return count;
|
||||
}
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// String helpers
|
||||
//-------------------------------------------------------------
|
||||
@@ -1002,11 +1024,6 @@ ic_public long ic_is_token(const char* s, long pos, ic_is_char_class_fun_t* is_t
|
||||
return (long)(i - pos);
|
||||
}
|
||||
|
||||
|
||||
static int ic_strncmp(const char* s1, const char* s2, ssize_t n) {
|
||||
return strncmp(s1, s2, to_size_t(n));
|
||||
}
|
||||
|
||||
// Convenience: Does this match the specified token?
|
||||
// Ensures not to match prefixes or suffixes, and returns the length of the match (in bytes).
|
||||
// E.g. `ic_match_token("function",0,&ic_char_is_letter,"fun")` returns 0.
|
||||
|
||||
Vendored
+2
@@ -69,6 +69,8 @@ ic_private ssize_t sbuf_find_word_end( stringbuf_t* sbuf, ssize_t pos );
|
||||
ic_private ssize_t sbuf_find_ws_word_start( stringbuf_t* sbuf, ssize_t pos );
|
||||
ic_private ssize_t sbuf_find_ws_word_end( stringbuf_t* sbuf, ssize_t pos );
|
||||
|
||||
ic_private ssize_t ic_count_end_overlap(const char* s, const char* postfix);
|
||||
|
||||
// parse a decimal
|
||||
ic_private bool ic_atoz(const char* s, ssize_t* i);
|
||||
// parse two decimals separated by a semicolon
|
||||
|
||||
Vendored
+88
-87
@@ -18,6 +18,7 @@
|
||||
#if defined(_WIN32)
|
||||
#include <windows.h>
|
||||
#define STDOUT_FILENO 1
|
||||
#define STDERR_FILENO 2
|
||||
#else
|
||||
#include <unistd.h>
|
||||
#include <errno.h>
|
||||
@@ -164,7 +165,7 @@ ic_private void term_set_attr( term_t* term, attr_t attr ) {
|
||||
if (attr.x.bgcolor != term->attr.x.bgcolor && attr.x.bgcolor != IC_COLOR_NONE) {
|
||||
term_bgcolor(term,attr.x.bgcolor);
|
||||
if (term->palette < ANSIRGB && color_is_rgb(attr.x.bgcolor)) {
|
||||
term->attr.x.bgcolor = attr.x.bgcolor;
|
||||
term->attr.x.bgcolor = attr.x.bgcolor;
|
||||
}
|
||||
}
|
||||
if (attr.x.bold != term->attr.x.bold && attr.x.bold != IC_NONE) {
|
||||
@@ -178,7 +179,7 @@ ic_private void term_set_attr( term_t* term, attr_t attr ) {
|
||||
}
|
||||
if (attr.x.italic != term->attr.x.italic && attr.x.italic != IC_NONE) {
|
||||
term_italic(term,attr.x.italic == IC_ON);
|
||||
}
|
||||
}
|
||||
assert(attr.x.color == term->attr.x.color || attr.x.color == IC_COLOR_NONE);
|
||||
assert(attr.x.bgcolor == term->attr.x.bgcolor || attr.x.bgcolor == IC_COLOR_NONE);
|
||||
assert(attr.x.bold == term->attr.x.bold || attr.x.bold == IC_NONE);
|
||||
@@ -206,7 +207,7 @@ ic_private void term_writef(term_t* term, const char* fmt, ...) {
|
||||
va_list ap;
|
||||
va_start(ap, fmt);
|
||||
term_vwritef(term,fmt,ap);
|
||||
va_end(ap);
|
||||
va_end(ap);
|
||||
}
|
||||
|
||||
ic_private void term_vwritef(term_t* term, const char* fmt, va_list args ) {
|
||||
@@ -234,20 +235,20 @@ ic_private void term_write_formatted_n( term_t* term, const char* s, const attr_
|
||||
ssize_t n = 0;
|
||||
while( i+n < len && s[i+n] != 0 ) {
|
||||
if (!attr_is_eq(attr,attrs[i+n])) {
|
||||
if (n > 0) {
|
||||
if (n > 0) {
|
||||
term_write_n( term, s+i, n );
|
||||
i += n;
|
||||
n = 0;
|
||||
}
|
||||
attr = attrs[i];
|
||||
term_set_attr( term, attr_update_with(default_attr,attr) );
|
||||
}
|
||||
n++;
|
||||
}
|
||||
n++;
|
||||
}
|
||||
if (n > 0) {
|
||||
term_write_n( term, s+i, n );
|
||||
i += n;
|
||||
n = 0;
|
||||
n = 0;
|
||||
}
|
||||
assert(s[i] != 0 || i == len);
|
||||
term_set_attr(term, default_attr);
|
||||
@@ -282,7 +283,7 @@ ic_private void term_write(term_t* term, const char* s) {
|
||||
ic_private void term_write_n(term_t* term, const char* s, ssize_t n) {
|
||||
if (s == NULL || n <= 0) return;
|
||||
// write to buffer to reduce flicker and to process escape sequences (this may flush too)
|
||||
term_append_buf(term, s, n);
|
||||
term_append_buf(term, s, n);
|
||||
}
|
||||
|
||||
|
||||
@@ -297,7 +298,7 @@ ic_private void term_flush(term_t* term) {
|
||||
term_write_direct(term, sbuf_string(term->buf), sbuf_len(term->buf));
|
||||
//term_show_cursor(term,true);
|
||||
sbuf_clear(term->buf);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ic_private buffer_mode_t term_set_buffer_mode(term_t* term, buffer_mode_t mode) {
|
||||
@@ -312,12 +313,12 @@ ic_private buffer_mode_t term_set_buffer_mode(term_t* term, buffer_mode_t mode)
|
||||
}
|
||||
|
||||
static void term_check_flush(term_t* term, bool contains_nl) {
|
||||
if (term->bufmode == UNBUFFERED ||
|
||||
if (term->bufmode == UNBUFFERED ||
|
||||
sbuf_len(term->buf) > 4000 ||
|
||||
(term->bufmode == LINEBUFFERED && contains_nl))
|
||||
(term->bufmode == LINEBUFFERED && contains_nl))
|
||||
{
|
||||
term_flush(term);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
@@ -326,21 +327,21 @@ static void term_check_flush(term_t* term, bool contains_nl) {
|
||||
|
||||
static void term_init_raw(term_t* term);
|
||||
|
||||
ic_private term_t* term_new(alloc_t* mem, tty_t* tty, bool nocolor, bool silent, int fd_out )
|
||||
ic_private term_t* term_new(alloc_t* mem, tty_t* tty, bool nocolor, bool silent, int fd_out )
|
||||
{
|
||||
term_t* term = mem_zalloc_tp(mem, term_t);
|
||||
if (term == NULL) return NULL;
|
||||
|
||||
term->fd_out = (fd_out < 0 ? STDOUT_FILENO : fd_out);
|
||||
term->nocolor = nocolor || (isatty(term->fd_out) == 0);
|
||||
term->silent = silent;
|
||||
term->nocolor = nocolor || !tty_is_atty(term->fd_out);
|
||||
term->silent = silent;
|
||||
term->mem = mem;
|
||||
term->tty = tty; // can be NULL
|
||||
term->width = 80;
|
||||
term->height = 25;
|
||||
term->is_utf8 = tty_is_utf8(tty);
|
||||
term->palette = ANSI16; // almost universally supported
|
||||
term->buf = sbuf_new(mem);
|
||||
term->buf = sbuf_new(mem);
|
||||
term->bufmode = LINEBUFFERED;
|
||||
term->attr = attr_default();
|
||||
|
||||
@@ -351,16 +352,16 @@ ic_private term_t* term_new(alloc_t* mem, tty_t* tty, bool nocolor, bool silent,
|
||||
if (!term->nocolor) {
|
||||
// detect color palette
|
||||
// COLORTERM takes precedence
|
||||
const char* colorterm = getenv("COLORTERM");
|
||||
const char* eterm = getenv("TERM");
|
||||
if (ic_contains(colorterm,"24bit") || ic_contains(colorterm,"truecolor") || ic_contains(colorterm,"direct")) {
|
||||
term->palette = ANSIRGB;
|
||||
const char* colorterm = getenv("COLORTERM");
|
||||
const char* eterm = getenv("TERM");
|
||||
if (ic_contains(colorterm,"24bit") || ic_contains(colorterm,"truecolor") || ic_contains(colorterm,"direct")) {
|
||||
term->palette = ANSIRGB;
|
||||
}
|
||||
else if (ic_contains(colorterm,"8bit") || ic_contains(colorterm,"256color")) { term->palette = ANSI256; }
|
||||
else if (ic_contains(colorterm,"8bit") || ic_contains(colorterm,"256color")) { term->palette = ANSI256; }
|
||||
else if (ic_contains(colorterm,"4bit") || ic_contains(colorterm,"16color")) { term->palette = ANSI16; }
|
||||
else if (ic_contains(colorterm,"3bit") || ic_contains(colorterm,"8color")) { term->palette = ANSI8; }
|
||||
else if (ic_contains(colorterm,"1bit") || ic_contains(colorterm,"nocolor") || ic_contains(colorterm,"monochrome")) {
|
||||
term->palette = MONOCHROME;
|
||||
else if (ic_contains(colorterm,"1bit") || ic_contains(colorterm,"nocolor") || ic_contains(colorterm,"monochrome")) {
|
||||
term->palette = MONOCHROME;
|
||||
}
|
||||
// otherwise check for some specific terminals
|
||||
else if (getenv("WT_SESSION") != NULL) { term->palette = ANSIRGB; } // Windows terminal
|
||||
@@ -374,24 +375,24 @@ ic_private term_t* term_new(alloc_t* mem, tty_t* tty, bool nocolor, bool silent,
|
||||
else if (ic_contains(eterm,"alacritty") || ic_contains(eterm,"kitty")) {
|
||||
term->palette = ANSIRGB;
|
||||
}
|
||||
else if (ic_contains(eterm,"256color") || ic_contains(eterm,"gnome")) {
|
||||
else if (ic_contains(eterm,"256color") || ic_contains(eterm,"gnome")) {
|
||||
term->palette = ANSI256;
|
||||
}
|
||||
}
|
||||
else if (ic_contains(eterm,"16color")){ term->palette = ANSI16; }
|
||||
else if (ic_contains(eterm,"8color")) { term->palette = ANSI8; }
|
||||
else if (ic_contains(eterm,"monochrome") || ic_contains(eterm,"nocolor") || ic_contains(eterm,"dumb")) {
|
||||
term->palette = MONOCHROME;
|
||||
else if (ic_contains(eterm,"monochrome") || ic_contains(eterm,"nocolor") || ic_contains(eterm,"dumb")) {
|
||||
term->palette = MONOCHROME;
|
||||
}
|
||||
}
|
||||
debug_msg("term: color-bits: %d (COLORTERM=%s, TERM=%s)\n", term_get_color_bits(term), colorterm, eterm);
|
||||
}
|
||||
|
||||
|
||||
// read COLUMS/LINES from the environment for a better initial guess.
|
||||
const char* env_columns = getenv("COLUMNS");
|
||||
if (env_columns != NULL) { ic_atoz(env_columns, &term->width); }
|
||||
const char* env_lines = getenv("LINES");
|
||||
if (env_lines != NULL) { ic_atoz(env_lines, &term->height); }
|
||||
|
||||
|
||||
// initialize raw terminal output and terminal dimensions
|
||||
term_init_raw(term);
|
||||
term_update_dim(term);
|
||||
@@ -403,8 +404,8 @@ ic_private term_t* term_new(alloc_t* mem, tty_t* tty, bool nocolor, bool silent,
|
||||
ic_private bool term_is_interactive(const term_t* term) {
|
||||
ic_unused(term);
|
||||
// check dimensions (0 is used for debuggers)
|
||||
// if (term->width <= 0) return false;
|
||||
|
||||
// if (term->width <= 0) return false;
|
||||
|
||||
// check editing support
|
||||
const char* eterm = getenv("TERM");
|
||||
debug_msg("term: TERM=%s\n", eterm);
|
||||
@@ -438,13 +439,13 @@ ic_private void term_free(term_t* term) {
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// For best portability and applications inserting CSI SGR (ESC[ .. m)
|
||||
// codes themselves in strings, we interpret these at the
|
||||
// codes themselves in strings, we interpret these at the
|
||||
// lowest level so we can have a `term_get_attr` function which
|
||||
// is needed for bracketed styles etc.
|
||||
//-------------------------------------------------------------
|
||||
|
||||
static void term_append_esc(term_t* term, const char* const s, ssize_t len) {
|
||||
if (s[1]=='[' && s[len-1] == 'm') {
|
||||
if (s[1]=='[' && s[len-1] == 'm') {
|
||||
// it is a CSI SGR sequence: ESC[ ... m
|
||||
if (term->nocolor) return; // ignore escape sequences if nocolor is set
|
||||
term->attr = attr_update_with(term->attr, attr_from_esc_sgr(s,len));
|
||||
@@ -482,10 +483,10 @@ static void term_append_buf( term_t* term, const char* s, ssize_t len ) {
|
||||
// handle ascii sequences in bulk
|
||||
ssize_t ascii = 0;
|
||||
ssize_t next;
|
||||
while ((next = str_next_ofs(s, len, pos+ascii, NULL)) > 0 &&
|
||||
(uint8_t)s[pos + ascii] > '\x1B' && (uint8_t)s[pos + ascii] <= 0x7F )
|
||||
while ((next = str_next_ofs(s, len, pos+ascii, NULL)) > 0 &&
|
||||
(uint8_t)s[pos + ascii] > '\x1B' && (uint8_t)s[pos + ascii] <= 0x7F )
|
||||
{
|
||||
ascii += next;
|
||||
ascii += next;
|
||||
}
|
||||
if (ascii > 0) {
|
||||
sbuf_append_n(term->buf, s+pos, ascii);
|
||||
@@ -510,9 +511,9 @@ static void term_append_buf( term_t* term, const char* s, ssize_t len ) {
|
||||
sbuf_append_n(term->buf, s+pos, next);
|
||||
}
|
||||
pos += next;
|
||||
}
|
||||
}
|
||||
// possibly flush
|
||||
term_check_flush(term, newline);
|
||||
term_check_flush(term, newline);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
@@ -523,7 +524,7 @@ static void term_append_buf( term_t* term, const char* s, ssize_t len ) {
|
||||
|
||||
// write to the console without further processing
|
||||
static bool term_write_direct(term_t* term, const char* s, ssize_t n) {
|
||||
ssize_t count = 0;
|
||||
ssize_t count = 0;
|
||||
while( count < n ) {
|
||||
ssize_t nwritten = write(term->fd_out, s + count, to_size_t(n - count));
|
||||
if (nwritten > 0) {
|
||||
@@ -613,7 +614,7 @@ static void term_cursor_visible( term_t* term, bool visible ) {
|
||||
SetConsoleCursorInfo(term->hcon,&info);
|
||||
}
|
||||
|
||||
static void term_erase_line( term_t* term, ssize_t mode ) {
|
||||
static void term_erase_line( term_t* term, ssize_t mode ) {
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (!GetConsoleScreenBufferInfo( term->hcon, &info )) return;
|
||||
DWORD written;
|
||||
@@ -632,7 +633,7 @@ static void term_erase_line( term_t* term, ssize_t mode ) {
|
||||
length = info.dwCursorPosition.X;
|
||||
}
|
||||
else {
|
||||
// to end of line
|
||||
// to end of line
|
||||
length = (ssize_t)info.srWindow.Right - info.dwCursorPosition.X + 1;
|
||||
start = info.dwCursorPosition;
|
||||
}
|
||||
@@ -650,7 +651,7 @@ static void term_clear_screen(term_t* term, ssize_t mode) {
|
||||
ssize_t width = (ssize_t)info.dwSize.X;
|
||||
if (mode == 2) {
|
||||
// entire screen
|
||||
length = width * info.dwSize.Y;
|
||||
length = width * info.dwSize.Y;
|
||||
}
|
||||
else if (mode == 1) {
|
||||
// to cursor
|
||||
@@ -680,9 +681,9 @@ static WORD attr_color[8] = {
|
||||
static void term_set_win_attr( term_t* term, attr_t ta ) {
|
||||
WORD def_attr = term->hcon_default_attr;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (!GetConsoleScreenBufferInfo( term->hcon, &info )) return;
|
||||
if (!GetConsoleScreenBufferInfo( term->hcon, &info )) return;
|
||||
WORD cur_attr = info.wAttributes;
|
||||
WORD attr = cur_attr;
|
||||
WORD attr = cur_attr;
|
||||
if (ta.x.color != IC_COLOR_NONE) {
|
||||
if (ta.x.color >= IC_ANSI_BLACK && ta.x.color <= IC_ANSI_SILVER) {
|
||||
attr = (attr & 0xFFF0) | attr_color[ta.x.color - IC_ANSI_BLACK];
|
||||
@@ -700,7 +701,7 @@ static void term_set_win_attr( term_t* term, attr_t ta ) {
|
||||
}
|
||||
else if (ta.x.bgcolor >= IC_ANSI_GRAY && ta.x.bgcolor <= IC_ANSI_WHITE) {
|
||||
attr = (attr & 0xFF0F) | (WORD)(attr_color[ta.x.bgcolor - IC_ANSI_GRAY] << 4) | BACKGROUND_INTENSITY;
|
||||
}
|
||||
}
|
||||
else if (ta.x.bgcolor == IC_ANSI_DEFAULT) {
|
||||
attr = (attr & 0xFF0F) | (def_attr & 0x00F0);
|
||||
}
|
||||
@@ -710,7 +711,7 @@ static void term_set_win_attr( term_t* term, attr_t ta ) {
|
||||
}
|
||||
if (ta.x.reverse != IC_NONE) {
|
||||
attr = (attr & ~COMMON_LVB_REVERSE_VIDEO) | (ta.x.reverse == IC_ON ? COMMON_LVB_REVERSE_VIDEO : 0);
|
||||
}
|
||||
}
|
||||
if (attr != cur_attr) {
|
||||
SetConsoleTextAttribute(term->hcon, attr);
|
||||
}
|
||||
@@ -724,10 +725,10 @@ static ssize_t esc_param( const char* s, ssize_t def ) {
|
||||
}
|
||||
|
||||
static void esc_param2( const char* s, ssize_t* p1, ssize_t* p2, ssize_t def ) {
|
||||
if (*s == '?') s++;
|
||||
if (*s == '?') s++;
|
||||
*p1 = def;
|
||||
*p2 = def;
|
||||
ic_atoz2(s, p1, p2);
|
||||
ic_atoz2(s, p1, p2);
|
||||
}
|
||||
|
||||
// Emulate escape sequences on older windows.
|
||||
@@ -749,15 +750,15 @@ static void term_write_esc( term_t* term, const char* s, ssize_t len ) {
|
||||
case 'D':
|
||||
term_move_cursor(term, 0, -1, esc_param(s+2, 1));
|
||||
break;
|
||||
case 'H':
|
||||
case 'H':
|
||||
esc_param2(s+2, &row, &col, 1);
|
||||
term_move_cursor_to(term, row, col);
|
||||
break;
|
||||
case 'K':
|
||||
term_erase_line(term, esc_param(s+2, 0));
|
||||
break;
|
||||
case 'm':
|
||||
term_set_win_attr( term, attr_from_esc_sgr(s,len) );
|
||||
case 'm':
|
||||
term_set_win_attr( term, attr_from_esc_sgr(s,len) );
|
||||
break;
|
||||
|
||||
// support some less standard escape codes (currently not used by isocline)
|
||||
@@ -776,7 +777,7 @@ static void term_write_esc( term_t* term, const char* s, ssize_t len ) {
|
||||
col = esc_param(s+2, 1);
|
||||
term_move_cursor_to(term, row, col);
|
||||
break;
|
||||
case 'J':
|
||||
case 'J':
|
||||
term_clear_screen(term, esc_param(s+2, 0));
|
||||
break;
|
||||
case 'h':
|
||||
@@ -784,14 +785,14 @@ static void term_write_esc( term_t* term, const char* s, ssize_t len ) {
|
||||
term_cursor_visible(term, true);
|
||||
}
|
||||
break;
|
||||
case 'l':
|
||||
case 'l':
|
||||
if (strncmp(s+2, "?25l", 4) == 0) {
|
||||
term_cursor_visible(term, false);
|
||||
}
|
||||
break;
|
||||
case 's':
|
||||
case 's':
|
||||
term_cursor_save(term);
|
||||
break;
|
||||
break;
|
||||
case 'u':
|
||||
term_cursor_restore(term);
|
||||
break;
|
||||
@@ -811,10 +812,10 @@ static void term_write_esc( term_t* term, const char* s, ssize_t len ) {
|
||||
|
||||
static bool term_write_direct(term_t* term, const char* s, ssize_t len ) {
|
||||
term_cursor_visible(term,false); // reduce flicker
|
||||
ssize_t pos = 0;
|
||||
ssize_t pos = 0;
|
||||
if ((term->hcon_mode & ENABLE_VIRTUAL_TERMINAL_PROCESSING) != 0) {
|
||||
// use the builtin virtual terminal processing. (enables truecolor for example)
|
||||
term_write_console(term, s, len);
|
||||
term_write_console(term, s, len);
|
||||
pos = len;
|
||||
}
|
||||
else {
|
||||
@@ -824,21 +825,21 @@ static bool term_write_direct(term_t* term, const char* s, ssize_t len ) {
|
||||
// (We don't need to handle utf-8 separately as we set the codepage to always be in utf-8 mode)
|
||||
ssize_t nonctrl = 0;
|
||||
ssize_t next;
|
||||
while( (next = str_next_ofs( s, len, pos+nonctrl, NULL )) > 0 &&
|
||||
while( (next = str_next_ofs( s, len, pos+nonctrl, NULL )) > 0 &&
|
||||
(uint8_t)s[pos + nonctrl] >= ' ' && (uint8_t)s[pos + nonctrl] <= 0x7F) {
|
||||
nonctrl += next;
|
||||
}
|
||||
if (nonctrl > 0) {
|
||||
term_write_console(term, s+pos, nonctrl);
|
||||
pos += nonctrl;
|
||||
}
|
||||
}
|
||||
if (next <= 0) break;
|
||||
|
||||
if ((uint8_t)s[pos] >= 0x80) {
|
||||
// utf8 is already processed
|
||||
term_write_console(term, s+pos, next);
|
||||
}
|
||||
else if (next > 1 && s[pos] == '\x1B') {
|
||||
else if (next > 1 && s[pos] == '\x1B') {
|
||||
// handle control (note: str_next_ofs considers whole CSI escape sequences at a time)
|
||||
term_write_esc(term, s+pos, next);
|
||||
}
|
||||
@@ -853,7 +854,7 @@ static bool term_write_direct(term_t* term, const char* s, ssize_t len ) {
|
||||
}
|
||||
term_cursor_visible(term,true);
|
||||
assert(pos == len);
|
||||
return (pos == len);
|
||||
return (pos == len);
|
||||
|
||||
}
|
||||
#endif
|
||||
@@ -867,29 +868,29 @@ static bool term_write_direct(term_t* term, const char* s, ssize_t len ) {
|
||||
#if !defined(_WIN32)
|
||||
|
||||
// send escape query that may return a response on the tty
|
||||
static bool term_esc_query_raw( term_t* term, const char* query, char* buf, ssize_t buflen )
|
||||
static bool term_esc_query_raw( term_t* term, const char* query, char* buf, ssize_t buflen )
|
||||
{
|
||||
if (buf==NULL || buflen <= 0 || query[0] == 0) return false;
|
||||
bool osc = (query[1] == ']');
|
||||
if (!term_write_direct(term, query, ic_strlen(query))) return false;
|
||||
debug_msg("term: read tty query response to: ESC %s\n", query + 1);
|
||||
debug_msg("term: read tty query response to: ESC %s\n", query + 1);
|
||||
return tty_read_esc_response( term->tty, query[1], osc, buf, buflen );
|
||||
}
|
||||
|
||||
static bool term_esc_query( term_t* term, const char* query, char* buf, ssize_t buflen )
|
||||
static bool term_esc_query( term_t* term, const char* query, char* buf, ssize_t buflen )
|
||||
{
|
||||
if (!tty_start_raw(term->tty)) return false;
|
||||
bool ok = term_esc_query_raw(term,query,buf,buflen);
|
||||
if (!tty_start_raw(term->tty)) return false;
|
||||
bool ok = term_esc_query_raw(term,query,buf,buflen);
|
||||
tty_end_raw(term->tty);
|
||||
return ok;
|
||||
}
|
||||
|
||||
// get the cursor position via an ESC[6n
|
||||
static bool term_get_cursor_pos( term_t* term, ssize_t* row, ssize_t* col)
|
||||
static bool term_get_cursor_pos( term_t* term, ssize_t* row, ssize_t* col)
|
||||
{
|
||||
// send escape query
|
||||
char buf[128];
|
||||
if (!term_esc_query(term,"\x1B[6n",buf,128)) return false;
|
||||
if (!term_esc_query(term,"\x1B[6n",buf,128)) return false;
|
||||
if (!ic_atoz2(buf,row,col)) return false;
|
||||
return true;
|
||||
}
|
||||
@@ -898,7 +899,7 @@ static void term_set_cursor_pos( term_t* term, ssize_t row, ssize_t col ) {
|
||||
term_writef( term, IC_CSI "%zd;%zdH", row, col );
|
||||
}
|
||||
|
||||
ic_private bool term_update_dim(term_t* term) {
|
||||
ic_private bool term_update_dim(term_t* term) {
|
||||
ssize_t cols = 0;
|
||||
ssize_t rows = 0;
|
||||
struct winsize ws;
|
||||
@@ -930,12 +931,12 @@ ic_private bool term_update_dim(term_t* term) {
|
||||
|
||||
// update width and return whether it changed.
|
||||
bool changed = (term->width != cols || term->height != rows);
|
||||
debug_msg("terminal dim: %zd,%zd: %s\n", rows, cols, changed ? "changed" : "unchanged");
|
||||
if (cols > 0) {
|
||||
debug_msg("terminal dim: %zd,%zd: %s\n", rows, cols, changed ? "changed" : "unchanged");
|
||||
if (cols > 0) {
|
||||
term->width = cols;
|
||||
term->height = rows;
|
||||
}
|
||||
return changed;
|
||||
return changed;
|
||||
}
|
||||
|
||||
#else
|
||||
@@ -945,8 +946,8 @@ ic_private bool term_update_dim(term_t* term) {
|
||||
term->hcon = GetConsoleWindow();
|
||||
}
|
||||
ssize_t rows = 0;
|
||||
ssize_t cols = 0;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbinfo;
|
||||
ssize_t cols = 0;
|
||||
CONSOLE_SCREEN_BUFFER_INFO sbinfo;
|
||||
if (GetConsoleScreenBufferInfo(term->hcon, &sbinfo)) {
|
||||
cols = (ssize_t)sbinfo.srWindow.Right - (ssize_t)sbinfo.srWindow.Left + 1;
|
||||
rows = (ssize_t)sbinfo.srWindow.Bottom - (ssize_t)sbinfo.srWindow.Top + 1;
|
||||
@@ -997,13 +998,13 @@ static bool term_esc_query_color_raw(term_t* term, int color_idx, uint32_t* colo
|
||||
rgb++; // skip ':'
|
||||
unsigned int r,g,b;
|
||||
if (sscanf(rgb,"%x/%x/%x",&r,&g,&b) != 3) return false;
|
||||
if (rgb[2]!='/') { // 48-bit rgb, hexadecimal round to 24-bit
|
||||
if (rgb[2]!='/') { // 48-bit rgb, hexadecimal round to 24-bit
|
||||
r = (r+0x7F)/0x100; // note: can "overflow", e.g. 0xFFFF -> 0x100. (and we need `ic_cap8` to convert.)
|
||||
g = (g+0x7F)/0x100;
|
||||
b = (b+0x7F)/0x100;
|
||||
b = (b+0x7F)/0x100;
|
||||
}
|
||||
*color = (ic_cap8(r)<<16) | (ic_cap8(g)<<8) | ic_cap8(b);
|
||||
debug_msg("color query: %02x,%02x,%02x: %06x\n", r, g, b, *color);
|
||||
debug_msg("color query: %02x,%02x,%02x: %06x\n", r, g, b, *color);
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -1031,13 +1032,13 @@ static void term_update_ansi16(term_t* term) {
|
||||
#if __APPLE__
|
||||
// otherwise use OSC 4 escape sequence query
|
||||
if (tty_start_raw(term->tty)) {
|
||||
for(ssize_t i = 0; i < 16; i++) {
|
||||
for(int i = 0; i < 16; i++) {
|
||||
uint32_t color;
|
||||
if (!term_esc_query_color_raw(term, i, &color)) break;
|
||||
debug_msg("term ansi color %d: 0x%06x\n", i, color);
|
||||
ansi256[i] = color;
|
||||
}
|
||||
tty_end_raw(term->tty);
|
||||
}
|
||||
tty_end_raw(term->tty);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
@@ -1051,7 +1052,7 @@ static void term_init_raw(term_t* term) {
|
||||
#else
|
||||
|
||||
ic_private void term_start_raw(term_t* term) {
|
||||
if (term->raw_enabled++ > 0) return;
|
||||
if (term->raw_enabled++ > 0) return;
|
||||
CONSOLE_SCREEN_BUFFER_INFO info;
|
||||
if (GetConsoleScreenBufferInfo(term->hcon, &info)) {
|
||||
term->hcon_orig_attr = info.wAttributes;
|
||||
@@ -1060,7 +1061,7 @@ ic_private void term_start_raw(term_t* term) {
|
||||
SetConsoleOutputCP(CP_UTF8);
|
||||
if (term->hcon_mode == 0) {
|
||||
// first time initialization
|
||||
DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_LVB_GRID_WORLDWIDE; // for \r \n and \b
|
||||
DWORD mode = ENABLE_PROCESSED_OUTPUT | ENABLE_WRAP_AT_EOL_OUTPUT | ENABLE_LVB_GRID_WORLDWIDE; // for \r \n and \b
|
||||
// use escape sequence handling if available and the terminal supports it (so we can use rgb colors in Windows terminal)
|
||||
// Unfortunately, in plain powershell, we can successfully enable terminal processing
|
||||
// but it still fails to render correctly; so we require the palette be large enough (like in Windows Terminal)
|
||||
@@ -1078,7 +1079,7 @@ ic_private void term_start_raw(term_t* term) {
|
||||
}
|
||||
else {
|
||||
SetConsoleMode(term->hcon, term->hcon_mode);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ic_private void term_end_raw(term_t* term, bool force) {
|
||||
@@ -1095,7 +1096,7 @@ ic_private void term_end_raw(term_t* term, bool force) {
|
||||
}
|
||||
|
||||
static void term_init_raw(term_t* term) {
|
||||
term->hcon = GetStdHandle(STD_OUTPUT_HANDLE);
|
||||
term->hcon = GetStdHandle( term->fd_out == STDERR_FILENO ? STD_ERROR_HANDLE : STD_OUTPUT_HANDLE );
|
||||
GetConsoleMode(term->hcon, &term->hcon_orig_mode);
|
||||
CONSOLE_SCREEN_BUFFER_INFOEX info;
|
||||
memset(&info, 0, sizeof(info));
|
||||
@@ -1103,15 +1104,15 @@ static void term_init_raw(term_t* term) {
|
||||
if (GetConsoleScreenBufferInfoEx(term->hcon, &info)) {
|
||||
// store default attributes
|
||||
term->hcon_default_attr = info.wAttributes;
|
||||
// update our color table with the actual colors used.
|
||||
// update our color table with the actual colors used.
|
||||
for (unsigned i = 0; i < 16; i++) {
|
||||
COLORREF cr = info.ColorTable[i];
|
||||
uint32_t color = (ic_cap8(GetRValue(cr))<<16) | (ic_cap8(GetGValue(cr))<<8) | ic_cap8(GetBValue(cr)); // COLORREF = BGR
|
||||
// index is also in reverse in the bits 0 and 2
|
||||
// index is also in reverse in the bits 0 and 2
|
||||
unsigned j = (i&0x08) | ((i&0x04)>>2) | (i&0x02) | (i&0x01)<<2;
|
||||
debug_msg("term: ansi color %d is 0x%06x\n", j, color);
|
||||
ansi256[j] = color;
|
||||
}
|
||||
}
|
||||
}
|
||||
else {
|
||||
DWORD err = GetLastError();
|
||||
|
||||
Vendored
+70
-66
@@ -42,13 +42,13 @@ struct tty_s {
|
||||
bool has_term_resize_event; // are resize events generated?
|
||||
bool term_resize_event; // did a term resize happen?
|
||||
alloc_t* mem; // memory allocator
|
||||
code_t pushbuf[TTY_PUSH_MAX]; // push back buffer for full key codes
|
||||
ssize_t push_count;
|
||||
code_t pushbuf[TTY_PUSH_MAX]; // push back buffer for full key codes
|
||||
ssize_t push_count;
|
||||
uint8_t cpushbuf[TTY_PUSH_MAX]; // low level push back buffer for bytes
|
||||
ssize_t cpush_count;
|
||||
long esc_initial_timeout; // initial ms wait to see if ESC starts an escape sequence
|
||||
long esc_timeout; // follow up delay for characters in an escape sequence
|
||||
#if defined(_WIN32)
|
||||
#if defined(_WIN32)
|
||||
HANDLE hcon; // console input handle
|
||||
DWORD hcon_orig_mode; // original console mode
|
||||
#else
|
||||
@@ -122,7 +122,7 @@ static code_t tty_read_utf8( tty_t* tty, uint8_t c0 ) {
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
buf[count] = 0;
|
||||
debug_msg("tty: read utf8: count: %zd: %02x,%02x,%02x,%02x", count, buf[0], buf[1], buf[2], buf[3]);
|
||||
|
||||
@@ -144,8 +144,8 @@ static code_t tty_read_utf8( tty_t* tty, uint8_t c0 ) {
|
||||
static bool tty_code_pop(tty_t* tty, code_t* code);
|
||||
|
||||
|
||||
// read a single char/key
|
||||
ic_private bool tty_read_timeout(tty_t* tty, long timeout_ms, code_t* code)
|
||||
// read a single char/key
|
||||
ic_private bool tty_read_timeout(tty_t* tty, long timeout_ms, code_t* code)
|
||||
{
|
||||
// is there a push_count back code?
|
||||
if (tty_code_pop(tty,code)) {
|
||||
@@ -155,7 +155,7 @@ ic_private bool tty_read_timeout(tty_t* tty, long timeout_ms, code_t* code)
|
||||
// read a single char/byte from a character stream
|
||||
uint8_t c;
|
||||
if (!tty_readc_noblock(tty, &c, timeout_ms)) return false;
|
||||
|
||||
|
||||
if (c == KEY_ESC) {
|
||||
// escape sequence?
|
||||
*code = tty_read_esc(tty, tty->esc_initial_timeout, tty->esc_timeout);
|
||||
@@ -181,7 +181,7 @@ ic_private bool tty_read_timeout(tty_t* tty, long timeout_ms, code_t* code)
|
||||
static code_t modify_code( code_t code ) {
|
||||
code_t key = KEY_NO_MODS(code);
|
||||
code_t mods = KEY_MODS(code);
|
||||
debug_msg( "tty: readc %s%s%s 0x%03x ('%c')\n",
|
||||
debug_msg( "tty: readc %s%s%s 0x%03x ('%c')\n",
|
||||
mods&KEY_MOD_SHIFT ? "shift+" : "", mods&KEY_MOD_CTRL ? "ctrl+" : "", mods&KEY_MOD_ALT ? "alt+" : "",
|
||||
key, (key >= ' ' && key <= '~' ? key : ' '));
|
||||
|
||||
@@ -189,7 +189,7 @@ static code_t modify_code( code_t code ) {
|
||||
if (key == KEY_RUBOUT) {
|
||||
code = KEY_BACKSP | mods;
|
||||
}
|
||||
// ctrl+'_' is translated to '\x1F' on Linux, translate it back
|
||||
// ctrl+'_' is translated to '\x1F' on Linux, translate it back
|
||||
else if (key == key_char('\x1F') && (mods & KEY_MOD_ALT) == 0) {
|
||||
key = '_';
|
||||
code = WITH_CTRL(key_char('_'));
|
||||
@@ -209,17 +209,17 @@ static code_t modify_code( code_t code ) {
|
||||
else if (code == WITH_ALT(KEY_UP) || code == WITH_ALT('<') || code == WITH_CTRL(KEY_HOME)) {
|
||||
code = KEY_PAGEUP;
|
||||
}
|
||||
|
||||
|
||||
// treat C0 codes without KEY_MOD_CTRL
|
||||
if (key < ' ' && (mods&KEY_MOD_CTRL) != 0) {
|
||||
code &= ~KEY_MOD_CTRL;
|
||||
code &= ~KEY_MOD_CTRL;
|
||||
}
|
||||
|
||||
|
||||
return code;
|
||||
}
|
||||
|
||||
|
||||
// read a single char/key
|
||||
// read a single char/key
|
||||
ic_private code_t tty_read(tty_t* tty)
|
||||
{
|
||||
code_t code;
|
||||
@@ -231,7 +231,7 @@ ic_private code_t tty_read(tty_t* tty)
|
||||
// Read back an ANSI query response
|
||||
//-------------------------------------------------------------
|
||||
|
||||
ic_private bool tty_read_esc_response(tty_t* tty, char esc_start, bool final_st, char* buf, ssize_t buflen )
|
||||
ic_private bool tty_read_esc_response(tty_t* tty, char esc_start, bool final_st, char* buf, ssize_t buflen )
|
||||
{
|
||||
buf[0] = 0;
|
||||
ssize_t len = 0;
|
||||
@@ -264,7 +264,7 @@ ic_private bool tty_read_esc_response(tty_t* tty, char esc_start, bool final_st,
|
||||
break;
|
||||
}
|
||||
}
|
||||
buf[len++] = (char)c;
|
||||
buf[len++] = (char)c;
|
||||
}
|
||||
buf[len] = 0;
|
||||
debug_msg("tty: escape query response: %s\n", buf);
|
||||
@@ -282,7 +282,7 @@ static bool tty_code_pop( tty_t* tty, code_t* code ) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ic_private void tty_code_pushback( tty_t* tty, code_t c ) {
|
||||
ic_private void tty_code_pushback( tty_t* tty, code_t c ) {
|
||||
// note: must be signal safe
|
||||
if (tty->push_count >= TTY_PUSH_MAX) return;
|
||||
tty->pushbuf[tty->push_count] = c;
|
||||
@@ -294,7 +294,7 @@ ic_private void tty_code_pushback( tty_t* tty, code_t c ) {
|
||||
// low-level character pushback (for escape sequences and windows)
|
||||
//-------------------------------------------------------------
|
||||
|
||||
ic_private bool tty_cpop(tty_t* tty, uint8_t* c) {
|
||||
ic_private bool tty_cpop(tty_t* tty, uint8_t* c) {
|
||||
if (tty->cpush_count <= 0) { // do not modify c on failure (see `tty_decode_unicode`)
|
||||
return false;
|
||||
}
|
||||
@@ -331,7 +331,7 @@ static void tty_cpushf(tty_t* tty, const char* fmt, ...) {
|
||||
return;
|
||||
}
|
||||
|
||||
ic_private void tty_cpush_char(tty_t* tty, uint8_t c) {
|
||||
ic_private void tty_cpush_char(tty_t* tty, uint8_t c) {
|
||||
uint8_t buf[2];
|
||||
buf[0] = c;
|
||||
buf[1] = 0;
|
||||
@@ -363,8 +363,8 @@ static void tty_cpush_csi_xterm( tty_t* tty, code_t mods, char xcode ) {
|
||||
|
||||
// push ESC [ <unicode> ; <mods> u
|
||||
static void tty_cpush_csi_unicode( tty_t* tty, code_t mods, uint32_t unicode ) {
|
||||
if ((unicode < 0x80 && mods == 0) ||
|
||||
(mods == KEY_MOD_CTRL && unicode < ' ' && unicode != KEY_TAB && unicode != KEY_ENTER
|
||||
if ((unicode < 0x80 && mods == 0) ||
|
||||
(mods == KEY_MOD_CTRL && unicode < ' ' && unicode != KEY_TAB && unicode != KEY_ENTER
|
||||
&& unicode != KEY_LINEFEED && unicode != KEY_BACKSP) ||
|
||||
(mods == KEY_MOD_SHIFT && unicode >= ' ' && unicode <= KEY_RUBOUT)) {
|
||||
tty_cpush_char(tty,(uint8_t)unicode);
|
||||
@@ -392,7 +392,7 @@ static bool tty_init_utf8(tty_t* tty) {
|
||||
return true;
|
||||
}
|
||||
|
||||
ic_private tty_t* tty_new(alloc_t* mem, int fd_in)
|
||||
ic_private tty_t* tty_new(alloc_t* mem, int fd_in)
|
||||
{
|
||||
tty_t* tty = mem_zalloc_tp(mem, tty_t);
|
||||
tty->mem = mem;
|
||||
@@ -400,7 +400,7 @@ ic_private tty_t* tty_new(alloc_t* mem, int fd_in)
|
||||
#if defined(__APPLE__)
|
||||
tty->esc_initial_timeout = 200; // apple use ESC+<key> for alt-<key>
|
||||
#else
|
||||
tty->esc_initial_timeout = 100;
|
||||
tty->esc_initial_timeout = 100;
|
||||
#endif
|
||||
tty->esc_timeout = 10;
|
||||
if (!(isatty(tty->fd_in) && tty_init_raw(tty) && tty_init_utf8(tty))) {
|
||||
@@ -426,7 +426,7 @@ ic_private bool tty_term_resize_event(tty_t* tty) {
|
||||
if (tty == NULL) return true;
|
||||
if (tty->has_term_resize_event) {
|
||||
if (!tty->term_resize_event) return false;
|
||||
tty->term_resize_event = false; // reset.
|
||||
tty->term_resize_event = false; // reset.
|
||||
}
|
||||
return true; // always return true on systems without a resize event (more expensive but still ok)
|
||||
}
|
||||
@@ -436,6 +436,10 @@ ic_private void tty_set_esc_delay(tty_t* tty, long initial_delay_ms, long follow
|
||||
tty->esc_timeout = (followup_delay_ms < 0 ? 0 : (followup_delay_ms > 1000 ? 1000 : followup_delay_ms));
|
||||
}
|
||||
|
||||
ic_private bool tty_is_atty(int fd) {
|
||||
return (isatty(fd) != 0);
|
||||
}
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Unix
|
||||
//-------------------------------------------------------------
|
||||
@@ -453,7 +457,7 @@ static bool tty_readc_blocking(tty_t* tty, uint8_t* c) {
|
||||
|
||||
|
||||
// non blocking read -- with a small timeout used for reading escape sequences.
|
||||
ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms)
|
||||
ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms)
|
||||
{
|
||||
// in our pushback buffer?
|
||||
if (tty_cpop(tty, c)) return true;
|
||||
@@ -478,18 +482,18 @@ ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms)
|
||||
#endif
|
||||
|
||||
// otherwise block for at most timeout milliseconds
|
||||
#if defined(FD_SET)
|
||||
#if defined(FD_SET)
|
||||
// we can use select to detect when input becomes available
|
||||
fd_set readset;
|
||||
struct timeval time;
|
||||
FD_ZERO(&readset);
|
||||
FD_SET(tty->fd_in, &readset);
|
||||
time.tv_sec = (timeout_ms > 0 ? timeout_ms / 1000 : 0);
|
||||
time.tv_usec = (timeout_ms > 0 ? 1000*(timeout_ms % 1000) : 0);
|
||||
time.tv_usec = (timeout_ms > 0 ? 1000*(timeout_ms % 1000) : 0);
|
||||
if (select(tty->fd_in + 1, &readset, NULL, NULL, &time) == 1) {
|
||||
// input available
|
||||
return tty_readc_blocking(tty, c);
|
||||
}
|
||||
}
|
||||
#else
|
||||
// no select, we cannot timeout; use usleeps :-(
|
||||
// todo: this seems very rare nowadays; should be even support this?
|
||||
@@ -522,14 +526,14 @@ ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms)
|
||||
usleep(50*1000L); // sleep at most 0.05s at a time
|
||||
timeout_ms -= 100;
|
||||
if (timeout_ms < 0) { timeout_ms = 0; }
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
while (timeout_ms > 0);
|
||||
#endif
|
||||
#endif
|
||||
return false;
|
||||
}
|
||||
|
||||
#if defined(TIOCSTI)
|
||||
#if defined(TIOCSTI)
|
||||
ic_private bool tty_async_stop(const tty_t* tty) {
|
||||
// insert ^C in the input stream
|
||||
char c = KEY_CTRL_C;
|
||||
@@ -543,7 +547,7 @@ ic_private bool tty_async_stop(const tty_t* tty) {
|
||||
|
||||
// We install various signal handlers to restore the terminal settings
|
||||
// in case of a terminating signal. This is also used to catch terminal window resizes.
|
||||
// This is not strictly needed so this can be disabled on
|
||||
// This is not strictly needed so this can be disabled on
|
||||
// (older) platforms that do not support signal handling well.
|
||||
#if defined(SIGWINCH) && defined(SA_RESTART) // ensure basic signal functionality is defined
|
||||
|
||||
@@ -561,15 +565,15 @@ typedef struct signal_handler_s {
|
||||
|
||||
static signal_handler_t sighandlers[] = {
|
||||
{ SIGWINCH, {0} },
|
||||
{ SIGTERM , {0} },
|
||||
{ SIGINT , {0} },
|
||||
{ SIGQUIT , {0} },
|
||||
{ SIGTERM , {0} },
|
||||
{ SIGINT , {0} },
|
||||
{ SIGQUIT , {0} },
|
||||
{ SIGHUP , {0} },
|
||||
// { SIGSEGV , {0} },
|
||||
{ SIGTRAP , {0} },
|
||||
{ SIGBUS , {0} },
|
||||
{ SIGSEGV , {0} },
|
||||
{ SIGTRAP , {0} },
|
||||
{ SIGBUS , {0} },
|
||||
{ SIGTSTP , {0} },
|
||||
{ SIGTTIN , {0} },
|
||||
{ SIGTTIN , {0} },
|
||||
{ SIGTTOU , {0} },
|
||||
{ 0 , {0} }
|
||||
};
|
||||
@@ -608,7 +612,7 @@ static void signals_install(tty_t* tty) {
|
||||
struct sigaction handler;
|
||||
memset(&handler,0,sizeof(handler));
|
||||
sigemptyset(&handler.sa_mask);
|
||||
handler.sa_sigaction = &sig_handler;
|
||||
handler.sa_sigaction = &sig_handler;
|
||||
handler.sa_flags = SA_RESTART;
|
||||
// install for all signals
|
||||
for( signal_handler_t* sh = sighandlers; sh->signum != 0; sh++ ) {
|
||||
@@ -621,7 +625,7 @@ static void signals_install(tty_t* tty) {
|
||||
sig_tty->has_term_resize_event = true;
|
||||
};
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -649,7 +653,7 @@ static void signals_restore(void) {
|
||||
ic_private bool tty_start_raw(tty_t* tty) {
|
||||
if (tty == NULL) return false;
|
||||
if (tty->raw_enabled) return true;
|
||||
if (tcsetattr(tty->fd_in,TCSAFLUSH,&tty->raw_ios) < 0) return false;
|
||||
if (tcsetattr(tty->fd_in,TCSAFLUSH,&tty->raw_ios) < 0) return false;
|
||||
tty->raw_enabled = true;
|
||||
return true;
|
||||
}
|
||||
@@ -662,15 +666,15 @@ ic_private void tty_end_raw(tty_t* tty) {
|
||||
tty->raw_enabled = false;
|
||||
}
|
||||
|
||||
static bool tty_init_raw(tty_t* tty)
|
||||
{
|
||||
static bool tty_init_raw(tty_t* tty)
|
||||
{
|
||||
// Set input to raw mode. See <https://man7.org/linux/man-pages/man3/termios.3.html>.
|
||||
if (tcgetattr(tty->fd_in,&tty->orig_ios) == -1) return false;
|
||||
tty->raw_ios = tty->orig_ios;
|
||||
tty->raw_ios = tty->orig_ios;
|
||||
// input: no break signal, no \r to \n, no parity check, no 8-bit to 7-bit, no flow control
|
||||
tty->raw_ios.c_iflag &= ~(unsigned long)(BRKINT | ICRNL | INPCK | ISTRIP | IXON);
|
||||
// control: allow 8-bit
|
||||
tty->raw_ios.c_cflag |= CS8;
|
||||
tty->raw_ios.c_cflag |= CS8;
|
||||
// local: no echo, no line-by-line (canonical), no extended input processing, no signals for ^z,^c
|
||||
tty->raw_ios.c_lflag &= ~(unsigned long)(ECHO | ICANON | IEXTEN | ISIG);
|
||||
// 1 byte at a time, no delay
|
||||
@@ -679,7 +683,7 @@ static bool tty_init_raw(tty_t* tty)
|
||||
|
||||
// store in global so our signal handlers can restore the terminal mode
|
||||
signals_install(tty);
|
||||
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@@ -708,7 +712,7 @@ ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms) { //
|
||||
}
|
||||
|
||||
// Read from the console input events and push escape codes into the tty cbuffer.
|
||||
static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
{
|
||||
// wait for a key down event
|
||||
INPUT_RECORD inp;
|
||||
@@ -718,7 +722,7 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
// check if there are events if in non-blocking timeout mode
|
||||
if (timeout_ms >= 0) {
|
||||
// first peek ahead
|
||||
if (!GetNumberOfConsoleInputEvents(tty->hcon, &count)) return;
|
||||
if (!GetNumberOfConsoleInputEvents(tty->hcon, &count)) return;
|
||||
if (count == 0) {
|
||||
if (timeout_ms == 0) {
|
||||
// out of time
|
||||
@@ -741,7 +745,7 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
case WAIT_TIMEOUT:
|
||||
case WAIT_ABANDONED:
|
||||
case WAIT_FAILED:
|
||||
default:
|
||||
default:
|
||||
return;
|
||||
}
|
||||
}
|
||||
@@ -758,12 +762,12 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
continue;
|
||||
}
|
||||
|
||||
// wait for key down events
|
||||
// wait for key down events
|
||||
if (inp.EventType != KEY_EVENT) continue;
|
||||
|
||||
// the modifier state
|
||||
DWORD modstate = inp.Event.KeyEvent.dwControlKeyState;
|
||||
|
||||
|
||||
// we need to handle shift up events separately
|
||||
if (!inp.Event.KeyEvent.bKeyDown && inp.Event.KeyEvent.wVirtualKeyCode == VK_SHIFT) {
|
||||
modstate &= (DWORD)~SHIFT_PRESSED;
|
||||
@@ -773,7 +777,7 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
DWORD altgr = LEFT_CTRL_PRESSED | RIGHT_ALT_PRESSED;
|
||||
if ((modstate & altgr) == altgr) { modstate &= ~altgr; }
|
||||
|
||||
|
||||
|
||||
// get modifiers
|
||||
code_t mods = 0;
|
||||
if ((modstate & ( RIGHT_CTRL_PRESSED | LEFT_CTRL_PRESSED )) != 0) mods |= KEY_MOD_CTRL;
|
||||
@@ -789,19 +793,19 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
if (!inp.Event.KeyEvent.bKeyDown && virt != VK_MENU) {
|
||||
continue;
|
||||
}
|
||||
|
||||
if (chr == 0) {
|
||||
|
||||
if (chr == 0) {
|
||||
switch (virt) {
|
||||
case VK_UP: tty_cpush_csi_xterm(tty, mods, 'A'); return;
|
||||
case VK_DOWN: tty_cpush_csi_xterm(tty, mods, 'B'); return;
|
||||
case VK_RIGHT: tty_cpush_csi_xterm(tty, mods, 'C'); return;
|
||||
case VK_LEFT: tty_cpush_csi_xterm(tty, mods, 'D'); return;
|
||||
case VK_END: tty_cpush_csi_xterm(tty, mods, 'F'); return;
|
||||
case VK_END: tty_cpush_csi_xterm(tty, mods, 'F'); return;
|
||||
case VK_HOME: tty_cpush_csi_xterm(tty, mods, 'H'); return;
|
||||
case VK_DELETE: tty_cpush_csi_vt(tty,mods,3); return;
|
||||
case VK_PRIOR: tty_cpush_csi_vt(tty,mods,5); return; //page up
|
||||
case VK_NEXT: tty_cpush_csi_vt(tty,mods,6); return; //page down
|
||||
case VK_TAB: tty_cpush_csi_unicode(tty,mods,9); return;
|
||||
case VK_TAB: tty_cpush_csi_unicode(tty,mods,9); return;
|
||||
case VK_RETURN: tty_cpush_csi_unicode(tty,mods,13); return;
|
||||
default: {
|
||||
uint32_t vtcode = 0;
|
||||
@@ -819,12 +823,12 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
// ignore other control keys (shift etc).
|
||||
}
|
||||
// high surrogate pair
|
||||
else if (chr >= 0xD800 && chr <= 0xDBFF) {
|
||||
surrogate_hi = (chr - 0xD800);
|
||||
surrogate_hi = (chr - 0xD800);
|
||||
}
|
||||
// low surrogate pair
|
||||
else if (chr >= 0xDC00 && chr <= 0xDFFF) {
|
||||
@@ -839,7 +843,7 @@ static void tty_waitc_console(tty_t* tty, long timeout_ms)
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ic_private bool tty_async_stop(const tty_t* tty) {
|
||||
// send ^c
|
||||
@@ -858,14 +862,14 @@ ic_private bool tty_async_stop(const tty_t* tty) {
|
||||
ic_private bool tty_start_raw(tty_t* tty) {
|
||||
if (tty->raw_enabled) return true;
|
||||
GetConsoleMode(tty->hcon,&tty->hcon_orig_mode);
|
||||
DWORD mode = ENABLE_QUICK_EDIT_MODE // cut&paste allowed
|
||||
| ENABLE_WINDOW_INPUT // to catch resize events
|
||||
// | ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
DWORD mode = ENABLE_QUICK_EDIT_MODE // cut&paste allowed
|
||||
| ENABLE_WINDOW_INPUT // to catch resize events
|
||||
// | ENABLE_VIRTUAL_TERMINAL_INPUT
|
||||
// | ENABLE_PROCESSED_INPUT
|
||||
;
|
||||
SetConsoleMode(tty->hcon, mode );
|
||||
tty->raw_enabled = true;
|
||||
return true;
|
||||
tty->raw_enabled = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
ic_private void tty_end_raw(tty_t* tty) {
|
||||
@@ -875,7 +879,7 @@ ic_private void tty_end_raw(tty_t* tty) {
|
||||
}
|
||||
|
||||
static bool tty_init_raw(tty_t* tty) {
|
||||
tty->hcon = GetStdHandle( STD_INPUT_HANDLE );
|
||||
tty->hcon = GetStdHandle( STD_INPUT_HANDLE );
|
||||
tty->has_term_resize_event = true;
|
||||
return true;
|
||||
}
|
||||
|
||||
Vendored
+6
-5
@@ -11,7 +11,7 @@
|
||||
#include "common.h"
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// TTY/Keyboard input
|
||||
// TTY/Keyboard input
|
||||
//-------------------------------------------------------------
|
||||
|
||||
// Key code
|
||||
@@ -47,13 +47,14 @@ ic_private bool tty_readc_noblock(tty_t* tty, uint8_t* c, long timeout_ms);
|
||||
ic_private code_t tty_read_esc(tty_t* tty, long esc_initial_timeout, long esc_timeout); // in tty_esc.c
|
||||
|
||||
// used by term.c to read back ANSI escape responses
|
||||
ic_private bool tty_read_esc_response(tty_t* tty, char esc_start, bool final_st, char* buf, ssize_t buflen );
|
||||
ic_private bool tty_read_esc_response(tty_t* tty, char esc_start, bool final_st, char* buf, ssize_t buflen );
|
||||
|
||||
ic_private bool tty_is_atty(int fd);
|
||||
|
||||
//-------------------------------------------------------------
|
||||
// Key codes: a code_t is 32 bits.
|
||||
// we use the bottom 24 (nah, 21) bits for unicode (up to x0010FFFF)
|
||||
// The codes after x01000000 are for virtual keys
|
||||
// The codes after x01000000 are for virtual keys
|
||||
// and events use x02000000.
|
||||
// The top 4 bits are used for modifiers.
|
||||
//-------------------------------------------------------------
|
||||
@@ -112,7 +113,7 @@ static inline code_t key_unicode( unicode_t u ) {
|
||||
#define KEY_UNICODE_MAX (0x0010FFFFU)
|
||||
|
||||
|
||||
#define KEY_VIRT (0x01000000U)
|
||||
#define KEY_VIRT (0x01000000U)
|
||||
#define KEY_UP (KEY_VIRT+0)
|
||||
#define KEY_DOWN (KEY_VIRT+1)
|
||||
#define KEY_LEFT (KEY_VIRT+2)
|
||||
@@ -152,7 +153,7 @@ static inline code_t key_unicode( unicode_t u ) {
|
||||
#define KEY_CTRL_END (WITH_CTRL(KEY_END))
|
||||
#define KEY_CTRL_DEL (WITH_CTRL(KEY_DEL))
|
||||
#define KEY_CTRL_PAGEUP (WITH_CTRL(KEY_PAGEUP))
|
||||
#define KEY_CTRL_PAGEDOWN (WITH_CTRL(KEY_PAGEDOWN)))
|
||||
#define KEY_CTRL_PAGEDOWN (WITH_CTRL(KEY_PAGEDOWN))
|
||||
#define KEY_CTRL_INS (WITH_CTRL(KEY_INS))
|
||||
|
||||
#define KEY_SHIFT_TAB (WITH_SHIFT(KEY_TAB))
|
||||
|
||||
+27
-4
@@ -10,15 +10,16 @@ MKDIRRANGE=../tools/mkdirrange
|
||||
MKFS_XFS="sudo mkfs.xfs"
|
||||
XFS_MIN_DISK_SIZE="302MiB"
|
||||
XFS_MKFS_OPTS="-q -i maxpct=0"
|
||||
XFS_MOUNT_OPTS="-t xfs"
|
||||
XFS_MOUNT_OPTS="-t xfs -o lazytime"
|
||||
|
||||
MKFS_EXT2="sudo mkfs.ext2"
|
||||
MKFS_EXT4="sudo mkfs.ext4"
|
||||
EXT_HASH_SEED="01234567-abcd-abcd-abcd-001122334455"
|
||||
EXT_MKFS_OPTS="-q"
|
||||
EXT_MOUNT_OPTS="-t ext4 -o lazytime"
|
||||
|
||||
MKFS_FAT="sudo mkfs.fat"
|
||||
FAT_MOUNT_OPTS="umask=111,dmask=000"
|
||||
FAT_MOUNT_OPTS="-t vfat -o lazytime,umask=111,dmask=000"
|
||||
|
||||
MKFS_EXFAT="sudo mkfs.exfat"
|
||||
|
||||
@@ -920,6 +921,17 @@ ext2_s05k.qcow2 () {
|
||||
#
|
||||
mkdir $TEMP_DIR/dir_f
|
||||
$MKDIRRANGE $TEMP_DIR/dir_f 0 64998 0 1
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/no_hole 0 65536
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_begin 0 65536
|
||||
fallocate -p -o 0 -l 16KiB $TEMP_DIR/hole_begin
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_middle 0 65536
|
||||
fallocate -p -o 32KiB -l 16KiB $TEMP_DIR/hole_middle
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_end 0 65536
|
||||
fallocate -p -o 48KiB -l 16KiB $TEMP_DIR/hole_end
|
||||
#
|
||||
sudo umount $TEMP_DIR
|
||||
sudo losetup -d $LOOP_DEV
|
||||
@@ -1112,6 +1124,17 @@ ext4_s05k.qcow2 () {
|
||||
#
|
||||
mkdir $TEMP_DIR/dir_g
|
||||
$MKDIRRANGE $TEMP_DIR/dir_g 0 1000000 0 1
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/no_hole 0 65536
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_begin 0 65536
|
||||
fallocate -p -o 0 -l 16KiB $TEMP_DIR/hole_begin
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_middle 0 65536
|
||||
fallocate -p -o 32KiB -l 16KiB $TEMP_DIR/hole_middle
|
||||
#
|
||||
$MKFILEPATTERN $TEMP_DIR/hole_end 0 65536
|
||||
fallocate -p -o 48KiB -l 16KiB $TEMP_DIR/hole_end
|
||||
#
|
||||
sudo umount $TEMP_DIR
|
||||
sudo losetup -d $LOOP_DEV
|
||||
@@ -1130,7 +1153,7 @@ fat12_s05k.qcow2 () {
|
||||
local p1="$LOOP_DEV"p1
|
||||
|
||||
$MKFS_FAT -F 12 $p1 > /dev/null
|
||||
sudo mount -o $FAT_MOUNT_OPTS $p1 $TEMP_DIR
|
||||
sudo mount $FAT_MOUNT_OPTS $p1 $TEMP_DIR
|
||||
#
|
||||
mkdir $TEMP_DIR/dir_a
|
||||
$MKDIRRANGE $TEMP_DIR/dir_a 0 3 0 1
|
||||
@@ -1164,7 +1187,7 @@ fat16_s05k.qcow2 () {
|
||||
local p1="$LOOP_DEV"p1
|
||||
|
||||
$MKFS_FAT -F 16 $p1 > /dev/null
|
||||
sudo mount -o $FAT_MOUNT_OPTS $p1 $TEMP_DIR
|
||||
sudo mount $FAT_MOUNT_OPTS $p1 $TEMP_DIR
|
||||
#
|
||||
mkdir $TEMP_DIR/dir_a
|
||||
$MKDIRRANGE $TEMP_DIR/dir_a 0 3 0 1
|
||||
|
||||
@@ -10,14 +10,14 @@ CC ?= gcc
|
||||
WARNINGS_COMMON=-Wall -Wextra \
|
||||
-Wnull-dereference -Wshadow -Wformat=2 -Wswitch -Wswitch-enum \
|
||||
-Wpedantic -Wstrict-prototypes -Wunused -Wformat-nonliteral \
|
||||
#-Wconversion -Wsign-conversion
|
||||
NOWARNINGS_COMMON=-Wno-address-of-packed-member
|
||||
#-Wconversion -Wsign-conversion -Wtrailing-whitespace=any
|
||||
NOWARNINGS_COMMON=-Wno-address-of-packed-member -Wno-missing-format-attribute
|
||||
|
||||
CFLAGS_ISOCLINE_COMMON=-D__MINGW_USE_VC2005_COMPAT
|
||||
CFLAGS_ISOCLINE_COMMON=-D__MINGW_USE_VC2005_COMPAT -Wno-shadow -Wno-unused-function -Wno-format-nonliteral
|
||||
ifeq (,$(findstring gcc,$(CC)))
|
||||
WARNINGS=$(WARNINGS_COMMON)
|
||||
NOWARNINGS=$(NOWARNINGS_COMMON) -Wno-missing-prototype-for-cc
|
||||
CFLAGS_ISOCLINE=$(CFLAGS_ISOCLINE_COMMON) -Wno-format-nonliteral
|
||||
NOWARNINGS=$(NOWARNINGS_COMMON)
|
||||
CFLAGS_ISOCLINE=$(CFLAGS_ISOCLINE_COMMON)
|
||||
else ifeq (,$(findstring clang,$(CC)))
|
||||
WARNINGS=$(WARNINGS_COMMON) -Wduplicated-cond -Wduplicated-branches \
|
||||
-Wrestrict -Wlogical-op -Wjump-misses-init
|
||||
@@ -114,8 +114,7 @@ deps/lodepng/lodepng.o: deps/lodepng/lodepng.c deps/lodepng/lodepng.h
|
||||
|
||||
deps/isocline/src/isocline.o: deps/isocline/src/isocline.c \
|
||||
deps/isocline/include/isocline.h
|
||||
$(CC) $(CFLAGS_32) $(CFLAGS_ISOCLINE) -c $< -o $@ -Wno-shadow \
|
||||
-Wno-unused-function
|
||||
$(CC) $(CFLAGS_32) $(CFLAGS_ISOCLINE) -c $< -o $@
|
||||
|
||||
deps/optparse/optparse.o: deps/optparse/optparse.c deps/optparse/optparse.h
|
||||
$(CC) $(CFLAGS_32) -c $< -o $@
|
||||
|
||||
+1
-1
@@ -320,7 +320,7 @@ run_test(const void *arg) {
|
||||
}
|
||||
pthread_join(t, &result);
|
||||
pthread_mutex_unlock(&mutex);
|
||||
|
||||
|
||||
return result;
|
||||
}
|
||||
#else
|
||||
|
||||
@@ -562,7 +562,7 @@ cmd_i40(struct shell_ctx *ctx, int argc, char **argv) {
|
||||
fputs(usage, ctx->fout);
|
||||
return;
|
||||
}
|
||||
pushad_t regs = {0, 0, 0, 0, 0, 0, 0, 0};
|
||||
pushad_t regs = {};
|
||||
if (argv[1]) regs.eax = strtoul(argv[1], NULL, 0);
|
||||
if (argv[2]) regs.ebx = strtoul(argv[2], NULL, 0);
|
||||
if (argv[3]) regs.ecx = strtoul(argv[3], NULL, 0);
|
||||
@@ -2530,7 +2530,7 @@ cmd_cd(struct shell_ctx *ctx, int argc, char **argv) {
|
||||
|
||||
static void
|
||||
ls_range(struct shell_ctx *sh, struct f7080s1arg *fX0, enum f70or80 f70or80) {
|
||||
size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
|
||||
size_t bdfe_len = (fX0->encoding <= CP866) ? BDFE_LEN_CP866 :
|
||||
BDFE_LEN_UNICODE;
|
||||
uint32_t requested = fX0->size;
|
||||
if (fX0->size > MAX_DIRENTS_TO_READ) {
|
||||
@@ -2567,7 +2567,7 @@ ls_range(struct shell_ctx *sh, struct f7080s1arg *fX0, enum f70or80 f70or80) {
|
||||
|
||||
static void
|
||||
ls_all(struct shell_ctx *ctx, struct f7080s1arg *fX0, enum f70or80 f70or80) {
|
||||
size_t bdfe_len = (fX0->encoding == CP866) ? BDFE_LEN_CP866 :
|
||||
size_t bdfe_len = (fX0->encoding <= CP866) ? BDFE_LEN_CP866 :
|
||||
BDFE_LEN_UNICODE;
|
||||
while (true) {
|
||||
struct f7080ret r = monitor_cmd_sys_lfn(ctx->monitor, f70or80,
|
||||
@@ -2775,23 +2775,6 @@ cmd_mkdir80(struct shell_ctx *ctx, int argc, char **argv) {
|
||||
cmd_mkdir(ctx, argc, argv, F80);
|
||||
}
|
||||
|
||||
const char *tz;
|
||||
|
||||
static void
|
||||
tz_to_utc() {
|
||||
tz = getenv("TZ");
|
||||
setenv("TZ", "UTC", 1);
|
||||
}
|
||||
|
||||
static void
|
||||
tz_from_utc() {
|
||||
if (tz) {
|
||||
setenv("TZ", tz, 1);
|
||||
} else {
|
||||
unsetenv("TZ");
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
cmd_stat(struct shell_ctx *ctx, int argc, char **argv, enum f70or80 f70or80) {
|
||||
const char *usage = \
|
||||
@@ -2848,30 +2831,28 @@ cmd_stat(struct shell_ctx *ctx, int argc, char **argv, enum f70or80 f70or80) {
|
||||
|
||||
time_t time;
|
||||
struct tm *t;
|
||||
tz_to_utc();
|
||||
if (!ctx->reproducible || force_atime) {
|
||||
time = kos_bdfe_time_to_epoch(&file.a_datetime);
|
||||
t = localtime(&time);
|
||||
t = gmtime(&time);
|
||||
fprintf(ctx->fout, "atime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
||||
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec);
|
||||
}
|
||||
if (!ctx->reproducible || force_mtime) {
|
||||
time = kos_bdfe_time_to_epoch(&file.m_datetime);
|
||||
t = localtime(&time);
|
||||
t = gmtime(&time);
|
||||
fprintf(ctx->fout, "mtime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
||||
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec);
|
||||
}
|
||||
if (!ctx->reproducible || force_ctime) {
|
||||
time = kos_bdfe_time_to_epoch(&file.c_datetime);
|
||||
t = localtime(&time);
|
||||
t = gmtime(&time);
|
||||
fprintf(ctx->fout, "ctime: %4.4i.%2.2i.%2.2i %2.2i:%2.2i:%2.2i\n",
|
||||
t->tm_year + 1900, t->tm_mon + 1, t->tm_mday,
|
||||
t->tm_hour, t->tm_min, t->tm_sec);
|
||||
}
|
||||
tz_from_utc();
|
||||
|
||||
|
||||
return;
|
||||
}
|
||||
|
||||
@@ -3249,24 +3230,20 @@ cmd_touch(struct shell_ctx *ctx, int argc, char **argv, enum f70or80 f70or80,
|
||||
return;
|
||||
}
|
||||
|
||||
struct tm t = {0};
|
||||
struct tm t = {};
|
||||
while ((opt = optparse(&ctx->opts, "a:c:hHm:nNrRsS")) != -1) {
|
||||
switch (opt) {
|
||||
case 'a':
|
||||
if (!parse_datetime(ctx, ctx->opts.optarg, &t)) {
|
||||
return;
|
||||
}
|
||||
tz_to_utc();
|
||||
kos_epoch_to_bdfe_time(mktime(&t), &info.a_datetime);
|
||||
tz_from_utc();
|
||||
kos_epoch_to_bdfe_time(timegm(&t), &info.a_datetime);
|
||||
break;
|
||||
case 'c':
|
||||
if (!parse_datetime(ctx, ctx->opts.optarg, &t)) {
|
||||
return;
|
||||
}
|
||||
tz_to_utc();
|
||||
kos_epoch_to_bdfe_time(mktime(&t), &info.c_datetime);
|
||||
tz_from_utc();
|
||||
kos_epoch_to_bdfe_time(timegm(&t), &info.c_datetime);
|
||||
break;
|
||||
case 'h':
|
||||
fX0.info->attr &= ~BDFE_ATTR_HIDDEN;
|
||||
@@ -3278,9 +3255,7 @@ cmd_touch(struct shell_ctx *ctx, int argc, char **argv, enum f70or80 f70or80,
|
||||
if (!parse_datetime(ctx, ctx->opts.optarg, &t)) {
|
||||
return;
|
||||
}
|
||||
tz_to_utc();
|
||||
kos_epoch_to_bdfe_time(mktime(&t), &info.m_datetime);
|
||||
tz_from_utc();
|
||||
kos_epoch_to_bdfe_time(timegm(&t), &info.m_datetime);
|
||||
break;
|
||||
case 'n':
|
||||
fX0.info->attr &= ~BDFE_ATTR_NOT_ARCHIVED;
|
||||
@@ -4761,7 +4736,7 @@ run_test(struct shell_ctx *ctx) {
|
||||
dup2(fileno(ctx->fin), STDIN_FILENO);
|
||||
fclose(ctx->fin);
|
||||
}
|
||||
ic_init_custom_malloc(NULL, NULL, NULL);
|
||||
ic_init_custom_alloc(NULL, NULL, NULL);
|
||||
// ic_style_def("ic-prompt","ansi-default");
|
||||
ic_enable_color(0);
|
||||
ic_set_prompt_marker(NULL, NULL);
|
||||
|
||||
@@ -211,3 +211,5 @@ status = 6 end_of_file, count = 0
|
||||
/> read70 /hd0/1/btree_l1_no_hole 0x80000 11 -b
|
||||
status = 0 success, count = 11
|
||||
0000080004000800080008
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -73,3 +73,5 @@ read70 /hd0/1/no_hole 0xffffffffffffffff 11 -b
|
||||
|
||||
# btree
|
||||
read70 /hd0/1/btree_l1_no_hole 0x80000 11 -b
|
||||
|
||||
disk_del hd0
|
||||
|
||||
@@ -10,3 +10,4 @@ hd0> pwd
|
||||
hd0> cd 1
|
||||
1> pwd
|
||||
/hd0/1
|
||||
1> disk_del hd0
|
||||
|
||||
@@ -5,3 +5,4 @@ cd /hd0
|
||||
pwd
|
||||
cd 1
|
||||
pwd
|
||||
disk_del hd0
|
||||
|
||||
@@ -274,3 +274,5 @@ status = 6 end_of_file, count = 0
|
||||
/> read70 /hd0/1/hole_end 0x10001 11 -b
|
||||
status = 6 end_of_file, count = 0
|
||||
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -100,3 +100,5 @@ read70 /hd0/1/hole_end 0xfffe 11 -b
|
||||
read70 /hd0/1/hole_end 0xffff 11 -b
|
||||
read70 /hd0/1/hole_end 0x10000 11 -b
|
||||
read70 /hd0/1/hole_end 0x10001 11 -b
|
||||
|
||||
disk_del hd0
|
||||
|
||||
+17
-17
@@ -110,12 +110,12 @@ total = 7
|
||||
status = 6 end_of_file, count = 7
|
||||
total = 7
|
||||
----f .
|
||||
-----
|
||||
-----
|
||||
-----
|
||||
-----
|
||||
-----
|
||||
-----
|
||||
----f ..
|
||||
----f dir0
|
||||
----f дир_
|
||||
----f ___
|
||||
----f ___
|
||||
----f дир3
|
||||
/> ls70 /hd0/1/тЭжтЭжтЭж/ -e utf8
|
||||
status = 5 file_not_found
|
||||
/> ls70 /hd0/1/тЭжтЭжтЭж/ -e utf16
|
||||
@@ -167,12 +167,12 @@ total = 7
|
||||
status = 6 end_of_file, count = 7
|
||||
total = 7
|
||||
----f .
|
||||
r-s-f
|
||||
--s-f
|
||||
-hs-f
|
||||
rhs-f
|
||||
--slf
|
||||
---lf
|
||||
----f ..
|
||||
----f dir0
|
||||
----f дир_
|
||||
----f ___
|
||||
----f ___
|
||||
----f дир3
|
||||
/> ls80 /hd0/1/тЭжтЭжтЭж/ -e utf8
|
||||
status = 6 end_of_file, count = 3
|
||||
total = 3
|
||||
@@ -196,7 +196,7 @@ status = 6 end_of_file, count = 3
|
||||
total = 3
|
||||
----f .
|
||||
----f ..
|
||||
----f 4f'@2
|
||||
----f д_р22
|
||||
/> ls80 /hd0/1/╨┤╨╕╤А3/ -e utf8
|
||||
status = 6 end_of_file, count = 3
|
||||
total = 3
|
||||
@@ -220,7 +220,7 @@ status = 6 end_of_file, count = 3
|
||||
total = 3
|
||||
----f .
|
||||
----f ..
|
||||
----- D09;3
|
||||
----- файл33
|
||||
/>
|
||||
/> ls80 /hd0/1/тЭжЁЯСйтЭж/ -e utf8
|
||||
status = 6 end_of_file, count = 5
|
||||
@@ -251,8 +251,8 @@ status = 6 end_of_file, count = 5
|
||||
total = 5
|
||||
----f .
|
||||
----f ..
|
||||
----f i╪=▄f'f'
|
||||
----f f'i╪=▄f'
|
||||
----f f'f'i╪=▄
|
||||
----f ___
|
||||
----f ___
|
||||
----f ___
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -274,3 +274,5 @@ status = 6 end_of_file, count = 0
|
||||
/> read70 /hd0/1/hole_end 0x10001 11 -b
|
||||
status = 6 end_of_file, count = 0
|
||||
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -100,3 +100,5 @@ read70 /hd0/1/hole_end 0xfffe 11 -b
|
||||
read70 /hd0/1/hole_end 0xffff 11 -b
|
||||
read70 /hd0/1/hole_end 0x10000 11 -b
|
||||
read70 /hd0/1/hole_end 0x10001 11 -b
|
||||
|
||||
disk_del hd0
|
||||
|
||||
@@ -211,3 +211,5 @@ status = 6 end_of_file, count = 0
|
||||
/> read70 /hd0/1/btree_l1_no_hole 0x80000 11 -b
|
||||
status = 0 success, count = 11
|
||||
0000080004000800080008
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -73,3 +73,5 @@ read70 /hd0/1/no_hole 0xffffffffffffffff 11 -b
|
||||
|
||||
# btree
|
||||
read70 /hd0/1/btree_l1_no_hole 0x80000 11 -b
|
||||
|
||||
disk_del hd0
|
||||
|
||||
@@ -251,3 +251,5 @@ status = 0 success, count = 24576
|
||||
/> read70 /hd0/1/4GiB_plus 0x11ffff001 0x6000 -h
|
||||
status = 0 success, count = 24576
|
||||
22a8dca8c78a49cdde0cd804f032e8fdf19a8609b8ad79ac128468a798601315
|
||||
/>
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -95,3 +95,5 @@ read70 /hd0/1/4GiB_plus 0x120004001 0x6000 -h
|
||||
read70 /hd0/1/4GiB_plus 0x11fffefff 0x6000 -h
|
||||
read70 /hd0/1/4GiB_plus 0x11ffff000 0x6000 -h
|
||||
read70 /hd0/1/4GiB_plus 0x11ffff001 0x6000 -h
|
||||
|
||||
disk_del hd0
|
||||
|
||||
@@ -10,3 +10,5 @@ dump_appdata 2
|
||||
load_dll /sys/lib/network.obj
|
||||
dump_dlls
|
||||
dump_appdata 2
|
||||
|
||||
disk_del rd
|
||||
|
||||
+6
-2
@@ -94,8 +94,8 @@ total = 5
|
||||
----f d0000000001_
|
||||
----f d0000000002_
|
||||
/> ls70 /hd0/1
|
||||
status = 6 end_of_file, count = 9
|
||||
total = 9
|
||||
status = 6 end_of_file, count = 13
|
||||
total = 13
|
||||
-h--f .
|
||||
-h--f ..
|
||||
----f lost+found
|
||||
@@ -105,4 +105,8 @@ total = 9
|
||||
----f dir_d
|
||||
----f dir_e
|
||||
----f dir_f
|
||||
----- no_hole
|
||||
----- hole_begin
|
||||
----- hole_middle
|
||||
----- hole_end
|
||||
/> disk_del hd0
|
||||
|
||||
@@ -1200,7 +1200,7 @@ extern void *acpi_ctx;
|
||||
extern uint32_t kos_acpi_usage;
|
||||
extern uint32_t kos_acpi_node_alloc_cnt;
|
||||
extern uint32_t kos_acpi_node_free_cnt;
|
||||
extern uint32_t kos_acpi_count_nodes(void *ctx) [[gnu::stdcall]];
|
||||
[[gnu::stdcall]] extern uint32_t kos_acpi_count_nodes(void *ctx);
|
||||
extern struct srv srv_list;
|
||||
extern struct dlldescr dll_list;
|
||||
extern struct smem shmem_list;
|
||||
|
||||
@@ -179,7 +179,7 @@ main (int argc, char *argv[]) {
|
||||
perror("Can't open file");
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
size_t len = fread(acpi_path, 1, PATH_MAX, f);
|
||||
acpi_path[len-1] = '\0';
|
||||
fclose(f);
|
||||
|
||||
@@ -12,6 +12,7 @@
|
||||
#include <fcntl.h>
|
||||
#include <inttypes.h>
|
||||
#include <limits.h>
|
||||
#include <locale.h>
|
||||
#include <stdio.h>
|
||||
#include <stdlib.h>
|
||||
#include <string.h>
|
||||
@@ -72,6 +73,7 @@ main(int argc, char **argv) {
|
||||
const char *infile = NULL, *outfile = NULL;
|
||||
FILE *fin = stdin;
|
||||
FILE *fout = stdout;
|
||||
setlocale(LC_ALL, "");
|
||||
build_history_filename();
|
||||
/*
|
||||
kos_boot.memmap_block_cnt = 3;
|
||||
|
||||
@@ -139,7 +139,7 @@ io_async_read(int fd, void *buf, size_t count, void *arg) {
|
||||
cmd->read.arg.buf = buf;
|
||||
cmd->read.arg.count = count;
|
||||
atomic_store_explicit(&cmd->status, IOT_CMD_STATUS_READY, memory_order_release);
|
||||
|
||||
|
||||
pthread_cond_signal(&cmd->iot_cond);
|
||||
kos_wait_events(io_async_complete_wait_test, NULL);
|
||||
|
||||
|
||||
Reference in New Issue
Block a user