Skip to content

Instantly share code, notes, and snippets.

@agrif
Created May 7, 2013 13:48
Show Gist options
  • Select an option

  • Save agrif/5532705 to your computer and use it in GitHub Desktop.

Select an option

Save agrif/5532705 to your computer and use it in GitHub Desktop.
/* 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