| | 1986 | /* |
|---|
| | 1987 | * Given a "formatted" chunk of text (i.e. one including tags like {red}{/}) |
|---|
| | 1988 | * in 'source', with starting point 'init', this finds the next section of |
|---|
| | 1989 | * text and any tag that goes with it, return TRUE if it finds something to |
|---|
| | 1990 | * print. |
|---|
| | 1991 | * |
|---|
| | 1992 | * If it returns TRUE, then it also fills 'text' with a pointer to the start |
|---|
| | 1993 | * of the next printable section of text, and 'len' with the length of that |
|---|
| | 1994 | * text, and 'end' with a pointer to the start of the next section. This |
|---|
| | 1995 | * may differ from "text + len" because of the presence of tags. If a tag |
|---|
| | 1996 | * applies to the section of text, it returns a pointer to the start of that |
|---|
| | 1997 | * tag in 'tag' and the length in 'taglen'. Otherwise, 'tag' is filled with |
|---|
| | 1998 | * NULL. |
|---|
| | 1999 | * |
|---|
| | 2000 | * See text_out_e for an example of its use. |
|---|
| | 2001 | */ |
|---|
| | 2002 | bool next_section(const char *source, size_t init, const char **text, size_t *len, const char **tag, size_t *taglen, const char **end) |
|---|
| | 2003 | { |
|---|
| | 2004 | const char *next; |
|---|
| | 2005 | |
|---|
| | 2006 | *tag = NULL; |
|---|
| | 2007 | *text = source + init; |
|---|
| | 2008 | if (*text[0] == '\0') return FALSE; |
|---|
| | 2009 | |
|---|
| | 2010 | next = strchr(*text, '{'); |
|---|
| | 2011 | while (next) |
|---|
| | 2012 | { |
|---|
| | 2013 | const char *s = next + 1; |
|---|
| | 2014 | |
|---|
| | 2015 | while (*s && isalpha((unsigned char) *s)) s++; |
|---|
| | 2016 | |
|---|
| | 2017 | /* Woo! valid opening tag thing */ |
|---|
| | 2018 | if (*s == '}') |
|---|
| | 2019 | { |
|---|
| | 2020 | const char *close = strstr(s, "{/}"); |
|---|
| | 2021 | |
|---|
| | 2022 | /* There's a closing thing, so it's valid. */ |
|---|
| | 2023 | if (close) |
|---|
| | 2024 | { |
|---|
| | 2025 | /* If this tag is at the start of the fragment */ |
|---|
| | 2026 | if (next == *text) |
|---|
| | 2027 | { |
|---|
| | 2028 | *tag = *text + 1; |
|---|
| | 2029 | *taglen = s - *text - 1; |
|---|
| | 2030 | *text = s + 1; |
|---|
| | 2031 | *len = close - *text; |
|---|
| | 2032 | *end = close + 3; |
|---|
| | 2033 | return TRUE; |
|---|
| | 2034 | } |
|---|
| | 2035 | /* Otherwise return the chunk up to this */ |
|---|
| | 2036 | else |
|---|
| | 2037 | { |
|---|
| | 2038 | *len = next - *text; |
|---|
| | 2039 | *end = *text + *len; |
|---|
| | 2040 | return TRUE; |
|---|
| | 2041 | } |
|---|
| | 2042 | } |
|---|
| | 2043 | /* No closing thing, therefore all one lump of text. */ |
|---|
| | 2044 | else |
|---|
| | 2045 | { |
|---|
| | 2046 | *len = strlen(*text); |
|---|
| | 2047 | *end = *text + *len; |
|---|
| | 2048 | return TRUE; |
|---|
| | 2049 | } |
|---|
| | 2050 | } |
|---|
| | 2051 | /* End of the string, that's fine. */ |
|---|
| | 2052 | else if (*s == '\0') |
|---|
| | 2053 | { |
|---|
| | 2054 | *len = strlen(*text); |
|---|
| | 2055 | *end = *text + *len; |
|---|
| | 2056 | return TRUE; |
|---|
| | 2057 | } |
|---|
| | 2058 | /* An invalid tag, skip it. */ |
|---|
| | 2059 | else |
|---|
| | 2060 | { |
|---|
| | 2061 | next = next + 1; |
|---|
| | 2062 | } |
|---|
| | 2063 | |
|---|
| | 2064 | next = strchr(next, '{'); |
|---|
| | 2065 | } |
|---|
| | 2066 | |
|---|
| | 2067 | /* Default to the rest of the string */ |
|---|
| | 2068 | *len = strlen(*text); |
|---|
| | 2069 | *end = *text + *len; |
|---|
| | 2070 | |
|---|
| | 2071 | return TRUE; |
|---|
| | 2072 | } |
|---|
| | 2073 | |
|---|
| | 2074 | /* |
|---|
| | 2075 | * Output text to the screen or to a file depending on the |
|---|
| | 2076 | * selected hook. Takes strings with "embedded formatting", |
|---|
| | 2077 | * such that something within {red}{/} will be printed in red. |
|---|
| | 2078 | * |
|---|
| | 2079 | * Note that such formatting will be treated as a "breakpoint" |
|---|
| | 2080 | * for the printing, so if used within words may lead to part of the |
|---|
| | 2081 | * word being moved to the next line. |
|---|
| | 2082 | */ |
|---|
| | 2083 | void text_out_e(const char *fmt, ...) |
|---|
| | 2084 | { |
|---|
| | 2085 | char buf[1024]; |
|---|
| | 2086 | char smallbuf[1024]; |
|---|
| | 2087 | va_list vp; |
|---|
| | 2088 | |
|---|
| | 2089 | char *start; |
|---|
| | 2090 | const char *next, *text, *tag; |
|---|
| | 2091 | size_t textlen, taglen; |
|---|
| | 2092 | |
|---|
| | 2093 | /* Begin the Varargs Stuff */ |
|---|
| | 2094 | va_start(vp, fmt); |
|---|
| | 2095 | |
|---|
| | 2096 | /* Do the va_arg fmt to the buffer */ |
|---|
| | 2097 | (void)vstrnfmt(buf, sizeof(buf), fmt, vp); |
|---|
| | 2098 | |
|---|
| | 2099 | /* End the Varargs Stuff */ |
|---|
| | 2100 | va_end(vp); |
|---|
| | 2101 | |
|---|
| | 2102 | start = buf; |
|---|
| | 2103 | while (next_section(start, 0, &text, &textlen, &tag, &taglen, &next)) |
|---|
| | 2104 | { |
|---|
| | 2105 | int a = -1; |
|---|
| | 2106 | |
|---|
| | 2107 | memcpy(smallbuf, text, textlen); |
|---|
| | 2108 | smallbuf[textlen] = 0; |
|---|
| | 2109 | |
|---|
| | 2110 | if (tag) |
|---|
| | 2111 | { |
|---|
| | 2112 | char tagbuffer[11]; |
|---|
| | 2113 | |
|---|
| | 2114 | /* Colour names are less than 11 characters long. */ |
|---|
| | 2115 | assert(taglen < 11); |
|---|
| | 2116 | |
|---|
| | 2117 | memcpy(tagbuffer, tag, taglen); |
|---|
| | 2118 | tagbuffer[taglen] = '\0'; |
|---|
| | 2119 | |
|---|
| | 2120 | a = color_text_to_attr(tagbuffer); |
|---|
| | 2121 | } |
|---|
| | 2122 | |
|---|
| | 2123 | if (a == -1) |
|---|
| | 2124 | a = TERM_WHITE; |
|---|
| | 2125 | |
|---|
| | 2126 | /* Output now */ |
|---|
| | 2127 | text_out_hook(a, smallbuf); |
|---|
| | 2128 | |
|---|
| | 2129 | start = next; |
|---|
| | 2130 | } |
|---|
| | 2131 | } |
|---|
| | 2132 | |
|---|
| | 2133 | |
|---|