#include #include #include #include #include #include #include #include #include #include #include #include #include static void* in_wmalloc(void* ctx, size_t size) { (void)ctx; return malloc(size); } static void in_wfree(void* ctx, void* mem) { (void)ctx; free(mem); } static void* in_wrealloc(void* ctx, void* mem, size_t old, size_t new) { (void)ctx, (void)old; return realloc(mem, new); } struct edit_line { struct in_gb gb; size_t cursor; }; void in_stream_read_line(const char* prompt, char* buffer, size_t max) { memset(buffer, 0, max); struct edit_line edit_line; memset(&edit_line, 0, sizeof(edit_line)); const char* render = NULL; in_gb_init(&in_wmalloc, NULL, &edit_line.gb, max); edit_line.cursor = 0; mprintf("%s", prompt); for (;;) { uint8_t ch; if (stream_read(STREAM_IN, &ch, 1) <= 0) { sched(); continue; } if (ch == '\n') break; in_gb_move(&edit_line.gb, edit_line.cursor); switch (ch) { case '\b': if (edit_line.cursor > 0) { edit_line.cursor--; in_gb_backspace(&edit_line.gb); mprintf(ANSIQ_CUR_LEFT(1)); char* tail = in_gb_string_at(&in_wmalloc, NULL, &edit_line.gb, edit_line.cursor); mprintf("%s" ANSIQ_SCR_CLR2LEND, tail); int move_back = strlen(tail); if (move_back > 0) mprintf(ANSIQ_DYN_CUR_LEFT, move_back); } break; case KB_DELETE: if (edit_line.cursor < in_gb_length(&edit_line.gb)) { edit_line.gb.gap_end++; char* tail = in_gb_string_at(&in_wmalloc, NULL, &edit_line.gb, edit_line.cursor); mprintf("%s" ANSIQ_SCR_CLR2LEND, tail); int move_back = strlen(tail); if (move_back > 0) mprintf(ANSIQ_DYN_CUR_LEFT, move_back); } break; case KB_LEFT: if (edit_line.cursor > 0) { edit_line.cursor--; mprintf(ANSIQ_CUR_LEFT(1)); } break; case KB_RIGHT: if (edit_line.cursor < in_gb_length(&edit_line.gb)) { edit_line.cursor++; mprintf(ANSIQ_CUR_RIGHT(1)); } break; default: if (isprint(ch)) { in_gb_insert(&in_wrealloc, NULL, &edit_line.gb, ch); edit_line.cursor++; if (edit_line.cursor == in_gb_length(&edit_line.gb)) { mprintf("%c", ch); } else { char* tail = in_gb_string_at(&in_wmalloc, NULL, &edit_line.gb, edit_line.cursor - 1); size_t move_back = strlen(tail) - 1; mprintf("%s" ANSIQ_DYN_CUR_LEFT, tail, move_back); } } break; } } mprintf("\n"); render = in_gb_string_at(&in_wmalloc, NULL, &edit_line.gb, 0); if (render != NULL) { size_t len_render = strlen(render); memcpy(buffer, render, min(len_render, max)); } in_gb_fini(&in_wfree, NULL, &edit_line.gb); }