#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) { 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 (process_get_pgid (), 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); }