diff --git a/Readme.md b/Readme.md index 21ddbbb..0c704e1 100755 --- a/Readme.md +++ b/Readme.md @@ -8,7 +8,7 @@ Small utility libraries and copy-paste snippets of reusable code. |-------------|-------------------------------------------------|----------|-----------------|---------|-----------------------------------------| | apg | Generic C programming utils. | C | 1 | 1.13 | No | | apg_bmp | BMP bitmap image reader/writer library. | C | 2 | 3.4 | [AFL](https://lcamtuf.coredump.cx/afl/) | -| apg_console | Quake-style graphical console. API-independent. | C | 2 + apg_pixfont | 0.13 | No | +| apg_console | Quake-style graphical console. API-independent. | C | 2 + apg_pixfont + apg_unicode | 0.14 | No | | apg_jobs | Simple worker/jobs thread pool system. | C | 2 | 0.2 | No | | apg_gldb | OpenGL debug drawing (lines, boxes, ... ) | C | 2 | 0.3 | No | | apg_interp | Interpolation / "tweening" / "easing". | C, JS | 1, 1 | 0.7 | No | diff --git a/apg_console/apg_console.c b/apg_console/apg_console.c index fa66520..613dfbc 100644 --- a/apg_console/apg_console.c +++ b/apg_console/apg_console.c @@ -1,12 +1,13 @@ /* ======================================================================================================================= APG_C - A Quake-style Console mini-library Author: Anton Gerdelan - @capnramses -Version: 0.13.1 +Version: 0.14.0 Language: C99 Licence: See bottom of header file. ======================================================================================================================= */ #include "apg_console.h" -#include "apg_pixfont.h" // used for adding glyphs to image output +#include "apg_pixfont.h" // Used for adding glyphs to image output. +#include "apg_unicode.h" #include #include #include @@ -64,8 +65,8 @@ static void apg_c_strncat( char* dst, const char* src, const int dest_max_len, c int dst_len = apg_c_strnlen( dst, dest_max_len ); dst[dst_len] = '\0'; // just in case it wasn't already terminated before max length int remaining_space = dest_max_len - dst_len; - const int n = remaining_space < src_max_copy ? remaining_space : src_max_copy; // use src_max if smaller - strncat( dst, src, n - 1 ); // strncat manual guarantees null termination. + const int n = remaining_space < src_max_copy ? remaining_space : src_max_copy; // use src_max if smaller + strncat( dst, src, n - 1 ); // strncat manual guarantees null termination. } static void _apg_c_command_hist_append( const char* c_user_entered_text ) { @@ -186,7 +187,7 @@ static bool _parse_user_entered_instruction( const char* str ) { default: { apg_c_printf( "%s OTHER", one ); } break; // some other data type - } // endswitch + } // endswitch return true; } @@ -224,7 +225,7 @@ static bool _parse_user_entered_instruction( const char* str ) { *(float*)var_ptr = fval; } break; default: break; // do nothing for complex data types - } // endswitch + } // endswitch return true; } else { apg_c_printf_rgba( 0xFF, 0x00, 0x00, 0xFF, "ERROR: `%s` is not a recognised variable name.", one ); @@ -291,18 +292,31 @@ void apg_c_reuse_hist_ahead_one( void ) { apg_c_reuse_hist( _hist_curr_rewind_idx ); } -// WARNING(Anton) not unicode-aware! void apg_c_backspace( void ) { int uet_len = apg_c_strnlen( _c_user_entered_text, APG_C_STR_MAX ); if ( uet_len < 1 ) { return; } - _c_user_entered_text[uet_len - 1] = '\0'; - _c_redraw_required = true; + + // Find if last chars are part of a multi-byte sequence. + int last_cp_n = 0; + for ( int i = 0; i < uet_len; i += last_cp_n ) { + last_cp_n = 0; + uint32_t cp = apg_utf8_to_cp( &_c_user_entered_text[i], &last_cp_n ); + (void)cp; + assert( last_cp_n > 0 ); + if ( 0 == last_cp_n ) { + last_cp_n = 1; // So the next instruction, truncating the string, won't overflow. + break; + } + } + + _c_user_entered_text[uet_len - last_cp_n] = '\0'; + _c_redraw_required = true; } void apg_c_clear_user_entered_text( void ) { _c_user_entered_text[0] = '\0'; _c_redraw_required = true; - _hist_curr_rewind_idx = -1; // reset history rewind + _hist_curr_rewind_idx = -1; // Reset history rewind. } // WARNING(Anton) - assumes string is ASCII diff --git a/apg_console/apg_console.h b/apg_console/apg_console.h index adda7a1..065bbc9 100644 --- a/apg_console/apg_console.h +++ b/apg_console/apg_console.h @@ -8,6 +8,7 @@ Contact: Website: https://github.com/capnramses/apg - http://antongerdelan.net/ Licence: See bottom of this file. Version History: + v0.14 - 2024/06/15 - Unicode-aware backspace. v0.13.1 - 2023/04/19 - Small function prototype fixes. v0.13 - 2022/09/23 - Updated API to match new apg_pixfont. v0.12 - 2021/10/03 - Fix to missing nul-terminator in long string copies. diff --git a/apg_console/build.sh b/apg_console/build.sh index 3b457d4..c3a10b1 100755 --- a/apg_console/build.sh +++ b/apg_console/build.sh @@ -6,5 +6,7 @@ SAN="-fsanitize=address -fsanitize=undefined" cp ../apg_pixfont/apg_pixfont.c ./ cp ../apg_pixfont/apg_pixfont.h ./ +cp ../apg_unicode/apg_unicode.c ./ +cp ../apg_unicode/apg_unicode.h ./ -$CC $FLAGS $SAN tests/main.c apg_console.c apg_pixfont.c -I ./ +$CC $FLAGS $SAN tests/main.c apg_console.c apg_pixfont.c apg_unicode.c -I ./ diff --git a/build_linux.sh b/build_linux.sh index 641bfce..ef89f4e 100755 --- a/build_linux.sh +++ b/build_linux.sh @@ -41,7 +41,9 @@ echo "building apg_console tests..." cd apg_console cp ../apg_pixfont/apg_pixfont.c ./ cp ../apg_pixfont/apg_pixfont.h ./ -$CC $FLAGS tests/main.c apg_console.c apg_pixfont.c -I ./ +cp ../apg_unicode/apg_unicode.c ./ +cp ../apg_unicode/apg_unicode.h ./ +$CC $FLAGS tests/main.c apg_console.c apg_pixfont.c apg_unicode.c -I ./ cd .. # NOTE -- no tests for apg_gldb at the moment (opengl is a pain to set up on build servers)