Update isocline, fix t011, use timegm

This commit is contained in:
2026-05-17 22:34:49 +01:00
parent 88193193fc
commit 4230ff4a92
38 changed files with 479 additions and 361 deletions
+58 -50
View File
@@ -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 );
+3 -3
View File
@@ -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));
+11 -3
View File
@@ -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;
+11 -5
View File
@@ -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;
+8
View File
@@ -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);
+5 -5
View File
@@ -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
View File
@@ -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
}
}
+1 -1
View File
@@ -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"
+15 -12
View File
@@ -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);
}
+48 -28
View File
@@ -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);
}
+23 -6
View File
@@ -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.
+2
View File
@@ -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
+88 -87
View File
@@ -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();
+70 -66
View File
@@ -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;
}
+6 -5
View File
@@ -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
View File
@@ -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
+6 -7
View File
@@ -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
View File
@@ -320,7 +320,7 @@ run_test(const void *arg) {
}
pthread_join(t, &result);
pthread_mutex_unlock(&mutex);
return result;
}
#else
+12 -37
View File
@@ -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);
+2
View File
@@ -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
+2
View File
@@ -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
+1
View File
@@ -10,3 +10,4 @@ hd0> pwd
hd0> cd 1
1> pwd
/hd0/1
1> disk_del hd0
+1
View File
@@ -5,3 +5,4 @@ cd /hd0
pwd
cd 1
pwd
disk_del hd0
+2
View File
@@ -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
+2
View File
@@ -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
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -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
+2
View File
@@ -10,3 +10,5 @@ dump_appdata 2
load_dll /sys/lib/network.obj
dump_dlls
dump_appdata 2
disk_del rd
+6 -2
View File
@@ -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
+1 -1
View File
@@ -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;
+1 -1
View File
@@ -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);
+2
View File
@@ -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;
+1 -1
View File
@@ -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);