mirror of
https://git.zap.org.au/git/trader.git
synced 2024-12-04 14:46:45 -05:00
Do parse of format string in prepstr_parse(); add the "%c" specifier
This commit is contained in:
parent
746155078b
commit
3ad62688da
476
src/intf.c
476
src/intf.c
@ -48,6 +48,7 @@ typedef struct txwin {
|
|||||||
|
|
||||||
enum argument_type {
|
enum argument_type {
|
||||||
TYPE_NONE, // No type yet assigned
|
TYPE_NONE, // No type yet assigned
|
||||||
|
TYPE_CHAR, // char
|
||||||
TYPE_INT, // int
|
TYPE_INT, // int
|
||||||
TYPE_LONGINT, // long int
|
TYPE_LONGINT, // long int
|
||||||
TYPE_DOUBLE, // double
|
TYPE_DOUBLE, // double
|
||||||
@ -57,6 +58,7 @@ enum argument_type {
|
|||||||
struct argument {
|
struct argument {
|
||||||
enum argument_type a_type;
|
enum argument_type a_type;
|
||||||
union a {
|
union a {
|
||||||
|
char a_char;
|
||||||
int a_int;
|
int a_int;
|
||||||
long int a_longint;
|
long int a_longint;
|
||||||
double a_double;
|
double a_double;
|
||||||
@ -65,6 +67,18 @@ struct argument {
|
|||||||
};
|
};
|
||||||
|
|
||||||
|
|
||||||
|
#define MAXFMTSPECS 16 // Maximum number of conversion specifiers
|
||||||
|
|
||||||
|
struct convspec {
|
||||||
|
int len; // Length of conversion specifier, 0 = unused
|
||||||
|
int arg_num; // Which variable argument to use
|
||||||
|
char spec; // Conversion specifier: c d N s
|
||||||
|
bool flag_group; // Flag "'" (thousands grouping)
|
||||||
|
bool flag_nosym; // Flag "!" (omit currency symbol)
|
||||||
|
bool flag_long; // Length modifier "l" (long)
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Global variable definitions *
|
* Global variable definitions *
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
@ -189,6 +203,23 @@ static int prepstr_addch (chtype *restrict *restrict chbuf,
|
|||||||
const char *restrict *restrict str);
|
const char *restrict *restrict str);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: prepstr_parse - Parse the format string for prepstr()
|
||||||
|
Parameters: format - Format string as described for prepstr()
|
||||||
|
format_arg - Pointer to variable arguments array
|
||||||
|
format_spec - Pointer to conversion specifiers array
|
||||||
|
args - Variable argument list passed to prepstr()
|
||||||
|
Returns: int - 0 if OK, -1 if error (with errno set)
|
||||||
|
|
||||||
|
This helper function parses the format string passed to prepstr(),
|
||||||
|
setting the format_arg and format_spec arrays appropriately.
|
||||||
|
*/
|
||||||
|
static int prepstr_parse (const char *restrict format,
|
||||||
|
struct argument *restrict format_arg,
|
||||||
|
struct convspec *restrict format_spec,
|
||||||
|
va_list args);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -716,48 +747,29 @@ int prepstr_addch (chtype *restrict *restrict chbuf, int *restrict chbufsize,
|
|||||||
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
// vprepstr: Prepare a string for printing to screen
|
// prepstr_parse: Parse the format string for prepstr()
|
||||||
|
|
||||||
int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
int prepstr_parse (const char *restrict format,
|
||||||
chtype attr_alt1, chtype attr_alt2, int maxlines, int maxwidth,
|
struct argument *restrict format_arg,
|
||||||
int *restrict widthbuf, int widthbufsize,
|
struct convspec *restrict format_spec, va_list args)
|
||||||
const char *restrict format, va_list args)
|
|
||||||
{
|
{
|
||||||
struct argument format_arg[MAXFMTARGS];
|
int num_args = 0; // 0 .. MAXFMTARGS
|
||||||
int num_format_args, arg_num;
|
int arg_num = 0; // Current index into format_arg[]
|
||||||
const char *orig_format;
|
int specs_left = MAXFMTSPECS; // MAXFMTSPECS .. 0 (counting down)
|
||||||
int line, width;
|
|
||||||
chtype *lastspc;
|
|
||||||
int widthspc;
|
|
||||||
chtype curattr;
|
|
||||||
int saved_errno;
|
|
||||||
|
|
||||||
|
|
||||||
assert(chbuf != NULL);
|
memset(format_arg, 0, MAXFMTARGS * sizeof(format_arg[0]));
|
||||||
assert(chbufsize > 0);
|
memset(format_spec, 0, MAXFMTSPECS * sizeof(format_spec[0]));
|
||||||
assert(maxlines > 0);
|
|
||||||
assert(maxwidth > 0);
|
|
||||||
assert(widthbuf != NULL);
|
|
||||||
assert(widthbufsize >= maxlines);
|
|
||||||
assert(format != NULL);
|
|
||||||
|
|
||||||
/* Do a preliminary scan through the format parameter to determine
|
|
||||||
the types of each positional argument (conversion specifier). If
|
|
||||||
we did not support "%m$"-style specifiers, this would not be
|
|
||||||
necessary. */
|
|
||||||
|
|
||||||
orig_format = format;
|
|
||||||
memset(format_arg, 0, sizeof(format_arg));
|
|
||||||
num_format_args = 0;
|
|
||||||
arg_num = 0;
|
|
||||||
|
|
||||||
while (*format != '\0') {
|
while (*format != '\0') {
|
||||||
switch (*format++) {
|
switch (*format++) {
|
||||||
case '^':
|
case '^':
|
||||||
// Switch to a different character rendition
|
// Switch to a different character rendition
|
||||||
if (*format == '\0') {
|
if (*format == '\0') {
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
} else {
|
} else {
|
||||||
|
// Ignore next character for now
|
||||||
format++;
|
format++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -765,14 +777,17 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
case '%':
|
case '%':
|
||||||
// Process a conversion specifier
|
// Process a conversion specifier
|
||||||
if (*format == '\0') {
|
if (*format == '\0') {
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
} else if (*format == '%') {
|
} else if (*format == '%') {
|
||||||
|
// Ignore "%%" specifier
|
||||||
format++;
|
format++;
|
||||||
} else {
|
} else {
|
||||||
enum argument_type arg_type = TYPE_NONE;
|
const char *start = format;
|
||||||
|
enum argument_type arg_type;
|
||||||
bool inspec = true;
|
bool inspec = true;
|
||||||
bool flag_posn = false;
|
bool flag_posn = false; // Have we already seen "$"?
|
||||||
bool flag_long = false;
|
bool flag_other = false; // Have we seen something else?
|
||||||
int count = 0;
|
int count = 0;
|
||||||
|
|
||||||
while (inspec && *format != '\0') {
|
while (inspec && *format != '\0') {
|
||||||
@ -780,8 +795,11 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
switch (c) {
|
switch (c) {
|
||||||
case '0':
|
case '0':
|
||||||
// Zero flag, or part of numeric count
|
// Zero flag, or part of numeric count
|
||||||
if (count == 0)
|
if (count == 0) {
|
||||||
goto error_inval;
|
// Zero flag is NOT supported
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
count *= 10;
|
count *= 10;
|
||||||
break;
|
break;
|
||||||
@ -801,12 +819,14 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
|
|
||||||
case '$':
|
case '$':
|
||||||
// Fixed-position argument
|
// Fixed-position argument
|
||||||
if (flag_posn || count == 0)
|
if (flag_posn || flag_other || count == 0) {
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
if (count > MAXFMTARGS) {
|
if (count > MAXFMTARGS) {
|
||||||
errno = E2BIG;
|
errno = E2BIG;
|
||||||
goto error;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
flag_posn = true;
|
flag_posn = true;
|
||||||
@ -815,61 +835,116 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
break;
|
break;
|
||||||
|
|
||||||
case '\'':
|
case '\'':
|
||||||
// Use locale-specific thousands separator
|
// Use locale-specific thousands group separator
|
||||||
|
if (format_spec->flag_group) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_spec->flag_group = true;
|
||||||
|
flag_other = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '!':
|
||||||
|
// Omit the locale-specific currency symbol
|
||||||
|
if (format_spec->flag_nosym) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
format_spec->flag_nosym = true;
|
||||||
|
flag_other = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case 'l':
|
case 'l':
|
||||||
// Long length modifier
|
// Long length modifier
|
||||||
if (flag_long)
|
if (format_spec->flag_long) {
|
||||||
goto error_inval;
|
// "ll" is NOT supported
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
flag_long = true;
|
format_spec->flag_long = true;
|
||||||
|
flag_other = true;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case 'c':
|
||||||
|
// Insert a character (char)
|
||||||
|
if (format_spec->flag_group || format_spec->flag_nosym
|
||||||
|
|| format_spec->flag_long || count != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_type = TYPE_CHAR;
|
||||||
|
goto handlefmt;
|
||||||
|
|
||||||
case 'd':
|
case 'd':
|
||||||
// Insert an integer (int or long int)
|
// Insert an integer (int or long int)
|
||||||
arg_type = flag_long ? TYPE_LONGINT : TYPE_INT;
|
if (count != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_type = format_spec->flag_long ?
|
||||||
|
TYPE_LONGINT : TYPE_INT;
|
||||||
goto handlefmt;
|
goto handlefmt;
|
||||||
|
|
||||||
case 'N':
|
case 'N':
|
||||||
// Insert a monetary amount (double)
|
// Insert a monetary amount (double)
|
||||||
if (flag_long)
|
if (format_spec->flag_group || format_spec->flag_long
|
||||||
goto error_inval;
|
|| count != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
arg_type = TYPE_DOUBLE;
|
arg_type = TYPE_DOUBLE;
|
||||||
goto handlefmt;
|
goto handlefmt;
|
||||||
|
|
||||||
case 's':
|
case 's':
|
||||||
// Insert a string (const char *)
|
// Insert a string (const char *)
|
||||||
if (flag_long)
|
if (format_spec->flag_group || format_spec->flag_nosym
|
||||||
goto error_inval;
|
|| format_spec->flag_long || count != 0) {
|
||||||
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
arg_type = TYPE_STRING;
|
arg_type = TYPE_STRING;
|
||||||
|
|
||||||
handlefmt:
|
handlefmt:
|
||||||
if (arg_num >= MAXFMTARGS) {
|
if (arg_num >= MAXFMTARGS || specs_left == 0) {
|
||||||
errno = E2BIG;
|
errno = E2BIG;
|
||||||
goto error;
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
if (format_arg[arg_num].a_type == TYPE_NONE) {
|
if (format_arg[arg_num].a_type == TYPE_NONE) {
|
||||||
format_arg[arg_num].a_type = arg_type;
|
format_arg[arg_num].a_type = arg_type;
|
||||||
} else if (format_arg[arg_num].a_type != arg_type) {
|
} else if (format_arg[arg_num].a_type != arg_type) {
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
format_spec->len = format - start;
|
||||||
|
format_spec->arg_num = arg_num;
|
||||||
|
format_spec->spec = c;
|
||||||
|
|
||||||
arg_num++;
|
arg_num++;
|
||||||
num_format_args = MAX(num_format_args, arg_num);
|
num_args = MAX(num_args, arg_num);
|
||||||
|
|
||||||
|
format_spec++;
|
||||||
|
specs_left--;
|
||||||
|
|
||||||
inspec = false;
|
inspec = false;
|
||||||
break;
|
break;
|
||||||
|
|
||||||
default:
|
default:
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (inspec) {
|
if (inspec) {
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
@ -880,36 +955,73 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
for (int i = 0; i < num_format_args; i++) {
|
for (int i = 0; i < num_args; format_arg++, i++) {
|
||||||
switch (format_arg[i].a_type) {
|
switch (format_arg->a_type) {
|
||||||
|
case TYPE_CHAR:
|
||||||
|
format_arg->a.a_char = (char) va_arg(args, int);
|
||||||
|
break;
|
||||||
|
|
||||||
case TYPE_INT:
|
case TYPE_INT:
|
||||||
format_arg[i].a.a_int = va_arg(args, int);
|
format_arg->a.a_int = va_arg(args, int);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_LONGINT:
|
case TYPE_LONGINT:
|
||||||
format_arg[i].a.a_longint = va_arg(args, long int);
|
format_arg->a.a_longint = va_arg(args, long int);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_DOUBLE:
|
case TYPE_DOUBLE:
|
||||||
format_arg[i].a.a_double = va_arg(args, double);
|
format_arg->a.a_double = va_arg(args, double);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
case TYPE_STRING:
|
case TYPE_STRING:
|
||||||
format_arg[i].a.a_string = va_arg(args, const char *);
|
format_arg->a.a_string = va_arg(args, const char *);
|
||||||
break;
|
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
|
||||||
int). */
|
int). */
|
||||||
goto error_inval;
|
errno = EINVAL;
|
||||||
|
return -1;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Actually process the format parameter string
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
format = orig_format;
|
|
||||||
arg_num = 0;
|
/***********************************************************************/
|
||||||
|
// vprepstr: Prepare a string for printing to screen
|
||||||
|
|
||||||
|
int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
||||||
|
chtype attr_alt1, chtype attr_alt2, int maxlines, int maxwidth,
|
||||||
|
int *restrict widthbuf, int widthbufsize,
|
||||||
|
const char *restrict format, va_list args)
|
||||||
|
{
|
||||||
|
const char *orig_format = format;
|
||||||
|
struct argument format_arg[MAXFMTARGS];
|
||||||
|
struct convspec format_spec[MAXFMTSPECS];
|
||||||
|
struct convspec *spec;
|
||||||
|
int line, width;
|
||||||
|
chtype *lastspc;
|
||||||
|
int widthspc;
|
||||||
|
chtype curattr;
|
||||||
|
int saved_errno;
|
||||||
|
|
||||||
|
|
||||||
|
assert(chbuf != NULL);
|
||||||
|
assert(chbufsize > 0);
|
||||||
|
assert(maxlines > 0);
|
||||||
|
assert(maxwidth > 0);
|
||||||
|
assert(widthbuf != NULL);
|
||||||
|
assert(widthbufsize >= maxlines);
|
||||||
|
assert(format != NULL);
|
||||||
|
|
||||||
|
if (prepstr_parse(format, format_arg, format_spec, args) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
spec = format_spec;
|
||||||
|
|
||||||
curattr = attr_norm;
|
curattr = attr_norm;
|
||||||
line = -1; // Current line number (0 = first)
|
line = -1; // Current line number (0 = first)
|
||||||
@ -967,184 +1079,94 @@ int vprepstr (chtype *restrict chbuf, int chbufsize, chtype attr_norm,
|
|||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
bool inspec = true;
|
assert(spec->len != 0);
|
||||||
bool flag_posn = false;
|
|
||||||
bool flag_long = false;
|
|
||||||
bool flag_thou = false;
|
|
||||||
int count = 0;
|
|
||||||
const char *str;
|
|
||||||
|
|
||||||
|
const char *str;
|
||||||
char *buf = xmalloc(BUFSIZE);
|
char *buf = xmalloc(BUFSIZE);
|
||||||
|
|
||||||
while (inspec && *format != '\0') {
|
switch (spec->spec) {
|
||||||
char c = *format++;
|
case 'c':
|
||||||
switch (c) {
|
// Insert a character (char) into the output
|
||||||
case '0':
|
if (snprintf(buf, BUFSIZE, "%c",
|
||||||
// Zero flag, or part of numeric count
|
format_arg[spec->arg_num].a.a_char) < 0) {
|
||||||
if (count == 0) {
|
saved_errno = errno;
|
||||||
// Zero flag is not supported
|
free(buf);
|
||||||
free(buf);
|
errno = saved_errno;
|
||||||
goto error_inval;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
count *= 10;
|
str = buf;
|
||||||
break;
|
goto insertstr;
|
||||||
|
|
||||||
case '1':
|
case 'd':
|
||||||
case '2':
|
// Insert an integer (int or long int) into the output
|
||||||
case '3':
|
if (spec->flag_long) {
|
||||||
case '4':
|
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
||||||
case '5':
|
"%'ld" : "%ld",
|
||||||
case '6':
|
format_arg[spec->arg_num].a.a_longint) < 0) {
|
||||||
case '7':
|
|
||||||
case '8':
|
|
||||||
case '9':
|
|
||||||
// Part of some numeric count
|
|
||||||
count = count * 10 + (c - '0');
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '$':
|
|
||||||
// Fixed-position argument
|
|
||||||
if (flag_posn || count == 0) {
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (count > MAXFMTARGS) {
|
|
||||||
free(buf);
|
|
||||||
errno = E2BIG;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
flag_posn = true;
|
|
||||||
arg_num = count - 1;
|
|
||||||
count = 0;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case '\'':
|
|
||||||
// Use locale-specific thousands separator
|
|
||||||
if (flag_thou) {
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
|
|
||||||
flag_thou = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'l':
|
|
||||||
// Long length modifier
|
|
||||||
if (flag_long) {
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
|
|
||||||
flag_long = true;
|
|
||||||
break;
|
|
||||||
|
|
||||||
case 'd':
|
|
||||||
// Insert an integer (int or long int) into the output
|
|
||||||
if (count != 0) {
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_num >= MAXFMTARGS) {
|
|
||||||
free(buf);
|
|
||||||
errno = E2BIG;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (flag_long) {
|
|
||||||
if (snprintf(buf, BUFSIZE, flag_thou ? "%'ld" : "%ld",
|
|
||||||
format_arg[arg_num].a.a_longint) < 0) {
|
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
} else {
|
|
||||||
if (snprintf(buf, BUFSIZE, flag_thou ? "%'d" : "%d",
|
|
||||||
format_arg[arg_num].a.a_int) < 0) {
|
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
str = buf;
|
|
||||||
goto insertstr;
|
|
||||||
|
|
||||||
case 'N':
|
|
||||||
// Insert a monetary amount (double) into the output
|
|
||||||
if (count != 0 || flag_thou || flag_long) {
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_num >= MAXFMTARGS) {
|
|
||||||
free(buf);
|
|
||||||
errno = E2BIG;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
|
|
||||||
if (l_strfmon(buf, BUFSIZE, "%n",
|
|
||||||
format_arg[arg_num].a.a_double) < 0) {
|
|
||||||
saved_errno = errno;
|
saved_errno = errno;
|
||||||
free(buf);
|
free(buf);
|
||||||
errno = saved_errno;
|
errno = saved_errno;
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
str = buf;
|
if (snprintf(buf, BUFSIZE, spec->flag_group ?
|
||||||
goto insertstr;
|
"%'d" : "%d",
|
||||||
|
format_arg[spec->arg_num].a.a_int) < 0) {
|
||||||
case 's':
|
saved_errno = errno;
|
||||||
// Insert a string (const char *) into the output
|
|
||||||
if (count != 0 || flag_thou || flag_long) {
|
|
||||||
free(buf);
|
free(buf);
|
||||||
goto error_inval;
|
errno = saved_errno;
|
||||||
}
|
|
||||||
|
|
||||||
if (arg_num >= MAXFMTARGS) {
|
|
||||||
free(buf);
|
|
||||||
errno = E2BIG;
|
|
||||||
goto error;
|
goto error;
|
||||||
}
|
}
|
||||||
|
|
||||||
str = format_arg[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 (prepstr_addch(&chbuf, &chbufsize, curattr,
|
|
||||||
maxlines, maxwidth, &line, &width,
|
|
||||||
&lastspc, &widthspc, widthbuf,
|
|
||||||
widthbufsize, &str) < 0) {
|
|
||||||
saved_errno = errno;
|
|
||||||
free(buf);
|
|
||||||
errno = saved_errno;
|
|
||||||
goto error;
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
arg_num++;
|
|
||||||
inspec = false;
|
|
||||||
break;
|
|
||||||
|
|
||||||
default:
|
|
||||||
free(buf);
|
|
||||||
goto error_inval;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
str = buf;
|
||||||
|
goto insertstr;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
// Insert a monetary amount (double) into the output
|
||||||
|
if (l_strfmon(buf, BUFSIZE, spec->flag_nosym ? "%!n" : "%n",
|
||||||
|
format_arg[spec->arg_num].a.a_double) < 0) {
|
||||||
|
saved_errno = errno;
|
||||||
|
free(buf);
|
||||||
|
errno = saved_errno;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = buf;
|
||||||
|
goto insertstr;
|
||||||
|
|
||||||
|
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 (prepstr_addch(&chbuf, &chbufsize, curattr,
|
||||||
|
maxlines, maxwidth, &line, &width,
|
||||||
|
&lastspc, &widthspc, widthbuf,
|
||||||
|
widthbufsize, &str) < 0) {
|
||||||
|
saved_errno = errno;
|
||||||
|
free(buf);
|
||||||
|
errno = saved_errno;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
format += spec->len;
|
||||||
|
spec++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
assert(spec->spec);
|
||||||
}
|
}
|
||||||
|
|
||||||
free(buf);
|
free(buf);
|
||||||
if (inspec) {
|
|
||||||
goto error_inval;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
@ -314,13 +314,17 @@ extern int txdlgbox (int maxlines, int ncols, int begin_y, int begin_x,
|
|||||||
|
|
||||||
%% - Print the ASCII percent sign (ASCII code U+0025)
|
%% - Print the ASCII percent sign (ASCII code U+0025)
|
||||||
|
|
||||||
%s - Insert the next parameter as a string
|
%c - Insert the next parameter as a character (type char)
|
||||||
|
%s - Insert the next parameter as a string (type char *)
|
||||||
%d - Insert the next parameter as an integer (type int)
|
%d - Insert the next parameter as an integer (type int)
|
||||||
%'d - Insert as an int, using the locale's thousands separator
|
%'d - Insert as an int, using the locale's thousands separator
|
||||||
%ld - Insert the next parameter as a long int
|
%ld - Insert the next parameter as a long int
|
||||||
%'ld - Insert as a long int, using the locale's thousands separator
|
%'ld - Insert as a long int, using the locale's thousands separator
|
||||||
%N - Insert the next parameter as a double, using the locale's
|
%N - Insert the next parameter as a double, using the locale's
|
||||||
national currency format (extension to printf())
|
national currency format (extension to printf())
|
||||||
|
%!N - Insert the next parameter as a double, using the locale's
|
||||||
|
national currency format without the actual currency symbol
|
||||||
|
(extension to printf())
|
||||||
|
|
||||||
Instead of using "%" to convert the next parameter, "%m$" can be used
|
Instead of using "%" to convert the next parameter, "%m$" can be used
|
||||||
to indicate fixed parameter m (where m is an integer from 1 to 8). For
|
to indicate fixed parameter m (where m is an integer from 1 to 8). For
|
||||||
|
Loading…
Reference in New Issue
Block a user