Changeset View
Changeset View
Standalone View
Standalone View
lib/libedit/eln.c
/* $NetBSD: eln.c,v 1.28 2016/02/28 23:02:24 christos Exp $ */ | /* $NetBSD: eln.c,v 1.35 2019/04/26 16:56:57 christos Exp $ */ | ||||
/*- | /*- | ||||
* Copyright (c) 2009 The NetBSD Foundation, Inc. | * Copyright (c) 2009 The NetBSD Foundation, Inc. | ||||
* All rights reserved. | * All rights reserved. | ||||
* | * | ||||
* Redistribution and use in source and binary forms, with or without | * Redistribution and use in source and binary forms, with or without | ||||
* modification, are permitted provided that the following conditions | * modification, are permitted provided that the following conditions | ||||
* are met: | * are met: | ||||
Show All 12 Lines | |||||
* SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS | ||||
* INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | * INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN | ||||
* CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) | * 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 | * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE | ||||
* POSSIBILITY OF SUCH DAMAGE. | * POSSIBILITY OF SUCH DAMAGE. | ||||
*/ | */ | ||||
#include "config.h" | #include "config.h" | ||||
#if !defined(lint) && !defined(SCCSID) | #if !defined(lint) && !defined(SCCSID) | ||||
__RCSID("$NetBSD: eln.c,v 1.28 2016/02/28 23:02:24 christos Exp $"); | __RCSID("$NetBSD: eln.c,v 1.35 2019/04/26 16:56:57 christos Exp $"); | ||||
#endif /* not lint && not SCCSID */ | #endif /* not lint && not SCCSID */ | ||||
#include <sys/cdefs.h> | #include <sys/cdefs.h> | ||||
__FBSDID("$FreeBSD$"); | __FBSDID("$FreeBSD$"); | ||||
#include <errno.h> | #include <errno.h> | ||||
#include <stdarg.h> | #include <stdarg.h> | ||||
#include <stdio.h> | #include <stdio.h> | ||||
#include <stdlib.h> | #include <stdlib.h> | ||||
#include "el.h" | #include "el.h" | ||||
public int | int | ||||
el_getc(EditLine *el, char *cp) | el_getc(EditLine *el, char *cp) | ||||
{ | { | ||||
int num_read; | int num_read; | ||||
wchar_t wc = 0; | wchar_t wc = 0; | ||||
num_read = el_wgetc(el, &wc); | num_read = el_wgetc(el, &wc); | ||||
*cp = '\0'; | *cp = '\0'; | ||||
if (num_read <= 0) | if (num_read <= 0) | ||||
return num_read; | return num_read; | ||||
num_read = ct_wctob(wc); | num_read = wctob(wc); | ||||
if (num_read == EOF) { | if (num_read == EOF) { | ||||
errno = ERANGE; | errno = ERANGE; | ||||
return -1; | return -1; | ||||
} else { | } else { | ||||
*cp = (char)num_read; | *cp = (char)num_read; | ||||
return 1; | return 1; | ||||
} | } | ||||
} | } | ||||
#ifdef WIDECHAR | void | ||||
public void | |||||
el_push(EditLine *el, const char *str) | el_push(EditLine *el, const char *str) | ||||
{ | { | ||||
/* Using multibyte->wide string decoding works fine under single-byte | /* Using multibyte->wide string decoding works fine under single-byte | ||||
* character sets too, and Does The Right Thing. */ | * character sets too, and Does The Right Thing. */ | ||||
el_wpush(el, ct_decode_string(str, &el->el_lgcyconv)); | el_wpush(el, ct_decode_string(str, &el->el_lgcyconv)); | ||||
} | } | ||||
public const char * | const char * | ||||
el_gets(EditLine *el, int *nread) | el_gets(EditLine *el, int *nread) | ||||
{ | { | ||||
const wchar_t *tmp; | const wchar_t *tmp; | ||||
tmp = el_wgets(el, nread); | tmp = el_wgets(el, nread); | ||||
if (tmp != NULL) { | if (tmp != NULL) { | ||||
int i; | int i; | ||||
size_t nwread = 0; | size_t nwread = 0; | ||||
for (i = 0; i < *nread; i++) | for (i = 0; i < *nread; i++) | ||||
nwread += ct_enc_width(tmp[i]); | nwread += ct_enc_width(tmp[i]); | ||||
*nread = (int)nwread; | *nread = (int)nwread; | ||||
} | } | ||||
return ct_encode_string(tmp, &el->el_lgcyconv); | return ct_encode_string(tmp, &el->el_lgcyconv); | ||||
} | } | ||||
public int | int | ||||
el_parse(EditLine *el, int argc, const char *argv[]) | el_parse(EditLine *el, int argc, const char *argv[]) | ||||
{ | { | ||||
int ret; | int ret; | ||||
const wchar_t **wargv; | const wchar_t **wargv; | ||||
wargv = (const wchar_t **) | wargv = (void *)ct_decode_argv(argc, argv, &el->el_lgcyconv); | ||||
ct_decode_argv(argc, argv, &el->el_lgcyconv); | |||||
if (!wargv) | if (!wargv) | ||||
return -1; | return -1; | ||||
ret = el_wparse(el, argc, wargv); | ret = el_wparse(el, argc, wargv); | ||||
ct_free_argv(wargv); | el_free(wargv); | ||||
return ret; | return ret; | ||||
} | } | ||||
public int | int | ||||
el_set(EditLine *el, int op, ...) | el_set(EditLine *el, int op, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
int ret; | int ret; | ||||
if (!el) | if (!el) | ||||
return -1; | return -1; | ||||
va_start(ap, op); | va_start(ap, op); | ||||
▲ Show 20 Lines • Show All 52 Lines • ▼ Show 20 Lines | el_set(EditLine *el, int op, ...) | ||||
case EL_SETTY: { | case EL_SETTY: { | ||||
const char *argv[20]; | const char *argv[20]; | ||||
int i; | int i; | ||||
const wchar_t **wargv; | const wchar_t **wargv; | ||||
for (i = 1; i < (int)__arraycount(argv) - 1; ++i) | for (i = 1; i < (int)__arraycount(argv) - 1; ++i) | ||||
if ((argv[i] = va_arg(ap, const char *)) == NULL) | if ((argv[i] = va_arg(ap, const char *)) == NULL) | ||||
break; | break; | ||||
argv[0] = argv[i] = NULL; | argv[0] = argv[i] = NULL; | ||||
wargv = (const wchar_t **) | wargv = (void *)ct_decode_argv(i + 1, argv, &el->el_lgcyconv); | ||||
ct_decode_argv(i + 1, argv, &el->el_lgcyconv); | |||||
if (!wargv) { | if (!wargv) { | ||||
ret = -1; | ret = -1; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* | /* | ||||
* AFAIK we can't portably pass through our new wargv to | * AFAIK we can't portably pass through our new wargv to | ||||
* el_wset(), so we have to reimplement the body of | * el_wset(), so we have to reimplement the body of | ||||
* el_wset() for these ops. | * el_wset() for these ops. | ||||
*/ | */ | ||||
switch (op) { | switch (op) { | ||||
case EL_BIND: | case EL_BIND: | ||||
wargv[0] = STR("bind"); | wargv[0] = L"bind"; | ||||
ret = map_bind(el, i, wargv); | ret = map_bind(el, i, wargv); | ||||
break; | break; | ||||
case EL_TELLTC: | case EL_TELLTC: | ||||
wargv[0] = STR("telltc"); | wargv[0] = L"telltc"; | ||||
ret = terminal_telltc(el, i, wargv); | ret = terminal_telltc(el, i, wargv); | ||||
break; | break; | ||||
case EL_SETTC: | case EL_SETTC: | ||||
wargv[0] = STR("settc"); | wargv[0] = L"settc"; | ||||
ret = terminal_settc(el, i, wargv); | ret = terminal_settc(el, i, wargv); | ||||
break; | break; | ||||
case EL_ECHOTC: | case EL_ECHOTC: | ||||
wargv[0] = STR("echotc"); | wargv[0] = L"echotc"; | ||||
ret = terminal_echotc(el, i, wargv); | ret = terminal_echotc(el, i, wargv); | ||||
break; | break; | ||||
case EL_SETTY: | case EL_SETTY: | ||||
wargv[0] = STR("setty"); | wargv[0] = L"setty"; | ||||
ret = tty_stty(el, i, wargv); | ret = tty_stty(el, i, wargv); | ||||
break; | break; | ||||
default: | default: | ||||
ret = -1; | ret = -1; | ||||
} | } | ||||
ct_free_argv(wargv); | el_free(wargv); | ||||
break; | break; | ||||
} | } | ||||
/* XXX: do we need to change el_func_t too? */ | /* XXX: do we need to change el_func_t too? */ | ||||
case EL_ADDFN: { /* const char *, const char *, el_func_t */ | case EL_ADDFN: { /* const char *, const char *, el_func_t */ | ||||
const char *args[2]; | const char *args[2]; | ||||
el_func_t func; | el_func_t func; | ||||
wchar_t **wargv; | wchar_t **wargv; | ||||
args[0] = va_arg(ap, const char *); | args[0] = va_arg(ap, const char *); | ||||
args[1] = va_arg(ap, const char *); | args[1] = va_arg(ap, const char *); | ||||
func = va_arg(ap, el_func_t); | func = va_arg(ap, el_func_t); | ||||
wargv = ct_decode_argv(2, args, &el->el_lgcyconv); | wargv = ct_decode_argv(2, args, &el->el_lgcyconv); | ||||
if (!wargv) { | if (!wargv) { | ||||
ret = -1; | ret = -1; | ||||
goto out; | goto out; | ||||
} | } | ||||
/* XXX: The two strdup's leak */ | /* XXX: The two strdup's leak */ | ||||
ret = map_addfunc(el, Strdup(wargv[0]), Strdup(wargv[1]), | ret = map_addfunc(el, wcsdup(wargv[0]), wcsdup(wargv[1]), | ||||
func); | func); | ||||
ct_free_argv(wargv); | el_free(wargv); | ||||
break; | break; | ||||
} | } | ||||
case EL_HIST: { /* hist_fun_t, const char * */ | case EL_HIST: { /* hist_fun_t, const char * */ | ||||
hist_fun_t fun = va_arg(ap, hist_fun_t); | hist_fun_t fun = va_arg(ap, hist_fun_t); | ||||
void *ptr = va_arg(ap, void *); | void *ptr = va_arg(ap, void *); | ||||
ret = hist_set(el, fun, ptr); | ret = hist_set(el, fun, ptr); | ||||
el->el_flags |= NARROW_HISTORY; | el->el_flags |= NARROW_HISTORY; | ||||
break; | break; | ||||
Show All 27 Lines | el_set(EditLine *el, int op, ...) | ||||
} | } | ||||
out: | out: | ||||
va_end(ap); | va_end(ap); | ||||
return ret; | return ret; | ||||
} | } | ||||
public int | int | ||||
el_get(EditLine *el, int op, ...) | el_get(EditLine *el, int op, ...) | ||||
{ | { | ||||
va_list ap; | va_list ap; | ||||
int ret; | int ret; | ||||
if (!el) | if (!el) | ||||
return -1; | return -1; | ||||
Show All 34 Lines | el_get(EditLine *el, int op, ...) | ||||
case EL_SIGNAL: /* int * */ | case EL_SIGNAL: /* int * */ | ||||
case EL_EDITMODE: | case EL_EDITMODE: | ||||
case EL_UNBUFFERED: | case EL_UNBUFFERED: | ||||
case EL_PREP_TERM: | case EL_PREP_TERM: | ||||
ret = el_wget(el, op, va_arg(ap, int *)); | ret = el_wget(el, op, va_arg(ap, int *)); | ||||
break; | break; | ||||
case EL_GETTC: { | case EL_GETTC: { | ||||
char *argv[20]; | char *argv[3]; | ||||
static char gettc[] = "gettc"; | static char gettc[] = "gettc"; | ||||
int i; | |||||
for (i = 1; i < (int)__arraycount(argv); ++i) | |||||
if ((argv[i] = va_arg(ap, char *)) == NULL) | |||||
break; | |||||
argv[0] = gettc; | argv[0] = gettc; | ||||
ret = terminal_gettc(el, i, argv); | argv[1] = va_arg(ap, char *); | ||||
argv[2] = va_arg(ap, void *); | |||||
ret = terminal_gettc(el, 3, argv); | |||||
break; | break; | ||||
} | } | ||||
case EL_GETCFN: /* el_rfunc_t */ | case EL_GETCFN: /* el_rfunc_t */ | ||||
ret = el_wget(el, op, va_arg(ap, el_rfunc_t *)); | ret = el_wget(el, op, va_arg(ap, el_rfunc_t *)); | ||||
break; | break; | ||||
case EL_CLIENTDATA: /* void ** */ | case EL_CLIENTDATA: /* void ** */ | ||||
Show All 18 Lines | |||||
const LineInfo * | const LineInfo * | ||||
el_line(EditLine *el) | el_line(EditLine *el) | ||||
{ | { | ||||
const LineInfoW *winfo = el_wline(el); | const LineInfoW *winfo = el_wline(el); | ||||
LineInfo *info = &el->el_lgcylinfo; | LineInfo *info = &el->el_lgcylinfo; | ||||
size_t offset; | size_t offset; | ||||
const Char *p; | const wchar_t *p; | ||||
info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv); | info->buffer = ct_encode_string(winfo->buffer, &el->el_lgcyconv); | ||||
offset = 0; | offset = 0; | ||||
for (p = winfo->buffer; p < winfo->cursor; p++) | for (p = winfo->buffer; p < winfo->cursor; p++) | ||||
offset += ct_enc_width(*p); | offset += ct_enc_width(*p); | ||||
info->cursor = info->buffer + offset; | info->cursor = info->buffer + offset; | ||||
offset = 0; | offset = 0; | ||||
for (p = winfo->buffer; p < winfo->lastchar; p++) | for (p = winfo->buffer; p < winfo->lastchar; p++) | ||||
offset += ct_enc_width(*p); | offset += ct_enc_width(*p); | ||||
info->lastchar = info->buffer + offset; | info->lastchar = info->buffer + offset; | ||||
return info; | return info; | ||||
} | } | ||||
int | int | ||||
el_insertstr(EditLine *el, const char *str) | el_insertstr(EditLine *el, const char *str) | ||||
{ | { | ||||
return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv)); | return el_winsertstr(el, ct_decode_string(str, &el->el_lgcyconv)); | ||||
} | } | ||||
#endif /* WIDECHAR */ |