Skip to content

Instantly share code, notes, and snippets.

@abhinav-upadhyay
Last active April 11, 2017 12:51
Show Gist options
  • Save abhinav-upadhyay/a8be393a21a0aa01d976c3e3ef225ed1 to your computer and use it in GitHub Desktop.
Save abhinav-upadhyay/a8be393a21a0aa01d976c3e3ef225ed1 to your computer and use it in GitHub Desktop.
Test program for the history commands of libedit(3)
/*-
* Copyright (c) 2017 Abhinav Upadhyay <er.abhinav.upadhyay@gmail.com>
* All rights reserved.
*
* Redistribution and use in source and binary forms, with or without
* modification, are permitted provided that the following conditions
* are met:
*
* 1. Redistributions of source code must retain the above copyright
* notice, this list of conditions and the following disclaimer.
* 2. Redistributions in binary form must reproduce the above copyright
* notice, this list of conditions and the following disclaimer in
* the documentation and/or other materials provided with the
* distribution.
*
* THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
* ``AS IS'' AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
* LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
* FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE
* COPYRIGHT HOLDERS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT,
* INCIDENTAL, SPECIAL, EXEMPLARY OR CONSEQUENTIAL DAMAGES (INCLUDING,
* BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES;
* LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED
* AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY,
* OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
* OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
* SUCH DAMAGE.
*/
#include <err.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "histedit.h"
#define DEFAULT_ARGV_SIZE 5
static const char *PROMPT = ">> ";
typedef struct {
size_t nargs;
char **args;
} args_t;
typedef struct {
const char *name;
size_t nargs;
void (*func) (History *, HistEvent *, args_t *);
} builtin_t;
static void builtin_load (History *, HistEvent *, args_t *);
static void builtin_save (History *, HistEvent *, args_t *);
static void builtin_clear (History *, HistEvent *, args_t *);
static void builtin_get_size (History *, HistEvent *, args_t *);
static void builtin_set_size (History *, HistEvent *, args_t *);
static void builtin_history (History *, HistEvent *, args_t *);
static void builtin_first (History *, HistEvent *, args_t *);
static void builtin_last (History *, HistEvent *, args_t *);
builtin_t builtins [] = {
{"load", 1, builtin_load},
{"clear", 0, builtin_clear},
{"set_size", 1, builtin_set_size},
{"get_size", 0, builtin_get_size},
{"save", 1, builtin_save},
{"history", 0, builtin_history},
{"first", 0, builtin_first},
{"last", 0, builtin_last}
};
static args_t *
get_argv(char *input)
{
size_t whitespace_offset;
char *arg;
size_t argv_offset = 0;
size_t argv_size = DEFAULT_ARGV_SIZE;
char **argv = malloc(argv_size * sizeof(*argv));
args_t *args = malloc(sizeof(*args));
while (*input) {
whitespace_offset = strcspn(input, " \t");
arg = malloc(whitespace_offset + 1);
memcpy(arg, input, whitespace_offset);
arg[whitespace_offset] = 0;
input += whitespace_offset + 1;
if (argv_offset == argv_size - 1) {
argv_size += DEFAULT_ARGV_SIZE;
argv = realloc(argv, argv_size);
}
argv[argv_offset++] = arg;
}
if (argv_offset == DEFAULT_ARGV_SIZE - 1)
argv = realloc(argv, argv_size + 1);
args->args = argv;
args->nargs = argv_offset;
return args;
}
static void
free_args(args_t *args)
{
size_t i;
if (args == NULL)
return;
for (i = 0; i < args->nargs; i++)
free(args->args[i]);
free(args->args);
free(args);
}
static long
my_strtol(const char *str)
{
char *endptr = NULL;
long value = strtol(str, &endptr, 10);
if (str[0] == '\0' || endptr[0] != '\0')
return -1;
return value;
}
int
main(int argc, char **argv)
{
ssize_t bytes_read;
size_t linesize = 0;
size_t i;
char *line = NULL;
args_t *args = NULL;
long histsize;
HistEvent ev;
History *hist = history_init();
history(hist, &ev, H_SETSIZE, 100);
int is_builtin = 0;
printf("%s", PROMPT);
while ((bytes_read = getline(&line, &linesize, stdin)) != -1) {
is_builtin = 0;
if (bytes_read == 1)
goto PRINT_PROMPT;
line[bytes_read - 1] = 0;
args = get_argv(line);
if (strcmp("exit", args->args[0]) == 0) {
printf("Bye\n");
break;
}
for (i = 0; i < sizeof(builtins) / sizeof(builtins[0]); i++) {
builtin_t builtin = builtins[i];
if (strcmp(builtin.name, args->args[0]) == 0) {
is_builtin = 1;
if (args->nargs - 1 != builtin.nargs) {
warnx("Expected %zu number of arguments for %s command",
builtin.nargs, builtin.name);
goto PRINT_PROMPT;
}
builtin.func(hist, &ev, args);
break;
}
}
if (!is_builtin) {
printf("Executed %s\n", line);
history(hist, &ev, H_ENTER, line);
}
PRINT_PROMPT:
free(line);
line = NULL;
free_args(args);
args = NULL;
printf("%s", PROMPT);
}
history_end(hist);
}
static void
builtin_load (History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_LOAD, args->args[1]);
}
static void
builtin_clear (History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_CLEAR);
}
static void
builtin_set_size(History *hist, HistEvent *ev, args_t *args)
{
long size = my_strtol(args->args[1]);
if (size == -1) {
warnx("Usage: set_size size");
return;
}
history(hist, ev, H_SETSIZE, size);
}
static void
builtin_get_size(History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_GETSIZE);
printf("%d\n", ev->num);
}
static void
builtin_save(History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_SAVE, args->args[1]);
}
static void
builtin_first(History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_FIRST);
printf("%s\n", ev->str);
}
static void
builtin_last(History *hist, HistEvent *ev, args_t *args)
{
history(hist, ev, H_LAST);
printf("%s\n", ev->str);
}
static void
builtin_history(History * hist, HistEvent * ev, args_t *args)
{
size_t i;
for (i = history(hist, ev, H_LAST); i != -1; i = history(hist, ev, H_PREV))
printf("%s\n", ev->str);
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment