Created
May 7, 2013 13:48
-
-
Save agrif/5532705 to your computer and use it in GitHub Desktop.
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
| /* carl -- C Asynchronous Readline | |
| * Copyright (C) 2010 Dawid Ciężarkiewicz | |
| * | |
| * Originally part of xmppconsole <http://github.com/dpc/xmppconsole> | |
| * as io.c and io.h, but repackaged for general-purpose use, and with | |
| * a different namespace, by Aaron Griffith. | |
| * | |
| * For documentation, see carl.h. | |
| * | |
| * This program is free software: you can redistribute it and/or modify | |
| * it under the terms of the GNU General Public License as published by | |
| * the Free Software Foundation, either version 3 of the License, or | |
| * (at your option) any later version. | |
| * | |
| * This program is distributed in the hope that it will be useful, | |
| * but WITHOUT ANY WARRANTY; without even the implied warranty of | |
| * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the | |
| * GNU General Public License for more details. | |
| * | |
| * You should have received a copy of the GNU General Public License | |
| * along with this program. If not, see <http://www.gnu.org/licenses/>. | |
| */ | |
| #include "carl.h" | |
| #include <stdio.h> | |
| #include <readline/readline.h> | |
| #include <readline/history.h> | |
| #include <unistd.h> | |
| #include <stdlib.h> | |
| #include <sys/select.h> | |
| /* global status variables */ | |
| static fd_set carl_fds; | |
| static const char* carl_prompt = NULL; | |
| static int carl_echo = 1; | |
| static int carl_running = 0; | |
| static carl_callback_t carl_callback_func = NULL; | |
| static void* carl_callback_data = NULL; | |
| static void carl_handle_line_fake(char* line) | |
| { | |
| if (line != NULL) | |
| { | |
| if (carl_running) | |
| { | |
| rl_set_prompt(carl_prompt); | |
| rl_already_prompted = 1; | |
| } | |
| return; | |
| } | |
| carl_running = 0; | |
| rl_set_prompt(""); | |
| rl_replace_line("", 0); | |
| rl_redisplay(); | |
| } | |
| static int carl_handle_enter(int x, int y) | |
| { | |
| char* line = NULL; | |
| line = rl_copy_text(0, rl_end); | |
| rl_set_prompt(""); | |
| rl_replace_line("", 1); | |
| rl_redisplay(); | |
| if (carl_echo) | |
| carl_printfln("%s%s", carl_prompt, line); | |
| if (carl_callback_func != NULL) | |
| (*carl_callback_func)(line, carl_callback_data); | |
| if (strcmp(line, "") != 0) | |
| { | |
| add_history(line); | |
| } | |
| free(line); | |
| rl_set_prompt(carl_prompt); | |
| return 0; | |
| } | |
| void carl_init() | |
| { | |
| /* sane defaults */ | |
| carl_prompt_set(""); | |
| carl_echo_set(1); | |
| carl_callback_set(NULL, NULL); | |
| FD_ZERO(&carl_fds); | |
| rl_callback_handler_install(carl_prompt, carl_handle_line_fake); | |
| if (rl_bind_key(RETURN, carl_handle_enter)) | |
| { | |
| carl_printfln("failed to bind RETURN"); | |
| abort(); | |
| } | |
| carl_running = 1; | |
| } | |
| int carl_process() | |
| { | |
| int count; | |
| struct timeval t; | |
| if (carl_running == 0) | |
| return 0; | |
| t.tv_sec = 0; | |
| t.tv_usec = 0; | |
| FD_SET(STDIN_FILENO, &carl_fds); | |
| count = select(FD_SETSIZE, &carl_fds, NULL, NULL, &t); | |
| if (count < 0) | |
| { | |
| carl_printfln("select() returned an error"); | |
| abort(); | |
| } else if (count == 0) { | |
| return carl_running; | |
| } | |
| rl_callback_read_char(); | |
| return carl_running; | |
| } | |
| void carl_deinit() | |
| { | |
| carl_running = 0; | |
| rl_callback_handler_remove(); | |
| } | |
| void carl_prompt_set(const char* p) | |
| { | |
| carl_prompt = p; | |
| rl_set_prompt(carl_prompt); | |
| rl_redisplay(); | |
| } | |
| const char* carl_prompt_get() | |
| { | |
| return carl_prompt; | |
| } | |
| void carl_echo_set(int echo) | |
| { | |
| carl_echo = echo; | |
| } | |
| int carl_echo_get() | |
| { | |
| return carl_echo; | |
| } | |
| void carl_callback_set(carl_callback_t func, void* userdata) | |
| { | |
| carl_callback_func = func; | |
| carl_callback_data = userdata; | |
| } | |
| carl_callback_t carl_callback_get() | |
| { | |
| return carl_callback_func; | |
| } | |
| void* carl_callback_userdata_get() | |
| { | |
| return carl_callback_data; | |
| } | |
| typedef void (*print_func)(void*); | |
| static void carl_async_print(print_func func, void* data) | |
| { | |
| char* saved_line; | |
| int saved_point; | |
| saved_point = rl_point; | |
| saved_line = rl_copy_text(0, rl_end); | |
| rl_save_prompt(); | |
| rl_set_prompt(""); | |
| rl_replace_line("", 0); | |
| rl_redisplay(); | |
| (*func)(data); | |
| rl_replace_line(saved_line, 0); | |
| if (carl_running) | |
| rl_set_prompt(carl_prompt); | |
| rl_restore_prompt(); | |
| rl_point = saved_point; | |
| rl_forced_update_display(); | |
| free(saved_line); | |
| } | |
| struct carl_async_func_data | |
| { | |
| const char* fmt; | |
| va_list args; | |
| }; | |
| static void carl_print_func(void* data) | |
| { | |
| struct carl_async_func_data* d = (struct carl_async_func_data*)data; | |
| vprintf(d->fmt, d->args); | |
| printf("\n"); | |
| } | |
| void carl_printfln(const char* const fmt, ...) | |
| { | |
| va_list arg; | |
| va_start(arg, fmt); | |
| carl_vprintfln(fmt, arg); | |
| va_end(arg); | |
| } | |
| void carl_vprintfln(const char* const fmt, va_list arg) | |
| { | |
| struct carl_async_func_data d; | |
| d.fmt = fmt; | |
| va_copy(d.args, arg); | |
| carl_async_print(carl_print_func, &d); | |
| } | |
| struct carl_async_pass_data | |
| { | |
| const char* prompt; | |
| char* pass; | |
| }; | |
| static void carl_getpass_func(void* data) | |
| { | |
| struct carl_async_pass_data* d = (struct carl_async_pass_data*)(data); | |
| d->pass = getpass(d->prompt); | |
| rl_already_prompted = 1; | |
| } | |
| char* carl_getpass(const char* p) | |
| { | |
| struct carl_async_pass_data d; | |
| d.pass = NULL; | |
| d.prompt = p; | |
| rl_callback_handler_remove(); | |
| carl_async_print(carl_getpass_func, &d); | |
| rl_callback_handler_install(carl_prompt, carl_handle_line_fake); | |
| return d.pass; | |
| } |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment