2019-09-03 08:41:37 +00:00
|
|
|
#include <assert.h>
|
|
|
|
#include <float.h>
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
|
|
|
|
#include "default.h"
|
|
|
|
#include "main.h"
|
|
|
|
#include "style.h"
|
|
|
|
#include "token.h"
|
|
|
|
#include "utf8.h"
|
|
|
|
|
|
|
|
const char *Type_Name[] =
|
|
|
|
{ [EMPTY] = "EMPTY", [STRING] = "STRING", [FLOAT] = "FLOAT", [INT] = "INT",
|
|
|
|
[OPERATOR] = "OPERATOR", [LIDENT] = "LABEL", [FIDENT] = "FUNCTION",
|
|
|
|
[LOCATION] = "LOCATION", [FUNCALL] = "FUNCTION-CALL", [EEK] = "ERROR",
|
|
|
|
[BOOL] = "BOOL", [STYLE] = "STYLE"
|
|
|
|
};
|
|
|
|
|
|
|
|
const char *Op_Name[] =
|
|
|
|
{ [PLUS] = "+", [MINUS] = "-", [MUL] = "*", [DIV] = "/",
|
|
|
|
[OP] = "(", [CP] = ")", [COMMA] = ",",
|
|
|
|
[LT] = "<", [LE] = "<=", [GE] = ">=", [GT] = ">",
|
|
|
|
[ISEQUAL] = "==", [ABOUTEQ] = "~=", [NE] = "!=",
|
|
|
|
[POW] = "^", [MOD] = "%", [LAND] = "and", [LOR] = "or"
|
|
|
|
};
|
|
|
|
|
|
|
|
/* loc_in_box -- returns true if test is in the box determined by b and c */
|
|
|
|
bool loc_in_box(const Location test,
|
|
|
|
const Location b, const Location c)
|
|
|
|
{
|
|
|
|
for (Dimensions dim = X; dim < HYPER; ++dim)
|
|
|
|
{
|
|
|
|
if (test[dim] < b[dim] && test[dim] < c[dim]) return false;
|
|
|
|
if (test[dim] > b[dim] && test[dim] > c[dim]) return false;
|
|
|
|
}
|
|
|
|
return true;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* cleartoken - Initialize all of the memory of a token */ /*{{{*/
|
|
|
|
void cleartoken(Token* tok)
|
|
|
|
{
|
|
|
|
tok->type = EMPTY;
|
|
|
|
clearstyle(&(tok->u.style));
|
|
|
|
tok->u.flt = 0.0;
|
|
|
|
tok->u.location[0] = 0;
|
|
|
|
tok->u.location[1] = 0;
|
|
|
|
tok->u.location[2] = 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* tok_matches - return true if l and r appear to be the same token */ /*{{{*/
|
|
|
|
bool tok_matches(const Token* l, const Token *r)
|
|
|
|
{
|
|
|
|
if (l->type != r->type) return false;
|
|
|
|
switch (l->type) {
|
|
|
|
case EMPTY: return true;
|
|
|
|
case STRING: return l->u.string == r->u.string;
|
|
|
|
case FLOAT: return l->u.flt == r->u.flt;
|
|
|
|
case INT: return l->u.integer == r->u.integer;
|
|
|
|
case OPERATOR: return l->u.op == r->u.op;
|
|
|
|
case LIDENT: return l->u.lident == r->u.lident;
|
|
|
|
case FIDENT: return l->u.fident == r->u.fident;
|
|
|
|
case LOCATION:
|
|
|
|
return l->u.location[X] == r->u.location[X]
|
|
|
|
&& l->u.location[Y] == r->u.location[Y]
|
|
|
|
&& l->u.location[Z] == r->u.location[Z];
|
|
|
|
case EEK: return l->u.err == r->u.err;
|
|
|
|
case FUNCALL:
|
|
|
|
return l->u.funcall.fident == r->u.funcall.fident
|
|
|
|
&& l->u.funcall.argc == r->u.funcall.argc
|
|
|
|
&& l->u.funcall.argv == r->u.funcall.argv;
|
|
|
|
case BOOL:
|
|
|
|
return l->u.bl == r->u.bl;
|
|
|
|
case STYLE:
|
|
|
|
return style_equal(l->u.style, r->u.style);
|
|
|
|
}
|
|
|
|
assert(0);
|
|
|
|
return false;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* duperror - Sets tok to an error and strdups the message into place */
|
|
|
|
Token duperror(Token* tok, const char* erro)
|
|
|
|
{
|
|
|
|
tok->type = EEK;
|
|
|
|
tok->u.err = strdup(erro);
|
|
|
|
return *tok;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
/* print_fident -- print a field identifier to a dest and return the number
|
|
|
|
of characters written
|
|
|
|
*/ /*{{{*/
|
2019-09-05 07:24:24 +00:00
|
|
|
static size_t print_fident(char* dest, size_t space, FunctionIdentifier id)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
|
|
|
size_t identlen = strlen(tfunc[id].name);
|
|
|
|
if ((identlen+1) < space) strcpy(dest, tfunc[id].name);
|
|
|
|
else {
|
|
|
|
(void)strncpy(dest, tfunc[id].name, space);
|
|
|
|
dest[space-1] = '\0';
|
|
|
|
}
|
|
|
|
return identlen;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* print_string -- print a string value to a dest and return the number of
|
|
|
|
characters written
|
|
|
|
*/ /*{{{*/
|
2019-09-05 07:24:24 +00:00
|
|
|
static size_t print_string(char* dest, size_t space,
|
2019-09-03 08:41:37 +00:00
|
|
|
const char *str, StringFormat sf)
|
|
|
|
{
|
|
|
|
size_t cur = 0;
|
|
|
|
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
|
|
|
for ( ; cur < space && *str != '\0'; ++str)
|
|
|
|
{
|
|
|
|
if (sf == QUOTE_STRING && (*str == '"' || *str=='\\')) dest[cur++] = '\\';
|
|
|
|
if (cur < space) dest[cur++] = *str;
|
|
|
|
}
|
|
|
|
if (sf == QUOTE_STRING && cur < space) dest[cur++] = '"';
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
2019-09-05 07:24:24 +00:00
|
|
|
static size_t print_chars(char* d, size_t l, const char *s)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
|
|
|
return print_string(d, l, s, DIRECT_STRING);
|
|
|
|
}
|
|
|
|
|
2019-09-05 07:24:24 +00:00
|
|
|
/* ptokatprec -- like printtok but with an ambient precedence */
|
|
|
|
static size_t ptokatprec(char *dest, size_t size, size_t field_width,
|
2019-09-09 14:33:41 +00:00
|
|
|
StringFormat sf, FloatFormat ff, PrecisionLevel pl,
|
2019-09-05 07:24:24 +00:00
|
|
|
ErrorFormat ef, const Token *tok,
|
|
|
|
FunctionPrecedence atprec)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
2019-09-09 14:33:41 +00:00
|
|
|
int digits = pl;
|
2019-09-03 08:41:37 +00:00
|
|
|
if (debug_level > 2) {
|
2019-09-09 14:33:41 +00:00
|
|
|
printf("..Entering ptokatprec; bufsize %zu, field_width %zu, qs %d, ff %s,"
|
|
|
|
"precision %d, verr %d, precedence %d\n",
|
|
|
|
size, field_width, sf, FloatFormat_Name[ff], digits,
|
|
|
|
ef, (int)atprec);
|
2019-09-03 08:41:37 +00:00
|
|
|
}
|
|
|
|
if (size > 0 ) *dest = '\0';
|
|
|
|
if (tok == NULLTOKEN || tok->type == EMPTY) return 0;
|
|
|
|
size_t cur = 0;
|
|
|
|
switch (tok->type)
|
|
|
|
{
|
|
|
|
case STRING: cur += print_string(dest, size, tok->u.string, sf); break;
|
2019-09-05 07:24:24 +00:00
|
|
|
case INT: cur += (size_t)snprintf(dest, size, INT_T_FMT, tok->u.integer); break;
|
2019-09-03 08:41:37 +00:00
|
|
|
case FLOAT: /*{{{*/
|
|
|
|
{
|
2019-09-05 07:24:24 +00:00
|
|
|
char buf[1100], buf2[1100];
|
2019-09-03 08:41:37 +00:00
|
|
|
|
|
|
|
if (digits == 0) digits = def_precision;
|
|
|
|
else if (digits < 0) digits += FLT_T_DIG + 1;
|
2019-09-05 07:24:24 +00:00
|
|
|
assert(digits > 0);
|
|
|
|
if ((size_t)digits > sizeof(buf) - FLT_T_DIG - 1)
|
|
|
|
digits = (PrecisionLevel)(sizeof(buf) - FLT_T_DIG - 1);
|
|
|
|
int len = 0, len2;
|
|
|
|
char *use = NULL;
|
2019-09-03 08:41:37 +00:00
|
|
|
switch (ff) {
|
2019-09-05 07:24:24 +00:00
|
|
|
case FLT_DECIMAL:
|
|
|
|
len = sprintf(buf, FLT_T_STD_FMT, digits, tok->u.flt);
|
|
|
|
use = buf;
|
|
|
|
break;
|
|
|
|
case FLT_SCIENTIFIC:
|
|
|
|
len = sprintf(buf, FLT_T_SCI_FMT, digits, tok->u.flt);
|
|
|
|
use = buf;
|
|
|
|
break;
|
|
|
|
case FLT_COMPACT:
|
|
|
|
len = sprintf(buf, FLT_T_CPT_FMT, digits, tok->u.flt);
|
|
|
|
/* Unfortunately, %g is so clever that sometimes it omits the
|
|
|
|
decimal; it also has a penchant for not switching to scientific
|
|
|
|
notation until the magnitude gets very large. So we try to
|
|
|
|
counteract these bad tendencies here. If there is no decimal,
|
|
|
|
we take the shorter of %.1f and %e with the same number of digits.
|
|
|
|
*/
|
|
|
|
use = buf;
|
|
|
|
if (strchr(buf, '.') == NULL) {
|
|
|
|
len = sprintf(buf, FLT_T_STD_FMT, 1, tok->u.flt);
|
|
|
|
len2 = sprintf(buf2, FLT_T_SCI_FMT, digits, tok->u.flt);
|
|
|
|
/* remove trailing 0s from sci format to be fair */
|
|
|
|
long epos = strchr(buf2, 'e') - buf2;
|
|
|
|
long tpos = epos;
|
|
|
|
while (tpos > 1 && buf2[tpos-1] == '0' && buf2[tpos-2] != '.') --tpos;
|
|
|
|
if (tpos < epos) {
|
2019-09-09 14:33:41 +00:00
|
|
|
memmove(buf2+tpos, buf2+epos, (size_t)(len2-epos+1));
|
|
|
|
len2 -= (int)(epos - tpos);
|
2019-09-05 07:24:24 +00:00
|
|
|
}
|
|
|
|
if (len2 < len) { use = buf2; len = len2; }
|
2019-09-03 08:41:37 +00:00
|
|
|
}
|
2019-09-05 07:24:24 +00:00
|
|
|
break;
|
|
|
|
case FLT_HEXACT:
|
|
|
|
len = sprintf(buf, FLT_T_HEX_FMT, tok->u.flt);
|
|
|
|
use = buf;
|
|
|
|
break;
|
|
|
|
default: assert(0);
|
2019-09-03 08:41:37 +00:00
|
|
|
}
|
2019-09-09 14:33:41 +00:00
|
|
|
assert((size_t)len < sizeof(buf));
|
2019-09-05 07:24:24 +00:00
|
|
|
char *p = use + len;
|
2019-09-03 08:41:37 +00:00
|
|
|
while (*--p == ' ') { *p = '\0'; --len; }
|
|
|
|
(void)strncpy(dest, use, size);
|
2019-09-05 07:24:24 +00:00
|
|
|
cur += (size_t)len;
|
2019-09-03 08:41:37 +00:00
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
case OPERATOR: /*{{{*/
|
|
|
|
{
|
|
|
|
static const char *ops[]={ "+", "-", "*", "/", "(", ")", ",", "<", "<=", ">=", ">", "==", "~=", "!=", "^", "%" };
|
|
|
|
|
|
|
|
if (size >1)
|
|
|
|
{
|
|
|
|
dest[cur++]=*ops[tok->u.op];
|
|
|
|
if (*(ops[tok->u.op]+1) && size > cur) dest[cur++]=*(ops[tok->u.op]+1);
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
case LIDENT:
|
|
|
|
cur += print_chars(dest, size, tok->u.lident); break;
|
|
|
|
case FIDENT: cur += print_fident(dest, size, tok->u.fident); break;
|
|
|
|
case LOCATION: /*{{{*/
|
|
|
|
{
|
|
|
|
char buf[128];
|
|
|
|
sprintf(buf, "&(%d,%d,%d)",
|
|
|
|
tok->u.location[X], tok->u.location[Y], tok->u.location[Z]);
|
|
|
|
cur += print_chars(dest, size, buf);
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
case FUNCALL: /*{{{*/
|
|
|
|
{
|
|
|
|
FunctionIdentifier fid = tok->u.funcall.fident;
|
|
|
|
if (tok->u.funcall.argc <= 0)
|
|
|
|
{
|
|
|
|
cur += print_fident(dest+cur, size-cur-1, fid);
|
|
|
|
if (tok->u.funcall.argc == 0)
|
|
|
|
{
|
|
|
|
if (cur < size - 2) { dest[cur++] = '('; dest[cur++] = ')'; }
|
|
|
|
else cur += 2;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
FunctionPrecedence fp = tfunc[fid].precedence;
|
|
|
|
switch (fp)
|
|
|
|
{
|
|
|
|
case PREFIX_FUNC: {
|
|
|
|
cur += print_fident(dest+cur, size-cur-1, fid);
|
|
|
|
if (cur < size) dest[cur++] = '(';
|
2019-09-05 07:24:24 +00:00
|
|
|
for (int ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
|
|
|
if (ai > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
/* The commas eliminate the need for precedence worries in arguments*/
|
|
|
|
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef, tok->u.funcall.argv + ai,
|
2019-09-03 08:41:37 +00:00
|
|
|
NO_PRECEDENCE);
|
|
|
|
}
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case PREFIX_NEG: {
|
|
|
|
assert(tok->u.funcall.argc == 1);
|
|
|
|
assert(tfunc[fid].display_symbol != NULL);
|
|
|
|
if (fp < atprec && cur < size) dest[cur++] = '(';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, tfunc[fid].display_symbol);
|
|
|
|
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef, tok->u.funcall.argv, fp);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (fp < atprec && cur < size) dest[cur++] = ')';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
default: /* infix argument */
|
|
|
|
assert(tok->u.funcall.argc > 1);
|
|
|
|
if (fp < atprec && cur < size) dest[cur++] = '(';
|
|
|
|
/* Check for the special relation sequence notation */
|
|
|
|
bool specialrel = true;
|
|
|
|
if (fid != FUNC_AND || tok->u.funcall.argc < 2) specialrel = false;
|
|
|
|
else {
|
|
|
|
for (int ai = 0; ai < tok->u.funcall.argc; ++ai) {
|
|
|
|
if (tok->u.funcall.argv[ai].type != FUNCALL
|
|
|
|
|| tok->u.funcall.argv[ai].u.funcall.argc != 2
|
|
|
|
|| !IS_RELATION_FUNC(tok->u.funcall.argv[ai].u.funcall.fident))
|
|
|
|
{
|
|
|
|
specialrel = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
if (ai > 0
|
|
|
|
&& !tok_matches(tok->u.funcall.argv[ai].u.funcall.argv,
|
|
|
|
tok->u.funcall.argv[ai-1].u.funcall.argv+1))
|
|
|
|
{
|
|
|
|
specialrel = false;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (specialrel) {
|
|
|
|
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef, tok->u.funcall.argv, INFIX_BOOL);
|
2019-09-03 08:41:37 +00:00
|
|
|
for (int ai = 1; ai < tok->u.funcall.argc && cur < size-1; ++ ai) {
|
|
|
|
dest[cur++] = ' ';
|
|
|
|
const char *use =
|
|
|
|
tfunc[tok->u.funcall.argv[ai].u.funcall.fident].name;
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, use);
|
|
|
|
if (cur < size) dest[cur++] = ' ';
|
|
|
|
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef,
|
2019-09-03 08:41:37 +00:00
|
|
|
tok->u.funcall.argv[ai].u.funcall.argv + 1,
|
|
|
|
INFIX_REL);
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
for (int ai = 0; ai < tok->u.funcall.argc && cur < size-1; ++ai)
|
|
|
|
{
|
|
|
|
bool parenarg = false;
|
|
|
|
if (ai > 0) {
|
|
|
|
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
|
|
|
const char *use = tfunc[fid].display_symbol;
|
|
|
|
if (use == NULL) use = tfunc[fid].name;
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, use);
|
|
|
|
if (fp < INFIX_MUL && cur < size) dest[cur++] = ' ';
|
|
|
|
} else if (fp > PREFIX_NEG) {
|
|
|
|
char powbuf[4096];
|
|
|
|
size_t arglen = ptokatprec(powbuf, sizeof(powbuf), 0, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef, tok->u.funcall.argv, fp);
|
2019-09-05 07:24:24 +00:00
|
|
|
if (arglen >= sizeof(powbuf)-1) assert(0);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (powbuf[0] == '-') {
|
|
|
|
parenarg = true;
|
|
|
|
if (cur < size) dest[cur++] = '(';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
cur += ptokatprec(dest+cur, size-cur-1, field_width-cur, sf, ff,
|
2019-09-09 14:33:41 +00:00
|
|
|
pl, ef, tok->u.funcall.argv + ai, fp);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (parenarg && cur < size) dest[cur++] = ')';
|
|
|
|
}
|
|
|
|
}
|
|
|
|
if (fp < atprec && cur < size) dest[cur++] = ')';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
case BOOL:
|
|
|
|
cur += print_chars(dest, size, (tok->u.bl) ? "true" : "false"); break;
|
|
|
|
case STYLE: /*{{{*/
|
|
|
|
{
|
|
|
|
const char *emptyrep = "background(0)";
|
|
|
|
size_t nfields = 0;
|
|
|
|
if (tok->u.style.precision != NO_PRECISION) ++nfields;
|
|
|
|
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
|
|
|
if (tok->u.style.aspect[ca] != NO_COLOR_SET) ++nfields;
|
|
|
|
if (tok->u.style.adjust != AUTOADJUST) ++nfields;
|
|
|
|
if (tok->u.style.fform != FLT_NO_FORMAT) ++nfields;
|
|
|
|
if (tok->u.style.shadowed_set) ++nfields;
|
|
|
|
if (tok->u.style.transparent_set) ++nfields;
|
2019-09-18 12:49:53 +00:00
|
|
|
if (tok->u.style.dim_set) ++nfields;
|
2019-09-03 08:41:37 +00:00
|
|
|
if (tok->u.style.bold_set) ++nfields;
|
2019-09-18 12:49:53 +00:00
|
|
|
if (tok->u.style.italic_set) ++nfields;
|
2019-09-03 08:41:37 +00:00
|
|
|
if (tok->u.style.underline_set) ++nfields;
|
|
|
|
if (nfields == 0) cur += print_chars(dest, size, emptyrep);
|
|
|
|
else {
|
|
|
|
if (nfields > 1) cur += print_chars(dest, size, "+(");
|
|
|
|
size_t shownfields = 0;
|
|
|
|
if (tok->u.style.precision != NO_PRECISION) {
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "precision(");
|
2019-09-05 07:24:24 +00:00
|
|
|
cur += (size_t)snprintf(dest+cur, size-cur-1, PRECISION_FORMAT,
|
|
|
|
tok->u.style.precision);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
for (ColorAspect ca = FOREGROUND; ca < NUM_COLOR_ASPECTS; ++ca)
|
|
|
|
if (tok->u.style.aspect[ca] != NO_COLOR_SET) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, ColorAspect_Name[ca]);
|
|
|
|
if (cur < size) dest[cur++] = '(';
|
2019-09-05 07:24:24 +00:00
|
|
|
cur += (size_t)snprintf(dest+cur, size-cur-1, COLOR_FORMAT,
|
|
|
|
tok->u.style.aspect[ca]);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
if (tok->u.style.adjust != AUTOADJUST) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "justify(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
Adjust_Name[tok->u.style.adjust]);
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
if (tok->u.style.fform != FLT_NO_FORMAT) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "floatfmt(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
FloatFormat_Name[tok->u.style.fform]);
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
if (tok->u.style.shadowed_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "shadowed(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.shadowed) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
if (tok->u.style.transparent_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "transparent(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.transparent) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
2019-09-18 12:49:53 +00:00
|
|
|
if (tok->u.style.dim_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "dim(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.dim) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
2019-09-03 08:41:37 +00:00
|
|
|
if (tok->u.style.bold_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "bold(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.bold) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
2019-09-18 12:49:53 +00:00
|
|
|
if (tok->u.style.italic_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "italic(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.italic) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
2019-09-03 08:41:37 +00:00
|
|
|
if (tok->u.style.underline_set) {
|
|
|
|
if (shownfields > 0 && cur < size) dest[cur++] = ',';
|
|
|
|
cur += print_chars(dest+cur, size-cur-1, "underline(");
|
|
|
|
cur += print_chars(dest+cur, size-cur-1,
|
|
|
|
(tok->u.style.underline) ? "" : "false");
|
|
|
|
if (cur < size) dest[cur++] = ')';
|
|
|
|
++shownfields;
|
|
|
|
}
|
|
|
|
if (nfields > 1 && cur < size) dest[cur++] = ')';
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
} /*}}}*/
|
|
|
|
case EEK: /*{{{*/
|
|
|
|
{
|
|
|
|
if (ef == RESTORE_ERROR) {
|
|
|
|
strncpy(dest + cur, "error(", size-cur-1);
|
|
|
|
cur += 6;
|
|
|
|
if (cur < size - 1)
|
|
|
|
cur += print_string(dest+cur, size-cur-1, tok->u.err, QUOTE_STRING);
|
|
|
|
if (cur < size - 1)
|
|
|
|
dest[cur++] = ')';
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
(void)strncpy(dest+cur, _("ERROR"), size-cur-1);
|
|
|
|
cur += strlen(_("ERROR"));
|
|
|
|
if (ef == VERBOSE_ERROR)
|
|
|
|
{
|
|
|
|
(void)strncpy(dest+cur, ": ", size-cur-1);
|
|
|
|
cur += 2;
|
|
|
|
size_t errlen = strlen(tok->u.err);
|
|
|
|
if ((cur+errlen+1) < size) strcpy(dest+cur, tok->u.err);
|
|
|
|
else (void)strncpy(dest+cur, tok->u.err, size-cur-1);
|
|
|
|
cur += errlen;
|
|
|
|
}
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
/* default */ /*{{{*/
|
|
|
|
default: assert(0);
|
|
|
|
/*}}}*/
|
|
|
|
}
|
|
|
|
if (cur<size) dest[cur] = 0;
|
|
|
|
else
|
|
|
|
{
|
|
|
|
dest[size-1] = 0;
|
|
|
|
cur = size;
|
|
|
|
}
|
2019-09-05 07:24:24 +00:00
|
|
|
size_t mlen = mbslen(dest);
|
2019-09-03 08:41:37 +00:00
|
|
|
if (field_width && mlen > field_width) {
|
|
|
|
if (field_width < 6) {
|
|
|
|
for (cur = 0; cur < field_width; ++cur) dest[cur] = '#';
|
2019-09-09 14:33:41 +00:00
|
|
|
dest[cur] = '\0';
|
2019-09-03 08:41:37 +00:00
|
|
|
} else {
|
2019-09-09 14:33:41 +00:00
|
|
|
char *ov = mbspos(dest, (int)field_width - 5);
|
2019-09-05 07:24:24 +00:00
|
|
|
cur = (size_t)(ov - dest);
|
2019-09-03 08:41:37 +00:00
|
|
|
cur += print_chars(dest+cur, size-cur-1, "...##");
|
2019-09-09 14:33:41 +00:00
|
|
|
dest[cur] = '\0';
|
2019-09-03 08:41:37 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
return cur;
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
/* printtok -- print a single token, passed by address, although not changed */ /*{{{*/
|
|
|
|
size_t printtok(char* dest, size_t size, size_t field_width,
|
|
|
|
StringFormat sf, FloatFormat ff,
|
2019-09-05 07:24:24 +00:00
|
|
|
PrecisionLevel digits, ErrorFormat ef, const Token *tok)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
|
|
|
return ptokatprec(dest, size, field_width, sf, ff, digits, ef, tok,
|
|
|
|
NO_PRECEDENCE);
|
|
|
|
}
|
|
|
|
/*}}}*/
|
|
|
|
|
|
|
|
static char dbgpbuf[4096];
|
|
|
|
|
|
|
|
/* dbgprint -- simple on the fly print for in the debugger */
|
|
|
|
const char *dbgprint(const Token* tok) {
|
|
|
|
size_t used = printtok(dbgpbuf, sizeof(dbgpbuf), 0, QUOTE_STRING, FLT_COMPACT,
|
|
|
|
-1, VERBOSE_ERROR, tok);
|
|
|
|
if (used > sizeof(dbgpbuf) - 2) {
|
|
|
|
printf(_("Warning: buffer overflow in dbgprint"));
|
|
|
|
}
|
|
|
|
return dbgpbuf;
|
|
|
|
}
|
|
|
|
|
|
|
|
/* print -- print token sequence */ /*{{{*/
|
|
|
|
void print(char *s, size_t size, size_t chars, StringFormat sf, FloatFormat ff,
|
2019-09-05 07:24:24 +00:00
|
|
|
PrecisionLevel digits, Token **n)
|
2019-09-03 08:41:37 +00:00
|
|
|
{
|
|
|
|
size_t cur;
|
|
|
|
|
|
|
|
cur=0;
|
|
|
|
if (n != EMPTY_TVEC)
|
|
|
|
for (; cur<size-1 && (*n) != NULLTOKEN; ++n)
|
|
|
|
cur += printtok(s+cur, size-cur, 0, sf, ff, digits, TRUNCATED_ERROR, *n);
|
|
|
|
if (cur<size) s[cur] = 0;
|
|
|
|
else s[size-1] = 0;
|
|
|
|
if (chars && mbslen(s) > chars) {
|
|
|
|
for (cur=0; cur < chars; ++cur) s[cur] = '#';
|
|
|
|
s[cur] = 0;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
/*}}}*/
|