mirror of
https://git.zap.org.au/git/trader.git
synced 2024-10-27 18:20:13 -04:00
Add functions prepstr(), pr_left(), pr_center() and pr_right()
These functions allow multiple lines to be printed left-aligned, centered or right-aligned, with automatic line-wrapping where needed.
This commit is contained in:
parent
3984468894
commit
2612eddf3d
697
src/intf.c
697
src/intf.c
@ -42,6 +42,29 @@ typedef struct txwin {
|
|||||||
} txwin_t;
|
} txwin_t;
|
||||||
|
|
||||||
|
|
||||||
|
// Declarations for argument processing in prepstr()
|
||||||
|
|
||||||
|
#define MAXFMTARGS 8 // Maximum number of positional arguments
|
||||||
|
|
||||||
|
enum argument_type {
|
||||||
|
TYPE_NONE, // No type yet assigned
|
||||||
|
TYPE_INT, // int
|
||||||
|
TYPE_LONGINT, // long int
|
||||||
|
TYPE_DOUBLE, // double
|
||||||
|
TYPE_STRING // const char *
|
||||||
|
};
|
||||||
|
|
||||||
|
struct argument {
|
||||||
|
enum argument_type a_type;
|
||||||
|
union a {
|
||||||
|
int a_int;
|
||||||
|
long int a_longint;
|
||||||
|
double a_double;
|
||||||
|
const char *a_string;
|
||||||
|
} a;
|
||||||
|
};
|
||||||
|
|
||||||
|
|
||||||
/************************************************************************
|
/************************************************************************
|
||||||
* Global variable definitions *
|
* Global variable definitions *
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
@ -132,6 +155,40 @@ static void txresize (void);
|
|||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: prepstr_addch - Add a character to the prepstr buffer
|
||||||
|
Parameters: chbuf - Pointer to chtype pointer in which to store string
|
||||||
|
chbufsize - Pointer to number of chtype elements in chbuf
|
||||||
|
attr - Character rendition to use
|
||||||
|
maxlines - Maximum number of screen lines to use
|
||||||
|
maxwidth - Maximum width of each line, in chars
|
||||||
|
line - Pointer to current line number
|
||||||
|
width - Pointer to current line width
|
||||||
|
lastspc - Pointer to const char * pointer to last space
|
||||||
|
widthspc - Pointer to width just before last space
|
||||||
|
widthbuf - Pointer to buffer to store widths of each line
|
||||||
|
widthbufsize - Number of int elements in widthbuf
|
||||||
|
str - Pointer to const char * pointer to string
|
||||||
|
Returns: int - -1 on error (with errno set), 0 otherwise
|
||||||
|
|
||||||
|
This helper function adds the character **str to **chbuf, using attr as
|
||||||
|
the character rendition (attributes), incrementing both *str and *chbuf
|
||||||
|
and decrementing *chbufsize. If a string is too long for the current
|
||||||
|
line, a previous space in the current line is converted to a new line
|
||||||
|
(if possible), else a new line is inserted into the current location
|
||||||
|
(if not on the last line). *line, *width, *lastspc, *widthspc and
|
||||||
|
widthbuf[] are all updated appropriately.
|
||||||
|
*/
|
||||||
|
static int prepstr_addch (chtype *restrict *restrict chbuf,
|
||||||
|
int *restrict chbufsize, chtype attr,
|
||||||
|
int maxlines, int maxwidth, int *restrict line,
|
||||||
|
int *restrict width,
|
||||||
|
chtype *restrict *restrict lastspc,
|
||||||
|
int *restrict widthspc, int *restrict widthbuf,
|
||||||
|
int widthbufsize,
|
||||||
|
const char *restrict *restrict str);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
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
|
||||||
@ -155,7 +212,8 @@ static void txinput_fixup (char *restrict dest, char *restrict src,
|
|||||||
* Basic text input/output function definitions *
|
* Basic text input/output function definitions *
|
||||||
************************************************************************/
|
************************************************************************/
|
||||||
|
|
||||||
// These functions are documented in the file "intf.h"
|
/* These functions are documented either in the file "intf.h" or in the
|
||||||
|
comments above. */
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
@ -497,6 +555,643 @@ void txresize (void)
|
|||||||
#endif // HANDLE_RESIZE_EVENTS
|
#endif // HANDLE_RESIZE_EVENTS
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// prepstr_addch: Add a character to the prepstr buffer
|
||||||
|
|
||||||
|
int prepstr_addch (chtype *restrict *restrict chbuf, int *restrict chbufsize,
|
||||||
|
chtype attr, int maxlines, int maxwidth,
|
||||||
|
int *restrict line, int *restrict width,
|
||||||
|
chtype *restrict *restrict lastspc, int *restrict widthspc,
|
||||||
|
int *restrict widthbuf, int widthbufsize,
|
||||||
|
const char *restrict *restrict str)
|
||||||
|
{
|
||||||
|
if (*line < 0) {
|
||||||
|
// First character in buffer: start line 0
|
||||||
|
*line = 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (**str == '\n') {
|
||||||
|
// Start a new line
|
||||||
|
|
||||||
|
if (*line < maxlines - 1) {
|
||||||
|
*(*chbuf)++ = '\n';
|
||||||
|
(*chbufsize)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
widthbuf[*line] = *width;
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
*lastspc = NULL;
|
||||||
|
*widthspc = 0;
|
||||||
|
|
||||||
|
(*line)++;
|
||||||
|
(*str)++;
|
||||||
|
} else if (*width == maxwidth) {
|
||||||
|
// Current line is now too long
|
||||||
|
|
||||||
|
if (! isspace(**str) && *lastspc != NULL && *line < maxlines - 1) {
|
||||||
|
// Break on the last space in this line
|
||||||
|
**lastspc = '\n';
|
||||||
|
|
||||||
|
widthbuf[*line] = *widthspc;
|
||||||
|
*width -= *widthspc + 1;
|
||||||
|
|
||||||
|
*lastspc = NULL;
|
||||||
|
*widthspc = 0;
|
||||||
|
|
||||||
|
(*line)++;
|
||||||
|
} else {
|
||||||
|
// Insert a new-line character (if not on last line)
|
||||||
|
if (*line < maxlines - 1) {
|
||||||
|
*(*chbuf)++ = '\n';
|
||||||
|
(*chbufsize)--;
|
||||||
|
}
|
||||||
|
|
||||||
|
widthbuf[*line] = *width;
|
||||||
|
*width = 0;
|
||||||
|
|
||||||
|
*lastspc = NULL;
|
||||||
|
*widthspc = 0;
|
||||||
|
|
||||||
|
(*line)++;
|
||||||
|
|
||||||
|
// Skip any following spaces
|
||||||
|
while (isspace(**str)) {
|
||||||
|
if (*(*str)++ == '\n') {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
// Insert an ordinary character into the output string
|
||||||
|
|
||||||
|
if (isspace(**str)) {
|
||||||
|
*lastspc = *chbuf;
|
||||||
|
*widthspc = *width;
|
||||||
|
}
|
||||||
|
|
||||||
|
*(*chbuf)++ = (unsigned char) **str | attr;
|
||||||
|
(*chbufsize)--;
|
||||||
|
(*width)++;
|
||||||
|
(*str)++;
|
||||||
|
}
|
||||||
|
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// prepstr: Prepare a string for printing to screen
|
||||||
|
|
||||||
|
int prepstr (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, ...)
|
||||||
|
{
|
||||||
|
struct argument format_arg[MAXFMTARGS];
|
||||||
|
int num_format_args, arg_num;
|
||||||
|
const char *orig_format;
|
||||||
|
va_list args;
|
||||||
|
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);
|
||||||
|
|
||||||
|
/* 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;
|
||||||
|
va_start(args, format);
|
||||||
|
|
||||||
|
while (*format != '\0') {
|
||||||
|
switch (*format++) {
|
||||||
|
case '^':
|
||||||
|
// Switch to a different character rendition
|
||||||
|
if (*format == '\0') {
|
||||||
|
goto error_inval;
|
||||||
|
} else {
|
||||||
|
format++;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
// Process a conversion specifier
|
||||||
|
if (*format == '\0') {
|
||||||
|
goto error_inval;
|
||||||
|
} else if (*format == '%') {
|
||||||
|
format++;
|
||||||
|
} else {
|
||||||
|
enum argument_type arg_type = TYPE_NONE;
|
||||||
|
bool inspec = true;
|
||||||
|
bool flag_posn = false;
|
||||||
|
bool flag_long = false;
|
||||||
|
int count = 0;
|
||||||
|
|
||||||
|
while (inspec && *format != '\0') {
|
||||||
|
char c = *format++;
|
||||||
|
switch (c) {
|
||||||
|
case '0':
|
||||||
|
// Zero flag, or part of numeric count
|
||||||
|
if (count == 0)
|
||||||
|
goto error_inval;
|
||||||
|
|
||||||
|
count *= 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
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)
|
||||||
|
goto error_inval;
|
||||||
|
|
||||||
|
if (count > MAXFMTARGS) {
|
||||||
|
errno = E2BIG;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
flag_posn = true;
|
||||||
|
arg_num = count - 1;
|
||||||
|
count = 0;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '\'':
|
||||||
|
// Use locale-specific thousands separator
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'l':
|
||||||
|
// Long length modifier
|
||||||
|
if (flag_long)
|
||||||
|
goto error_inval;
|
||||||
|
|
||||||
|
flag_long = true;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case 'd':
|
||||||
|
// Insert an integer (int or long int)
|
||||||
|
arg_type = flag_long ? TYPE_LONGINT : TYPE_INT;
|
||||||
|
goto handlefmt;
|
||||||
|
|
||||||
|
case 'N':
|
||||||
|
// Insert a monetary amount (double)
|
||||||
|
if (flag_long)
|
||||||
|
goto error_inval;
|
||||||
|
|
||||||
|
arg_type = TYPE_DOUBLE;
|
||||||
|
goto handlefmt;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
// Insert a string (const char *)
|
||||||
|
if (flag_long)
|
||||||
|
goto error_inval;
|
||||||
|
|
||||||
|
arg_type = TYPE_STRING;
|
||||||
|
|
||||||
|
handlefmt:
|
||||||
|
if (arg_num >= MAXFMTARGS) {
|
||||||
|
errno = E2BIG;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (format_arg[arg_num].a_type == TYPE_NONE) {
|
||||||
|
format_arg[arg_num].a_type = arg_type;
|
||||||
|
} else if (format_arg[arg_num].a_type != arg_type) {
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
|
||||||
|
arg_num++;
|
||||||
|
num_format_args = MAX(num_format_args, arg_num);
|
||||||
|
|
||||||
|
inspec = false;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
if (inspec)
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Process an ordinary character: do nothing for now
|
||||||
|
;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
for (int i = 0; i < num_format_args; i++) {
|
||||||
|
switch (format_arg[i].a_type) {
|
||||||
|
case TYPE_INT:
|
||||||
|
format_arg[i].a.a_int = va_arg(args, int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_LONGINT:
|
||||||
|
format_arg[i].a.a_longint = va_arg(args, long int);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_DOUBLE:
|
||||||
|
format_arg[i].a.a_double = va_arg(args, double);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case TYPE_STRING:
|
||||||
|
format_arg[i].a.a_string = va_arg(args, const char *);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
/* Cannot allow unused arguments, as we have no way of
|
||||||
|
knowing how much space they take (cf. int vs. long long
|
||||||
|
int). */
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// Actually process the format parameter string
|
||||||
|
|
||||||
|
format = orig_format;
|
||||||
|
arg_num = 0;
|
||||||
|
|
||||||
|
curattr = attr_norm;
|
||||||
|
line = -1; // Current line number (0 = first)
|
||||||
|
width = 0; // Width of the current line
|
||||||
|
lastspc = NULL; // Pointer to last space in line
|
||||||
|
widthspc = 0; // Width of line before last space
|
||||||
|
|
||||||
|
while (*format != '\0' && chbufsize > 1 && line < maxlines) {
|
||||||
|
switch (*format) {
|
||||||
|
case '^':
|
||||||
|
// Switch to a different character rendition
|
||||||
|
if (*++format == '\0') {
|
||||||
|
goto error_inval;
|
||||||
|
} else {
|
||||||
|
switch (*format) {
|
||||||
|
case '^':
|
||||||
|
if (prepstr_addch(&chbuf, &chbufsize, curattr, maxlines,
|
||||||
|
maxwidth, &line, &width, &lastspc,
|
||||||
|
&widthspc, widthbuf, widthbufsize,
|
||||||
|
&format) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '{':
|
||||||
|
curattr = attr_alt1;
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '[':
|
||||||
|
curattr = attr_alt2;
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '}':
|
||||||
|
case ']':
|
||||||
|
curattr = attr_norm;
|
||||||
|
format++;
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '%':
|
||||||
|
// Process a conversion specifier
|
||||||
|
if (*++format == '\0') {
|
||||||
|
goto error_inval;
|
||||||
|
} else if (*format == '%') {
|
||||||
|
if (prepstr_addch(&chbuf, &chbufsize, curattr, maxlines,
|
||||||
|
maxwidth, &line, &width, &lastspc, &widthspc,
|
||||||
|
widthbuf, widthbufsize, &format) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
bool inspec = true;
|
||||||
|
bool flag_posn = false;
|
||||||
|
bool flag_long = false;
|
||||||
|
bool flag_thou = false;
|
||||||
|
int count = 0;
|
||||||
|
const char *str;
|
||||||
|
|
||||||
|
char *buf = malloc(BUFSIZE);
|
||||||
|
if (buf == NULL)
|
||||||
|
err_exit_nomem();
|
||||||
|
|
||||||
|
while (inspec && *format != '\0') {
|
||||||
|
char c = *format++;
|
||||||
|
switch (c) {
|
||||||
|
case '0':
|
||||||
|
// Zero flag, or part of numeric count
|
||||||
|
if (count == 0) {
|
||||||
|
// Zero flag is not supported
|
||||||
|
free(buf);
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
|
||||||
|
count *= 10;
|
||||||
|
break;
|
||||||
|
|
||||||
|
case '1':
|
||||||
|
case '2':
|
||||||
|
case '3':
|
||||||
|
case '4':
|
||||||
|
case '5':
|
||||||
|
case '6':
|
||||||
|
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;
|
||||||
|
free(buf);
|
||||||
|
errno = saved_errno;
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
|
||||||
|
str = buf;
|
||||||
|
goto insertstr;
|
||||||
|
|
||||||
|
case 's':
|
||||||
|
// Insert a string (const char *) 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;
|
||||||
|
}
|
||||||
|
|
||||||
|
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;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
free(buf);
|
||||||
|
if (inspec)
|
||||||
|
goto error_inval;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
// Process an ordinary character (including new-line)
|
||||||
|
if (prepstr_addch(&chbuf, &chbufsize, curattr, maxlines, maxwidth,
|
||||||
|
&line, &width, &lastspc, &widthspc, widthbuf,
|
||||||
|
widthbufsize, &format) < 0) {
|
||||||
|
goto error;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
*chbuf = 0; // Terminating NUL byte
|
||||||
|
|
||||||
|
if (line >= 0 && line < maxlines) {
|
||||||
|
widthbuf[line] = width;
|
||||||
|
} else if (line >= maxlines) {
|
||||||
|
line = maxlines - 1;
|
||||||
|
}
|
||||||
|
|
||||||
|
va_end(args);
|
||||||
|
return line + 1;
|
||||||
|
|
||||||
|
error_inval:
|
||||||
|
errno = EINVAL;
|
||||||
|
|
||||||
|
error:
|
||||||
|
va_end(args);
|
||||||
|
return -1;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// pr_left: Print strings in chbuf left-aligned
|
||||||
|
|
||||||
|
int pr_left (WINDOW *win, int y, int x, const chtype *restrict chbuf,
|
||||||
|
int lines, const int *restrict widthbuf)
|
||||||
|
{
|
||||||
|
assert(win != NULL);
|
||||||
|
assert(chbuf != NULL);
|
||||||
|
assert(lines > 0);
|
||||||
|
assert(widthbuf != NULL);
|
||||||
|
|
||||||
|
wmove(win, y, x);
|
||||||
|
for ( ; *chbuf != '\0'; chbuf++) {
|
||||||
|
if (*chbuf == '\n') {
|
||||||
|
wmove(win, getcury(win) + 1, x);
|
||||||
|
} else {
|
||||||
|
waddch(win, *chbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// pr_center: Print strings in chbuf centered in window
|
||||||
|
|
||||||
|
int pr_center (WINDOW *win, int y, int offset, const chtype *restrict chbuf,
|
||||||
|
int lines, const int *restrict widthbuf)
|
||||||
|
{
|
||||||
|
int ln = 0;
|
||||||
|
|
||||||
|
|
||||||
|
assert(win != NULL);
|
||||||
|
assert(chbuf != NULL);
|
||||||
|
assert(lines > 0);
|
||||||
|
assert(widthbuf != NULL);
|
||||||
|
|
||||||
|
wmove(win, y, (getmaxx(win) - widthbuf[ln]) / 2 + offset);
|
||||||
|
for ( ; *chbuf != '\0'; chbuf++) {
|
||||||
|
if (*chbuf == '\n') {
|
||||||
|
if (ln++ >= lines) {
|
||||||
|
return ERR;
|
||||||
|
} else {
|
||||||
|
wmove(win, getcury(win) + 1,
|
||||||
|
(getmaxx(win) - widthbuf[ln]) / 2 + offset);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
waddch(win, *chbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
|
/***********************************************************************/
|
||||||
|
// pr_right: Print strings in chbuf right-aligned
|
||||||
|
|
||||||
|
int pr_right (WINDOW *win, int y, int x, const chtype *restrict chbuf,
|
||||||
|
int lines, const int *restrict widthbuf)
|
||||||
|
{
|
||||||
|
int ln = 0;
|
||||||
|
|
||||||
|
|
||||||
|
assert(win != NULL);
|
||||||
|
assert(chbuf != NULL);
|
||||||
|
assert(lines > 0);
|
||||||
|
assert(widthbuf != NULL);
|
||||||
|
|
||||||
|
wmove(win, y, x - widthbuf[ln]);
|
||||||
|
for ( ; *chbuf != '\0'; chbuf++) {
|
||||||
|
if (*chbuf == '\n') {
|
||||||
|
if (ln++ >= lines) {
|
||||||
|
return ERR;
|
||||||
|
} else {
|
||||||
|
wmove(win, getcury(win) + 1, x - widthbuf[ln]);
|
||||||
|
}
|
||||||
|
} else {
|
||||||
|
waddch(win, *chbuf);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
return OK;
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
/***********************************************************************/
|
/***********************************************************************/
|
||||||
// attrpr: Print a string with a particular character rendition
|
// attrpr: Print a string with a particular character rendition
|
||||||
|
|
||||||
|
126
src/intf.h
126
src/intf.h
@ -254,6 +254,132 @@ extern int delalltxwin (void);
|
|||||||
extern int txrefresh (void);
|
extern int txrefresh (void);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: prepstr - Prepare a string for printing to screen
|
||||||
|
Parameters: chbuf - Pointer to chtype buffer in which to store string
|
||||||
|
chbufsize - Number of chtype elements in chbuf
|
||||||
|
attr_norm - Normal character rendition to use
|
||||||
|
attr_alt1 - First alternate character rendition to use
|
||||||
|
attr_alt2 - Second alternate character rendition to use
|
||||||
|
maxlines - Maximum number of screen lines to use
|
||||||
|
maxwidth - Maximum width of each line, in chars
|
||||||
|
widthbuf - Pointer to buffer to store widths of each line
|
||||||
|
widthbufsize - Number of int elements in widthbuf
|
||||||
|
format - Format string as described below
|
||||||
|
... - Arguments for the format string
|
||||||
|
Returns: int - Number of lines actually used, or -1 on error
|
||||||
|
|
||||||
|
This function converts the format string and following arguments into
|
||||||
|
chbuf, a chtype buffer that can be used for calls to pr_left(),
|
||||||
|
pr_center() and pr_right(). At most maxlines lines are used, each with
|
||||||
|
a maximum width of maxwidth. The actual widths of each resulting line
|
||||||
|
are stored in widthbuf (which must not be NULL). If maxlines is
|
||||||
|
greater than 1, lines are wrapped as needed.
|
||||||
|
|
||||||
|
The format string is similar to but more limited than printf(). In
|
||||||
|
particular, the following conversion specifiers are understood:
|
||||||
|
|
||||||
|
%% - Print the ASCII percent sign (ASCII code U+0025)
|
||||||
|
|
||||||
|
%s - Insert the next parameter as a string
|
||||||
|
%d - Insert the next parameter as an integer (type int)
|
||||||
|
%'d - Insert as an int, using the locale's thousands separator
|
||||||
|
%ld - Insert the next parameter as a long int
|
||||||
|
%'ld - Insert as a long int, using the locale's thousands separator
|
||||||
|
%N - Insert the next parameter as a double, using the locale's
|
||||||
|
national currency format (extension to printf())
|
||||||
|
|
||||||
|
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
|
||||||
|
example, "%4$s" inserts the fourth parameter after "format" as a string
|
||||||
|
into chbuf. As with printf(), using "%m$" together with ordinary "%"
|
||||||
|
forms is undefined. If "%m$" is used, no parameter m can be skipped.
|
||||||
|
|
||||||
|
Note that no other flag, field width, precision or length modifier
|
||||||
|
characters are recognised: if needed, these should be formatted FIRST
|
||||||
|
with snprintf(), then inserted using %s as appropriate.
|
||||||
|
|
||||||
|
In addition to the conversion specifiers, the following character
|
||||||
|
rendition flags are understood, where the "^" character is a literal
|
||||||
|
ASCII circumflex accent:
|
||||||
|
|
||||||
|
^^ - Print the circumflex accent (ASCII code U+005E)
|
||||||
|
^{ - Switch to using attr_alt1 character rendition (alternate mode 1)
|
||||||
|
^} - Switch to using attr_norm character rendition
|
||||||
|
^[ - Switch to using attr_alt2 character rendition (alternate mode 2)
|
||||||
|
^] - Switch to using attr_norm character rendition
|
||||||
|
|
||||||
|
Characters other than these are inserted as literals, except that '\n'
|
||||||
|
will force the start of a new line. By default, attr_norm is used as
|
||||||
|
the character rendition (attributes).
|
||||||
|
|
||||||
|
This function returns the actual number of lines used (from 0 to
|
||||||
|
maxlines), or -1 on error (with errno set to EINVAL for an invalid
|
||||||
|
format conversion specifier or argument).
|
||||||
|
*/
|
||||||
|
extern int prepstr (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, ...);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: pr_left - Print strings in chbuf left-aligned
|
||||||
|
Parameters: win - Window to use (should be curwin)
|
||||||
|
y - Line on which to print first string
|
||||||
|
x - Starting column number for each line
|
||||||
|
chbuf - chtype buffer as returned from prepstr()
|
||||||
|
lines - Number of lines in chbuf (as returned from prepstr())
|
||||||
|
widthbuf - Widths of each line (as returned from prepstr())
|
||||||
|
Returns: int - Error code OK
|
||||||
|
|
||||||
|
This function takes the strings in the chtype array chbuf and prints
|
||||||
|
them left-aligned in the window win. Note that wrefresh() is NOT
|
||||||
|
called.
|
||||||
|
*/
|
||||||
|
extern int pr_left (WINDOW *win, int y, int x, const chtype *restrict chbuf,
|
||||||
|
int lines, const int *restrict widthbuf);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: pr_center - Print strings in chbuf centered in window
|
||||||
|
Parameters: win - Window to use (should be curwin)
|
||||||
|
y - Line on which to print first string
|
||||||
|
offset - Column offset to add to position for each line
|
||||||
|
chbuf - chtype buffer as returned from prepstr()
|
||||||
|
lines - Number of lines in chbuf (as returned from prepstr())
|
||||||
|
widthbuf - Widths of each line (as returned from prepstr())
|
||||||
|
Returns: int - ERR if more lines in chbuf[] than lines, else OK
|
||||||
|
|
||||||
|
This function takes the strings in the chtype array chbuf and prints
|
||||||
|
them centered in the window win, offset by the parameter offset. Note
|
||||||
|
that wrefresh() is NOT called. ERR is returned if there are more lines
|
||||||
|
in chbuf[] than are passed in the parameter lines.
|
||||||
|
*/
|
||||||
|
extern int pr_center (WINDOW *win, int y, int offset,
|
||||||
|
const chtype *restrict chbuf, int lines,
|
||||||
|
const int *restrict widthbuf);
|
||||||
|
|
||||||
|
|
||||||
|
/*
|
||||||
|
Function: pr_right - Print strings in chbuf right-aligned
|
||||||
|
Parameters: win - Window to use (should be curwin)
|
||||||
|
y - Line on which to print first string
|
||||||
|
x - Ending column number for each line
|
||||||
|
chbuf - chtype buffer as returned from prepstr()
|
||||||
|
lines - Number of lines in chbuf (as returned from prepstr())
|
||||||
|
widthbuf - Widths of each line (as returned from prepstr())
|
||||||
|
Returns: int - ERR if more lines in chbuf[] than lines, else OK
|
||||||
|
|
||||||
|
This function takes the strings in the chtype array chbuf and prints
|
||||||
|
them right-aligned in the window win, with each line ending at column
|
||||||
|
x. Note that wrefresh() is NOT called. ERR is returned if there are
|
||||||
|
more lines in chbuf[] than are passed in the parameter lines.
|
||||||
|
*/
|
||||||
|
extern int pr_right (WINDOW *win, int y, int x, const chtype *restrict chbuf,
|
||||||
|
int lines, const int *restrict widthbuf);
|
||||||
|
|
||||||
|
|
||||||
/*
|
/*
|
||||||
Function: attrpr - Print a string with a particular character rendition
|
Function: attrpr - Print a string with a particular character rendition
|
||||||
Parameters: win - Window to use (should be curwin)
|
Parameters: win - Window to use (should be curwin)
|
||||||
|
Loading…
Reference in New Issue
Block a user