чување 22f4c4021dbfa9be3525d7909f3aad7058f32fca
родитељ 6bd6096738037e6b5504b6caeeb20140afbe47e3
Аутор: Страхиња Радић <contact@strahinja.org>
Датум: Mon, 28 Feb 2022 22:45:08 +0100
Add search functionality
Signed-off-by: Страхиња Радић <contact@strahinja.org>
Diffstat:
| M | TODO | | | 4 | ++-- |
| M | config.def.h | | | 15 | +++++++++++++++ |
| M | config.h | | | 15 | +++++++++++++++ |
| M | draw.c | | | 59 | +++++++++++++++++++++++++++++++---------------------------- |
| M | draw.h | | | 5 | ++++- |
| M | sled.1.in | | | 8 | ++++++++ |
| M | sled.c | | | 249 | +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++-------------------- |
| M | util.c | | | 17 | +++++++++++++++-- |
| M | util.h | | | 5 | +++-- |
измењених датотека: 9, додавања: 280(+), брисања: 97(-)
diff --git a/TODO b/TODO
@@ -1,9 +1,9 @@
TODO
====
- < > Search?
+ <x> Search?
- < > Replace?
+ </> Replace?
Legend
diff --git a/config.def.h b/config.def.h
@@ -19,6 +19,8 @@ static const char* backup_suffix = "~";
#define INPUT_EDIT_BG TB_BLACK
#define PROMPT_FG TB_YELLOW | TB_BOLD
#define PROMPT_BG TB_MAGENTA
+#define SEARCH_FG TB_WHITE | TB_BOLD
+#define SEARCH_BG TB_GREEN
#define SEL_FG TB_BLACK
#define SEL_BG TB_WHITE
#define SHADOW_FG TB_BLACK
@@ -79,10 +81,13 @@ int move_screen_top(struct DrawState* state);
int move_start(struct DrawState* state);
int move_top(struct DrawState* state);
int move_up(struct DrawState* state);
+int next_match(struct DrawState* state);
int paste_from_paste(struct DrawState* state);
+int prev_match(struct DrawState* state);
int reread_or_callback(struct DrawState* state);
int show_go_to_line(struct DrawState* state);
int show_help(struct DrawState* state);
+int show_search(struct DrawState* state);
int toggle_overwrite(struct DrawState* state);
int toggle_selection(struct DrawState* state);
int write_file(struct DrawState* state);
@@ -125,8 +130,12 @@ static const struct Key global_keys[] = {
.callback = erase_to_end },
{ .ev = { .key = TB_KEY_CTRL_L },
.callback = show_go_to_line },
+ { .ev = { .key = TB_KEY_CTRL_N },
+ .callback = next_match },
{ .ev = { .key = TB_KEY_CTRL_O },
.callback = reread_or_callback },
+ { .ev = { .key = TB_KEY_CTRL_P },
+ .callback = prev_match },
{ .ev = { .key = TB_KEY_CTRL_R },
.callback = move_prev_word },
{ .ev = { .key = TB_KEY_CTRL_SPACE },
@@ -146,6 +155,9 @@ static const struct Key global_keys[] = {
{ .ev = { .key = TB_KEY_DELETE },
.callback = erase_forward },
{ .ev = { .key = TB_KEY_F1 }, .callback = show_help },
+ { .ev = { .key = TB_KEY_F3 }, .callback = next_match },
+ { .ev = { .key = TB_KEY_F4 }, .callback = prev_match },
+ { .ev = { .key = TB_KEY_F7 }, .callback = show_search },
{ .ev = { .key = TB_KEY_END }, .callback = move_end },
{ .ev = { .key = TB_KEY_HOME }, .callback = move_start },
{ .ev = { .key = TB_KEY_INSERT },
@@ -205,6 +217,7 @@ static const struct Key insert_keys[] = {
static const struct Key command_keys[] = {
{ .ev = { .key = TB_KEY_CTRL_BACKSLASH },
.callback = enter_insert_mode },
+ { .ev = { .ch = '/' }, .callback = show_search },
{ .ev = { .ch = ':' }, .callback = show_go_to_line },
{ .ev = { .ch = '0' }, .callback = move_start },
{ .ev = { .ch = '$' }, .callback = move_end },
@@ -218,6 +231,8 @@ static const struct Key command_keys[] = {
{ .ev = { .ch = 'L' }, .callback = move_screen_bottom },
{ .ev = { .ch = 'l' }, .callback = move_right },
{ .ev = { .ch = 'M' }, .callback = move_screen_middle },
+ { .ev = { .ch = 'N' }, .callback = prev_match },
+ { .ev = { .ch = 'n' }, .callback = next_match },
{ .ev = { .ch = 'P' }, .callback = paste_from_paste },
{ .ev = { .ch = 'q' }, .callback = exit_program },
{ .ev = { .ch = 'R' }, .callback = toggle_overwrite },
diff --git a/config.h b/config.h
@@ -19,6 +19,8 @@ static const char* backup_suffix = "~";
#define INPUT_EDIT_BG TB_BLACK
#define PROMPT_FG TB_YELLOW | TB_BOLD
#define PROMPT_BG TB_MAGENTA
+#define SEARCH_FG TB_WHITE | TB_BOLD
+#define SEARCH_BG TB_GREEN
#define SEL_FG TB_BLACK
#define SEL_BG TB_WHITE
#define SHADOW_FG TB_BLACK
@@ -79,10 +81,13 @@ int move_screen_top(struct DrawState* state);
int move_start(struct DrawState* state);
int move_top(struct DrawState* state);
int move_up(struct DrawState* state);
+int next_match(struct DrawState* state);
int paste_from_paste(struct DrawState* state);
+int prev_match(struct DrawState* state);
int reread_or_callback(struct DrawState* state);
int show_go_to_line(struct DrawState* state);
int show_help(struct DrawState* state);
+int show_search(struct DrawState* state);
int toggle_overwrite(struct DrawState* state);
int toggle_selection(struct DrawState* state);
int write_file(struct DrawState* state);
@@ -125,8 +130,12 @@ static const struct Key global_keys[] = {
.callback = erase_to_end },
{ .ev = { .key = TB_KEY_CTRL_L },
.callback = show_go_to_line },
+ { .ev = { .key = TB_KEY_CTRL_N },
+ .callback = next_match },
{ .ev = { .key = TB_KEY_CTRL_O },
.callback = reread_or_callback },
+ { .ev = { .key = TB_KEY_CTRL_P },
+ .callback = prev_match },
{ .ev = { .key = TB_KEY_CTRL_R },
.callback = move_prev_word },
{ .ev = { .key = TB_KEY_CTRL_SPACE },
@@ -146,6 +155,9 @@ static const struct Key global_keys[] = {
{ .ev = { .key = TB_KEY_DELETE },
.callback = erase_forward },
{ .ev = { .key = TB_KEY_F1 }, .callback = show_help },
+ { .ev = { .key = TB_KEY_F3 }, .callback = next_match },
+ { .ev = { .key = TB_KEY_F4 }, .callback = prev_match },
+ { .ev = { .key = TB_KEY_F7 }, .callback = show_search },
{ .ev = { .key = TB_KEY_END }, .callback = move_end },
{ .ev = { .key = TB_KEY_HOME }, .callback = move_start },
{ .ev = { .key = TB_KEY_INSERT },
@@ -205,6 +217,7 @@ static const struct Key insert_keys[] = {
static const struct Key command_keys[] = {
{ .ev = { .key = TB_KEY_CTRL_BACKSLASH },
.callback = enter_insert_mode },
+ { .ev = { .ch = '/' }, .callback = show_search },
{ .ev = { .ch = ':' }, .callback = show_go_to_line },
{ .ev = { .ch = '0' }, .callback = move_start },
{ .ev = { .ch = '$' }, .callback = move_end },
@@ -218,6 +231,8 @@ static const struct Key command_keys[] = {
{ .ev = { .ch = 'L' }, .callback = move_screen_bottom },
{ .ev = { .ch = 'l' }, .callback = move_right },
{ .ev = { .ch = 'M' }, .callback = move_screen_middle },
+ { .ev = { .ch = 'N' }, .callback = prev_match },
+ { .ev = { .ch = 'n' }, .callback = next_match },
{ .ev = { .ch = 'P' }, .callback = paste_from_paste },
{ .ev = { .ch = 'q' }, .callback = exit_program },
{ .ev = { .ch = 'R' }, .callback = toggle_overwrite },
diff --git a/draw.c b/draw.c
@@ -80,18 +80,6 @@ init_bufferline(struct BufferLine* bl)
}
void
-free_bufferline(struct BufferLine* bl)
-{
- if (!bl)
- return;
- free(bl->text);
- bl->text = NULL;
- bl->length = 0;
- bl->fg = 0;
- bl->bg = 0;
-}
-
-void
init_drawstate(struct DrawState* state, char* error, char* action,
char* filename, char* prompt, int skip_paste_and_mode_init)
{
@@ -99,6 +87,7 @@ init_drawstate(struct DrawState* state, char* error, char* action,
state->action = action;
state->filename = filename;
state->input = NULL;
+ state->search = NULL;
state->buffer = NULL;
state->column = 0;
state->display_column = 0;
@@ -121,20 +110,33 @@ init_drawstate(struct DrawState* state, char* error, char* action,
state->in_overwrite_mode = 0;
state->in_command_mode = 0;
}
- state->prompt = prompt;
- state->prompt_callback = NULL;
- state->input_callback = NULL;
- state->running = 1;
- state->dirty = 0;
- state->in_prompt = 0;
- state->in_selection_mode = 0;
- state->show_help = 0;
- state->show_input_dialog = 0;
- state->input_numerical = 0;
- state->sel_start_row = 0;
- state->sel_start_col = 0;
- state->sel_end_row = 0;
- state->sel_end_col = 0;
+ state->prompt = prompt;
+ state->prompt_callback = NULL;
+ state->input_callback = NULL;
+ state->input_update_callback = NULL;
+ state->running = 1;
+ state->dirty = 0;
+ state->in_prompt = 0;
+ state->in_selection_mode = 0;
+ state->show_help = 0;
+ state->show_input_dialog = 0;
+ state->input_numerical = 0;
+ state->sel_start_row = 0;
+ state->sel_start_col = 0;
+ state->sel_end_row = 0;
+ state->sel_end_col = 0;
+}
+
+void
+free_bufferline(struct BufferLine* bl)
+{
+ if (!bl)
+ return;
+ free(bl->text);
+ bl->text = NULL;
+ bl->length = 0;
+ bl->fg = 0;
+ bl->bg = 0;
}
void
@@ -151,6 +153,7 @@ free_drawstate(struct DrawState* state, int skip_paste_free)
free(state->paste);
}
free(state->input);
+ free(state->search);
}
void
@@ -693,8 +696,8 @@ draw_screen(const struct DrawState* state)
if (current->text)
u32_draw_string(0, cy, TEXT_FG, TEXT_BG, current->text,
state->maxx, state->maxx, 0, 0, CENTER,
- state->first_shown_column, 0, NULL, 0, 0, ssi,
- sei, SEL_FG, SEL_BG);
+ state->first_shown_column, 0, state->search,
+ SEARCH_FG, SEARCH_BG, ssi, sei, SEL_FG, SEL_BG);
i++;
cy++;
}
diff --git a/draw.h b/draw.h
@@ -36,6 +36,7 @@ struct DrawState {
char* action;
char* filename;
uint32_t* input;
+ uint32_t* search;
struct BufferLine* buffer;
size_t buffer_size;
int column;
@@ -56,6 +57,7 @@ struct DrawState {
size_t paste_size;
void (*prompt_callback)(struct DrawState*, struct tb_event*);
void (*input_callback)(struct DrawState*);
+ void (*input_update_callback)(struct DrawState*);
int running;
int dirty;
int in_prompt;
@@ -87,9 +89,9 @@ struct StatusSegment {
};
void init_bufferline(struct BufferLine* bl);
-void free_bufferline(struct BufferLine* bl);
void init_drawstate(struct DrawState* state, char* error, char* action,
char* filename, char* prompt, int skip_paste_and_mode_init);
+void free_bufferline(struct BufferLine* bl);
void free_drawstate(struct DrawState* state, int skip_paste_free);
size_t display_length(const struct DrawState* state, uint32_t* buffer,
const size_t max_index);
@@ -116,6 +118,7 @@ void u32_draw_string(const int x, const int y, const uint16_t fg,
const size_t ssi, const size_t sei, const uint16_t slfg,
const uint16_t slbg);
const struct DrawState* draw_help(const struct DrawState* state);
+const struct DrawState* draw_input_dialog(const struct DrawState* state);
const struct DrawState* draw_screen(const struct DrawState* state);
const struct DrawState* draw_status(const struct DrawState* state);
const struct DrawState* redraw_status(const struct DrawState* state);
diff --git a/sled.1.in b/sled.1.in
@@ -90,6 +90,9 @@ l l.
_
\fCEsc\fP@Close dialog, clear error, cancel selection
\fCF1\fP@Show help dialog
+\fCF3\fP@Go to next found match
+\fCF4\fP@Go to previous found match
+\fCF7\fP@Show search dialog
\fCHome\fP or \fCC-A\fP@Go to start of line
\fCPgUp\fP or \fCC-B\fP@Go to previous page
\fCBackspace\fP@Erase character before cursor
@@ -101,7 +104,9 @@ _
\fCPgDown\fP or \fCC-F\fP@Go to next page
\fCC-K\fP@Erase to end of line
\fCC-L\fP@Show Go to line dialog
+\fCC-N\fP@Go to next found match
\fCC-O\fP@Reread (reopen) file
+\fCC-P\fP@Go to previous found match
\fCC-Q\fP@Quit
\fCC-R\fP@Go to previous word
\fCC-S\fP@Write (save) file
@@ -137,6 +142,7 @@ box tab(@);
l l.
\fBKey\fP@\fBAction\fP
_
+\fC/\fP@Show search dialog
\fC:\fP@Show Go to line dialog
\fC0\fP@Go to start of line
\fC$\fP@Go to end of line
@@ -150,6 +156,8 @@ _
\fCL\fP@Go to last line on the screen
\fCl\fP@Go to next character
\fCM\fP@Go to middle line on the screen
+\fCN\fP@Go to previous found match
+\fCn\fP@Go to next found match
\fCP\fP@Paste from paste buffer
\fCq\fP@Quit
\fCR\fP@Toggle overwrite mode
diff --git a/sled.c b/sled.c
@@ -68,6 +68,7 @@ void reread_callback(struct DrawState* state, struct tb_event* ev);
void reread_file(struct DrawState* state);
void quit_callback(struct DrawState* state, struct tb_event* ev);
int save_file(struct DrawState* state);
+void search_dialog_callback(struct DrawState* state);
int
clear_selection(struct DrawState* state)
@@ -177,6 +178,46 @@ erase_selection(struct DrawState* state)
}
void
+go_to_line_callback(struct DrawState* state)
+{
+ size_t lineno = 0;
+ size_t len = 0;
+ char* u8_input = NULL;
+
+ if (!state)
+ return;
+
+ if (*state->input)
+ {
+ len = u32_strlen(state->input);
+ u8_input = calloc(len + 1, UTF8REPMAX);
+ if (!u8_input)
+ {
+ strcpy(state->error, errors[ERR_CANT_ALLOC]);
+ state->running = 0;
+ return;
+ }
+ unicode_string_to_u8(u8_input, state->input, len + 1);
+ errno = 0;
+ lineno = strtoul(u8_input, NULL, 10);
+ if (errno)
+ strcpy(state->error, errors[ERR_INVALID_NUM]);
+ if (!*state->error)
+ {
+ if (lineno > state->rows_count - 1)
+ lineno = state->rows_count;
+ else if (lineno < 1)
+ lineno = 1;
+ position_to(state, lineno - 1, state->column);
+ *state->input = 0;
+ }
+ free(u8_input);
+ }
+ if (!*state->error)
+ state->input_callback = NULL;
+}
+
+void
handle_key_event(struct tb_event* ev, struct DrawState* state)
{
const struct Key* current = NULL;
@@ -307,6 +348,8 @@ input_insert_char(struct DrawState* state, uint32_t ch)
input_position_to(state, state->input_column + 1);
if (add_null)
state->input[state->input_column] = 0;
+ if (state->input_update_callback)
+ state->input_update_callback(state);
}
return 0;
}
@@ -314,14 +357,17 @@ input_insert_char(struct DrawState* state, uint32_t ch)
void
input_position_to(struct DrawState* state, const int column)
{
+ size_t len = u32_strlen(state->input);
state->input_column = column;
- if (state->input_column >= MAXINPUT)
- state->input_column = MAXINPUT - 1;
+ if (state->input_column > len)
+ state->input_column = len;
state->input_display_column
= display_length(state, state->input, state->input_column);
- if (state->input_display_column > state->input_first_shown_column
- + state->input_dialog_width - 4)
+ if (state->input_first_shown_column > state->input_display_column)
+ state->input_first_shown_column = state->input_display_column;
+ if (state->input_first_shown_column + (state->input_dialog_width - 4)
+ < state->input_column)
state->input_first_shown_column = state->input_display_column
- (state->input_dialog_width - 4);
}
@@ -527,8 +573,7 @@ position_to(struct DrawState* state, const int row, const int column)
}
if (state->first_shown_column > state->display_column)
state->first_shown_column = state->display_column;
- if (state->first_shown_column + (state->maxx - 1)
- < state->column)
+ if (state->first_shown_column + (state->maxx - 1) < state->column)
state->first_shown_column
= state->display_column - (state->maxx - 1);
@@ -688,12 +733,24 @@ save_file_cleanup:
return SAVE_ERR_NONE;
}
+void
+search_dialog_callback(struct DrawState* state)
+{
+ next_match(state);
+ if (!*state->error)
+ state->input_callback = NULL;
+}
+
+void
+search_update_callback(struct DrawState* state)
+{
+ if (*state->input)
+ u32_strcpy(state->search, state->input);
+}
+
int
cancel_close(struct DrawState* state)
{
- if (!state)
- return 1;
-
if (!*state->error && !state->in_prompt && !state->show_help)
{
if (SEL_NOT_EMPTY(state))
@@ -928,8 +985,10 @@ input_cancel(struct DrawState* state)
*state->error = 0;
return 0;
}
- state->show_input_dialog = 0;
- *state->input = 0;
+ state->show_input_dialog = 0;
+ *state->input = 0;
+ state->input_callback = NULL;
+ state->input_update_callback = NULL;
return 0;
}
@@ -960,7 +1019,8 @@ input_erase_backwards(struct DrawState* state)
} while (state->input[i]);
state->input[i - 1] = 0;
input_position_to(state, state->input_column - 1);
- state->dirty = 1;
+ if (state->input_update_callback)
+ state->input_update_callback(state);
}
return 0;
}
@@ -977,7 +1037,8 @@ input_erase_forward(struct DrawState* state)
i++;
}
state->input[i] = 0;
- state->dirty = 1;
+ if (state->input_update_callback)
+ state->input_update_callback(state);
}
return 0;
}
@@ -987,7 +1048,9 @@ input_erase_to_end(struct DrawState* state)
{
state->input[state->input_column] = 0;
input_move_end(state);
- state->dirty = 1;
+ u32_strcpy(state->search, state->input);
+ if (state->input_update_callback)
+ state->input_update_callback(state);
return 0;
}
@@ -1004,7 +1067,8 @@ input_erase_to_start(struct DrawState* state)
} while (state->input[i]);
state->input[len - state->input_column] = 0;
input_move_start(state);
- state->dirty = 1;
+ if (state->input_update_callback)
+ state->input_update_callback(state);
return 0;
}
@@ -1299,6 +1363,41 @@ move_up(struct DrawState* state)
}
int
+next_match(struct DrawState* state)
+{
+ struct BufferLine* current = NULL;
+ const uint32_t* found = NULL;
+ size_t xpos;
+
+ if (!state->search || !*state->search)
+ return 0;
+
+ *state->error = 0;
+ for (size_t row = state->row; row < state->rows_count; row++)
+ {
+ current = state->buffer + row;
+ found = current->text;
+ if (row == state->row)
+ found += state->column + 1;
+ do
+ {
+ found = u32_strstr(found, state->search);
+ if (found)
+ {
+ xpos = found - (const uint32_t*)current->text;
+ state->saved_column = xpos;
+ if (*current->text)
+ {
+ position_to(state, row, xpos);
+ return 0;
+ }
+ }
+ } while (found);
+ }
+ return 0;
+}
+
+int
paste_from_paste(struct DrawState* state)
{
uint32_t* newtext = NULL;
@@ -1401,6 +1500,41 @@ paste_from_paste_cleanup:
}
int
+prev_match(struct DrawState* state)
+{
+ struct BufferLine* current = NULL;
+ const uint32_t* found = NULL;
+ size_t xpos;
+
+ if (!state->search || !*state->search)
+ return 0;
+
+ *state->error = 0;
+ for (size_t row = state->row + 1; row > 0; row--)
+ {
+ current = state->buffer + row - 1;
+ found = current->text;
+ if (row == state->row + 1)
+ found += state->column + 1;
+ do
+ {
+ found = u32_strstr(found, state->search);
+ if (found)
+ {
+ xpos = found - (const uint32_t*)current->text;
+ state->saved_column = xpos;
+ if (*current->text)
+ {
+ position_to(state, row - 1, xpos);
+ return 0;
+ }
+ }
+ } while (found);
+ }
+ return 0;
+}
+
+int
reread_or_callback(struct DrawState* state)
{
if (!state)
@@ -1430,13 +1564,44 @@ show_go_to_line(struct DrawState* state)
return 0;
}
}
- state->input_numerical = 1;
- state->show_input_dialog = 1;
- state->input_column = 0;
- state->input_display_column = 0;
- state->input_first_shown_column = 0;
- *state->input = 0;
- *state->error = 0;
+ state->input_numerical = 1;
+ state->show_input_dialog = 1;
+ *state->input = 0;
+ *state->error = 0;
+ input_position_to(state, 0);
+ return 0;
+}
+
+int
+show_search(struct DrawState* state)
+{
+ if (!state->search)
+ {
+ if (!(state->search = calloc(MAXINPUT, sizeof(uint32_t))))
+ {
+ state->running = 0;
+ strcpy(state->error, errors[ERR_CANT_ALLOC]);
+ return 0;
+ }
+ }
+ *state->search = 0;
+ state->input_title = (char*)search_dialog_title;
+ state->input_callback = search_dialog_callback;
+ state->input_update_callback = search_update_callback;
+ if (!state->input)
+ {
+ if (!(state->input = calloc(MAXINPUT, sizeof(uint32_t))))
+ {
+ state->running = 0;
+ strcpy(state->error, errors[ERR_CANT_ALLOC]);
+ return 0;
+ }
+ }
+ *state->input = 0;
+ state->input_numerical = 0;
+ state->show_input_dialog = 1;
+ *state->error = 0;
+ input_position_to(state, 0);
return 0;
}
@@ -1597,46 +1762,6 @@ yank_to_paste(struct DrawState* state)
return 0;
}
-void
-go_to_line_callback(struct DrawState* state)
-{
- size_t lineno = 0;
- size_t len = 0;
- char* u8_input = NULL;
-
- if (!state)
- return;
-
- if (*state->input)
- {
- len = u32_strlen(state->input);
- u8_input = calloc(len + 1, UTF8REPMAX);
- if (!u8_input)
- {
- strcpy(state->error, errors[ERR_CANT_ALLOC]);
- state->running = 0;
- return;
- }
- unicode_string_to_u8(u8_input, state->input, len + 1);
- errno = 0;
- lineno = strtoul(u8_input, NULL, 10);
- if (errno)
- strcpy(state->error, errors[ERR_INVALID_NUM]);
- if (!*state->error)
- {
- if (lineno > state->rows_count - 1)
- lineno = state->rows_count;
- else if (lineno < 1)
- lineno = 1;
- position_to(state, lineno - 1, state->column);
- *state->input = 0;
- }
- free(u8_input);
- }
- if (!*state->error)
- state->input_callback = NULL;
-}
-
int
main(int argc, char** argv)
{
diff --git a/util.c b/util.c
@@ -69,6 +69,19 @@ u32_strlen(const uint32_t* s)
}
const uint32_t*
+u32_strstr(const uint32_t* haystack, const uint32_t* needle)
+{
+ const uint32_t* ph = haystack;
+ while (*ph)
+ {
+ if (u32_starts_with(ph, needle))
+ return ph;
+ ph++;
+ }
+ return NULL;
+}
+
+const uint32_t*
u32_strchr(const uint32_t* haystack, const uint32_t needle)
{
const uint32_t* ph = haystack;
@@ -174,7 +187,7 @@ u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace)
: u32_strchr((uint32_t*)L" \v\t()[]{},.;:/\\", ch) != NULL;
}
-int
+const int
starts_with(const char* s, const char* with)
{
while (*s && *s == *with)
@@ -187,7 +200,7 @@ starts_with(const char* s, const char* with)
return *with == 0;
}
-int
+const int
u32_starts_with(const uint32_t* s, const uint32_t* with)
{
while (*s && *s == *with)
diff --git a/util.h b/util.h
@@ -48,6 +48,7 @@ enum {
size_t u8_string_to_unicode(uint32_t* us, const char* s, const size_t max);
size_t unicode_string_to_u8(char* s, const uint32_t* us, const size_t max);
size_t u32_strlen(const uint32_t* s);
+const uint32_t* u32_strstr(const uint32_t* haystack, const uint32_t* needle);
const uint32_t* u32_strchr(const uint32_t* haystack, const uint32_t needle);
size_t u32_strcpy(uint32_t* to, const uint32_t* from);
size_t u32_strncpy(uint32_t* to, const uint32_t* from, size_t max);
@@ -55,6 +56,6 @@ size_t u32_strcat(uint32_t* to, const uint32_t* from);
size_t u32_strncat(uint32_t* to, const uint32_t* from, size_t max);
size_t u32_u8_strcpy(uint32_t* to, const char* from);
int u32_is_word_boundary(const uint32_t ch, const int strictly_whitespace);
-int starts_with(const char* s, const char* with);
-int u32_starts_with(const uint32_t* s, const uint32_t* with);
+const int starts_with(const char* s, const char* with);
+const int u32_starts_with(const uint32_t* s, const uint32_t* with);
const char* u8_basename(const char* path);