• new ksh_mbswidth

• fix: when printing menus (tab expansion, for instance), honour width of
  the multibyte characters printed
• some int→bool while here
This commit is contained in:
tg 2008-04-19 17:21:55 +00:00
parent 6c6be2a87e
commit 7ddf56dbbc
7 changed files with 157 additions and 139 deletions

208
edit.c
View File

@ -5,7 +5,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.119 2008/04/01 21:50:57 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/edit.c,v 1.120 2008/04/19 17:21:52 tg Exp $");
/* tty driver characters we are interested in */
typedef struct {
@ -29,8 +29,9 @@ static int x_getc(void);
static void x_putcf(int);
static bool x_mode(bool);
static int x_do_comment(char *, int, int *);
static void x_print_expansions(int, char *const *, int);
static int x_cf_glob(int, const char *, int, int, int *, int *, char ***, int *);
static void x_print_expansions(int, char *const *, bool);
static int x_cf_glob(int, const char *, int, int, int *, int *, char ***,
bool *);
static int x_longest_prefix(int, char *const *);
static int x_basename(const char *, const char *);
static void x_free_words(int, char **);
@ -55,7 +56,13 @@ static void glob_table(const char *, XPtrV *, struct table *);
static void glob_path(int flags, const char *, XPtrV *, const char *);
static int x_file_glob(int, const char *, int, char ***);
static int x_command_glob(int, const char *, int, char ***);
static int x_locate_word(const char *, int, int, int *, int *);
static int x_locate_word(const char *, int, int, int *, bool *);
static size_t mbxtowc(unsigned *, const char *);
static size_t wcxtomb(char *, unsigned);
static int wcxwidth(unsigned);
static int x_e_getmbc(char *);
static char *utf_getcpfromcols(char *, int);
/* +++ generic editing functions +++ */
@ -162,15 +169,14 @@ x_putcf(int c)
static int
x_do_comment(char *buf, int bsize, int *lenp)
{
int i, j;
int len = *lenp;
int i, j, len = *lenp;
if (len == 0)
return 1; /* somewhat arbitrary - it's what at&t ksh does */
/* Already commented? */
if (buf[0] == '#') {
int saw_nl = 0;
bool saw_nl = false;
for (j = 0, i = 1; i < len; i++) {
if (!saw_nl || buf[i] != '#')
@ -203,11 +209,10 @@ x_do_comment(char *buf, int bsize, int *lenp)
/* ------------------------------------------------------------------------- */
/* Common file/command completion code for vi/emacs */
static void
x_print_expansions(int nwords, char * const *words, int is_command)
x_print_expansions(int nwords, char * const *words, bool is_command)
{
int use_copy = 0;
bool use_copy = false;
int prefix_len;
XPtrV l = { NULL, NULL, NULL };
@ -230,7 +235,7 @@ x_print_expansions(int nwords, char * const *words, int is_command)
if (i == nwords) {
while (prefix_len > 0 && words[0][prefix_len - 1] != '/')
prefix_len--;
use_copy = 1;
use_copy = true;
XPinit(l, nwords + 1);
for (i = 0; i < nwords; i++)
XPput(l, words[i] + prefix_len);
@ -258,8 +263,7 @@ x_print_expansions(int nwords, char * const *words, int is_command)
static int
x_file_glob(int flags __unused, const char *str, int slen, char ***wordsp)
{
char *toglob;
char **words;
char *toglob, **words;
int nwords, i, idx, escaping;
XPtrV w;
struct source *s, *sold;
@ -355,9 +359,7 @@ path_order_cmp(const void *aa, const void *bb)
static int
x_command_glob(int flags, const char *str, int slen, char ***wordsp)
{
char *toglob;
char *pat;
char *fpath;
char *toglob, *pat, *fpath;
int nwords;
XPtrV w;
struct block *l;
@ -393,11 +395,9 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
/* Sort entries */
if (flags & XCF_FULLPATH) {
/* Sort by basename, then path order */
struct path_order_info *info;
struct path_order_info *last_info = 0;
struct path_order_info *info, *last_info = NULL;
char **words = (char **)XPptrv(w);
int path_order = 0;
int i;
int i, path_order = 0;
info = (struct path_order_info *)
alloc(sizeof(struct path_order_info) * nwords, ATEMP);
@ -444,15 +444,14 @@ x_command_glob(int flags, const char *str, int slen, char ***wordsp)
static int
x_locate_word(const char *buf, int buflen, int pos, int *startp,
int *is_commandp)
bool *is_commandp)
{
int p;
int start, end;
/* Bad call? Probably should report error */
if (pos < 0 || pos > buflen) {
*startp = pos;
*is_commandp = 0;
*is_commandp = false;
return 0;
}
/* The case where pos == buflen happens to take care of itself... */
@ -471,12 +470,12 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
}
if (is_commandp) {
int iscmd;
bool iscmd;
int p = start - 1;
/* Figure out if this is a command */
for (p = start - 1; p >= 0 && ksh_isspace(buf[p]);
p--)
;
while (p >= 0 && ksh_isspace(buf[p]))
p--;
iscmd = p < 0 || vstrchr(";|&()`", buf[p]);
if (iscmd) {
/* If command has a /, path, etc. is not searched;
@ -497,16 +496,15 @@ x_locate_word(const char *buf, int buflen, int pos, int *startp,
static int
x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp,
int *endp, char ***wordsp, int *is_commandp)
int *endp, char ***wordsp, bool *is_commandp)
{
int len;
int nwords;
int len, nwords;
char **words = NULL;
int is_command;
bool is_command;
len = x_locate_word(buf, buflen, pos, startp, &is_command);
if (!(flags & XCF_COMMAND))
is_command = 0;
is_command = false;
/* Don't do command globing on zero length strings - it takes too
* long and isn't very useful. File globs are more likely to be
* useful, so allow these.
@ -535,8 +533,7 @@ x_cf_glob(int flags, const char *buf, int buflen, int pos, int *startp,
static char *
add_glob(const char *str, int slen)
{
char *toglob;
char *s;
char *toglob, *s;
bool saw_slash = false;
if (slen < 0)
@ -573,8 +570,7 @@ add_glob(const char *str, int slen)
static int
x_longest_prefix(int nwords, char * const * words)
{
int i, j;
int prefix_len;
int i, j, prefix_len;
char *p;
if (nwords <= 0)
@ -593,10 +589,8 @@ x_longest_prefix(int nwords, char * const * words)
static void
x_free_words(int nwords, char **words)
{
int i;
for (i = 0; i < nwords; i++)
afreechk(words[i]);
while (nwords)
afreechk(words[--nwords]);
afree(words, ATEMP);
}
@ -653,12 +647,8 @@ static void
glob_path(int flags, const char *pat, XPtrV *wp, const char *lpath)
{
const char *sp, *p;
char *xp;
int staterr;
int pathlen;
int patlen;
int oldsize, newsize, i, j;
char **words;
char *xp, **words;
int staterr, pathlen, patlen, oldsize, newsize, i, j;
XString xs;
patlen = strlen(pat) + 1;
@ -750,15 +740,6 @@ x_escape(const char *s, size_t len, int (*putbuf_func)(const char *, size_t))
return (rval);
}
/* +++ UTF-8 hack +++ */
static size_t mbxtowc(unsigned *, const char *);
static size_t wcxtomb(char *, unsigned);
static int wcxwidth(unsigned);
static int x_e_getmbc(char *);
static char *utf_getcpfromcols(char *, int);
static void utf_ptradj(char *, char **);
/* UTF-8 hack: high-level functions */
#if HAVE_EXPSTMT
@ -805,30 +786,67 @@ utf_widthadj(const char *src, const char **dst)
return (width == -1 ? 2 : width);
}
static void
utf_ptradj(char *src, char **dst)
int
ksh_mbswidth(const char *s)
{
size_t len;
unsigned int wc;
int width = 0, cw;
if (!Flag(FUTFHACK))
return (strlen(s));
while (*s)
if (((len = mbxtowc(&wc, s)) == (size_t)-1) ||
((cw = wcxwidth(wc)) == -1)) {
s++;
width += 1;
} else {
s += len;
width += cw;
}
return (width);
}
size_t
utf_cptradj(const char *src, const char **dst)
{
size_t len;
if (!Flag(FUTFHACK) || *(unsigned char *)src < 0xC2)
if (!Flag(FUTFHACK) || *(const unsigned char *)src < 0xC2)
len = 1;
else if (*(unsigned char *)src < 0xE0)
else if (*(const unsigned char *)src < 0xE0)
len = 2;
else if (*(unsigned char *)src < 0xF0)
else if (*(const unsigned char *)src < 0xF0)
len = 3;
else
len = 1;
if (len > 1)
if ((*(unsigned char *)(src + 1) & 0xC0) != 0x80)
if ((*(const unsigned char *)(src + 1) & 0xC0) != 0x80)
len = 1;
if (len > 2)
if ((*(unsigned char *)(src + 2) & 0xC0) != 0x80)
if ((*(const unsigned char *)(src + 2) & 0xC0) != 0x80)
len = 2;
if (dst)
*dst = src + len;
return (len);
}
#if HAVE_EXPSTMT
#define utf_ptradj(s,d) ({ \
union mksh_cchack out; \
char **dst = (d); \
size_t rv; \
\
rv = utf_cptradj((s), &out.ro); \
if (dst) \
*dst = out.rw; \
})
#else
#define utf_ptradj(s,d) utf_cptradj((s), (const char **)(d))
#endif
static char *
utf_getcpfromcols(char *p, int cols)
{
@ -939,8 +957,7 @@ static size_t
mbxtowc(unsigned *dst, const char *src)
{
const unsigned char *s = (const unsigned char *)src;
unsigned c, wc;
unsigned count;
unsigned int c, wc, count;
wc = *s++;
if (wc < 0x80) {
@ -989,7 +1006,7 @@ static size_t
wcxtomb(char *src, unsigned wc)
{
unsigned char *s = (unsigned char *)src;
unsigned count;
unsigned int count;
if (wc > 0xFFFD)
wc = 0xFFFD;
@ -1967,9 +1984,8 @@ x_search_char_forw(int c __unused)
static int
x_search_char_back(int c __unused)
{
char *cp = xcp, *p;
char tmp[4];
int b;
char *cp = xcp, *p, tmp[4];
bool b;
if (x_e_getmbc(tmp) < 0) {
x_e_putc2(7);
@ -1986,13 +2002,13 @@ x_search_char_back(int c __unused)
if ((tmp[1] && ((p+1) > xep)) ||
(tmp[2] && ((p+2) > xep)))
continue;
b = 1;
b = true;
if (*p != tmp[0])
b = 0;
b = false;
if (b && tmp[1] && p[1] != tmp[1])
b = 0;
b = false;
if (b && tmp[2] && p[2] != tmp[2])
b = 0;
b = false;
if (b)
break;
}
@ -2329,7 +2345,7 @@ x_redraw(int limit)
static int
x_transpose(int c __unused)
{
unsigned tmpa, tmpb;
unsigned int tmpa, tmpb;
/* What transpose is meant to do seems to be up for debate. This
* is a general summary of the options; the text is abcd with the
@ -2463,6 +2479,7 @@ static int
x_meta_yank(int c __unused)
{
int len;
if ((x_last_command != XFUNC_yank && x_last_command != XFUNC_meta_yank) ||
killstack[killtp] == 0) {
killtp = killsp;
@ -2572,8 +2589,7 @@ x_bind(const char *a1, const char *a2,
{
unsigned char f;
int prefix, key;
char *sp = NULL;
char *m1, *m2;
char *sp = NULL, *m1, *m2;
bool hastilde;
if (x_tab == NULL) {
@ -2802,10 +2818,8 @@ static int
x_expand(int c __unused)
{
char **words;
int nwords;
int start, end;
int is_command;
int i;
int start, end, nwords, i;
bool is_command;
nwords = x_cf_glob(XCF_FILE, xbuf, xep - xbuf, xcp - xbuf,
&start, &end, &words, &is_command);
@ -2834,10 +2848,8 @@ do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
Comp_type type)
{
char **words;
int nwords;
int start, end, nlen, olen;
int is_command;
int completed = 0;
int start, end, nlen, olen, nwords;
bool is_command, completed = false;
nwords = x_cf_glob(flags, xbuf, xep - xbuf, xcp - xbuf,
&start, &end, &words, &is_command);
@ -2860,16 +2872,16 @@ do_complete(int flags, /* XCF_{COMMAND,FILE,COMMAND_FILE} */
x_delete(olen, false);
x_escape(words[0], nlen, x_do_ins);
x_adjust();
completed = 1;
completed = true;
}
/* add space if single non-dir match */
if (nwords == 1 && words[0][nlen - 1] != '/') {
x_ins(" ");
completed = 1;
completed = true;
}
if (type == CT_COMPLIST && !completed) {
x_print_expansions(nwords, words, is_command);
completed = 1;
completed = true;
}
if (completed)
x_redraw(0);
@ -3029,8 +3041,7 @@ x_e_puts(const char *s)
static int
x_set_arg(int c)
{
int n = 0;
int first = 1;
int n = 0, first = 1;
c &= 255; /* strip command prefix */
for (; c >= 0 && ksh_isdigit(c); c = x_e_getc(), first = 0)
@ -3073,9 +3084,8 @@ x_version(int c __unused)
{
char *o_xbuf = xbuf, *o_xend = xend;
char *o_xbp = xbp, *o_xep = xep, *o_xcp = xcp;
int lim = x_lastcp() - xbp;
int vlen, lim = x_lastcp() - xbp;
char *v = str_save(KSH_VERSION, ATEMP);
int vlen;
xbuf = xbp = xcp = v;
xend = xep = v + (vlen = strlen(v));
@ -3117,8 +3127,7 @@ x_version(int c __unused)
static int
x_prev_histword(int c __unused)
{
char *rcp;
char *cp;
char *rcp, *cp;
cp = *histptr;
if (!cp)
@ -5264,14 +5273,10 @@ static int
complete_word(int cmd, int count)
{
static struct edstate *buf;
int rval;
int nwords;
int start, end;
int rval, nwords, start, end, match_len;
char **words;
char *match;
int match_len;
int is_unique;
int is_command;
bool is_command, is_unique;
/* Undo previous completion */
if (cmd == 0 && expanded == COMPLETE && buf) {
@ -5328,7 +5333,7 @@ complete_word(int cmd, int count)
} else
match = words[count];
match_len = strlen(match);
is_unique = 1;
is_unique = true;
/* expanded = PRINT; next call undo */
} else {
match = words[0];
@ -5369,10 +5374,9 @@ complete_word(int cmd, int count)
static int
print_expansions(struct edstate *est, int cmd __unused)
{
int nwords;
int start, end;
int start, end, nwords;
char **words;
int is_command;
bool is_command;
nwords = x_cf_glob(XCF_COMMAND_FILE | XCF_FULLPATH,
est->cbuf, est->linelen, est->cursor,

17
exec.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.41 2008/04/01 22:20:18 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.42 2008/04/19 17:21:53 tg Exp $");
static int comexec(struct op *, struct tbl *volatile, const char **,
int volatile);
@ -1337,8 +1337,7 @@ pr_menu(const char *const *ap)
{
struct select_menu_info smi;
const char *const *pp;
int nwidth, dwidth;
int i, n;
int nwidth, dwidth, i, n;
/* Width/column calculations were done once and saved, but this
* means select can't be used recursively so we re-calculate each
@ -1350,7 +1349,7 @@ pr_menu(const char *const *ap)
* get dimensions of the list
*/
for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
i = strlen(*pp);
i = ksh_mbswidth(*pp);
nwidth = (i > nwidth) ? i : nwidth;
}
/*
@ -1365,7 +1364,7 @@ pr_menu(const char *const *ap)
smi.args = ap;
smi.arg_width = nwidth;
smi.num_width = dwidth;
print_columns(shl_out, n, select_fmt_entry, (void *) &smi,
print_columns(shl_out, n, select_fmt_entry, (void *)&smi,
dwidth + nwidth + 2, 1);
return n;
@ -1386,14 +1385,14 @@ int
pr_list(char *const *ap)
{
char *const *pp;
int nwidth;
int i, n;
int nwidth, i, n;
for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) {
i = strlen(*pp);
i = ksh_mbswidth(*pp);
nwidth = (i > nwidth) ? i : nwidth;
}
print_columns(shl_out, n, plain_fmt_entry, (const void *)ap, nwidth + 1, 0);
print_columns(shl_out, n, plain_fmt_entry, (const void *)ap,
nwidth + 1, 0);
return n;
}

View File

@ -3,7 +3,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.60 2008/04/02 16:55:06 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/histrap.c,v 1.61 2008/04/19 17:21:53 tg Exp $");
/*-
* MirOS: This is the default mapping type, and need not be specified.
@ -189,9 +189,13 @@ c_fc(const char **wp)
hist_source->line - (int)(histptr - hp));
shf_putc('\t', shl_stdout);
/* print multi-line commands correctly */
for (s = *hp; (t = strchr(s, '\n')); s = t)
shf_fprintf(shl_stdout, "%.*s\t",
(int)(++t - s), s);
s = *hp;
while ((t = strchr(s, '\n'))) {
*t = '\0';
shf_fprintf(shl_stdout, "%s\n\t", s);
*t++ = '\n';
s = t;
}
shf_fprintf(shl_stdout, "%s\n", s);
}
shf_flush(shl_stdout);

7
misc.c
View File

@ -6,7 +6,7 @@
#include <grp.h>
#endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.73 2008/04/16 21:56:02 tg Exp $\t"
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.74 2008/04/19 17:21:54 tg Exp $\t"
MKSH_SH_H_ID);
#undef USE_CHVT
@ -958,10 +958,7 @@ print_columns(struct shf *shf, int n,
const void *arg, int max_width, int prefcol)
{
char *str = (char *) alloc(max_width + 1, ATEMP);
int i;
int r, c;
int rows, cols;
int nspace;
int i, r, c, rows, cols, nspace;
/* max_width + 1 for the space. Note that no space
* is printed after the last column to avoid problems

4
sh.h
View File

@ -8,7 +8,7 @@
/* $OpenBSD: c_test.h,v 1.4 2004/12/20 11:34:26 otto Exp $ */
/* $OpenBSD: tty.h,v 1.5 2004/12/20 11:34:26 otto Exp $ */
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.205 2008/04/16 21:56:03 tg Exp $"
#define MKSH_SH_H_ID "$MirOS: src/bin/mksh/sh.h,v 1.206 2008/04/19 17:21:54 tg Exp $"
#define MKSH_VERSION "R33 2008/04/16"
#if HAVE_SYS_PARAM_H
@ -1219,6 +1219,8 @@ void x_init(void);
int x_read(char *, size_t);
int x_bind(const char *, const char *, int, int);
/* UTF-8 hack stuff */
size_t utf_cptradj(const char *, const char **);
int ksh_mbswidth(const char *);
int utf_widthadj(const char *, const char **);
/* eval.c */
char *substitute(const char *, int);

19
shf.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.17 2008/03/28 13:28:33 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/shf.c,v 1.18 2008/04/19 17:21:55 tg Exp $");
/* flags to shf_emptybuf() */
#define EB_READSW 0x01 /* about to switch to reading */
@ -598,9 +598,7 @@ shf_puts(const char *s, struct shf *shf)
int
shf_write(const char *buf, int nbytes, struct shf *shf)
{
int orig_nbytes = nbytes;
int n;
int ncopy;
int n, ncopy, orig_nbytes = nbytes;
if (!(shf->flags & SHF_WR))
internal_errorf("shf_write: flags %x", shf->flags);
@ -918,7 +916,7 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
case 's':
if (!(s = va_arg(args, const char *)))
s = "(null)";
len = strlen(s);
len = ksh_mbswidth(s);
break;
case 'c':
@ -981,8 +979,17 @@ shf_vfprintf(struct shf *shf, const char *fmt, va_list args)
if (precision > 0) {
nwritten += precision;
for ( ; precision-- > 0 ; s++)
if (Flag(FUTFHACK)) {
const char *q = s;
while (precision-- > 0)
utf_cptradj(q, &q);
do {
shf_putc(*s, shf);
} while (++s < q);
} else while (precision-- > 0) {
shf_putc(*s, shf);
s++;
}
}
if (field > 0) {
nwritten += field;

29
var.c
View File

@ -2,7 +2,7 @@
#include "sh.h"
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.51 2008/02/24 15:20:52 tg Exp $");
__RCSID("$MirOS: src/bin/mksh/var.c,v 1.52 2008/04/19 17:21:55 tg Exp $");
/*
* Variables
@ -491,8 +491,9 @@ formatstr(struct tbl *vp, const char *s)
{
int olen, nlen;
char *p, *q;
size_t psiz;
olen = strlen(s);
olen = ksh_mbswidth(s);
if (vp->flag & (RJUST|LJUST)) {
if (!vp->u2.field) /* default field width */
@ -501,25 +502,29 @@ formatstr(struct tbl *vp, const char *s)
} else
nlen = olen;
p = (char *) alloc(nlen + 1, ATEMP);
p = (char *)alloc((psiz = nlen * /* MB_LEN_MAX */ 3 + 1), ATEMP);
if (vp->flag & (RJUST|LJUST)) {
int slen;
int slen = olen, i;
if (vp->flag & RJUST) {
const char *qq = s + olen;
const char *qq = s;
for (i = 0; i < slen; ++i)
utf_widthadj(qq, &qq);
/* strip trailing spaces (at&t uses qq[-1] == ' ') */
while (qq > s && ksh_isspace(qq[-1]))
while (qq > s && ksh_isspace(qq[-1])) {
--qq;
slen = qq - s;
if (slen > vp->u2.field) {
s += slen - vp->u2.field;
slen = vp->u2.field;
--slen;
}
while (slen > vp->u2.field) {
utf_widthadj(s, &s);
--slen;
}
if (vp->u2.field - slen)
memset(p, (vp->flag & ZEROFIL) ? '0' : ' ',
vp->u2.field - slen);
shf_snprintf(p + vp->u2.field - slen,
nlen + 1 - (vp->u2.field - slen),
psiz - (vp->u2.field - slen),
"%.*s", slen, s);
} else {
/* strip leading spaces/zeros */
@ -532,7 +537,7 @@ formatstr(struct tbl *vp, const char *s)
vp->u2.field, vp->u2.field, s);
}
} else
memcpy(p, s, olen + 1);
memcpy(p, s, strlen(s) + 1);
if (vp->flag & UCASEV_AL) {
for (q = p; *q; q++)