mirror of
https://git.zap.org.au/git/trader.git
synced 2025-02-02 15:08:13 -05:00
Handle multibyte characters correctly in mkchstr()
Internal processing is now done in terms of wide characters (type wchar_t).
This commit is contained in:
parent
74031a0415
commit
8a7dfcaf99
490
src/intf.c
490
src/intf.c
@ -44,25 +44,31 @@ typedef struct txwin {
|
|||||||
|
|
||||||
// Declarations for argument processing in mkchstr()
|
// Declarations for argument processing in mkchstr()
|
||||||
|
|
||||||
|
#define EILSEQ_REPL '?' // Illegal byte sequence replacement character
|
||||||
|
|
||||||
#define MAXFMTARGS 8 // Maximum number of positional arguments
|
#define MAXFMTARGS 8 // Maximum number of positional arguments
|
||||||
|
|
||||||
enum argument_type {
|
enum argument_type {
|
||||||
TYPE_NONE, // No type yet assigned
|
TYPE_NONE, // No type yet assigned
|
||||||
TYPE_CHAR, // char
|
TYPE_CHAR, // char
|
||||||
|
TYPE_WCHAR, // wchar_t
|
||||||
TYPE_INT, // int
|
TYPE_INT, // int
|
||||||
TYPE_LONGINT, // long int
|
TYPE_LONGINT, // long int
|
||||||
TYPE_DOUBLE, // double
|
TYPE_DOUBLE, // double
|
||||||
TYPE_STRING // const char *
|
TYPE_STRING, // const char *
|
||||||
|
TYPE_WSTRING // const wchar_t *
|
||||||
};
|
};
|
||||||
|
|
||||||
struct argument {
|
struct argument {
|
||||||
enum argument_type a_type;
|
enum argument_type a_type;
|
||||||
union a {
|
union a {
|
||||||
char a_char;
|
char a_char;
|
||||||
|
wchar_t a_wchar;
|
||||||
int a_int;
|
int a_int;
|
||||||
long int a_longint;
|
long int a_longint;
|
||||||
double a_double;
|
double a_double;
|
||||||
const char *a_string;
|
const char *a_string;
|
||||||
|
const wchar_t *a_wstring;
|
||||||
} a;
|
} a;
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -70,9 +76,9 @@ struct argument {
|
|||||||
#define MAXFMTSPECS 16 // Maximum number of conversion specifiers
|
#define MAXFMTSPECS 16 // Maximum number of conversion specifiers
|
||||||
|
|
||||||
struct convspec {
|
struct convspec {
|
||||||
char spec; // Conversion specifier: c d f N s
|
wchar_t spec; // Conversion specifier: c d f N s
|
||||||
int arg_num; // Which variable argument to use
|
int arg_num; // Which variable argument to use
|
||||||
int len; // Length of conversion specifier, 0 = unused
|
ptrdiff_t len; // Length of conversion specifier, 0 = unused
|
||||||
int precision; // Precision value
|
int precision; // Precision value
|
||||||
bool flag_group; // Flag "'" (thousands grouping)
|
bool flag_group; // Flag "'" (thousands grouping)
|
||||||
bool flag_nosym; // Flag "!" (omit currency symbol)
|
bool flag_nosym; // Flag "!" (omit currency symbol)
|
||||||
@ -173,37 +179,39 @@ static void txresize (void);
|
|||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: mkchstr_addch - Add a character to the mkchstr buffer
|
Function: mkchstr_add - Add one character to the mkchstr() buffers
|
||||||
Parameters: chbuf - Pointer to chtype pointer in which to store string
|
Parameters: outbuf - Pointer to wchar_t pointer in which to store char
|
||||||
chbufsize - Pointer to number of chtype elements in chbuf
|
attrbuf - Pointer to chtype pointer in which to store attr
|
||||||
|
count - Pointer to number of wchar_t elements left in outbuf
|
||||||
attr - Character rendition to use
|
attr - Character rendition to use
|
||||||
maxlines - Maximum number of screen lines to use
|
maxlines - Maximum number of screen lines to use
|
||||||
maxwidth - Maximum width of each line, in chars
|
maxwidth - Maximum width of each line, in column positions
|
||||||
line - Pointer to current line number
|
line - Pointer to current line number
|
||||||
width - Pointer to current line width
|
width - Pointer to current line width
|
||||||
lastspc - Pointer to const char * pointer to last space
|
lastspc - Pointer to wchar_t * pointer to last space
|
||||||
|
spcattr - Pointer to corresponding place in attrbuf
|
||||||
widthspc - Pointer to width just before last space
|
widthspc - Pointer to width just before last space
|
||||||
widthbuf - Pointer to buffer to store widths of each line
|
widthbuf - Pointer to buffer to store widths of each line
|
||||||
widthbufsize - Number of int elements in widthbuf
|
widthbufsize - Number of int elements in widthbuf
|
||||||
str - Pointer to const char * pointer to string
|
str - Pointer to const wchar_t * pointer to string
|
||||||
Returns: int - -1 on error (with errno set), 0 otherwise
|
Returns: int - -1 on error (with errno set), 0 otherwise
|
||||||
|
|
||||||
This helper function adds the character **str to **chbuf, using attr as
|
This helper function adds one wide character from **str to **outbuf,
|
||||||
the character rendition (attributes), incrementing both *str and *chbuf
|
and the character rendition attr to **attrbuf, incrementing *str and
|
||||||
and decrementing *chbufsize. If a string is too long for the current
|
*outbuf and decrementing *count. If a string is too long for the
|
||||||
line, a previous space in the current line is converted to a new line
|
current line, a previous space in the current line is converted to a
|
||||||
(if possible), else a new line is inserted into the current location
|
new line (if possible), else a new line is inserted into the current
|
||||||
(if not on the last line). *line, *width, *lastspc, *widthspc and
|
location (if not on the last line). *line, *width, *lastspc, *widthspc
|
||||||
widthbuf[] are all updated appropriately.
|
and widthbuf[] are all updated appropriately.
|
||||||
*/
|
*/
|
||||||
static int mkchstr_addch (chtype *restrict *restrict chbuf,
|
static int mkchstr_add (wchar_t *restrict *restrict outbuf,
|
||||||
int *restrict chbufsize, chtype attr,
|
chtype *restrict *restrict attrbuf,
|
||||||
int maxlines, int maxwidth, int *restrict line,
|
int *restrict count, chtype attr, int maxlines,
|
||||||
int *restrict width,
|
int maxwidth, int *restrict line, int *restrict width,
|
||||||
chtype *restrict *restrict lastspc,
|
wchar_t *restrict *restrict lastspc,
|
||||||
|
chtype *restrict *restrict spcattr,
|
||||||
int *restrict widthspc, int *restrict widthbuf,
|
int *restrict widthspc, int *restrict widthbuf,
|
||||||
int widthbufsize,
|
int widthbufsize, const wchar_t *restrict *restrict str);
|
||||||
const char *restrict *restrict str);
|
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
@ -217,12 +225,27 @@ static int mkchstr_addch (chtype *restrict *restrict chbuf,
|
|||||||
This helper function parses the format string passed to mkchstr(),
|
This helper function parses the format string passed to mkchstr(),
|
||||||
setting the format_arg and format_spec arrays appropriately.
|
setting the format_arg and format_spec arrays appropriately.
|
||||||
*/
|
*/
|
||||||
static int mkchstr_parse (const char *restrict format,
|
static int mkchstr_parse (const wchar_t *restrict format,
|
||||||
struct argument *restrict format_arg,
|
struct argument *restrict format_arg,
|
||||||
struct convspec *restrict format_spec,
|
struct convspec *restrict format_spec,
|
||||||
va_list args);
|
va_list args);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: mkchstr_conv - Convert (wcbuf, attrbuf) to chbuf
|
||||||
|
Parameters: chbuf - Pointer to chtype buffer in which to store string
|
||||||
|
chbufsize - Number of chtype elements in chbuf
|
||||||
|
wcbuf - Wide-character string from which to convert
|
||||||
|
attrbuf - Associated character rendition array
|
||||||
|
Returns: (nothing)
|
||||||
|
|
||||||
|
This helper function converts the wide-character string in wcbuf and
|
||||||
|
the array of character renditions in attrbuf to a chtype * string.
|
||||||
|
*/
|
||||||
|
static void mkchstr_conv (chtype *restrict chbuf, int chbufsize,
|
||||||
|
wchar_t *restrict wcbuf, chtype *restrict attrbuf);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: txinput_fixup - Copy strings with fixup
|
Function: txinput_fixup - Copy strings with fixup
|
||||||
Parameters: dest - Destination buffer of size BUFSIZE
|
Parameters: dest - Destination buffer of size BUFSIZE
|
||||||
@ -649,15 +672,19 @@ int mkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
// mkchstr_addch: Add a character to the mkchstr buffer
|
// mkchstr_add: Add a character to the mkchstr buffer
|
||||||
|
|
||||||
int mkchstr_addch (chtype *restrict *restrict chbuf, int *restrict chbufsize,
|
int mkchstr_add (wchar_t *restrict *restrict outbuf,
|
||||||
chtype attr, int maxlines, int maxwidth,
|
chtype *restrict *restrict attrbuf, int *restrict count,
|
||||||
int *restrict line, int *restrict width,
|
chtype attr, int maxlines, int maxwidth, int *restrict line,
|
||||||
chtype *restrict *restrict lastspc, int *restrict widthspc,
|
int *restrict width, wchar_t *restrict *restrict lastspc,
|
||||||
|
chtype *restrict *restrict spcattr, int *restrict widthspc,
|
||||||
int *restrict widthbuf, int widthbufsize,
|
int *restrict widthbuf, int widthbufsize,
|
||||||
const char *restrict *restrict str)
|
const wchar_t *restrict *restrict str)
|
||||||
{
|
{
|
||||||
|
int w, wspc;
|
||||||
|
|
||||||
|
|
||||||
if (*line < 0) {
|
if (*line < 0) {
|
||||||
// First character in buffer: start line 0
|
// First character in buffer: start line 0
|
||||||
*line = 0;
|
*line = 0;
|
||||||
@ -667,67 +694,88 @@ int mkchstr_addch (chtype *restrict *restrict chbuf, int *restrict chbufsize,
|
|||||||
// Start a new line
|
// Start a new line
|
||||||
|
|
||||||
if (*line < maxlines - 1) {
|
if (*line < maxlines - 1) {
|
||||||
*(*chbuf)++ = '\n';
|
*(*outbuf)++ = '\n';
|
||||||
(*chbufsize)--;
|
*(*attrbuf)++ = 0;
|
||||||
|
(*count)--;
|
||||||
}
|
}
|
||||||
|
|
||||||
widthbuf[*line] = *width;
|
widthbuf[*line] = *width;
|
||||||
*width = 0;
|
*width = 0;
|
||||||
|
|
||||||
*lastspc = NULL;
|
*lastspc = NULL;
|
||||||
|
*spcattr = NULL;
|
||||||
*widthspc = 0;
|
*widthspc = 0;
|
||||||
|
|
||||||
(*line)++;
|
(*line)++;
|
||||||
(*str)++;
|
(*str)++;
|
||||||
} else if (*width == maxwidth) {
|
} else {
|
||||||
// Current line is now too long
|
w = wcwidth(**str);
|
||||||
|
if (w < 0) {
|
||||||
|
// We don't support control or non-printable characters
|
||||||
|
errno = EILSEQ;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (! isspace(**str) && *lastspc != NULL && *line < maxlines - 1) {
|
if (*width + w > maxwidth) {
|
||||||
|
// Current line would be too long to fit in **str
|
||||||
|
|
||||||
|
if (! iswspace(**str) && *lastspc != NULL && *line < maxlines - 1) {
|
||||||
// Break on the last space in this line
|
// Break on the last space in this line
|
||||||
|
wspc = wcwidth(**lastspc);
|
||||||
|
|
||||||
**lastspc = '\n';
|
**lastspc = '\n';
|
||||||
|
**spcattr = 0;
|
||||||
|
|
||||||
widthbuf[*line] = *widthspc;
|
widthbuf[*line] = *widthspc;
|
||||||
*width -= *widthspc + 1;
|
*width -= *widthspc + wspc;
|
||||||
|
|
||||||
*lastspc = NULL;
|
*lastspc = NULL;
|
||||||
|
*spcattr = NULL;
|
||||||
*widthspc = 0;
|
*widthspc = 0;
|
||||||
|
|
||||||
(*line)++;
|
(*line)++;
|
||||||
} else {
|
} else {
|
||||||
// Insert a new-line character (if not on last line)
|
// Insert a new-line character (if not on last line)
|
||||||
if (*line < maxlines - 1) {
|
if (*line < maxlines - 1) {
|
||||||
*(*chbuf)++ = '\n';
|
*(*outbuf)++ = '\n';
|
||||||
(*chbufsize)--;
|
*(*attrbuf)++ = 0;
|
||||||
|
(*count)--;
|
||||||
}
|
}
|
||||||
|
|
||||||
widthbuf[*line] = *width;
|
widthbuf[*line] = *width;
|
||||||
*width = 0;
|
*width = 0;
|
||||||
|
|
||||||
*lastspc = NULL;
|
*lastspc = NULL;
|
||||||
|
*spcattr = NULL;
|
||||||
*widthspc = 0;
|
*widthspc = 0;
|
||||||
|
|
||||||
(*line)++;
|
(*line)++;
|
||||||
|
|
||||||
// Skip any following spaces
|
/* Skip any following spaces. This assumes that no-one
|
||||||
while (isspace(**str)) {
|
will ever have combining diacritical marks following a
|
||||||
|
(line-breaking) space! */
|
||||||
|
while (iswspace(**str)) {
|
||||||
if (*(*str)++ == '\n') {
|
if (*(*str)++ == '\n') {
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// Insert an ordinary character into the output string
|
// Insert an ordinary character into the output buffer
|
||||||
|
|
||||||
if (isspace(**str)) {
|
if (iswspace(**str)) {
|
||||||
*lastspc = *chbuf;
|
*lastspc = *outbuf;
|
||||||
|
*spcattr = *attrbuf;
|
||||||
*widthspc = *width;
|
*widthspc = *width;
|
||||||
}
|
}
|
||||||
|
|
||||||
*(*chbuf)++ = (unsigned char) **str | attr;
|
*(*outbuf)++ = **str;
|
||||||
(*chbufsize)--;
|
*(*attrbuf)++ = attr;
|
||||||
(*width)++;
|
(*count)--;
|
||||||
|
*width += w;
|
||||||
(*str)++;
|
(*str)++;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
@ -736,7 +784,7 @@ int mkchstr_addch (chtype *restrict *restrict chbuf, int *restrict chbufsize,
|
|||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
// mkchstr_parse: Parse the format string for mkchstr()
|
// mkchstr_parse: Parse the format string for mkchstr()
|
||||||
|
|
||||||
int mkchstr_parse (const char *restrict format,
|
int mkchstr_parse (const wchar_t *restrict format,
|
||||||
struct argument *restrict format_arg,
|
struct argument *restrict format_arg,
|
||||||
struct convspec *restrict format_spec, va_list args)
|
struct convspec *restrict format_spec, va_list args)
|
||||||
{
|
{
|
||||||
@ -770,7 +818,7 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
// Ignore "%%" specifier
|
// Ignore "%%" specifier
|
||||||
format++;
|
format++;
|
||||||
} else {
|
} else {
|
||||||
const char *start = format;
|
const wchar_t *start = format;
|
||||||
enum argument_type arg_type;
|
enum argument_type arg_type;
|
||||||
bool inspec = true;
|
bool inspec = true;
|
||||||
bool flag_posn = false; // Have we already seen "$"?
|
bool flag_posn = false; // Have we already seen "$"?
|
||||||
@ -778,8 +826,8 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
while (inspec && *format != '\0') {
|
while (inspec && *format != '\0') {
|
||||||
char c = *format++;
|
wchar_t wc = *format++;
|
||||||
switch (c) {
|
switch (wc) {
|
||||||
case '0':
|
case '0':
|
||||||
// Zero flag, or part of numeric count
|
// Zero flag, or part of numeric count
|
||||||
if (count == 0) {
|
if (count == 0) {
|
||||||
@ -801,7 +849,7 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
case '8':
|
case '8':
|
||||||
case '9':
|
case '9':
|
||||||
// Part of some numeric count
|
// Part of some numeric count
|
||||||
count = count * 10 + (c - '0');
|
count = count * 10 + (wc - '0');
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '$':
|
case '$':
|
||||||
@ -867,15 +915,15 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case 'c':
|
case 'c':
|
||||||
// Insert a character (char)
|
// Insert a character (char or wchar_t)
|
||||||
if (format_spec->flag_group || format_spec->flag_nosym
|
if (format_spec->flag_group || format_spec->flag_nosym
|
||||||
|| format_spec->flag_prec || format_spec->flag_long
|
|| format_spec->flag_prec || count != 0) {
|
||||||
|| count != 0) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_type = TYPE_CHAR;
|
arg_type = format_spec->flag_long ?
|
||||||
|
TYPE_WCHAR : TYPE_CHAR;
|
||||||
goto handlefmt;
|
goto handlefmt;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
@ -915,15 +963,15 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
goto handlefmt;
|
goto handlefmt;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
// Insert a string (const char *)
|
// Insert a string (const char * or const wchar_t *)
|
||||||
if (format_spec->flag_group || format_spec->flag_nosym
|
if (format_spec->flag_group || format_spec->flag_nosym
|
||||||
|| format_spec->flag_prec || format_spec->flag_long
|
|| format_spec->flag_prec || count != 0) {
|
||||||
|| count != 0) {
|
|
||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
arg_type = TYPE_STRING;
|
arg_type = format_spec->flag_long ?
|
||||||
|
TYPE_WSTRING : TYPE_STRING;
|
||||||
|
|
||||||
handlefmt:
|
handlefmt:
|
||||||
if (arg_num >= MAXFMTARGS || specs_left == 0) {
|
if (arg_num >= MAXFMTARGS || specs_left == 0) {
|
||||||
@ -940,7 +988,7 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
|
|
||||||
format_spec->len = format - start;
|
format_spec->len = format - start;
|
||||||
format_spec->arg_num = arg_num;
|
format_spec->arg_num = arg_num;
|
||||||
format_spec->spec = c;
|
format_spec->spec = wc;
|
||||||
|
|
||||||
arg_num++;
|
arg_num++;
|
||||||
num_args = MAX(num_args, arg_num);
|
num_args = MAX(num_args, arg_num);
|
||||||
@ -975,6 +1023,10 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
format_arg->a.a_char = (char) va_arg(args, int);
|
format_arg->a.a_char = (char) va_arg(args, int);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_WCHAR:
|
||||||
|
format_arg->a.a_wchar = va_arg(args, wchar_t);
|
||||||
|
break;
|
||||||
|
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
format_arg->a.a_int = va_arg(args, int);
|
format_arg->a.a_int = va_arg(args, int);
|
||||||
break;
|
break;
|
||||||
@ -991,6 +1043,10 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
format_arg->a.a_string = va_arg(args, const char *);
|
format_arg->a.a_string = va_arg(args, const char *);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case TYPE_WSTRING:
|
||||||
|
format_arg->a.a_wstring = va_arg(args, const wchar_t *);
|
||||||
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
/* Cannot allow unused arguments, as we have no way of
|
/* Cannot allow unused arguments, as we have no way of
|
||||||
knowing how much space they take (cf. int vs. long long
|
knowing how much space they take (cf. int vs. long long
|
||||||
@ -1004,6 +1060,77 @@ int mkchstr_parse (const char *restrict format,
|
|||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// mkchstr_conv: Convert (wcbuf, attrbuf) to chbuf
|
||||||
|
|
||||||
|
void mkchstr_conv (chtype *restrict chbuf, int chbufsize,
|
||||||
|
wchar_t *restrict wcbuf, chtype *restrict attrbuf)
|
||||||
|
{
|
||||||
|
char *convbuf = xmalloc(chbufsize);
|
||||||
|
mbstate_t mbstate;
|
||||||
|
wchar_t *wp;
|
||||||
|
char *p;
|
||||||
|
bool done;
|
||||||
|
size_t n;
|
||||||
|
|
||||||
|
|
||||||
|
/* Perform a preliminary conversion to weed out any problems with
|
||||||
|
EILSEQ and insufficient buffer space. */
|
||||||
|
while (true) {
|
||||||
|
memset(&mbstate, 0, sizeof(mbstate));
|
||||||
|
wp = wcbuf;
|
||||||
|
if (wcsrtombs(convbuf, (const wchar_t **) &wp, chbufsize, &mbstate)
|
||||||
|
== (size_t) -1) {
|
||||||
|
if (errno == EILSEQ) {
|
||||||
|
/* Replace problematic wide characters with a known-good
|
||||||
|
(ASCII) one. This is better than terminating! */
|
||||||
|
*wp = EILSEQ_REPL;
|
||||||
|
} else {
|
||||||
|
errno_exit("mkchstr_conv: `%ls'", wcbuf);
|
||||||
|
}
|
||||||
|
} else if (wp != NULL) {
|
||||||
|
// convbuf is too small: truncate wcbuf if possible
|
||||||
|
if (wp == wcbuf) {
|
||||||
|
errno = E2BIG;
|
||||||
|
errno_exit("mkchstr_conv: `%ls'", wcbuf);
|
||||||
|
} else {
|
||||||
|
*(wp - 1) = '\0';
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// wcbuf CAN fit into convbuf when converted
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Convert for real, combining each multibyte character with attrbuf
|
||||||
|
memset(&mbstate, 0, sizeof(mbstate));
|
||||||
|
done = false;
|
||||||
|
while (! done) {
|
||||||
|
// Yes, we want to convert a wide NUL, too!
|
||||||
|
if ((n = wcrtomb(convbuf, *wcbuf, &mbstate)) == (size_t) -1) {
|
||||||
|
errno_exit("mkchstr_conv: `%ls'", wcbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
for (p = convbuf; n > 0; n--, p++, chbuf++) {
|
||||||
|
if (*p == '\0' || *p == '\n') {
|
||||||
|
/* This code assumes '\n' can never appear in a multibyte
|
||||||
|
string except as a control character---which is true
|
||||||
|
of all multibyte encodings (I believe!) */
|
||||||
|
*chbuf = (unsigned char) *p;
|
||||||
|
} else {
|
||||||
|
*chbuf = (unsigned char) *p | *attrbuf;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
done = (*wcbuf == '\0');
|
||||||
|
wcbuf++;
|
||||||
|
attrbuf++;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(convbuf);
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
// vmkchstr: Prepare a string for printing to screen
|
// vmkchstr: Prepare a string for printing to screen
|
||||||
|
|
||||||
@ -1012,12 +1139,20 @@ int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
int *restrict widthbuf, int widthbufsize,
|
int *restrict widthbuf, int widthbufsize,
|
||||||
const char *restrict format, va_list args)
|
const char *restrict format, va_list args)
|
||||||
{
|
{
|
||||||
const char *orig_format = format;
|
|
||||||
struct argument format_arg[MAXFMTARGS];
|
struct argument format_arg[MAXFMTARGS];
|
||||||
struct convspec format_spec[MAXFMTSPECS];
|
struct convspec format_spec[MAXFMTSPECS];
|
||||||
struct convspec *spec;
|
struct convspec *spec;
|
||||||
int line, width;
|
const wchar_t *wcformat;
|
||||||
chtype *lastspc;
|
wchar_t *orig_wcformat;
|
||||||
|
mbstate_t mbstate;
|
||||||
|
|
||||||
|
wchar_t *outbuf, *orig_outbuf;
|
||||||
|
chtype *attrbuf, *orig_attrbuf;
|
||||||
|
wchar_t *fmtbuf;
|
||||||
|
|
||||||
|
int count, line, width;
|
||||||
|
wchar_t *lastspc;
|
||||||
|
chtype *spcattr;
|
||||||
int widthspc;
|
int widthspc;
|
||||||
chtype curattr;
|
chtype curattr;
|
||||||
int saved_errno;
|
int saved_errno;
|
||||||
@ -1025,55 +1160,78 @@ int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
|
|
||||||
assert(chbuf != NULL);
|
assert(chbuf != NULL);
|
||||||
assert(chbufsize > 0);
|
assert(chbufsize > 0);
|
||||||
|
assert(chbufsize <= BUFSIZE);
|
||||||
assert(maxlines > 0);
|
assert(maxlines > 0);
|
||||||
assert(maxwidth > 0);
|
assert(maxwidth > 0);
|
||||||
assert(widthbuf != NULL);
|
assert(widthbuf != NULL);
|
||||||
assert(widthbufsize >= maxlines);
|
assert(widthbufsize >= maxlines);
|
||||||
assert(format != NULL);
|
assert(format != NULL);
|
||||||
|
|
||||||
if (mkchstr_parse(format, format_arg, format_spec, args) < 0) {
|
outbuf = orig_outbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||||
|
attrbuf = orig_attrbuf = xmalloc(BUFSIZE * sizeof(chtype));
|
||||||
|
wcformat = orig_wcformat = xmalloc(chbufsize * sizeof(wchar_t));
|
||||||
|
fmtbuf = xmalloc(BUFSIZE * sizeof(wchar_t));
|
||||||
|
|
||||||
|
// Convert format to a wide-character string
|
||||||
|
{
|
||||||
|
memset(&mbstate, 0, sizeof(mbstate));
|
||||||
|
const char *p = format;
|
||||||
|
if (mbsrtowcs(orig_wcformat, &p, BUFSIZE, &mbstate) == (size_t) -1) {
|
||||||
|
goto error;
|
||||||
|
} else if (p != NULL) {
|
||||||
|
errno = E2BIG;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (mkchstr_parse(wcformat, format_arg, format_spec, args) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
// Construct the (outbuf, attrbuf) pair of arrays
|
||||||
|
|
||||||
spec = format_spec;
|
spec = format_spec;
|
||||||
|
|
||||||
curattr = attr_norm;
|
curattr = attr_norm;
|
||||||
|
count = BUFSIZE; // Space left in outbuf
|
||||||
line = -1; // Current line number (0 = first)
|
line = -1; // Current line number (0 = first)
|
||||||
width = 0; // Width of the current line
|
width = 0; // Width of the current line
|
||||||
|
|
||||||
lastspc = NULL; // Pointer to last space in line
|
lastspc = NULL; // Pointer to last space in line
|
||||||
|
spcattr = NULL; // Equivalent in attrbuf
|
||||||
widthspc = 0; // Width of line before last space
|
widthspc = 0; // Width of line before last space
|
||||||
|
|
||||||
while (*format != '\0' && chbufsize > 1 && line < maxlines) {
|
while (*wcformat != '\0' && count > 1 && line < maxlines) {
|
||||||
switch (*format) {
|
switch (*wcformat) {
|
||||||
case '^':
|
case '^':
|
||||||
// Switch to a different character rendition
|
// Switch to a different character rendition
|
||||||
if (*++format == '\0') {
|
if (*++wcformat == '\0') {
|
||||||
goto error_inval;
|
goto error_inval;
|
||||||
} else {
|
} else {
|
||||||
switch (*format) {
|
switch (*wcformat) {
|
||||||
case '^':
|
case '^':
|
||||||
if (mkchstr_addch(&chbuf, &chbufsize, curattr, maxlines,
|
if (mkchstr_add(&outbuf, &attrbuf, &count, curattr,
|
||||||
maxwidth, &line, &width, &lastspc,
|
maxlines, maxwidth, &line, &width,
|
||||||
&widthspc, widthbuf, widthbufsize,
|
&lastspc, &spcattr, &widthspc, widthbuf,
|
||||||
&format) < 0) {
|
widthbufsize, &wcformat) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '{':
|
case '{':
|
||||||
curattr = attr_alt1;
|
curattr = attr_alt1;
|
||||||
format++;
|
wcformat++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '[':
|
case '[':
|
||||||
curattr = attr_alt2;
|
curattr = attr_alt2;
|
||||||
format++;
|
wcformat++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case '}':
|
case '}':
|
||||||
case ']':
|
case ']':
|
||||||
curattr = attr_norm;
|
curattr = attr_norm;
|
||||||
format++;
|
wcformat++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
@ -1084,86 +1242,82 @@ int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
|
|
||||||
case '%':
|
case '%':
|
||||||
// Process a conversion specifier
|
// Process a conversion specifier
|
||||||
if (*++format == '\0') {
|
if (*++wcformat == '\0') {
|
||||||
goto error_inval;
|
goto error_inval;
|
||||||
} else if (*format == '%') {
|
} else if (*wcformat == '%') {
|
||||||
if (mkchstr_addch(&chbuf, &chbufsize, curattr, maxlines,
|
if (mkchstr_add(&outbuf, &attrbuf, &count, curattr, maxlines,
|
||||||
maxwidth, &line, &width, &lastspc, &widthspc,
|
maxwidth, &line, &width, &lastspc, &spcattr,
|
||||||
widthbuf, widthbufsize, &format) < 0) {
|
&widthspc, widthbuf, widthbufsize, &wcformat)
|
||||||
|
< 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
assert(spec->len != 0);
|
assert(spec->len != 0);
|
||||||
|
const wchar_t *str;
|
||||||
const char *str;
|
wint_t wc;
|
||||||
char *buf = xmalloc(BUFSIZE);
|
|
||||||
|
|
||||||
switch (spec->spec) {
|
switch (spec->spec) {
|
||||||
case 'c':
|
case 'c':
|
||||||
// Insert a character (char) into the output
|
// Insert a character (char or wchar_t) into the output
|
||||||
if (snprintf(buf, BUFSIZE, "%c",
|
if (spec->flag_long) {
|
||||||
format_arg[spec->arg_num].a.a_char) < 0) {
|
wc = format_arg[spec->arg_num].a.a_wchar;
|
||||||
saved_errno = errno;
|
} else {
|
||||||
free(buf);
|
wc = btowc(format_arg[spec->arg_num].a.a_char);
|
||||||
errno = saved_errno;
|
}
|
||||||
|
|
||||||
|
if (wc == '\0' || wc == WEOF) {
|
||||||
|
errno = EILSEQ;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = buf;
|
fmtbuf[0] = wc;
|
||||||
|
fmtbuf[1] = '\0';
|
||||||
|
|
||||||
|
str = fmtbuf;
|
||||||
goto insertstr;
|
goto insertstr;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
// Insert an integer (int or long int) into the output
|
// Insert an integer (int or long int) into the output
|
||||||
if (spec->flag_long) {
|
if (spec->flag_long) {
|
||||||
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
if (swprintf(fmtbuf, BUFSIZE, spec->flag_group ?
|
||||||
"%'ld" : "%ld",
|
L"%'ld" : L"%ld",
|
||||||
format_arg[spec->arg_num].a.a_longint) < 0) {
|
format_arg[spec->arg_num].a.a_longint) < 0)
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
if (swprintf(fmtbuf, BUFSIZE, spec->flag_group ?
|
||||||
"%'d" : "%d",
|
L"%'d" : L"%d",
|
||||||
format_arg[spec->arg_num].a.a_int) < 0) {
|
format_arg[spec->arg_num].a.a_int) < 0)
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
str = buf;
|
str = fmtbuf;
|
||||||
goto insertstr;
|
goto insertstr;
|
||||||
|
|
||||||
case 'f':
|
case 'f':
|
||||||
// Insert a floating-point number (double) into the output
|
// Insert a floating-point number (double) into the output
|
||||||
if (spec->flag_prec) {
|
if (spec->flag_prec) {
|
||||||
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
if (swprintf(fmtbuf, BUFSIZE, spec->flag_group ?
|
||||||
"%'.*f" : "%.*f", spec->precision,
|
L"%'.*f" : L"%.*f", spec->precision,
|
||||||
format_arg[spec->arg_num].a.a_double) < 0) {
|
format_arg[spec->arg_num].a.a_double) < 0)
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
|
||||||
} else {
|
} else {
|
||||||
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
if (swprintf(fmtbuf, BUFSIZE, spec->flag_group ?
|
||||||
"%'f" : "%f",
|
L"%'f" : L"%f",
|
||||||
format_arg[spec->arg_num].a.a_double) < 0) {
|
format_arg[spec->arg_num].a.a_double) < 0)
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
str = buf;
|
str = fmtbuf;
|
||||||
goto insertstr;
|
goto insertstr;
|
||||||
|
|
||||||
case 'N':
|
case 'N':
|
||||||
// Insert a monetary amount (double) into the output
|
// Insert a monetary amount (double) into the output
|
||||||
|
{
|
||||||
|
/* strfmon() is not available in a wide-char
|
||||||
|
version, so we need a multibyte char buffer */
|
||||||
|
char *buf = xmalloc(BUFSIZE);
|
||||||
|
const char *p = buf;
|
||||||
|
|
||||||
if (l_strfmon(buf, BUFSIZE, spec->flag_nosym ? "%!n" : "%n",
|
if (l_strfmon(buf, BUFSIZE, spec->flag_nosym ? "%!n" : "%n",
|
||||||
format_arg[spec->arg_num].a.a_double) < 0) {
|
format_arg[spec->arg_num].a.a_double) < 0) {
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
@ -1172,54 +1326,83 @@ int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = buf;
|
memset(&mbstate, 0, sizeof(mbstate));
|
||||||
goto insertstr;
|
if (mbsrtowcs(fmtbuf, &p, BUFSIZE, &mbstate)
|
||||||
|
== (size_t) -1) {
|
||||||
case 's':
|
|
||||||
// Insert a string (const char *) into the output
|
|
||||||
str = format_arg[spec->arg_num].a.a_string;
|
|
||||||
|
|
||||||
if (str == NULL) {
|
|
||||||
str = "(null)"; // As per GNU printf()
|
|
||||||
}
|
|
||||||
|
|
||||||
insertstr:
|
|
||||||
// Insert the string pointed to by str
|
|
||||||
while (*str != '\0' && chbufsize > 1 && line < maxlines) {
|
|
||||||
if (mkchstr_addch(&chbuf, &chbufsize, curattr,
|
|
||||||
maxlines, maxwidth, &line, &width,
|
|
||||||
&lastspc, &widthspc, widthbuf,
|
|
||||||
widthbufsize, &str) < 0) {
|
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
free(buf);
|
free(buf);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
goto error;
|
goto error;
|
||||||
|
} else if (p != NULL) {
|
||||||
|
free(buf);
|
||||||
|
errno = E2BIG;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
free(buf);
|
||||||
|
}
|
||||||
|
|
||||||
|
str = fmtbuf;
|
||||||
|
goto insertstr;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
// Insert a string (const char * or const wchar_t *)
|
||||||
|
if (spec->flag_long) {
|
||||||
|
str = format_arg[spec->arg_num].a.a_wstring;
|
||||||
|
} else {
|
||||||
|
const char *p = format_arg[spec->arg_num].a.a_string;
|
||||||
|
if (p == NULL) {
|
||||||
|
str = NULL;
|
||||||
|
} else {
|
||||||
|
memset(&mbstate, 0, sizeof(mbstate));
|
||||||
|
if (mbsrtowcs(fmtbuf, &p, BUFSIZE, &mbstate)
|
||||||
|
== (size_t) -1) {
|
||||||
|
goto error;
|
||||||
|
} else if (p != NULL) {
|
||||||
|
errno = E2BIG;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
str = fmtbuf;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
format += spec->len;
|
if (str == NULL) {
|
||||||
|
str = L"(null)"; // As per GNU printf()
|
||||||
|
}
|
||||||
|
|
||||||
|
insertstr:
|
||||||
|
// Insert the string pointed to by str
|
||||||
|
while (*str != '\0' && count > 1 && line < maxlines) {
|
||||||
|
if (mkchstr_add(&outbuf, &attrbuf, &count, curattr,
|
||||||
|
maxlines, maxwidth, &line, &width,
|
||||||
|
&lastspc, &spcattr, &widthspc,
|
||||||
|
widthbuf, widthbufsize, &str) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
wcformat += spec->len;
|
||||||
spec++;
|
spec++;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
assert(spec->spec);
|
assert(spec->spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
// Process an ordinary character (including new-line)
|
// Process an ordinary character (including new-line)
|
||||||
if (mkchstr_addch(&chbuf, &chbufsize, curattr, maxlines, maxwidth,
|
if (mkchstr_add(&outbuf, &attrbuf, &count, curattr, maxlines,
|
||||||
&line, &width, &lastspc, &widthspc, widthbuf,
|
maxwidth, &line, &width, &lastspc, &spcattr,
|
||||||
widthbufsize, &format) < 0) {
|
&widthspc, widthbuf, widthbufsize, &wcformat) < 0) {
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
*chbuf = 0; // Terminating NUL byte
|
*outbuf = '\0'; // Terminating NUL character
|
||||||
|
*attrbuf = 0;
|
||||||
|
|
||||||
if (line >= 0 && line < maxlines) {
|
if (line >= 0 && line < maxlines) {
|
||||||
widthbuf[line] = width;
|
widthbuf[line] = width;
|
||||||
@ -1227,6 +1410,14 @@ int vmkchstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
line = maxlines - 1;
|
line = maxlines - 1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Convert the (outbuf, attrbuf) pair of arrays to chbuf
|
||||||
|
mkchstr_conv(chbuf, chbufsize, orig_outbuf, orig_attrbuf);
|
||||||
|
|
||||||
|
free(fmtbuf);
|
||||||
|
free(orig_wcformat);
|
||||||
|
free(orig_attrbuf);
|
||||||
|
free(orig_outbuf);
|
||||||
|
|
||||||
return line + 1;
|
return line + 1;
|
||||||
|
|
||||||
|
|
||||||
@ -1234,7 +1425,14 @@ error_inval:
|
|||||||
errno = EINVAL;
|
errno = EINVAL;
|
||||||
|
|
||||||
error:
|
error:
|
||||||
errno_exit(_("mkchstr: `%s'"), orig_format);
|
saved_errno = errno;
|
||||||
|
free(fmtbuf);
|
||||||
|
free(orig_wcformat);
|
||||||
|
free(orig_attrbuf);
|
||||||
|
free(orig_outbuf);
|
||||||
|
errno = saved_errno;
|
||||||
|
|
||||||
|
errno_exit(_("mkchstr: `%s'"), format);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
25
src/intf.h
25
src/intf.h
@ -43,8 +43,7 @@
|
|||||||
/*
|
/*
|
||||||
This version of Star Traders only utilises WIN_COLS x WIN_LINES of a
|
This version of Star Traders only utilises WIN_COLS x WIN_LINES of a
|
||||||
terminal screen; this terminal must be at least MIN_COLS x MIN_LINES in
|
terminal screen; this terminal must be at least MIN_COLS x MIN_LINES in
|
||||||
size. The newtxwin() function automatically places a new window in the
|
size. Windows are placed in the centre-top of the terminal screen.
|
||||||
centre-top of the terminal screen.
|
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#define MIN_LINES 24 // Minimum number of lines in terminal
|
#define MIN_LINES 24 // Minimum number of lines in terminal
|
||||||
@ -57,6 +56,7 @@
|
|||||||
|
|
||||||
#define MAX_DLG_LINES 10 // Default maximum lines of text in dialog box
|
#define MAX_DLG_LINES 10 // Default maximum lines of text in dialog box
|
||||||
|
|
||||||
|
// Space (number of terminal columns) to allow for various fields
|
||||||
#define YESNO_COLS 4 // Space to allow for "Yes" or "No" response
|
#define YESNO_COLS 4 // Space to allow for "Yes" or "No" response
|
||||||
#define ORDINAL_COLS 5 // Space for ordinals (1st, 2nd, etc)
|
#define ORDINAL_COLS 5 // Space for ordinals (1st, 2nd, etc)
|
||||||
#define TOTAL_VALUE_COLS 18 // Space for total value (monetary)
|
#define TOTAL_VALUE_COLS 18 // Space for total value (monetary)
|
||||||
@ -288,13 +288,13 @@ extern int txrefresh (void);
|
|||||||
alt2_attr - Alternate character rendition 2 (more highlighted)
|
alt2_attr - Alternate character rendition 2 (more highlighted)
|
||||||
keywait_attr - "Press any key" character rendition
|
keywait_attr - "Press any key" character rendition
|
||||||
boxtitle - Dialog box title (may be NULL)
|
boxtitle - Dialog box title (may be NULL)
|
||||||
format - Dialog box text, as passed to prepstr()
|
format - Dialog box text, as passed to mkchstr()
|
||||||
... - Dialog box text format parameters
|
... - Dialog box text format parameters
|
||||||
Returns: int - OK is always returned
|
Returns: int - OK is always returned
|
||||||
|
|
||||||
This function creates a dialog box window using newtxwin(), displays
|
This function creates a dialog box window using newtxwin(), displays
|
||||||
boxtitle centred on the first line (if boxtitle is not NULL), displays
|
boxtitle centred on the first line (if boxtitle is not NULL), displays
|
||||||
format (and associated parameters) centred using prepstr(), then waits
|
format (and associated parameters) centred using mkchstr(), then waits
|
||||||
for the user to press any key before closing the dialog box window.
|
for the user to press any key before closing the dialog box window.
|
||||||
Note that txrefresh() is NOT called once the window is closed.
|
Note that txrefresh() is NOT called once the window is closed.
|
||||||
*/
|
*/
|
||||||
@ -330,10 +330,12 @@ extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
|
|||||||
The format string is similar to but more limited than printf(). In
|
The format string is similar to but more limited than printf(). In
|
||||||
particular, only the following conversion specifiers are understood:
|
particular, only the following conversion specifiers are understood:
|
||||||
|
|
||||||
%% - Print the ASCII percent sign (ASCII code U+0025)
|
%% - Insert the ASCII percent sign (ASCII code U+0025)
|
||||||
|
|
||||||
%c - Insert the next parameter as a character (type char)
|
%c - Insert the next parameter as a character (type char)
|
||||||
|
%lc - Insert the next parameter as a wide char (type wchar_t)
|
||||||
%s - Insert the next parameter as a string (type char *)
|
%s - Insert the next parameter as a string (type char *)
|
||||||
|
%ls - Insert the next parameter as a wide string (type wchar_t *)
|
||||||
%d - Insert the next parameter as an integer (type int)
|
%d - Insert the next parameter as an integer (type int)
|
||||||
%'d - As above, using the locale's thousands group separator
|
%'d - As above, using the locale's thousands group separator
|
||||||
%ld - Insert the next parameter as a long int
|
%ld - Insert the next parameter as a long int
|
||||||
@ -360,19 +362,16 @@ extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
|
|||||||
rendition flags are understood, where the "^" character is a literal
|
rendition flags are understood, where the "^" character is a literal
|
||||||
ASCII circumflex accent:
|
ASCII circumflex accent:
|
||||||
|
|
||||||
^^ - Print the circumflex accent (ASCII code U+005E)
|
^^ - Insert the circumflex accent (ASCII code U+005E)
|
||||||
^{ - Switch to using attr_alt1 character rendition (alternate mode 1)
|
^{ - Switch to using attr_alt1 character rendition (alternate mode 1)
|
||||||
^} - Switch to using attr_norm character rendition
|
^} - Switch to using attr_norm character rendition
|
||||||
^[ - Switch to using attr_alt2 character rendition (alternate mode 2)
|
^[ - Switch to using attr_alt2 character rendition (alternate mode 2)
|
||||||
^] - Switch to using attr_norm character rendition
|
^] - Switch to using attr_norm character rendition
|
||||||
|
|
||||||
Characters other than these are inserted as literals, except that '\n'
|
Printable characters other than these are inserted as literals. The
|
||||||
will force the start of a new line. By default, attr_norm is used as
|
character '\n' will force the start of a new line; no other control (or
|
||||||
the character rendition (attributes).
|
non-printable) characters are allowed. By default, attr_norm is used
|
||||||
|
as the character rendition (attributes).
|
||||||
Please note that this function does NOT handle multibyte characters
|
|
||||||
correctly: widths may be incorrect (byte count, not actual width) and
|
|
||||||
multibyte characters may be split over two lines.
|
|
||||||
|
|
||||||
This function returns the actual number of lines used (from 0 to
|
This function returns the actual number of lines used (from 0 to
|
||||||
maxlines). If an error is detected, the application terminates.
|
maxlines). If an error is detected, the application terminates.
|
||||||
|
Loading…
x
Reference in New Issue
Block a user