From 7e5a816749efb89322ec8cd77457739ee770f5e5 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Juhani=20Krekel=C3=A4?= Date: Fri, 5 Nov 2021 00:09:48 +0200 Subject: [PATCH] Refactor movement code in editor(1). MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Firstly, lots of places in editor(1) would do a move from (x₀,y₀) to (x,y) by first moving to (x,y₀) or (x₀,y) and only then (x,y). If the intermediate positions were not valid cursor positions, this might cause out of bounds access. Categorically fixed this by removing functions for moving only horizontally or only vertically. Secondly, editor_select_set() would set the column before setting the line. Since the code for setting the column accesses the currently set line at the new cursor position, it might cause out of bounds access even on valid cursor positions. Fixed this by swapping the order in which column and row are set. Thirdly, the order of arguments passed to row_column_smallest() and row_column_biggest() was wrong, with column being passed before the row, even though they were defined the other way. However, this did not result in out of bounds memory accesses due to the parameters to editor_cursor_set() also being swapped at relevant callsites. Finally, the boundary condition for control-down was off by one. --- editor/command.c | 179 ++++++++++++++++++++++++++--------------------- editor/cursor.c | 101 +++++--------------------- editor/cursor.h | 13 ---- editor/modal.c | 8 +-- 4 files changed, 120 insertions(+), 181 deletions(-) diff --git a/editor/command.c b/editor/command.c index 4f2a2a12..f85e9018 100644 --- a/editor/command.c +++ b/editor/command.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2014, 2016 Jonas 'Sortie' Termansen. + * Copyright (c) 2021 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -134,8 +135,9 @@ void editor_type_backspace(struct editor* editor) editor->dirty = true; current_line->used--; - for ( size_t i = editor_cursor_column_dec(editor); i < current_line->used; i++ ) + for ( size_t i = editor->cursor_column - 1; i < current_line->used; i++ ) current_line->data[i] = current_line->data[i+1]; + editor_cursor_set(editor, editor->cursor_row, editor->cursor_column - 1); } void editor_type_combine_with_next(struct editor* editor) @@ -157,7 +159,7 @@ void editor_type_combine_with_next(struct editor* editor) memcpy(new_data, keep_line_data, sizeof(wchar_t) * keep_line->used); memcpy(new_data + keep_line->used, gone_line_data, sizeof(wchar_t) * gone_line->used); - editor_cursor_column_set(editor, keep_line->used); + editor_cursor_set(editor, editor->cursor_row, keep_line->used); keep_line->data = new_data; keep_line->used = new_length; @@ -227,8 +229,8 @@ void editor_type_exit_select_left(struct editor* editor) size_t column, row; row_column_smallest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); return; } } @@ -240,8 +242,8 @@ void editor_type_exit_select_right(struct editor* editor) size_t column, row; row_column_biggest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); return; } } @@ -250,23 +252,21 @@ void editor_type_left(struct editor* editor) { editor_type_exit_select_left(editor); if ( editor->cursor_column ) - editor_cursor_column_dec(editor); + editor_cursor_set(editor, editor->cursor_row, + editor->cursor_column - 1); else if ( editor->cursor_row ) - { - editor_cursor_row_dec(editor); - editor_cursor_column_set(editor, editor->lines[editor->cursor_row].used); - } + editor_cursor_set(editor, editor->cursor_row - 1, + editor->lines[editor->cursor_row - 1].used); } void editor_type_select_left(struct editor* editor) { if ( editor->select_column ) - editor_select_column_dec(editor); + editor_select_set(editor, editor->select_row, + editor->select_column - 1); else if ( editor->select_row ) - { - editor_select_row_dec(editor); - editor_select_column_set(editor, editor->lines[editor->select_row].used); - } + editor_select_set(editor, editor->select_row - 1, + editor->lines[editor->select_row - 1].used); } void editor_type_control_left(struct editor* editor) @@ -313,20 +313,20 @@ void editor_type_right(struct editor* editor) editor_type_exit_select_right(editor); struct line* current_line = &editor->lines[editor->cursor_row]; if ( editor->cursor_column != current_line->used ) - editor_cursor_column_inc(editor); - else if ( editor->cursor_row+1 != editor->lines_used ) - editor_cursor_row_inc(editor), - editor_cursor_column_set(editor, 0); + editor_cursor_set(editor, editor->cursor_row, + editor->cursor_column + 1); + else if ( editor->cursor_row + 1 != editor->lines_used ) + editor_cursor_set(editor, editor->cursor_row + 1, 0); } void editor_type_select_right(struct editor* editor) { struct line* current_line = &editor->lines[editor->select_row]; if ( editor->select_column != current_line->used ) - editor_select_column_inc(editor); - else if ( editor->select_row+1 != editor->lines_used ) - editor_select_row_inc(editor), - editor_select_column_set(editor, 0); + editor_select_set(editor, editor->select_row, + editor->select_column + 1); + else if ( editor->select_row + 1 != editor->lines_used ) + editor_select_set(editor, editor->select_row + 1, 0); } void editor_type_control_right(struct editor* editor) @@ -371,95 +371,106 @@ void editor_type_up(struct editor* editor) editor_type_exit_select_left(editor); if ( !editor->cursor_row ) { - editor_cursor_column_set(editor, 0); + editor_cursor_set(editor, 0, 0); return; } struct line* old_line = &editor->lines[editor->cursor_row]; - struct line* new_line = &editor->lines[editor_cursor_row_dec(editor)]; + struct line* new_line = &editor->lines[editor->cursor_row - 1]; size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->cursor_column); size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); - editor_cursor_column_set(editor, new_offset); + editor_cursor_set(editor, editor->cursor_row - 1, new_offset); } void editor_type_select_up(struct editor* editor) { if ( !editor->select_row ) { - editor_select_column_set(editor, 0); + editor_select_set(editor, 0, 0); return; } struct line* old_line = &editor->lines[editor->select_row]; - struct line* new_line = &editor->lines[editor_select_row_dec(editor)]; + struct line* new_line = &editor->lines[editor->select_row - 1]; size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->select_column); size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); - editor_select_column_set(editor, new_offset); + editor_select_set(editor, editor->select_row - 1, new_offset); } void editor_type_control_up(struct editor* editor) { editor_type_exit_select_left(editor); if ( editor->cursor_row ) - editor_cursor_row_dec(editor); - editor_cursor_column_set(editor, 0); + editor_cursor_set(editor, editor->cursor_row - 1, 0); + else + editor_cursor_set(editor, editor->cursor_row, 0); } void editor_type_control_select_up(struct editor* editor) { if ( editor->select_row ) - editor_select_row_dec(editor); - editor_select_column_set(editor, 0); + editor_select_set(editor, editor->select_row - 1, 0); + else + editor_select_set(editor, editor->select_row, 0); } void editor_type_down(struct editor* editor) { editor_type_exit_select_right(editor); - if ( editor->cursor_row+1 == editor->lines_used ) + if ( editor->cursor_row + 1 == editor->lines_used ) { - editor_cursor_column_set(editor, editor->lines[editor->cursor_row].used); + editor_cursor_set(editor, editor->cursor_row, + editor->lines[editor->cursor_row].used); return; } struct line* old_line = &editor->lines[editor->cursor_row]; - struct line* new_line = &editor->lines[editor_cursor_row_inc(editor)]; + struct line* new_line = &editor->lines[editor->cursor_row + 1]; size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->cursor_column); size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); - editor_cursor_column_set(editor, new_offset); + editor_cursor_set(editor, editor->cursor_row + 1, new_offset); } void editor_type_select_down(struct editor* editor) { if ( editor->select_row+1 == editor->lines_used ) { - editor_select_column_set(editor, editor->lines[editor->select_row].used); + editor_select_set(editor, editor->select_row, + editor->lines[editor->select_row].used); return; } struct line* old_line = &editor->lines[editor->select_row]; - struct line* new_line = &editor->lines[editor_select_row_inc(editor)]; + struct line* new_line = &editor->lines[editor->select_row + 1]; size_t old_column = editor_display_column_of_line_offset(editor, old_line, editor->select_column); size_t new_offset = editor_line_offset_of_display_column(editor, new_line, old_column); - editor_select_column_set(editor, new_offset); + editor_select_set(editor, editor->select_row + 1, new_offset); } void editor_type_control_down(struct editor* editor) { editor_type_exit_select_right(editor); - if ( editor->cursor_row < editor->lines_used ) - editor_cursor_row_inc(editor); - editor_cursor_column_set(editor, editor->lines[editor->cursor_row].used); + if ( editor->cursor_row + 1 < editor->lines_used ) + editor_cursor_set(editor, editor->cursor_row + 1, + editor->lines[editor->cursor_row + 1].used); + else + editor_cursor_set(editor, editor->cursor_row, + editor->lines[editor->cursor_row].used); } void editor_type_control_select_down(struct editor* editor) { - if ( editor->select_row < editor->lines_used ) - editor_select_row_inc(editor); - editor_select_column_set(editor, editor->lines[editor->select_row].used); + if ( editor->select_row + 1 < editor->lines_used ) + editor_select_set(editor, editor->select_row + 1, + editor->lines[editor->select_row + 1].used); + else + editor_select_set(editor, editor->select_row, + editor->lines[editor->select_row].used); } void editor_skip_leading(struct editor* editor) { struct line* current_line = &editor->lines[editor->cursor_row]; - for ( editor_cursor_column_set(editor, 0); + for ( editor_cursor_set(editor, editor->cursor_row, 0); editor->cursor_column < current_line->used; - editor_cursor_column_inc(editor) ) + editor_cursor_set(editor, editor->cursor_row, + editor->cursor_column + 1) ) if ( !iswspace(current_line->data[editor->cursor_column]) ) break; } @@ -467,9 +478,10 @@ void editor_skip_leading(struct editor* editor) void editor_select_skip_leading(struct editor* editor) { struct line* current_line = &editor->lines[editor->select_row]; - for ( editor_select_column_set(editor, 0); + for ( editor_select_set(editor, editor->select_row, 0); editor->select_column < current_line->used; - editor_select_column_inc(editor) ) + editor_select_set(editor, editor->select_row, + editor->select_column + 1) ) if ( !iswspace(current_line->data[editor->select_column]) ) break; } @@ -481,15 +493,15 @@ void editor_type_home(struct editor* editor) size_t column, row; row_column_smallest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); } if ( !editor->cursor_column ) { editor_skip_leading(editor); return; } - editor_cursor_column_set(editor, 0); + editor_cursor_set(editor, editor->cursor_row, 0); } void editor_type_select_home(struct editor* editor) @@ -499,15 +511,16 @@ void editor_type_select_home(struct editor* editor) editor_select_skip_leading(editor); return; } - editor_select_column_set(editor, 0); + editor_select_set(editor, editor->select_row, 0); } void editor_skip_ending(struct editor* editor) { struct line* current_line = &editor->lines[editor->cursor_row]; - for ( editor_cursor_column_set(editor, current_line->used); + for ( editor_cursor_set(editor, editor->cursor_row, current_line->used); editor->cursor_column; - editor_cursor_column_dec(editor) ) + editor_cursor_set(editor, editor->cursor_row, + editor->cursor_column - 1) ) if ( !iswspace(current_line->data[editor->cursor_column-1]) ) break; } @@ -515,9 +528,10 @@ void editor_skip_ending(struct editor* editor) void editor_select_skip_ending(struct editor* editor) { struct line* current_line = &editor->lines[editor->select_row]; - for ( editor_select_column_set(editor, current_line->used); + for ( editor_select_set(editor, editor->select_row, current_line->used); editor->select_column; - editor_select_column_dec(editor) ) + editor_select_set(editor, editor->select_row, + editor->select_column - 1) ) if ( !iswspace(current_line->data[editor->select_column-1]) ) break; } @@ -529,8 +543,8 @@ void editor_type_end(struct editor* editor) size_t column, row; row_column_biggest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); } struct line* current_line = &editor->lines[editor->cursor_row]; if ( editor->cursor_column == current_line->used ) @@ -538,7 +552,7 @@ void editor_type_end(struct editor* editor) editor_skip_ending(editor); return; } - editor_cursor_column_set(editor, current_line->used); + editor_cursor_set(editor, editor->cursor_row, current_line->used); } void editor_type_select_end(struct editor* editor) @@ -549,7 +563,7 @@ void editor_type_select_end(struct editor* editor) editor_select_skip_ending(editor); return; } - editor_select_column_set(editor, current_line->used); + editor_select_set(editor, editor->select_row, current_line->used); } void editor_type_page_up(struct editor* editor) @@ -559,8 +573,8 @@ void editor_type_page_up(struct editor* editor) size_t column, row; row_column_smallest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); } if ( editor->cursor_row < editor->viewport_height ) { @@ -568,10 +582,11 @@ void editor_type_page_up(struct editor* editor) return; } size_t new_line = editor->cursor_row - editor->viewport_height; - editor_cursor_row_set(editor, new_line); size_t new_line_len = editor->lines[new_line].used; if ( new_line_len < editor->cursor_column ) - editor_cursor_column_set(editor, new_line_len); + editor_cursor_set(editor, new_line, new_line_len); + else + editor_cursor_set(editor, new_line, editor->cursor_column); } void editor_type_select_page_up(struct editor* editor) @@ -582,10 +597,11 @@ void editor_type_select_page_up(struct editor* editor) return; } size_t new_line = editor->select_row - editor->viewport_height; - editor_select_row_set(editor, new_line); size_t new_line_len = editor->lines[new_line].used; if ( new_line_len < editor->select_column ) - editor_select_column_set(editor, new_line_len); + editor_select_set(editor, new_line, new_line_len); + else + editor_select_set(editor, new_line, editor->select_column); } void editor_type_page_down(struct editor* editor) @@ -595,20 +611,21 @@ void editor_type_page_down(struct editor* editor) size_t column, row; row_column_biggest(editor->cursor_row, editor->cursor_column, editor->select_row, editor->select_column, - &column, &row); - editor_cursor_set(editor, column, row); + &row, &column); + editor_cursor_set(editor, row, column); } size_t new_line = editor->cursor_row + editor->viewport_height; if ( editor->lines_used <= new_line ) { - editor_cursor_row_set(editor, editor->lines_used - 1); - editor_cursor_column_set(editor, editor->lines[editor->cursor_row].used); + editor_cursor_set(editor, editor->lines_used - 1, + editor->lines[editor->lines_used - 1].used); return; } - editor_cursor_row_set(editor, new_line); size_t new_line_len = editor->lines[new_line].used; if ( new_line_len < editor->cursor_column ) - editor_cursor_column_set(editor, new_line_len); + editor_cursor_set(editor, new_line, new_line_len); + else + editor_cursor_set(editor, new_line, editor->cursor_column); } void editor_type_select_page_down(struct editor* editor) @@ -616,14 +633,15 @@ void editor_type_select_page_down(struct editor* editor) size_t new_line = editor->select_row + editor->viewport_height; if ( editor->lines_used <= new_line ) { - editor_select_row_set(editor, editor->lines_used - 1); - editor_select_column_set(editor, editor->lines[editor->select_row].used); + editor_select_set(editor, editor->lines_used - 1, + editor->lines[editor->lines_used - 1].used); return; } - editor_select_row_set(editor, new_line); size_t new_line_len = editor->lines[new_line].used; if ( new_line_len < editor->select_column ) - editor_select_column_set(editor, new_line_len); + editor_select_set(editor, new_line, new_line_len); + else + editor_select_set(editor, new_line, editor->select_column); } void editor_type_edit(struct editor* editor) @@ -718,7 +736,8 @@ void editor_type_raw_character(struct editor* editor, wchar_t c) for ( size_t i = current_line->used; editor->cursor_column < i; i-- ) current_line->data[i] = current_line->data[i-1]; current_line->used++; - current_line->data[editor_cursor_column_inc(editor)-1] = c; + current_line->data[editor->cursor_column] = c; + editor_cursor_set(editor, editor->cursor_row, editor->cursor_column + 1); } void editor_type_copy(struct editor* editor) diff --git a/editor/cursor.c b/editor/cursor.c index b6676012..c378ee33 100644 --- a/editor/cursor.c +++ b/editor/cursor.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2014 Jonas 'Sortie' Termansen. + * Copyright (c) 2021 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -25,8 +26,19 @@ #include "display.h" #include "editor.h" -size_t editor_select_column_set(struct editor* editor, size_t x) +void editor_select_set(struct editor* editor, size_t y, size_t x) { + assert(y < editor->lines_used); + assert(x <= editor->lines[y].used); + if ( editor->viewport_height ) + { + if ( y < editor->page_y_offset ) + editor->page_y_offset = y; + if ( editor->page_y_offset + editor->viewport_height <= y ) + editor->page_y_offset = y + 1 - editor->viewport_height; + } + editor->select_row = y; + if ( editor->viewport_width ) { struct line* line = &editor->lines[editor->select_row]; @@ -36,91 +48,12 @@ size_t editor_select_column_set(struct editor* editor, size_t x) if ( editor->page_x_offset + editor->viewport_width <= rx ) editor->page_x_offset = rx + 1 - editor->viewport_width; } - return editor->select_column = x; -} - -size_t editor_select_row_set(struct editor* editor, size_t y) -{ - if ( editor->viewport_height ) - { - if ( y < editor->page_y_offset ) - editor->page_y_offset = y; - if ( editor->page_y_offset + editor->viewport_height <= y ) - editor->page_y_offset = y + 1 - editor->viewport_height; - } - return editor->select_row = y; -} - -void editor_select_set(struct editor* editor, size_t y, size_t x) -{ - editor_select_column_set(editor, x); - editor_select_row_set(editor, y); -} - -size_t editor_select_column_dec(struct editor* editor) -{ - assert(editor->select_column); - return editor_select_column_set(editor, editor->select_column-1); -} - -size_t editor_select_column_inc(struct editor* editor) -{ - // TODO: Assert line doesn't overflow! - return editor_select_column_set(editor, editor->select_column+1); -} - -size_t editor_select_row_dec(struct editor* editor) -{ - assert(editor->select_row); - return editor_select_row_set(editor, editor->select_row-1); -} - -size_t editor_select_row_inc(struct editor* editor) -{ - // TODO: Assert line doesn't overflow! - return editor_select_row_set(editor, editor->select_row+1); -} - -size_t editor_cursor_column_set(struct editor* editor, size_t x) -{ - editor_select_column_set(editor, x); - editor_select_row_set(editor, editor->cursor_row); - return editor->cursor_column = x; -} - -size_t editor_cursor_row_set(struct editor* editor, size_t y) -{ - editor_select_column_set(editor, editor->cursor_column); - editor_select_row_set(editor, y); - return editor->cursor_row = y; + editor->select_column = x; } void editor_cursor_set(struct editor* editor, size_t y, size_t x) { - editor_cursor_column_set(editor, x); - editor_cursor_row_set(editor, y); -} - -size_t editor_cursor_column_dec(struct editor* editor) -{ - assert(editor->cursor_column); - return editor_cursor_column_set(editor, editor->cursor_column-1); -} - -size_t editor_cursor_column_inc(struct editor* editor) -{ - // TODO: Assert line doesn't overflow! - return editor_cursor_column_set(editor, editor->cursor_column+1); -} - -size_t editor_cursor_row_dec(struct editor* editor) -{ - assert(editor->cursor_row); - return editor_cursor_row_set(editor, editor->cursor_row-1); -} - -size_t editor_cursor_row_inc(struct editor* editor) -{ - // TODO: Assert line doesn't overflow! - return editor_cursor_row_set(editor, editor->cursor_row+1); + editor_select_set(editor, y, x); + editor->cursor_column = x; + editor->cursor_row = y; } diff --git a/editor/cursor.h b/editor/cursor.h index 3159504e..6bca593a 100644 --- a/editor/cursor.h +++ b/editor/cursor.h @@ -24,20 +24,7 @@ struct editor; -size_t editor_select_column_set(struct editor* editor, size_t x); -size_t editor_select_row_set(struct editor* editor, size_t y); void editor_select_set(struct editor* editor, size_t y, size_t x); -size_t editor_select_column_dec(struct editor* editor); -size_t editor_select_column_inc(struct editor* editor); -size_t editor_select_row_dec(struct editor* editor); -size_t editor_select_row_inc(struct editor* editor); - -size_t editor_cursor_column_set(struct editor* editor, size_t x); -size_t editor_cursor_row_set(struct editor* editor, size_t y); void editor_cursor_set(struct editor* editor, size_t y, size_t x); -size_t editor_cursor_column_dec(struct editor* editor); -size_t editor_cursor_column_inc(struct editor* editor); -size_t editor_cursor_row_dec(struct editor* editor); -size_t editor_cursor_row_inc(struct editor* editor); #endif diff --git a/editor/modal.c b/editor/modal.c index 73e46fc7..b2c734d6 100644 --- a/editor/modal.c +++ b/editor/modal.c @@ -1,5 +1,6 @@ /* * Copyright (c) 2013, 2014, 2015, 2016 Jonas 'Sortie' Termansen. + * Copyright (c) 2021 Juhani 'nortti' Krekelä. * * Permission to use, copy, modify, and distribute this software for any * purpose with or without fee is hereby granted, provided that the above @@ -200,7 +201,7 @@ void editor_modal_goto_line(struct editor* editor, const char* linestr) editor->modal_error = true; return; } - editor_cursor_row_set(editor, editor->cursor_row - line); + editor_cursor_set(editor, editor->cursor_row - line, 0); } else if ( go_forward ) { @@ -209,7 +210,7 @@ void editor_modal_goto_line(struct editor* editor, const char* linestr) editor->modal_error = true; return; } - editor_cursor_row_set(editor, editor->cursor_row + line); + editor_cursor_set(editor, editor->cursor_row + line, 0); } else { @@ -218,9 +219,8 @@ void editor_modal_goto_line(struct editor* editor, const char* linestr) editor->modal_error = true; return; } - editor_cursor_row_set(editor, line ? line - 1 : 0); + editor_cursor_set(editor, line ? line - 1 : 0, 0); } - editor_cursor_column_set(editor, 0); } editor_type_edit(editor); }