-
-
Save aniruddha-a/dfca2c5f88fdc1df5591943422fe0349 to your computer and use it in GitHub Desktop.
rl.c - readline for crepl.sh
This file contains 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
/* shamelessly copied from: | |
* https://stackoverflow.com/questions/34660459/changing-tab-completion-for-read-builtin-in-bash | |
* And modified a bit | |
* Compile it like | |
* gcc rl.c -lreadline -o rl | |
* And copy the rl binary to the same directory as crepl.sh | |
* */ | |
#include <stdbool.h> | |
#include <stdio.h> | |
#include <stdlib.h> | |
#include <string.h> | |
#include <unistd.h> | |
#include <readline/readline.h> | |
static void version(const char* progname) { | |
fprintf(stderr, "%s 0.1\n", progname); | |
} | |
static void usage(const char* progname) { | |
fprintf(stderr, "Usage: %s [-fhv] [-p PROMPT] [-n PROGNAME] [COMPLETION...]\n", progname); | |
fprintf(stderr, | |
"Reads one line using readline, and prints it to stdout.\n" | |
"Returns success if a line was read.\n" | |
" -p PROMPT Output PROMPT before requesting input.\n" | |
" -H HISTFILE File to save the history to.\n" | |
" -n PROGNAME Set application name to PROGNAME for readline config file\n" | |
" (Default: %s).\n" | |
" -f Use filename completion as well as specified completions.\n" | |
" -h Print this help text and exit.\n" | |
" -v Print version number and exit.\n" | |
" COMPLETION word to add to the list of possible completions.\n", | |
progname); | |
} | |
/* Readline really likes globals, so none of its hooks take a context parameter. */ | |
static char** completions = NULL; | |
static char* generate_next_completion(const char* text, int state) { | |
static int index = 0; | |
if (state == 0) index = 0; /* reset index if we're starting */ | |
size_t textlen = strlen(text); | |
while (completions[index++]) | |
if (strncmp(completions[index - 1], text, textlen) == 0) | |
return strdup(completions[index - 1]); | |
return NULL; | |
} | |
/* We use this if we will fall back to filename completion */ | |
static char** generate_completions(const char* text, int start, int end) { | |
return rl_completion_matches(text, generate_next_completion); | |
} | |
int main (int argc, char **argv) { | |
const char* prompt = ""; | |
const char* progname = strrchr(argv[0], '/'); | |
progname = progname ? progname + 1 : argv[0]; | |
rl_readline_name = progname; | |
bool use_file_completion = false; | |
const char *histfile = NULL; | |
for (;;) { | |
int opt = getopt(argc, argv, "+fp:n:hH:v"); | |
switch (opt) { | |
case -1: break; | |
case 'f': use_file_completion = true; continue; | |
case 'p': prompt = optarg; continue; | |
case 'H': histfile = optarg; continue; | |
case 'n': rl_readline_name = optarg; continue; | |
case 'h': usage(progname); return 0; | |
case 'v': version(progname); return 0; | |
default: usage(progname); return 2; | |
} | |
break; | |
} | |
if (histfile) { | |
using_history(); | |
read_history(histfile); | |
} | |
/* The default is stdout, which would interfere with capturing output. */ | |
rl_outstream = stderr; | |
completions = argv + optind; | |
rl_completion_entry_function = rl_filename_completion_function; | |
if (*completions) { | |
if (use_file_completion) | |
rl_attempted_completion_function = generate_completions; | |
else | |
rl_completion_entry_function = generate_next_completion; | |
} else { | |
/* No specified strings */ | |
if (!use_file_completion) | |
rl_inhibit_completion = true; | |
} | |
char* line = readline(prompt); | |
if (line) { | |
puts(line); | |
add_history(line); | |
free(line); | |
if (histfile) write_history(histfile); | |
return 0; | |
} else { | |
fputc('\n', rl_outstream); | |
return 1; | |
} | |
} |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment