From: Ari Johnson Date: Sat, 24 Feb 2007 14:43:34 +0000 (+0000) Subject: decompose() now handles ANSI sequences and does not always include an opening backslash X-Git-Tag: 0.73~107 X-Git-Url: https://git.theari.com/?a=commitdiff_plain;h=3c048f1690863ad62a046771fe015d26e37d05d7;p=cobramush.git decompose() now handles ANSI sequences and does not always include an opening backslash --- diff --git a/game/txt/hlp/cobra_func.hlp b/game/txt/hlp/cobra_func.hlp index 8bc0f97..39307af 100644 --- a/game/txt/hlp/cobra_func.hlp +++ b/game/txt/hlp/cobra_func.hlp @@ -1137,7 +1137,8 @@ or used as an attribute for an object (like the description of a mail message object). Since the function preserves the original string, it is, in most cases, a better choice than SECURE(). - + + See also: decompose(), secure() & EVAL() & GET_EVAL() eval(, ) @@ -3121,8 +3122,7 @@ for an object named "Test", preferring a thing over other types. can make output slightly ugly, but it's a good way of preventing other people from doing nasty things with your objects. - See also: ESCAPE() - + See also: decompose(), escape() & SET() set(, ) set(/, ) diff --git a/src/look.c b/src/look.c index 7d28fc8..1be51c8 100644 --- a/src/look.c +++ b/src/look.c @@ -1414,21 +1414,29 @@ char * decompose_str(char *what) { static char value[BUFFER_LEN]; - char *ptr, *s; + char *ptr, *s, *codestart; + char ansi_letter; int len; int dospace; + int flag_depth, ansi_depth; + int digits; len = strlen(what); + flag_depth = 0; + ansi_depth = 0; + /* Go through the string, escaping characters and * turning every other space into %b. */ s = value; ptr = what; +#ifdef NEVER /* Put a \ at the beginning if it won't already be put there, * unless it's a space, which would require %b, %r, or %t anyway */ if (!escaped_chars[(unsigned int) *what] && !isspace(*what)) { safe_chr('\\', value, &s); } +#endif dospace = 1; for (; *ptr; ptr++) { switch (*ptr) { @@ -1448,6 +1456,155 @@ decompose_str(char *what) dospace = 0; safe_str("%t", value, &s); break; + case ESC_CHAR: + ptr++; + if (!*ptr) { + ptr--; + break; + } + /* Check if this is any sort of useful code. */ + if (*ptr == '[' && *(ptr + 1) && *(ptr + 2)) { + codestart = ptr; /* Save the address of the escape code. */ + ptr++; + digits = 0; /* Digit count is zero. */ + /* The following code works in this way: + * 1) If a character is a ;, we are allowed to count 2 more digits + * 2) If the digits count is 3, break out of the "ansi" code. + * 3) If the character is not a number or ;, break out. + * 4) If an 'm' is encountered, the for-loop exits. + * The only non-breaking exit occurs when the code ends with "m". + * Otherwise, we break out with the ptr pointing to the end of + * the invalid code, causing decompose() to ignore it entirely. + */ + for (; *ptr && (*ptr != 'm'); ptr++) { + if (*ptr == ';') { + if (digits == 0) { /* No double-;s are allowed. */ + digits = 3; + break; + } + digits = 0; + } else if (digits >= 2) { + digits = 3; /* If we encounter a 3-number code, break out. */ + break; + } else if (isdigit(*ptr)) { + digits++; /* Count the numbers we encounter. */ + } else { + digits = 3; + break; + } + } + + /* 3 is the break-code. 0 means there's no ANSI at all! */ + if (!*ptr || digits == 3 || digits == 0) { + break; + } + + /* It IS an ansi code! It ends in "m" anyway. + * Set ptr to point to the first digit in the code. We are + * promised at this point that ptr+1 is not NUL. + */ + ptr = codestart + 1; + + /* Check if the first part of the code is two-digit (color) */ + if (*(ptr + 1) >= '0' && *(ptr + 1) <= '7') { + if (flag_depth < ansi_depth) { + safe_str(")]", value, &s); + ansi_depth--; + } + } else { /* ansi "flag", inverse, flash, underline, hilight */ + flag_depth = ansi_depth + 1; + } + /* Check to see if this is an 'ansi-reset' code. */ + if (*ptr == '0' && *(ptr + 1) == 'm') { + for (; ansi_depth > 0; ansi_depth--) { + safe_str(")]", value, &s); + } + flag_depth = 0; + ptr++; + break; + } + + ansi_depth++; + safe_str("[ansi(", value, &s); + dospace = 1; + + /* code for decompiling ansi */ + for (; isdigit(*ptr) || *ptr == ';'; ptr++) { + if (*ptr == ';') /* Yes, it is necessary to do it this way. */ + ptr++; + /* Break if there is an 'm' here. */ + if (!*ptr || !isdigit(*ptr)) + break; + /* Check to see if the code is one character long. */ + if (*(ptr + 1) == ';' || *(ptr + 1) == 'm') { + /* ANSI flag */ + switch (*ptr) { + case '1': + safe_chr('h', value, &s); + break; + case '4': + safe_chr('u', value, &s); + break; + case '5': + safe_chr('f', value, &s); + break; + case '7': + safe_chr('i', value, &s); + break; + default: /* Not a valid code. */ + break; + } + } else { + if (!*(ptr + 1)) + break; /* Sudden string end or lack of real color code. */ + ptr++; + + /* Check if this could be a real color (starts with 3 or 4) */ + if (*(ptr - 1) == '3' || *(ptr - 1) == '4') { + switch (*ptr) { + case '0': + ansi_letter = 'x'; + break; + case '1': + ansi_letter = 'r'; + break; + case '2': + ansi_letter = 'g'; + break; + case '3': + ansi_letter = 'y'; + break; + case '4': + ansi_letter = 'b'; + break; + case '5': + ansi_letter = 'm'; + break; + case '6': + ansi_letter = 'c'; + break; + case '7': + ansi_letter = 'w'; + break; + default: + break; /* Not a valid color. */ + } + /* If background color, change the letter to a capital. */ + if (*(ptr - 1) == '4') + ansi_letter = toupper(ansi_letter); + safe_chr(ansi_letter, value, &s); + } + /* No "else" here: If a two-digit code + * doesn't start with 3 or 4, is isn't ANSI. */ + } + } + safe_chr(',', value, &s); + } else { + ptr--; + /* This shouldn't happen if we only have ansi codes + * So if more dirty things must be added later... */ + } + break; default: if (escaped_chars[(unsigned int) *ptr]) { safe_chr('\\', value, &s); @@ -1461,6 +1618,9 @@ decompose_str(char *what) s -= 1; safe_str("%b", value, &s); } + for (; ansi_depth > 0; ansi_depth--) { + safe_str(")]", value, &s); + } *s = '\0'; return value; }