make print_columns() aware that octets≠characters≠columns

This commit is contained in:
tg 2009-11-09 23:35:11 +00:00
parent 6e9d7f33e8
commit fe853065bb
5 changed files with 111 additions and 82 deletions

View File

@ -1,4 +1,4 @@
# $MirOS: src/bin/mksh/check.t,v 1.336 2009/10/30 00:57:35 tg Exp $ # $MirOS: src/bin/mksh/check.t,v 1.337 2009/11/09 23:35:07 tg Exp $
# $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: bksl-nl.t,v 1.2 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $ # $OpenBSD: history.t,v 1.5 2001/01/28 23:04:56 niklas Exp $
# $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $ # $OpenBSD: read.t,v 1.3 2003/03/10 03:48:16 david Exp $
@ -25,7 +25,7 @@
# http://www.research.att.com/~gsf/public/ifs.sh # http://www.research.att.com/~gsf/public/ifs.sh
expected-stdout: expected-stdout:
@(#)MIRBSD KSH R39 2009/10/30 @(#)MIRBSD KSH R39 2009/11/09
description: description:
Check version of shell. Check version of shell.
stdin: stdin:

70
exec.c
View File

@ -22,7 +22,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/exec.c,v 1.67 2009/10/15 16:25:15 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/exec.c,v 1.68 2009/11/09 23:35:09 tg Exp $");
static int comexec(struct op *, struct tbl *volatile, const char **, static int comexec(struct op *, struct tbl *volatile, const char **,
int volatile, volatile int *); int volatile, volatile int *);
@ -1338,16 +1338,15 @@ do_selectargs(const char **ap, bool print_menu)
} }
struct select_menu_info { struct select_menu_info {
const char *const *args; const char * const *args;
int arg_width;
int num_width; int num_width;
}; };
static char *select_fmt_entry(const void *, int, char *, int); static char *select_fmt_entry(char *, int, int, const void *);
/* format a single select menu item */ /* format a single select menu item */
static char * static char *
select_fmt_entry(const void *arg, int i, char *buf, int buflen) select_fmt_entry(char *buf, int buflen, int i, const void *arg)
{ {
const struct select_menu_info *smi = const struct select_menu_info *smi =
(const struct select_menu_info *)arg; (const struct select_menu_info *)arg;
@ -1361,66 +1360,73 @@ select_fmt_entry(const void *arg, int i, char *buf, int buflen)
* print a select style menu * print a select style menu
*/ */
int int
pr_menu(const char *const *ap) pr_menu(const char * const *ap)
{ {
struct select_menu_info smi; struct select_menu_info smi;
const char *const *pp; const char * const *pp;
int nwidth, dwidth, i, n; int acols = 0, aocts = 0, i, n;
/* Width/column calculations were done once and saved, but this /*
* means select can't be used recursively so we re-calculate each * width/column calculations were done once and saved, but this
* time (could save in a structure that is returned, but its probably * means select can't be used recursively so we re-calculate
* not worth the bother). * each time (could save in a structure that is returned, but
* it's probably not worth the bother)
*/ */
/* /*
* get dimensions of the list * get dimensions of the list
*/ */
for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) { for (n = 0, pp = ap; *pp; n++, pp++) {
i = strlen(*pp);
if (i > aocts)
aocts = i;
i = utf_mbswidth(*pp); i = utf_mbswidth(*pp);
nwidth = (i > nwidth) ? i : nwidth; if (i > acols)
acols = i;
} }
/* /*
* we will print an index of the form * we will print an index of the form "%d) " in front of
* %d) * each entry, so get the maximum width of this
* in front of each entry
* get the max width of this
*/ */
for (i = n, dwidth = 1; i >= 10; i /= 10) for (i = n, smi.num_width = 1; i >= 10; i /= 10)
dwidth++; smi.num_width++;
smi.args = 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); smi.num_width + 2 + aocts, smi.num_width + 2 + acols,
true);
return (n); return (n);
} }
/* XXX: horrible kludge to fit within the framework */ /* XXX: horrible kludge to fit within the framework */
static char *plain_fmt_entry(char *, int, int, const void *);
static char *plain_fmt_entry(const void *, int, char *, int);
static char * static char *
plain_fmt_entry(const void *arg, int i, char *buf, int buflen) plain_fmt_entry(char *buf, int buflen, int i, const void *arg)
{ {
shf_snprintf(buf, buflen, "%s", ((const char * const *)arg)[i]); shf_snprintf(buf, buflen, "%s", ((const char * const *)arg)[i]);
return (buf); return (buf);
} }
int int
pr_list(char *const *ap) pr_list(char * const *ap)
{ {
char *const *pp; int acols = 0, aocts = 0, i, n;
int nwidth, i, n; char * const *pp;
for (n = 0, nwidth = 0, pp = ap; *pp; n++, pp++) { for (n = 0, pp = ap; *pp; n++, pp++) {
i = strlen(*pp);
if (i > aocts)
aocts = i;
i = utf_mbswidth(*pp); i = utf_mbswidth(*pp);
nwidth = (i > nwidth) ? i : nwidth; if (i > acols)
acols = i;
} }
print_columns(shl_out, n, plain_fmt_entry, (const void *)ap, print_columns(shl_out, n, plain_fmt_entry, (const void *)ap,
nwidth + 1, 0); aocts, acols, false);
return (n); return (n);
} }

22
funcs.c
View File

@ -25,7 +25,7 @@
#include "sh.h" #include "sh.h"
__RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.141 2009/10/27 17:00:01 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/funcs.c,v 1.142 2009/11/09 23:35:09 tg Exp $");
#if HAVE_KILLPG #if HAVE_KILLPG
/* /*
@ -171,7 +171,7 @@ static int test_primary(Test_env *, bool);
static int ptest_isa(Test_env *, Test_meta); static int ptest_isa(Test_env *, Test_meta);
static const char *ptest_getopnd(Test_env *, Test_op, bool); static const char *ptest_getopnd(Test_env *, Test_op, bool);
static void ptest_error(Test_env *, int, const char *); static void ptest_error(Test_env *, int, const char *);
static char *kill_fmt_entry(const void *, int, char *, int); static char *kill_fmt_entry(char *, int, int, const void *);
static void p_time(struct shf *, bool, long, int, int, static void p_time(struct shf *, bool, long, int, int,
const char *, const char *) __attribute__((nonnull (6, 7))); const char *, const char *) __attribute__((nonnull (6, 7)));
static char *do_realpath(const char *); static char *do_realpath(const char *);
@ -1467,7 +1467,7 @@ c_fgbg(const char **wp)
/* format a single kill item */ /* format a single kill item */
static char * static char *
kill_fmt_entry(const void *arg, int i, char *buf, int buflen) kill_fmt_entry(char *buf, int buflen, int i, const void *arg)
{ {
const struct kill_info *ki = (const struct kill_info *)arg; const struct kill_info *ki = (const struct kill_info *)arg;
@ -1538,25 +1538,29 @@ c_kill(const char **wp)
shprintf("%d\n", n); shprintf("%d\n", n);
} }
} else { } else {
int w, j; int w, j, mess_cols, mess_octs;
int mess_width;
struct kill_info ki; struct kill_info ki;
for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10) for (j = NSIG, ki.num_width = 1; j >= 10; j /= 10)
ki.num_width++; ki.num_width++;
ki.name_width = mess_width = 0; ki.name_width = mess_cols = mess_octs = 0;
for (j = 0; j < NSIG; j++) { for (j = 0; j < NSIG; j++) {
w = strlen(sigtraps[j].name); w = strlen(sigtraps[j].name);
if (w > ki.name_width) if (w > ki.name_width)
ki.name_width = w; ki.name_width = w;
w = strlen(sigtraps[j].mess); w = strlen(sigtraps[j].mess);
if (w > mess_width) if (w > mess_octs)
mess_width = w; mess_octs = w;
w = utf_mbswidth(sigtraps[j].mess);
if (w > mess_cols)
mess_cols = w;
} }
print_columns(shl_stdout, NSIG - 1, print_columns(shl_stdout, NSIG - 1,
kill_fmt_entry, (void *)&ki, kill_fmt_entry, (void *)&ki,
ki.num_width + ki.name_width + mess_width + 3, 1); ki.num_width + 1 + ki.name_width + 1 + mess_octs,
ki.num_width + 1 + ki.name_width + 1 + mess_cols,
true);
} }
return (0); return (0);
} }

85
misc.c
View File

@ -29,7 +29,7 @@
#include <grp.h> #include <grp.h>
#endif #endif
__RCSID("$MirOS: src/bin/mksh/misc.c,v 1.128 2009/10/30 14:37:43 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/misc.c,v 1.129 2009/11/09 23:35:10 tg Exp $");
unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */ unsigned char chtypes[UCHAR_MAX + 1]; /* type bits for unsigned char */
@ -120,12 +120,12 @@ struct options_info {
int opts[NELEM(options)]; int opts[NELEM(options)];
}; };
static char *options_fmt_entry(const void *arg, int, char *, int); static char *options_fmt_entry(char *, int, int, const void *);
static void printoptions(int); static void printoptions(bool);
/* format a single select menu item */ /* format a single select menu item */
static char * static char *
options_fmt_entry(const void *arg, int i, char *buf, int buflen) options_fmt_entry(char *buf, int buflen, int i, const void *arg)
{ {
const struct options_info *oi = (const struct options_info *)arg; const struct options_info *oi = (const struct options_info *)arg;
@ -136,32 +136,40 @@ options_fmt_entry(const void *arg, int i, char *buf, int buflen)
} }
static void static void
printoptions(int verbose) printoptions(bool verbose)
{ {
unsigned int i; int i = 0;
if (verbose) { if (verbose) {
int n = 0, len, octs = 0;
struct options_info oi; struct options_info oi;
int n, len;
/* verbose version */ /* verbose version */
shf_puts("Current option settings\n", shl_stdout); shf_puts("Current option settings\n", shl_stdout);
for (i = n = oi.opt_width = 0; i < NELEM(options); i++) oi.opt_width = 0;
while (i < (int)NELEM(options)) {
if (options[i].name) { if (options[i].name) {
len = strlen(options[i].name);
oi.opts[n++] = i; oi.opts[n++] = i;
len = strlen(options[i].name);
if (len > octs)
octs = len;
len = utf_mbswidth(options[i].name);
if (len > oi.opt_width) if (len > oi.opt_width)
oi.opt_width = len; oi.opt_width = len;
} }
++i;
}
print_columns(shl_stdout, n, options_fmt_entry, &oi, print_columns(shl_stdout, n, options_fmt_entry, &oi,
oi.opt_width + 5, 1); octs + 4, oi.opt_width + 4, true);
} else { } else {
/* short version ala ksh93 */ /* short version á la AT&T ksh93 */
shf_puts("set", shl_stdout); shf_puts("set", shl_stdout);
for (i = 0; i < NELEM(options); i++) while (i < (int)NELEM(options)) {
if (Flag(i) && options[i].name) if (Flag(i) && options[i].name)
shprintf(" -o %s", options[i].name); shprintf(" -o %s", options[i].name);
++i;
}
shf_putc('\n', shl_stdout); shf_putc('\n', shl_stdout);
} }
} }
@ -899,53 +907,64 @@ print_value_quoted(const char *s)
shf_putc('\'', shl_stdout); shf_putc('\'', shl_stdout);
} }
/* Print things in columns and rows - func() is called to format the ith /*
* element * Print things in columns and rows - func() is called to format
* the i-th element
*/ */
void void
print_columns(struct shf *shf, int n, print_columns(struct shf *shf, int n,
char *(*func) (const void *, int, char *, int), char *(*func)(char *, int, int, const void *),
const void *arg, int max_width, int prefcol) const void *arg, int max_oct, int max_col, bool prefcol)
{ {
char *str = alloc(max_width + 1, ATEMP);
int i, r, c, rows, cols, nspace; int i, r, c, rows, cols, nspace;
char *str;
if (n <= 0) {
#ifndef MKSH_SMALL
internal_warningf("print_columns called with n=%d <= 0", n);
#endif
return;
}
++max_oct;
str = alloc(max_oct, ATEMP);
/* ensure x_cols is valid first */ /* ensure x_cols is valid first */
if (x_cols < MIN_COLS) if (x_cols < MIN_COLS)
change_winsz(); change_winsz();
/* max_width + 1 for the space. Note that no space /*
* is printed after the last column to avoid problems * We use (max_col + 1) to consider the space separator.
* with terminals that have auto-wrap. * Note that no space is printed after the last column
* to avoid problems with terminals that have auto-wrap.
*/ */
cols = x_cols / (max_width + 1); cols = x_cols / (max_col + 1);
/* if we can only print one column anyway, skip the goo */ /* if we can only print one column anyway, skip the goo */
if (cols < 2) { if (cols < 2) {
for (i = 0; i < n; ++i) for (i = 0; i < n; ++i)
shf_fprintf(shf, "%s \n", shf_fprintf(shf, "%s \n",
(*func)(arg, i, str, max_width + 1)); (*func)(str, max_oct, i, arg));
goto out; goto out;
} }
rows = (n + cols - 1) / cols;
if (prefcol && n && cols > rows) {
int tmp = rows;
rows = cols; rows = (n + cols - 1) / cols;
cols = tmp; if (prefcol && cols > rows) {
if (rows > n) i = rows;
rows = n; rows = cols > n ? n : cols;
cols = i;
} }
nspace = (x_cols - max_width * cols) / cols; max_col = -max_col;
nspace = (x_cols + max_col * cols) / cols;
if (nspace <= 0) if (nspace <= 0)
nspace = 1; nspace = 1;
for (r = 0; r < rows; r++) { for (r = 0; r < rows; r++) {
for (c = 0; c < cols; c++) { for (c = 0; c < cols; c++) {
i = c * rows + r; i = c * rows + r;
if (i < n) { if (i < n) {
shf_fprintf(shf, "%-*s", shf_fprintf(shf, "%*s", max_col,
max_width, (*func)(str, max_oct, i, arg));
(*func)(arg, i, str, max_width + 1));
if (c + 1 < cols) if (c + 1 < cols)
shf_fprintf(shf, "%*s", nspace, null); shf_fprintf(shf, "%*s", nspace, null);
} }

12
sh.h
View File

@ -134,9 +134,9 @@
#endif #endif
#ifdef EXTERN #ifdef EXTERN
__RCSID("$MirOS: src/bin/mksh/sh.h,v 1.359 2009/10/30 00:57:38 tg Exp $"); __RCSID("$MirOS: src/bin/mksh/sh.h,v 1.360 2009/11/09 23:35:11 tg Exp $");
#endif #endif
#define MKSH_VERSION "R39 2009/10/30" #define MKSH_VERSION "R39 2009/11/09"
#ifndef MKSH_INCLUDES_ONLY #ifndef MKSH_INCLUDES_ONLY
@ -1352,8 +1352,8 @@ struct tbl *findcom(const char *, int);
void flushcom(int); void flushcom(int);
const char *search(const char *, const char *, int, int *); const char *search(const char *, const char *, int, int *);
int search_access(const char *, int, int *); int search_access(const char *, int, int *);
int pr_menu(const char *const *); int pr_menu(const char * const *);
int pr_list(char *const *); int pr_list(char * const *);
/* expr.c */ /* expr.c */
int evaluate(const char *, mksh_ari_t *, int, bool); int evaluate(const char *, mksh_ari_t *, int, bool);
int v_evaluate(struct tbl *, const char *, volatile int, bool); int v_evaluate(struct tbl *, const char *, volatile int, bool);
@ -1546,8 +1546,8 @@ void ksh_getopt_reset(Getopt *, int);
int ksh_getopt(const char **, Getopt *, const char *); int ksh_getopt(const char **, Getopt *, const char *);
void print_value_quoted(const char *); void print_value_quoted(const char *);
void print_columns(struct shf *, int, void print_columns(struct shf *, int,
char *(*)(const void *, int, char *, int), char *(*)(char *, int, int, const void *),
const void *, int, int prefcol); const void *, int, int, bool);
void strip_nuls(char *, int); void strip_nuls(char *, int);
int blocking_read(int, char *, int) int blocking_read(int, char *, int)
__bound_att__((bounded (buffer, 2, 3))); __bound_att__((bounded (buffer, 2, 3)));