summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorpommicket <pommicket@gmail.com>2023-08-05 19:04:44 -0400
committerpommicket <pommicket@gmail.com>2023-08-05 19:04:44 -0400
commit9e68c6f3dd0b90f908c31c02fedb4b51836d4c8e (patch)
treed38e0caff8dfc6f8f52933d4411d11d6010ce19d
parentb847c7208f15e40999118443d5a808dfe389a8fb (diff)
move some stuff to ted-internal, reject null characters
-rw-r--r--buffer.c31
-rw-r--r--ted-internal.h23
-rw-r--r--ted.h56
3 files changed, 60 insertions, 50 deletions
diff --git a/buffer.c b/buffer.c
index bf54386..bc1e6da 100644
--- a/buffer.c
+++ b/buffer.c
@@ -91,15 +91,8 @@ void buffer_set_view_only(TextBuffer *buffer, bool view_only) {
buffer->view_only = view_only;
}
-size_t buffer_get_path(TextBuffer *buffer, char *buf, size_t bufsz) {
- if (!buffer->path) {
- if (bufsz) *buf = '\0';
- return 1;
- }
- if (bufsz > 0) {
- str_cpy(buf, bufsz, buffer->path);
- }
- return strlen(buffer->path) + 1;
+const char *buffer_get_path(TextBuffer *buffer) {
+ return buffer->path;
}
const char *buffer_display_filename(TextBuffer *buffer) {
@@ -1599,7 +1592,6 @@ static void buffer_send_lsp_did_change(LSP *lsp, TextBuffer *buffer, BufferPos p
lsp_document_changed(lsp, buffer->path, event);
}
-// inserts the given text, returning the position of the end of the text
BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 str) {
buffer_pos_validate(buffer, &pos);
@@ -1607,8 +1599,14 @@ BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32
return pos;
if (str.len > U32_MAX) {
buffer_error(buffer, "Inserting too much text (length: %zu).", str.len);
- BufferPos ret = {0,0};
- return ret;
+ return (BufferPos){0};
+ }
+ for (u32 i = 0; i < str.len; ++i) {
+ char32_t c = str.str[i];
+ if (c == 0 || c >= UNICODE_CODE_POINTS || (c >= 0xD800 && c <= 0xDFFF)) {
+ buffer_error(buffer, "Inserting null character or bad unicode.");
+ return (BufferPos){0};
+ }
}
if (str.len == 0) {
// no text to insert
@@ -2629,18 +2627,19 @@ Status buffer_load_file(TextBuffer *buffer, const char *path) {
} else {
size_t n = unicode_utf8_to_utf32(&c, (char *)p, (size_t)(end - p));
if (n == 0) {
- // null character
- c = 0;
- ++p;
+ buffer_error(buffer, "Null character in file (position: %td).", p - file_contents);
+ success = false;
+ break;
} else if (n >= (size_t)(-2)) {
// invalid UTF-8
- success = false;
buffer_error(buffer, "Invalid UTF-8 (position: %td).", p - file_contents);
+ success = false;
break;
} else {
p += n;
}
}
+
if (c == '\n') {
if (buffer_lines_set_min_capacity(buffer, &lines, &lines_capacity, nlines + 1))
++nlines;
diff --git a/ted-internal.h b/ted-internal.h
index 2761557..8357155 100644
--- a/ted-internal.h
+++ b/ted-internal.h
@@ -583,6 +583,16 @@ struct Ted {
};
// === buffer.c ===
+/// create a new empty buffer with no file name
+void buffer_create(TextBuffer *buffer, Ted *ted);
+/// create a new empty line buffer
+void line_buffer_create(TextBuffer *buffer, Ted *ted);
+/// Does this buffer have an error?
+bool buffer_has_error(TextBuffer *buffer);
+/// get buffer error
+const char *buffer_get_error(TextBuffer *buffer);
+/// clear buffer error
+void buffer_clear_error(TextBuffer *buffer);
/// Get the LSPDocumentID corresponding to the file this buffer contains.
/// The return value is only useful if `buffer_lsp(buffer) != NULL`.
LSPDocumentID buffer_lsp_document_id(TextBuffer *buffer);
@@ -600,6 +610,12 @@ LSPDocumentPosition buffer_cursor_pos_as_lsp_document_position(TextBuffer *buffe
///
/// make sure to call \ref gl_geometry_draw after this
void buffer_highlight_lsp_range(TextBuffer *buffer, LSPRange range, ColorSetting color);
+/// process a mouse click.
+/// returns true if the event was consumed.
+bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
+
+// === build.c ===
+void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
// === colors.c ====
void color_init(void);
@@ -636,6 +652,11 @@ void config_free(Ted *ted);
/// the context with the highest score will be chosen.
long context_score(const char *path, Language lang, const SettingsContext *context);
+// === find.c ===
+/// height of the find/find+replace menu in pixels
+float find_menu_height(Ted *ted);
+void find_menu_frame(Ted *ted, Rect menu_bounds);
+
// === gl.c ===
/// set by main()
extern float gl_window_width, gl_window_height;
@@ -721,6 +742,7 @@ void gl_geometry_init(void);
// === ide-autocomplete.c ===
void autocomplete_init(Ted *ted);
void autocomplete_quit(Ted *ted);
+void autocomplete_frame(Ted *ted);
void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response);
// === ide-definitions.c ===
@@ -730,6 +752,7 @@ void autocomplete_process_lsp_response(Ted *ted, const LSPResponse *response);
/// alone isn't sufficient)
void definition_goto(Ted *ted, LSP *lsp, const char *name, LSPDocumentPosition pos, GotoType type);
void definitions_process_lsp_response(Ted *ted, LSP *lsp, const LSPResponse *response);
+void definitions_frame(Ted *ted);
// === ide-document-link.c ===
void document_link_init(Ted *ted);
diff --git a/ted.h b/ted.h
index 53a2cb4..96e7b88 100644
--- a/ted.h
+++ b/ted.h
@@ -268,17 +268,10 @@ typedef enum {
bool buffer_is_view_only(TextBuffer *buffer);
/// Set whether the buffer should be in view only mode.
void buffer_set_view_only(TextBuffer *buffer, bool view_only);
-/// Get path to buffer's file. At most `bufsz` bytes are written to `buf`.
+/// Get path to buffer's file, or `NULL` if the buffer is unnamed.
///
-/// Returns the number of bytes needed to store the path including a null terminator,
-/// or 1 if the buffer is unnamed.
-size_t buffer_get_path(TextBuffer *buffer, char *buf, size_t bufsz);
-/// Does this buffer have an error?
-bool buffer_has_error(TextBuffer *buffer);
-/// get buffer error
-const char *buffer_get_error(TextBuffer *buffer);
-/// clear buffer error
-void buffer_clear_error(TextBuffer *buffer);
+/// This string can be freed if the buffer is saved under a different name or closed, so don't keep it around for long.
+const char *buffer_get_path(TextBuffer *buffer);
/// clear undo and redo history
void buffer_clear_undo_redo(TextBuffer *buffer);
/// is this buffer empty?
@@ -287,10 +280,6 @@ bool buffer_empty(TextBuffer *buffer);
const char *buffer_display_filename(TextBuffer *buffer);
/// does this buffer contained a named file (i.e. not a line buffer, not the build buffer, not untitled)
bool buffer_is_named_file(TextBuffer *buffer);
-/// create a new empty buffer with no file name
-void buffer_create(TextBuffer *buffer, Ted *ted);
-/// create a new empty line buffer
-void line_buffer_create(TextBuffer *buffer, Ted *ted);
/// does this buffer have unsaved changes?
bool buffer_unsaved_changes(TextBuffer *buffer);
/// returns the character after position pos, or 0 if pos is invalid
@@ -460,7 +449,9 @@ void buffer_cursor_move_to_end_of_line(TextBuffer *buffer);
void buffer_cursor_move_to_start_of_file(TextBuffer *buffer);
/// Move cursor to the end of the file, like Ctrl+End does.
void buffer_cursor_move_to_end_of_file(TextBuffer *buffer);
-/// Put text at a position. All text insertion should eventually go through this function.
+/// Put text at a position.
+///
+/// Returns the position of the end of the text, or (BufferPos){0} on error.
BufferPos buffer_insert_text_at_pos(TextBuffer *buffer, BufferPos pos, String32 str);
/// Insert a single character at a position.
void buffer_insert_char_at_pos(TextBuffer *buffer, BufferPos pos, char32_t c);
@@ -508,7 +499,6 @@ void buffer_select_page_up(TextBuffer *buffer, i64 npages);
/// Scroll down by `npages` pages, selecting everything in between
void buffer_select_page_down(TextBuffer *buffer, i64 npages);
/// Delete `nchars` characters starting from `pos`.
-/// All text deletion should eventually go through this function.
void buffer_delete_chars_at_pos(TextBuffer *buffer, BufferPos pos, i64 nchars);
/// Delete characters between the two positions.
/// The order of `p1` and `p2` is irrelevant.
@@ -552,7 +542,9 @@ void buffer_backspace_words_at_cursor(TextBuffer *buffer, i64 nwords);
void buffer_undo(TextBuffer *buffer, i64 ntimes);
/// Redo `ntimes` times
void buffer_redo(TextBuffer *buffer, i64 ntimes);
-/// Start a new "edit chain". Undoing once after an edit chain will undo everything in the chain.
+/// Start a new "edit chain".
+///
+/// Undoing once after an edit chain will undo everything in the chain.
void buffer_start_edit_chain(TextBuffer *buffer);
/// End the edit chain.
void buffer_end_edit_chain(TextBuffer *buffer);
@@ -575,17 +567,16 @@ void buffer_new_file(TextBuffer *buffer, const char *path);
/// Save the buffer to its current filename. This will rewrite the entire file,
/// even if there are no unsaved changes.
bool buffer_save(TextBuffer *buffer);
-/// save, but with a different path
-bool buffer_save_as(TextBuffer *buffer, const char *new_filename);
+/// Save, but with a different path.
+///
+/// `new_path` must be an absolute path.
+bool buffer_save_as(TextBuffer *buffer, const char *new_path);
/// index of first line that will be displayed on screen
u32 buffer_first_rendered_line(TextBuffer *buffer);
/// index of last line that will be displayed on screen
u32 buffer_last_rendered_line(TextBuffer *buffer);
/// go to the definition/declaration/etc of the word at the cursor.
void buffer_goto_word_at_cursor(TextBuffer *buffer, GotoType type);
-/// process a mouse click.
-/// returns true if the event was consumed.
-bool buffer_handle_click(Ted *ted, TextBuffer *buffer, vec2 click, u8 times);
/// render the buffer in the given rectangle
void buffer_render(TextBuffer *buffer, Rect r);
/// indent the given lines
@@ -618,7 +609,8 @@ bool buffer_pos_eq(BufferPos p1, BufferPos p2);
///
/// faster than \ref buffer_pos_diff (constant time)
int buffer_pos_cmp(BufferPos p1, BufferPos p2);
-/// returns "`p2 - p1`", that is, the number of characters between `p1` and `p2`.
+/// returns "`p2 - p1`", that is, the number of characters between `p1` and `p2`,
+/// but negative if `p1` comes after `p2`.
i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2);
// === build.c ===
@@ -626,15 +618,15 @@ i64 buffer_pos_diff(TextBuffer *buffer, BufferPos p1, BufferPos p2);
void build_stop(Ted *ted);
/// call before adding anything to the build queue
void build_queue_start(Ted *ted);
-/// add a command to the build queue. call build_queue_start before this.
+/// add a command to the build queue. call \ref build_queue_start before this.
void build_queue_command(Ted *ted, const char *command);
-/// call this after calling build_queue_start, build_queue_command.
-/// make sure you set ted->build_dir before running this!
+/// call this after calling \ref build_queue_start, \ref build_queue_command.
+/// make sure you set `ted->build_dir` before running this!
void build_queue_finish(Ted *ted);
/// set up the build output buffer.
void build_setup_buffer(Ted *ted);
/// run a single command in the build window.
-/// make sure you set ted->build_dir before running this!
+/// make sure you set `ted->build_dir` before running this!
void build_start_with_command(Ted *ted, const char *command);
/// figure out which build command to run, and run it.
void build_start(Ted *ted);
@@ -644,13 +636,14 @@ void build_next_error(Ted *ted);
void build_prev_error(Ted *ted);
/// find build errors in build buffer.
void build_check_for_errors(Ted *ted);
-void build_frame(Ted *ted, float x1, float y1, float x2, float y2);
// === colors.c ===
+/// parse color setting
ColorSetting color_setting_from_str(const char *str);
+/// get string corresponding to color setting
const char *color_setting_to_str(ColorSetting s);
Status color_from_str(const char *str, u32 *color);
-/// perform SRC_ALPHA, ONE_MINUS_SRC_ALPHA blending with `bg` and `fg`.
+/// perform alpha blending with `bg` and `fg`.
u32 color_blend(u32 bg, u32 fg);
/// multiply color's alpha value by `opacity`.
u32 color_apply_opacity(u32 color, float opacity);
@@ -670,8 +663,6 @@ char *settings_get_root_dir(Settings *settings, const char *path);
// === find.c ===
/// which buffer will be searched?
TextBuffer *find_search_buffer(Ted *ted);
-/// height of the find/find+replace menu in pixels
-float find_menu_height(Ted *ted);
/// update find results.
/// if `force` is true, the results will be updated even if the pattern & flags have not been changed.
void find_update(Ted *ted, bool force);
@@ -683,7 +674,6 @@ void find_next(Ted *ted);
void find_prev(Ted *ted);
/// replace all matches
void find_replace_all(Ted *ted);
-void find_menu_frame(Ted *ted, Rect menu_bounds);
/// open the find/find+replace menu.
void find_open(Ted *ted, bool replace);
/// close the find/find+replace menu.
@@ -730,7 +720,6 @@ void autocomplete_next(Ted *ted);
void autocomplete_prev(Ted *ted);
/// close completion menu
void autocomplete_close(Ted *ted);
-void autocomplete_frame(Ted *ted);
// === ide-definitions.c ===
/// cancel the last go-to-definition / find symbols request.
@@ -742,7 +731,6 @@ void definitions_selector_update(Ted *ted);
void definitions_selector_render(Ted *ted, Rect bounds);
/// close the definitions menu
void definitions_selector_close(Ted *ted);
-void definitions_frame(Ted *ted);
// === ide-document-link.c ===
/// get document link at this position in the active buffer.