diff options
Diffstat (limited to 'engines/glk/adrift/scprintf.cpp')
-rw-r--r-- | engines/glk/adrift/scprintf.cpp | 2213 |
1 files changed, 1041 insertions, 1172 deletions
diff --git a/engines/glk/adrift/scprintf.cpp b/engines/glk/adrift/scprintf.cpp index 91ee94e94f..1ea93e880a 100644 --- a/engines/glk/adrift/scprintf.cpp +++ b/engines/glk/adrift/scprintf.cpp @@ -37,20 +37,20 @@ namespace Adrift { /* Assorted definitions and constants. */ static const sc_uint PRINTFILTER_MAGIC = 0xb4736417; -enum -{ BUFFER_GROW_INCREMENT = 32, - ITERATION_LIMIT = 32 +enum { + BUFFER_GROW_INCREMENT = 32, + ITERATION_LIMIT = 32 }; static const sc_char NUL = '\0'; static const sc_char LESSTHAN = '<'; static const sc_char GREATERTHAN = '>'; static const sc_char PERCENT = '%'; static const sc_char *const ENTITY_LESSTHAN = "<", - *const ENTITY_GREATERTHAN = ">", - *const ENTITY_PERCENT = "+percent+"; -enum -{ ENTITY_LENGTH = 4, - PERCENT_LENGTH = 9 + *const ENTITY_GREATERTHAN = ">", + *const ENTITY_PERCENT = "+percent+"; +enum { + ENTITY_LENGTH = 4, + PERCENT_LENGTH = 9 }; static const sc_char *const ESCAPES = "<>%&+"; static const sc_char *const WHITESPACE = "\t\n\v\f\r "; @@ -65,26 +65,25 @@ static sc_bool pf_trace = FALSE; * come before shorter ones. The <br> tag is missing because this is * handled separately, as a simple put of '\n'. */ -typedef struct -{ - const sc_char *const name; - const sc_int length; - const sc_int tag; +typedef struct { + const sc_char *const name; + const sc_int length; + const sc_int tag; } sc_html_tags_t; static const sc_html_tags_t HTML_TAGS_TABLE[] = { - {"bgcolour", 8, SC_TAG_BGCOLOR}, {"bgcolor", 7, SC_TAG_BGCOLOR}, - {"waitkey", 7, SC_TAG_WAITKEY}, - {"center", 6, SC_TAG_CENTER}, {"/center", 7, SC_TAG_ENDCENTER}, - {"centre", 6, SC_TAG_CENTER}, {"/centre", 7, SC_TAG_ENDCENTER}, - {"right", 5, SC_TAG_RIGHT}, {"/right", 6, SC_TAG_ENDRIGHT}, - {"font", 4, SC_TAG_FONT}, {"/font", 5, SC_TAG_ENDFONT}, - {"wait", 4, SC_TAG_WAIT}, {"cls", 3, SC_TAG_CLS}, - {"i", 1, SC_TAG_ITALICS}, {"/i", 2, SC_TAG_ENDITALICS}, - {"b", 1, SC_TAG_BOLD}, {"/b", 2, SC_TAG_ENDBOLD}, - {"u", 1, SC_TAG_UNDERLINE}, {"/u", 2, SC_TAG_ENDUNDERLINE}, - {"c", 1, SC_TAG_COLOR}, {"/c", 2, SC_TAG_ENDCOLOR}, - {NULL, 0, SC_TAG_UNKNOWN} + {"bgcolour", 8, SC_TAG_BGCOLOR}, {"bgcolor", 7, SC_TAG_BGCOLOR}, + {"waitkey", 7, SC_TAG_WAITKEY}, + {"center", 6, SC_TAG_CENTER}, {"/center", 7, SC_TAG_ENDCENTER}, + {"centre", 6, SC_TAG_CENTER}, {"/centre", 7, SC_TAG_ENDCENTER}, + {"right", 5, SC_TAG_RIGHT}, {"/right", 6, SC_TAG_ENDRIGHT}, + {"font", 4, SC_TAG_FONT}, {"/font", 5, SC_TAG_ENDFONT}, + {"wait", 4, SC_TAG_WAIT}, {"cls", 3, SC_TAG_CLS}, + {"i", 1, SC_TAG_ITALICS}, {"/i", 2, SC_TAG_ENDITALICS}, + {"b", 1, SC_TAG_BOLD}, {"/b", 2, SC_TAG_ENDBOLD}, + {"u", 1, SC_TAG_UNDERLINE}, {"/u", 2, SC_TAG_ENDUNDERLINE}, + {"c", 1, SC_TAG_COLOR}, {"/c", 2, SC_TAG_ENDCOLOR}, + {NULL, 0, SC_TAG_UNKNOWN} }; /* @@ -92,15 +91,14 @@ static const sc_html_tags_t HTML_TAGS_TABLE[] = { * associated size and length, a note of any conversion to apply to the next * buffered character, and a flag to let the filter ignore incoming text. */ -typedef struct sc_filter_s -{ - sc_uint magic; - sc_int buffer_length; - sc_int buffer_allocation; - sc_char *buffer; - sc_bool new_sentence; - sc_bool is_muted; - sc_bool needs_filtering; +typedef struct sc_filter_s { + sc_uint magic; + sc_int buffer_length; + sc_int buffer_allocation; + sc_char *buffer; + sc_bool new_sentence; + sc_bool is_muted; + sc_bool needs_filtering; } sc_filter_t; @@ -110,9 +108,8 @@ typedef struct sc_filter_s * Return TRUE if pointer is a valid printfilter, FALSE otherwise. */ static sc_bool -pf_is_valid (sc_filterref_t filter) -{ - return filter && filter->magic == PRINTFILTER_MAGIC; +pf_is_valid(sc_filterref_t filter) { + return filter && filter->magic == PRINTFILTER_MAGIC; } @@ -122,42 +119,38 @@ pf_is_valid (sc_filterref_t filter) * Create and return a new printfilter. */ sc_filterref_t -pf_create (void) -{ - static sc_bool initialized = FALSE; - - sc_filterref_t filter; - - /* On first call only, verify the string lengths in the table. */ - if (!initialized) - { - const sc_html_tags_t *entry; - - /* Compare table lengths with string lengths. */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (entry->length != (sc_int) strlen (entry->name)) - { - sc_fatal ("pf_create:" - " table string length is wrong for \"%s\"\n", - entry->name); - } - } - - initialized = TRUE; - } - - /* Create a new printfilter. */ - filter = (sc_filterref_t)sc_malloc(sizeof (*filter)); - filter->magic = PRINTFILTER_MAGIC; - filter->buffer_length = 0; - filter->buffer_allocation = 0; - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; - - return filter; +pf_create(void) { + static sc_bool initialized = FALSE; + + sc_filterref_t filter; + + /* On first call only, verify the string lengths in the table. */ + if (!initialized) { + const sc_html_tags_t *entry; + + /* Compare table lengths with string lengths. */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (entry->length != (sc_int) strlen(entry->name)) { + sc_fatal("pf_create:" + " table string length is wrong for \"%s\"\n", + entry->name); + } + } + + initialized = TRUE; + } + + /* Create a new printfilter. */ + filter = (sc_filterref_t)sc_malloc(sizeof(*filter)); + filter->magic = PRINTFILTER_MAGIC; + filter->buffer_length = 0; + filter->buffer_allocation = 0; + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; + + return filter; } @@ -167,14 +160,13 @@ pf_create (void) * Destroy a printfilter and free its allocated memory. */ void -pf_destroy (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* Free buffer space, and poison and free the printfilter. */ - sc_free (filter->buffer); - memset (filter, 0xaa, sizeof (*filter)); - sc_free (filter); +pf_destroy(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* Free buffer space, and poison and free the printfilter. */ + sc_free(filter->buffer); + memset(filter, 0xaa, sizeof(*filter)); + sc_free(filter); } @@ -192,115 +184,103 @@ pf_destroy (sc_filterref_t filter) * this is probably all that can be done. */ static sc_char * -pf_interpolate_vars (const sc_char *string, sc_var_setref_t vars) -{ - sc_char *buffer, *name; - const sc_char *cursor; - const sc_char *marker; - sc_bool is_interpolated; - - /* - * Begin with NULL buffer and name strings for lazy allocation, and clear - * interpolation detection flag. - */ - buffer = NULL; - name = NULL; - is_interpolated = FALSE; - - /* Run through the string looking for variables. */ - marker = string; - for (cursor = (const sc_char *)strchr (marker, PERCENT); - cursor; cursor = (const sc_char *)strchr(marker, PERCENT)) - { - sc_int type; - sc_vartype_t vt_rvalue; - sc_char close; - - /* - * If not yet allocated, allocate a buffer for the return string and - * copy up to the percent character into it; otherwise append to buffer - * up to percent character. And if not yet done, allocate a name - * buffer guaranteed long enough. - */ - if (!buffer) - { - buffer = (sc_char *)sc_malloc (cursor - marker + 1); - memcpy (buffer, marker, cursor - marker); - buffer[cursor - marker] = NUL; - } - else - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - strncat (buffer, marker, cursor - marker); - } - if (!name) - name = (sc_char *)sc_malloc (strlen (string) + 1); - - /* - * Get the variable name, and from that, the value. If we encounter a - * mismatched '%' or unknown variable, skip it. - */ - if (sscanf (cursor, "%%%[^%]%c", name, &close) != 2 - || close != PERCENT - || !var_get (vars, name, &type, &vt_rvalue)) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + 2); - strncat (buffer, cursor, 1); - marker = cursor + 1; - continue; - } - - /* Get variable value and append to the string. */ - switch (type) - { - case VAR_INTEGER: - { - sc_char value[32]; - - sprintf (value, "%ld", vt_rvalue.integer); - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (value) + 1); - strcat (buffer, value); - break; - } - - case VAR_STRING: - buffer = (sc_char *)sc_realloc (buffer, - strlen (buffer) + strlen (vt_rvalue.string) + 1); - strcat (buffer, vt_rvalue.string); - break; - - default: - sc_fatal ("pf_interpolate_vars: invalid variable type, %ld\n", type); - } - - /* Advance over the %...% variable name, and note success. */ - marker = cursor + strlen (name) + 2; - is_interpolated = TRUE; - } - - /* - * If we allocated a buffer and interpolated into it, append the remainder - * of the string. If we didn't interpolate successfully (the input contained - * a rogue '%' character), throw out the buffer as it will be the same as - * our input. - */ - if (buffer) - { - if (is_interpolated) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (marker) + 1); - strcat (buffer, marker); - } - else - { - sc_free (buffer); - buffer = NULL; - } - } - - /* Clean up, and return either the updated string or NULL. */ - sc_free (name); - return buffer; +pf_interpolate_vars(const sc_char *string, sc_var_setref_t vars) { + sc_char *buffer, *name; + const sc_char *cursor; + const sc_char *marker; + sc_bool is_interpolated; + + /* + * Begin with NULL buffer and name strings for lazy allocation, and clear + * interpolation detection flag. + */ + buffer = NULL; + name = NULL; + is_interpolated = FALSE; + + /* Run through the string looking for variables. */ + marker = string; + for (cursor = (const sc_char *)strchr(marker, PERCENT); + cursor; cursor = (const sc_char *)strchr(marker, PERCENT)) { + sc_int type; + sc_vartype_t vt_rvalue; + sc_char close; + + /* + * If not yet allocated, allocate a buffer for the return string and + * copy up to the percent character into it; otherwise append to buffer + * up to percent character. And if not yet done, allocate a name + * buffer guaranteed long enough. + */ + if (!buffer) { + buffer = (sc_char *)sc_malloc(cursor - marker + 1); + memcpy(buffer, marker, cursor - marker); + buffer[cursor - marker] = NUL; + } else { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + strncat(buffer, marker, cursor - marker); + } + if (!name) + name = (sc_char *)sc_malloc(strlen(string) + 1); + + /* + * Get the variable name, and from that, the value. If we encounter a + * mismatched '%' or unknown variable, skip it. + */ + if (sscanf(cursor, "%%%[^%]%c", name, &close) != 2 + || close != PERCENT + || !var_get(vars, name, &type, &vt_rvalue)) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + 2); + strncat(buffer, cursor, 1); + marker = cursor + 1; + continue; + } + + /* Get variable value and append to the string. */ + switch (type) { + case VAR_INTEGER: { + sc_char value[32]; + + sprintf(value, "%ld", vt_rvalue.integer); + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(value) + 1); + strcat(buffer, value); + break; + } + + case VAR_STRING: + buffer = (sc_char *)sc_realloc(buffer, + strlen(buffer) + strlen(vt_rvalue.string) + 1); + strcat(buffer, vt_rvalue.string); + break; + + default: + sc_fatal("pf_interpolate_vars: invalid variable type, %ld\n", type); + } + + /* Advance over the %...% variable name, and note success. */ + marker = cursor + strlen(name) + 2; + is_interpolated = TRUE; + } + + /* + * If we allocated a buffer and interpolated into it, append the remainder + * of the string. If we didn't interpolate successfully (the input contained + * a rogue '%' character), throw out the buffer as it will be the same as + * our input. + */ + if (buffer) { + if (is_interpolated) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(marker) + 1); + strcat(buffer, marker); + } else { + sc_free(buffer); + buffer = NULL; + } + } + + /* Clean up, and return either the updated string or NULL. */ + sc_free(name); + return buffer; } @@ -312,69 +292,62 @@ pf_interpolate_vars (const sc_char *string, sc_var_setref_t vars) * reallocating if necessary. Return TRUE if the buffer was changed. */ static sc_bool -pf_replace_alr (const sc_char *string, - sc_char **buffer, sc_int alr, sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[3]; - const sc_char *marker, *cursor, *original, *replacement; - sc_char *buffer_ = *buffer; - - /* Retrieve the ALR original string, set replacement to NULL for now. */ - vt_key[0].string = "ALRs"; - vt_key[1].integer = alr; - vt_key[2].string = "Original"; - original = prop_get_string (bundle, "S<-sis", vt_key); - replacement = NULL; - - /* Ignore pathological empty originals. */ - if (original[0] == NUL) - return FALSE; - - /* Run through the marker string looking for things to replace. */ - marker = string; - for (cursor = strstr (marker, original); - cursor; cursor = strstr (marker, original)) - { - /* Optimize by retrieving the replacement string only on demand. */ - if (!replacement) - { - vt_key[2].string = "Replacement"; - replacement = prop_get_string (bundle, "S<-sis", vt_key); - } - - /* - * If not yet allocated, allocate a buffer for the return string and - * copy; else append to the existing buffer: basic copy-on-write. - */ - if (!buffer_) - { - buffer_ = (sc_char *)sc_malloc (cursor - marker + strlen (replacement) + 1); - memcpy (buffer_, marker, cursor - marker); - buffer_[cursor - marker] = NUL; - strcat (buffer_, replacement); - } - else - { - buffer_ = (sc_char *)sc_realloc (buffer_, strlen (buffer_) + - cursor - marker + strlen (replacement) + 1); - strncat (buffer_, marker, cursor - marker); - strcat (buffer_, replacement); - } - - /* Advance over the original. */ - marker = cursor + strlen (original); - } - - /* If any pending text, append it to the buffer. */ - if (replacement) - { - buffer_ = (sc_char *)sc_realloc (buffer_, strlen (buffer_) + strlen (marker) + 1); - strcat (buffer_, marker); - } - - /* Write back buffer, and if replacement set, the buffer was altered. */ - *buffer = buffer_; - return replacement != NULL; +pf_replace_alr(const sc_char *string, + sc_char **buffer, sc_int alr, sc_prop_setref_t bundle) { + sc_vartype_t vt_key[3]; + const sc_char *marker, *cursor, *original, *replacement; + sc_char *buffer_ = *buffer; + + /* Retrieve the ALR original string, set replacement to NULL for now. */ + vt_key[0].string = "ALRs"; + vt_key[1].integer = alr; + vt_key[2].string = "Original"; + original = prop_get_string(bundle, "S<-sis", vt_key); + replacement = NULL; + + /* Ignore pathological empty originals. */ + if (original[0] == NUL) + return FALSE; + + /* Run through the marker string looking for things to replace. */ + marker = string; + for (cursor = strstr(marker, original); + cursor; cursor = strstr(marker, original)) { + /* Optimize by retrieving the replacement string only on demand. */ + if (!replacement) { + vt_key[2].string = "Replacement"; + replacement = prop_get_string(bundle, "S<-sis", vt_key); + } + + /* + * If not yet allocated, allocate a buffer for the return string and + * copy; else append to the existing buffer: basic copy-on-write. + */ + if (!buffer_) { + buffer_ = (sc_char *)sc_malloc(cursor - marker + strlen(replacement) + 1); + memcpy(buffer_, marker, cursor - marker); + buffer_[cursor - marker] = NUL; + strcat(buffer_, replacement); + } else { + buffer_ = (sc_char *)sc_realloc(buffer_, strlen(buffer_) + + cursor - marker + strlen(replacement) + 1); + strncat(buffer_, marker, cursor - marker); + strcat(buffer_, replacement); + } + + /* Advance over the original. */ + marker = cursor + strlen(original); + } + + /* If any pending text, append it to the buffer. */ + if (replacement) { + buffer_ = (sc_char *)sc_realloc(buffer_, strlen(buffer_) + strlen(marker) + 1); + strcat(buffer_, marker); + } + + /* Write back buffer, and if replacement set, the buffer was altered. */ + *buffer = buffer_; + return replacement != NULL; } @@ -386,82 +359,75 @@ pf_replace_alr (const sc_char *string, * otherwise returns NULL. */ static sc_char * -pf_replace_alrs (const sc_char *string, sc_prop_setref_t bundle, - sc_bool alr_applied[], sc_int alr_count) -{ - sc_int index_; - sc_char *buffer1, *buffer2, **buffer; - const sc_char *marker; - - /* - * Begin with NULL buffers and alternate for lazy allocation. To avoid a - * lot of allocation and copying, we use two buffers to help with repeated - * ALR replacement. - */ - buffer1 = buffer2 = NULL; - buffer = &buffer1; - - /* Run through each ALR that exists. */ - marker = string; - for (index_ = 0; index_ < alr_count; index_++) - { - sc_vartype_t vt_key[3]; - sc_int alr; - - /* - * Ignore ALR indexes that have already been applied. This prevents - * endless loops in ALR replacement. - */ - if (alr_applied[index_]) - continue; - - /* - * Get the actual ALR number for the ALR. This comes from the index - * that we sorted earlier by length of original string. Try replacing - * that ALR in the current marker string. - */ - vt_key[0].string = "ALRs2"; - vt_key[1].integer = index_; - vt_key[2].string = "ALRIndex"; - alr = prop_get_integer (bundle, "I<-sis", vt_key); - - if (pf_replace_alr (marker, buffer, alr, bundle)) - { - /* - * The current buffer in use has been altered. This means that we - * have to switch the marker string to the buffer containing the - * replacement, and switch 'buffer' to the other one for the next - * ALR iteration. - */ - marker = *buffer; - buffer = (buffer == &buffer1) ? &buffer2 : &buffer1; - - /* Discard any content in the buffer switched to above. */ - if (*buffer) - (*buffer)[0] = NUL; - - /* Note this ALR as "used up", and unavailable for future passes. */ - alr_applied[index_] = TRUE; - } - } - - /* - * If marker points to one or other of the buffers, that buffer is the - * return string, and the other is garbage, and should now be freed (or - * was never used, in which case it is NULL). - */ - if (marker == buffer1) - { - sc_free (buffer2); - return buffer1; - } - else if (marker == buffer2) - { - sc_free (buffer1); - return buffer2; - } - else - return NULL; +pf_replace_alrs(const sc_char *string, sc_prop_setref_t bundle, + sc_bool alr_applied[], sc_int alr_count) { + sc_int index_; + sc_char *buffer1, *buffer2, **buffer; + const sc_char *marker; + + /* + * Begin with NULL buffers and alternate for lazy allocation. To avoid a + * lot of allocation and copying, we use two buffers to help with repeated + * ALR replacement. + */ + buffer1 = buffer2 = NULL; + buffer = &buffer1; + + /* Run through each ALR that exists. */ + marker = string; + for (index_ = 0; index_ < alr_count; index_++) { + sc_vartype_t vt_key[3]; + sc_int alr; + + /* + * Ignore ALR indexes that have already been applied. This prevents + * endless loops in ALR replacement. + */ + if (alr_applied[index_]) + continue; + + /* + * Get the actual ALR number for the ALR. This comes from the index + * that we sorted earlier by length of original string. Try replacing + * that ALR in the current marker string. + */ + vt_key[0].string = "ALRs2"; + vt_key[1].integer = index_; + vt_key[2].string = "ALRIndex"; + alr = prop_get_integer(bundle, "I<-sis", vt_key); + + if (pf_replace_alr(marker, buffer, alr, bundle)) { + /* + * The current buffer in use has been altered. This means that we + * have to switch the marker string to the buffer containing the + * replacement, and switch 'buffer' to the other one for the next + * ALR iteration. + */ + marker = *buffer; + buffer = (buffer == &buffer1) ? &buffer2 : &buffer1; + + /* Discard any content in the buffer switched to above. */ + if (*buffer) + (*buffer)[0] = NUL; + + /* Note this ALR as "used up", and unavailable for future passes. */ + alr_applied[index_] = TRUE; + } + } + + /* + * If marker points to one or other of the buffers, that buffer is the + * return string, and the other is garbage, and should now be freed (or + * was never used, in which case it is NULL). + */ + if (marker == buffer1) { + sc_free(buffer2); + return buffer1; + } else if (marker == buffer2) { + sc_free(buffer1); + return buffer2; + } else + return NULL; } @@ -472,56 +438,47 @@ pf_replace_alrs (const sc_char *string, sc_prop_setref_t bundle, * +percent+ with < > %, then send to the OS-specific output functions. */ static void -pf_output_text (const sc_char *string) -{ - sc_int index_, b_index; - sc_char *buffer; - - /* Optimize away the allocation and copy if possible. */ - if (!(strstr (string, ENTITY_LESSTHAN) - || strstr (string, ENTITY_GREATERTHAN) - || strstr (string, ENTITY_PERCENT))) - { - if_print_string (string); - return; - } - - /* - * Copy characters from the string into the buffer, replacing any &..; - * elements by their single-character equivalents. We also replace any - * +percent+ elements by percent characters; apparently an undocumented - * Adrift Runner extension. - */ - buffer = (sc_char *)sc_malloc (strlen (string) + 1); - for (index_ = 0, b_index = 0; - string[index_] != NUL; index_++, b_index++) - { - if (sc_strncasecmp (string + index_, - ENTITY_LESSTHAN, ENTITY_LENGTH) == 0) - { - buffer[b_index] = LESSTHAN; - index_ += ENTITY_LENGTH - 1; - } - else if (sc_strncasecmp (string + index_, - ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0) - { - buffer[b_index] = GREATERTHAN; - index_ += ENTITY_LENGTH - 1; - } - else if (sc_strncasecmp (string + index_, - ENTITY_PERCENT, PERCENT_LENGTH) == 0) - { - buffer[b_index] = PERCENT; - index_ += PERCENT_LENGTH - 1; - } - else - buffer[b_index] = string[index_]; - } - - /* Terminate, print, and free the buffer. */ - buffer[b_index] = NUL; - if_print_string (buffer); - sc_free (buffer); +pf_output_text(const sc_char *string) { + sc_int index_, b_index; + sc_char *buffer; + + /* Optimize away the allocation and copy if possible. */ + if (!(strstr(string, ENTITY_LESSTHAN) + || strstr(string, ENTITY_GREATERTHAN) + || strstr(string, ENTITY_PERCENT))) { + if_print_string(string); + return; + } + + /* + * Copy characters from the string into the buffer, replacing any &..; + * elements by their single-character equivalents. We also replace any + * +percent+ elements by percent characters; apparently an undocumented + * Adrift Runner extension. + */ + buffer = (sc_char *)sc_malloc(strlen(string) + 1); + for (index_ = 0, b_index = 0; + string[index_] != NUL; index_++, b_index++) { + if (sc_strncasecmp(string + index_, + ENTITY_LESSTHAN, ENTITY_LENGTH) == 0) { + buffer[b_index] = LESSTHAN; + index_ += ENTITY_LENGTH - 1; + } else if (sc_strncasecmp(string + index_, + ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0) { + buffer[b_index] = GREATERTHAN; + index_ += ENTITY_LENGTH - 1; + } else if (sc_strncasecmp(string + index_, + ENTITY_PERCENT, PERCENT_LENGTH) == 0) { + buffer[b_index] = PERCENT; + index_ += PERCENT_LENGTH - 1; + } else + buffer[b_index] = string[index_]; + } + + /* Terminate, print, and free the buffer. */ + buffer[b_index] = NUL; + if_print_string(buffer); + sc_free(buffer); } @@ -531,53 +488,48 @@ pf_output_text (const sc_char *string) * Output an HTML-like tag element to the OS-specific tag handling function. */ static void -pf_output_tag (const sc_char *contents) -{ - const sc_html_tags_t *entry; - const sc_char *argument; - - /* For a simple <br> tag, just print out a newline. */ - if (sc_compare_word (contents, "br", 2)) - { - if_print_character ('\n'); - return; - } - - /* - * Search for the name in the HTML tags table. It should be a full match, - * that is, the character after the matched name must be space or NUL. - * The <bgcolour="xyz"> tag is the exception; here the terminator is '='. - */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (sc_strncasecmp (contents, entry->name, entry->length) == 0) - { - sc_char next; - - next = contents[entry->length]; - if (next == NUL || sc_isspace (next) - || (entry->tag == SC_TAG_BGCOLOR && next == '=')) - break; - } - } - - /* If not matched, output an unknown tag with contents as its argument. */ - if (!entry->name) - { - if_print_tag (SC_TAG_UNKNOWN, contents); - return; - } - - /* - * Find the argument by skipping the tag name and any spaces. Again, for - * <bgcolour="xyz">, make a special case, passing the complete contents as - * argument (to match <font colour=...> for the client. - */ - argument = contents; - argument += (entry->tag != SC_TAG_BGCOLOR) ? entry->length : 0; - while (sc_isspace (argument[0])) - argument++; - if_print_tag (entry->tag, argument); +pf_output_tag(const sc_char *contents) { + const sc_html_tags_t *entry; + const sc_char *argument; + + /* For a simple <br> tag, just print out a newline. */ + if (sc_compare_word(contents, "br", 2)) { + if_print_character('\n'); + return; + } + + /* + * Search for the name in the HTML tags table. It should be a full match, + * that is, the character after the matched name must be space or NUL. + * The <bgcolour="xyz"> tag is the exception; here the terminator is '='. + */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (sc_strncasecmp(contents, entry->name, entry->length) == 0) { + sc_char next; + + next = contents[entry->length]; + if (next == NUL || sc_isspace(next) + || (entry->tag == SC_TAG_BGCOLOR && next == '=')) + break; + } + } + + /* If not matched, output an unknown tag with contents as its argument. */ + if (!entry->name) { + if_print_tag(SC_TAG_UNKNOWN, contents); + return; + } + + /* + * Find the argument by skipping the tag name and any spaces. Again, for + * <bgcolour="xyz">, make a special case, passing the complete contents as + * argument (to match <font colour=...> for the client. + */ + argument = contents; + argument += (entry->tag != SC_TAG_BGCOLOR) ? entry->length : 0; + while (sc_isspace(argument[0])) + argument++; + if_print_tag(entry->tag, argument); } @@ -588,79 +540,73 @@ pf_output_tag (const sc_char *contents) * tags. */ static void -pf_output_untagged (const sc_char *string) -{ +pf_output_untagged(const sc_char *string) { sc_char *temporary, *untagged, *contents; const sc_char *cursor; - const sc_char *marker; - - /* - * Optimize away the allocation and copy if possible. We need to check - * here both for tags and for entities; only if neither occurs is it safe - * to output the string directly. - */ - if (!strchr (string, LESSTHAN) - && !(strstr (string, ENTITY_LESSTHAN) - || strstr (string, ENTITY_GREATERTHAN) - || strstr (string, ENTITY_PERCENT))) - { - if_print_string (string); - return; - } - - /* - * Create a general temporary string, and alias it to both untagged text - * and the tag name, for sharing inside the loop. - */ - temporary = (sc_char *)sc_malloc (strlen (string) + 1); - untagged = contents = temporary; - - /* Run through the string looking for <...> tags. */ - marker = string; - for (cursor = (const sc_char *)strchr (marker, LESSTHAN); - cursor; cursor = (const sc_char *)strchr (marker, LESSTHAN)) - { - sc_char close; - - /* Handle characters up to the tag start; untagged text. */ - memcpy (untagged, marker, cursor - marker); - untagged[cursor - marker] = NUL; - pf_output_text (untagged); - - /* Catch and ignore completely empty tags. */ - if (cursor[1] == GREATERTHAN) - { - marker = cursor + 2; - continue; - } - - /* - * Get the text within the tag, reusing the temporary buffer. If this - * fails, allow the remainder of the line to be delivered as a tag; - * unknown, probably. - */ - if (sscanf (cursor, "<%[^>]%c", contents, &close) != 2 - || close != GREATERTHAN) - { - if (sscanf (cursor, "<%[^>]", contents) != 1) - { - sc_error ("pf_output_untagged: mismatched '%c'\n", LESSTHAN); - if_print_character (LESSTHAN); - marker = cursor + 1; - continue; - } - } - - /* Output tag, and advance marker over the <...> tag. */ - if (!sc_strempty (contents)) - pf_output_tag (contents); - marker = cursor + strlen (contents) + 1; - marker += (marker[0] == GREATERTHAN) ? 1 : 0; - } - - /* Output any remaining string text, and free the temporary buffer. */ - pf_output_text (marker); - sc_free (temporary); + const sc_char *marker; + + /* + * Optimize away the allocation and copy if possible. We need to check + * here both for tags and for entities; only if neither occurs is it safe + * to output the string directly. + */ + if (!strchr(string, LESSTHAN) + && !(strstr(string, ENTITY_LESSTHAN) + || strstr(string, ENTITY_GREATERTHAN) + || strstr(string, ENTITY_PERCENT))) { + if_print_string(string); + return; + } + + /* + * Create a general temporary string, and alias it to both untagged text + * and the tag name, for sharing inside the loop. + */ + temporary = (sc_char *)sc_malloc(strlen(string) + 1); + untagged = contents = temporary; + + /* Run through the string looking for <...> tags. */ + marker = string; + for (cursor = (const sc_char *)strchr(marker, LESSTHAN); + cursor; cursor = (const sc_char *)strchr(marker, LESSTHAN)) { + sc_char close; + + /* Handle characters up to the tag start; untagged text. */ + memcpy(untagged, marker, cursor - marker); + untagged[cursor - marker] = NUL; + pf_output_text(untagged); + + /* Catch and ignore completely empty tags. */ + if (cursor[1] == GREATERTHAN) { + marker = cursor + 2; + continue; + } + + /* + * Get the text within the tag, reusing the temporary buffer. If this + * fails, allow the remainder of the line to be delivered as a tag; + * unknown, probably. + */ + if (sscanf(cursor, "<%[^>]%c", contents, &close) != 2 + || close != GREATERTHAN) { + if (sscanf(cursor, "<%[^>]", contents) != 1) { + sc_error("pf_output_untagged: mismatched '%c'\n", LESSTHAN); + if_print_character(LESSTHAN); + marker = cursor + 1; + continue; + } + } + + /* Output tag, and advance marker over the <...> tag. */ + if (!sc_strempty(contents)) + pf_output_tag(contents); + marker = cursor + strlen(contents) + 1; + marker += (marker[0] == GREATERTHAN) ? 1 : 0; + } + + /* Output any remaining string text, and free the temporary buffer. */ + pf_output_text(marker); + sc_free(temporary); } @@ -691,118 +637,102 @@ pf_output_untagged (const sc_char *string) * */ static sc_char * -pf_filter_internal (const sc_char *string, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - sc_int alr_count, iteration; - sc_char *current; - sc_bool *alr_applied; - assert (string && vars); - - if (pf_trace) - sc_trace ("Printfilter: initial \"%s\"\n", string); - - /* If including ALRs, create a common set of ALR application flags. */ - if (bundle) - { - sc_vartype_t vt_key; - - /* Obtain a count of ALRs. */ - vt_key.string = "ALRs"; - alr_count = prop_get_child_count (bundle, "I<-s", &vt_key); - - /* - * Create a new set of ALR application flags. These are used to ensure - * that a given ALR is applied only once on a given pass. If the game - * has no ALRs, don't create a flag set. - */ - if (alr_count > 0) - { - alr_applied = (sc_bool *)sc_malloc (alr_count * sizeof (*alr_applied)); - memset (alr_applied, FALSE, alr_count * sizeof (*alr_applied)); - } - else - alr_applied = NULL; - } - else - { - /* Not including ALRs, so set alr count to 0, and flags to NULL. */ - alr_count = 0; - alr_applied = NULL; - } - - /* Loop for a sort-of arbitrary number of passes; probably enough. */ - current = NULL; - for (iteration = 0; iteration < ITERATION_LIMIT; iteration++) - { - sc_int inner_iteration; - const sc_char *initial; - sc_char *intermediate; - - /* Note the initial string, so we can check for no change. */ - initial = current; - - for (inner_iteration = 0; - inner_iteration < ITERATION_LIMIT; inner_iteration++) - { - /* - * Interpolate variables. If any changes were made, advance current - * to the interpolated version, and free the old current if required. - * Work on the current string, if any, otherwise the input string. - */ - intermediate = pf_interpolate_vars (current ? current : string, vars); - if (intermediate) - { - sc_free (current); - current = intermediate; - if (pf_trace) - { - sc_trace ("Printfilter: interpolated [%ld,%ld] \"%s\"\n", - iteration, inner_iteration, current); - } - } - else - break; - } - - /* If we have ALRs to process, search out and replace all findable. */ - if (alr_count > 0) - { - /* Replace ALRs until no more ALRs can be found. */ - inner_iteration = 0; - while (TRUE) - { - /* - * Replace ALRs, and advance current as for variables above. - * Leave the loop when ALR replacements stop. Again, work on - * the current string if any, otherwise the input string. - */ - intermediate = pf_replace_alrs (current ? current : string, - bundle, alr_applied, alr_count); - if (intermediate) - { - sc_free (current); - current = intermediate; - if (pf_trace) - { - sc_trace ("Printfilter: replaced [%ld,%ld] \"%s\"\n", - iteration, inner_iteration, current); - } - } - else - break; - inner_iteration++; - } - } - - /* If nothing changed this iteration, stop now. */ - if (current == initial) - break; - } - - /* Free any ALR application flags, and return current, NULL if no change. */ - sc_free (alr_applied); - return current; +pf_filter_internal(const sc_char *string, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + sc_int alr_count, iteration; + sc_char *current; + sc_bool *alr_applied; + assert(string && vars); + + if (pf_trace) + sc_trace("Printfilter: initial \"%s\"\n", string); + + /* If including ALRs, create a common set of ALR application flags. */ + if (bundle) { + sc_vartype_t vt_key; + + /* Obtain a count of ALRs. */ + vt_key.string = "ALRs"; + alr_count = prop_get_child_count(bundle, "I<-s", &vt_key); + + /* + * Create a new set of ALR application flags. These are used to ensure + * that a given ALR is applied only once on a given pass. If the game + * has no ALRs, don't create a flag set. + */ + if (alr_count > 0) { + alr_applied = (sc_bool *)sc_malloc(alr_count * sizeof(*alr_applied)); + memset(alr_applied, FALSE, alr_count * sizeof(*alr_applied)); + } else + alr_applied = NULL; + } else { + /* Not including ALRs, so set alr count to 0, and flags to NULL. */ + alr_count = 0; + alr_applied = NULL; + } + + /* Loop for a sort-of arbitrary number of passes; probably enough. */ + current = NULL; + for (iteration = 0; iteration < ITERATION_LIMIT; iteration++) { + sc_int inner_iteration; + const sc_char *initial; + sc_char *intermediate; + + /* Note the initial string, so we can check for no change. */ + initial = current; + + for (inner_iteration = 0; + inner_iteration < ITERATION_LIMIT; inner_iteration++) { + /* + * Interpolate variables. If any changes were made, advance current + * to the interpolated version, and free the old current if required. + * Work on the current string, if any, otherwise the input string. + */ + intermediate = pf_interpolate_vars(current ? current : string, vars); + if (intermediate) { + sc_free(current); + current = intermediate; + if (pf_trace) { + sc_trace("Printfilter: interpolated [%ld,%ld] \"%s\"\n", + iteration, inner_iteration, current); + } + } else + break; + } + + /* If we have ALRs to process, search out and replace all findable. */ + if (alr_count > 0) { + /* Replace ALRs until no more ALRs can be found. */ + inner_iteration = 0; + while (TRUE) { + /* + * Replace ALRs, and advance current as for variables above. + * Leave the loop when ALR replacements stop. Again, work on + * the current string if any, otherwise the input string. + */ + intermediate = pf_replace_alrs(current ? current : string, + bundle, alr_applied, alr_count); + if (intermediate) { + sc_free(current); + current = intermediate; + if (pf_trace) { + sc_trace("Printfilter: replaced [%ld,%ld] \"%s\"\n", + iteration, inner_iteration, current); + } + } else + break; + inner_iteration++; + } + } + + /* If nothing changed this iteration, stop now. */ + if (current == initial) + break; + } + + /* Free any ALR application flags, and return current, NULL if no change. */ + sc_free(alr_applied); + return current; } @@ -814,22 +744,20 @@ pf_filter_internal (const sc_char *string, * needs to free. */ sc_char * -pf_filter (const sc_char *string, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - sc_char *current; - - /* Filter this string, including ALRs replacements. */ - current = pf_filter_internal (string, vars, bundle); - - /* Our contract is to return an allocated string; copy if required. */ - if (!current) - { - current = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (current, string); - } - - return current; +pf_filter(const sc_char *string, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + sc_char *current; + + /* Filter this string, including ALRs replacements. */ + current = pf_filter_internal(string, vars, bundle); + + /* Our contract is to return an allocated string; copy if required. */ + if (!current) { + current = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(current, string); + } + + return current; } @@ -842,21 +770,19 @@ pf_filter (const sc_char *string, * an allocated string that the caller needs to free. */ sc_char * -pf_filter_for_info (const sc_char *string, sc_var_setref_t vars) -{ - sc_char *current; +pf_filter_for_info(const sc_char *string, sc_var_setref_t vars) { + sc_char *current; - /* Filter this string, excluding ALRs replacements. */ - current = pf_filter_internal (string, vars, NULL); + /* Filter this string, excluding ALRs replacements. */ + current = pf_filter_internal(string, vars, NULL); - /* Our contract is to return an allocated string; copy if required. */ - if (!current) - { - current = (sc_char *)sc_malloc (strlen (string) + 1); - strcpy (current, string); - } + /* Our contract is to return an allocated string; copy if required. */ + if (!current) { + current = (sc_char *)sc_malloc(strlen(string) + 1); + strcpy(current, string); + } - return current; + return current; } @@ -867,45 +793,39 @@ pf_filter_for_info (const sc_char *string, sc_var_setref_t vars) * send the resulting string to the output channel. */ void -pf_flush (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - assert (pf_is_valid (filter)); - assert (vars && bundle); - - /* See if there is any buffered data to flush. */ - if (filter->buffer_length > 0) - { - /* - * Filter the buffered string, then print it untagged. Remember to free - * the filtered version. If filtering made no difference, or if the - * buffer was already filtered by, say, checkpointing, just print the - * original buffer untagged instead. - */ - if (filter->needs_filtering) - { - sc_char *filtered; - - filtered = pf_filter_internal (filter->buffer, vars, bundle); - if (filtered) - { - pf_output_untagged (filtered); - sc_free (filtered); - } - else - pf_output_untagged (filter->buffer); - } - else - pf_output_untagged (filter->buffer); - - /* Remove buffered data by resetting length to zero. */ - filter->buffer_length = 0; - filter->needs_filtering = FALSE; - } - - /* Reset new sentence and mute flags. */ - filter->new_sentence = FALSE; - filter->is_muted = FALSE; +pf_flush(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + assert(pf_is_valid(filter)); + assert(vars && bundle); + + /* See if there is any buffered data to flush. */ + if (filter->buffer_length > 0) { + /* + * Filter the buffered string, then print it untagged. Remember to free + * the filtered version. If filtering made no difference, or if the + * buffer was already filtered by, say, checkpointing, just print the + * original buffer untagged instead. + */ + if (filter->needs_filtering) { + sc_char *filtered; + + filtered = pf_filter_internal(filter->buffer, vars, bundle); + if (filtered) { + pf_output_untagged(filtered); + sc_free(filtered); + } else + pf_output_untagged(filter->buffer); + } else + pf_output_untagged(filter->buffer); + + /* Remove buffered data by resetting length to zero. */ + filter->buffer_length = 0; + filter->needs_filtering = FALSE; + } + + /* Reset new sentence and mute flags. */ + filter->new_sentence = FALSE; + filter->is_muted = FALSE; } @@ -915,38 +835,36 @@ pf_flush (sc_filterref_t filter, * Append a string to the filter buffer. */ static void -pf_append_string (sc_filterref_t filter, const sc_char *string) -{ - sc_int length, required; - - /* - * Calculate the required buffer size to append string. Remember to add - * one for the terminating NUL. - */ - length = strlen (string); - required = filter->buffer_length + length + 1; - - /* If this is more than the current buffer allocation, resize it. */ - if (required > filter->buffer_allocation) - { - sc_int new_allocation; - - /* Calculate the new malloc size, in increment chunks. */ - new_allocation = ((required + BUFFER_GROW_INCREMENT - 1) - / BUFFER_GROW_INCREMENT) * BUFFER_GROW_INCREMENT; - - /* Grow the buffer. */ - filter->buffer = (sc_char *)sc_realloc (filter->buffer, new_allocation); - filter->buffer_allocation = new_allocation; - } - - /* If empty, put a NUL into the buffer to permit strcat. */ - if (filter->buffer_length == 0) - filter->buffer[0] = NUL; - - /* Append the string to the buffer and extend length. */ - strcat (filter->buffer, string); - filter->buffer_length += length; +pf_append_string(sc_filterref_t filter, const sc_char *string) { + sc_int length, required; + + /* + * Calculate the required buffer size to append string. Remember to add + * one for the terminating NUL. + */ + length = strlen(string); + required = filter->buffer_length + length + 1; + + /* If this is more than the current buffer allocation, resize it. */ + if (required > filter->buffer_allocation) { + sc_int new_allocation; + + /* Calculate the new malloc size, in increment chunks. */ + new_allocation = ((required + BUFFER_GROW_INCREMENT - 1) + / BUFFER_GROW_INCREMENT) * BUFFER_GROW_INCREMENT; + + /* Grow the buffer. */ + filter->buffer = (sc_char *)sc_realloc(filter->buffer, new_allocation); + filter->buffer_allocation = new_allocation; + } + + /* If empty, put a NUL into the buffer to permit strcat. */ + if (filter->buffer_length == 0) + filter->buffer[0] = NUL; + + /* Append the string to the buffer and extend length. */ + strcat(filter->buffer, string); + filter->buffer_length += length; } @@ -959,37 +877,33 @@ pf_append_string (sc_filterref_t filter, const sc_char *string) * values before those values are updated by task actions. */ void -pf_checkpoint (sc_filterref_t filter, - sc_var_setref_t vars, sc_prop_setref_t bundle) -{ - assert (pf_is_valid (filter)); - assert (vars && bundle); - - /* See if there is any buffered data to filter. */ - if (filter->buffer_length > 0) - { - /* - * Filter the buffered string, and place the filtered result, if any, - * back into the filter buffer. We do this by setting the buffer length - * back to zero, then appending the filtered string; this keeps the - * grown buffer intact. - */ - if (filter->needs_filtering) - { - sc_char *filtered; - - filtered = pf_filter_internal (filter->buffer, vars, bundle); - if (filtered) - { - filter->buffer_length = 0; - pf_append_string (filter, filtered); - sc_free (filtered); - } - } - - /* Note the buffer as filtered, to avoid pointless filtering. */ - filter->needs_filtering = FALSE; - } +pf_checkpoint(sc_filterref_t filter, + sc_var_setref_t vars, sc_prop_setref_t bundle) { + assert(pf_is_valid(filter)); + assert(vars && bundle); + + /* See if there is any buffered data to filter. */ + if (filter->buffer_length > 0) { + /* + * Filter the buffered string, and place the filtered result, if any, + * back into the filter buffer. We do this by setting the buffer length + * back to zero, then appending the filtered string; this keeps the + * grown buffer intact. + */ + if (filter->needs_filtering) { + sc_char *filtered; + + filtered = pf_filter_internal(filter->buffer, vars, bundle); + if (filtered) { + filter->buffer_length = 0; + pf_append_string(filter, filtered); + sc_free(filtered); + } + } + + /* Note the buffer as filtered, to avoid pointless filtering. */ + filter->needs_filtering = FALSE; + } } @@ -1005,54 +919,48 @@ pf_checkpoint (sc_filterref_t filter, * in client code. */ const sc_char * -pf_get_buffer (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* - * Return buffer if filter length is greater than zero. Note that this - * assumes that the buffer is a nul-terminated string. - */ - if (filter->buffer_length > 0) - { - assert (filter->buffer[filter->buffer_length] == NUL); - return filter->buffer; - } - else - return NULL; +pf_get_buffer(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* + * Return buffer if filter length is greater than zero. Note that this + * assumes that the buffer is a nul-terminated string. + */ + if (filter->buffer_length > 0) { + assert(filter->buffer[filter->buffer_length] == NUL); + return filter->buffer; + } else + return NULL; } sc_char * -pf_transfer_buffer (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* - * If the filter length is greater than zero, pass out the buffer (a nul- - * terminated string) and zero our length, allocation, and set the buffer - * back to NULL; an empty in all except the free-ing. - */ - if (filter->buffer_length > 0) - { - sc_char *retval; - - /* Set the return value to be the buffered text. */ - assert (filter->buffer[filter->buffer_length] == NUL); - retval = filter->buffer; - - /* Clear all filter fields down to empty values. */ - filter->buffer_length = 0; - filter->buffer_allocation = 0; - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; - - /* Return the allocated buffered text. */ - return retval; - } - else - return NULL; +pf_transfer_buffer(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* + * If the filter length is greater than zero, pass out the buffer (a nul- + * terminated string) and zero our length, allocation, and set the buffer + * back to NULL; an empty in all except the free-ing. + */ + if (filter->buffer_length > 0) { + sc_char *retval; + + /* Set the return value to be the buffered text. */ + assert(filter->buffer[filter->buffer_length] == NUL); + retval = filter->buffer; + + /* Clear all filter fields down to empty values. */ + filter->buffer_length = 0; + filter->buffer_allocation = 0; + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; + + /* Return the allocated buffered text. */ + return retval; + } else + return NULL; } @@ -1062,18 +970,17 @@ pf_transfer_buffer (sc_filterref_t filter) * Empty any text currently buffered in the filter. */ void -pf_empty (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); - - /* Free any allocation, and return the filter to initialization state. */ - filter->buffer_length = 0; - filter->buffer_allocation = 0; - sc_free (filter->buffer); - filter->buffer = NULL; - filter->new_sentence = FALSE; - filter->is_muted = FALSE; - filter->needs_filtering = FALSE; +pf_empty(sc_filterref_t filter) { + assert(pf_is_valid(filter)); + + /* Free any allocation, and return the filter to initialization state. */ + filter->buffer_length = 0; + filter->buffer_allocation = 0; + sc_free(filter->buffer); + filter->buffer = NULL; + filter->new_sentence = FALSE; + filter->is_muted = FALSE; + filter->needs_filtering = FALSE; } @@ -1085,39 +992,36 @@ pf_empty (sc_filterref_t filter) * these functions do nothing. */ void -pf_buffer_string (sc_filterref_t filter, const sc_char *string) -{ - assert (pf_is_valid (filter)); - assert (string); - - /* Ignore the call if the printfilter is muted. */ - if (!filter->is_muted) - { - sc_int noted; - - /* Note append start, then append the string to the buffer. */ - noted = filter->buffer_length; - pf_append_string (filter, string); - - /* Adjust the first character of the appended string if flagged. */ - if (filter->new_sentence) - filter->buffer[noted] = sc_toupper (filter->buffer[noted]); - - /* Clear new sentence, and note as currently needing filtering. */ - filter->needs_filtering = TRUE; - filter->new_sentence = FALSE; - } +pf_buffer_string(sc_filterref_t filter, const sc_char *string) { + assert(pf_is_valid(filter)); + assert(string); + + /* Ignore the call if the printfilter is muted. */ + if (!filter->is_muted) { + sc_int noted; + + /* Note append start, then append the string to the buffer. */ + noted = filter->buffer_length; + pf_append_string(filter, string); + + /* Adjust the first character of the appended string if flagged. */ + if (filter->new_sentence) + filter->buffer[noted] = sc_toupper(filter->buffer[noted]); + + /* Clear new sentence, and note as currently needing filtering. */ + filter->needs_filtering = TRUE; + filter->new_sentence = FALSE; + } } void -pf_buffer_character (sc_filterref_t filter, sc_char character) -{ - sc_char buffer[2]; - assert (pf_is_valid (filter)); - - buffer[0] = character; - buffer[1] = NUL; - pf_buffer_string (filter, buffer); +pf_buffer_character(sc_filterref_t filter, sc_char character) { + sc_char buffer[2]; + assert(pf_is_valid(filter)); + + buffer[0] = character; + buffer[1] = NUL; + pf_buffer_string(filter, buffer); } @@ -1130,47 +1034,43 @@ pf_buffer_character (sc_filterref_t filter, sc_char character) * completion text. If muted, this function does nothing. */ void -pf_prepend_string (sc_filterref_t filter, const sc_char *string) -{ - assert (pf_is_valid (filter)); - assert (string); - - /* Ignore the call if the printfilter is muted. */ - if (!filter->is_muted) - { - if (filter->buffer_length > 0) - { - sc_char *copy; - - /* Take a copy of the current buffered string. */ - assert (filter->buffer[filter->buffer_length] == NUL); - copy = (sc_char *)sc_malloc (filter->buffer_length + 1); - strcpy (copy, filter->buffer); - - /* - * Now restart buffering with the input string passed in. Removing - * the current content by zeroing the length preserves the grown - * allocation of the main buffer. - */ - filter->buffer_length = 0; - pf_append_string (filter, string); - - /* Append the string saved above and then free it. */ - pf_append_string (filter, copy); - sc_free (copy); - - /* Adjust the first character of the prepended string if flagged. */ - if (filter->new_sentence) - filter->buffer[0] = sc_toupper (filter->buffer[0]); - - /* Clear new sentence, and note as currently needing filtering. */ - filter->needs_filtering = TRUE; - filter->new_sentence = FALSE; - } - else - /* No data, so the call is equivalent to a normal buffer. */ - pf_buffer_string (filter, string); - } +pf_prepend_string(sc_filterref_t filter, const sc_char *string) { + assert(pf_is_valid(filter)); + assert(string); + + /* Ignore the call if the printfilter is muted. */ + if (!filter->is_muted) { + if (filter->buffer_length > 0) { + sc_char *copy; + + /* Take a copy of the current buffered string. */ + assert(filter->buffer[filter->buffer_length] == NUL); + copy = (sc_char *)sc_malloc(filter->buffer_length + 1); + strcpy(copy, filter->buffer); + + /* + * Now restart buffering with the input string passed in. Removing + * the current content by zeroing the length preserves the grown + * allocation of the main buffer. + */ + filter->buffer_length = 0; + pf_append_string(filter, string); + + /* Append the string saved above and then free it. */ + pf_append_string(filter, copy); + sc_free(copy); + + /* Adjust the first character of the prepended string if flagged. */ + if (filter->new_sentence) + filter->buffer[0] = sc_toupper(filter->buffer[0]); + + /* Clear new sentence, and note as currently needing filtering. */ + filter->needs_filtering = TRUE; + filter->new_sentence = FALSE; + } else + /* No data, so the call is equivalent to a normal buffer. */ + pf_buffer_string(filter, string); + } } @@ -1181,12 +1081,11 @@ pf_prepend_string (sc_filterref_t filter, const sc_char *string) * Ignored if the printfilter is muted. */ void -pf_new_sentence (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_new_sentence(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - if (!filter->is_muted) - filter->new_sentence = TRUE; + if (!filter->is_muted) + filter->new_sentence = TRUE; } @@ -1197,19 +1096,17 @@ pf_new_sentence (sc_filterref_t filter) * A muted printfilter ignores all new text additions. */ void -pf_mute (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_mute(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - filter->is_muted = TRUE; + filter->is_muted = TRUE; } void -pf_clear_mute (sc_filterref_t filter) -{ - assert (pf_is_valid (filter)); +pf_clear_mute(sc_filterref_t filter) { + assert(pf_is_valid(filter)); - filter->is_muted = FALSE; + filter->is_muted = FALSE; } @@ -1220,27 +1117,23 @@ pf_clear_mute (sc_filterref_t filter) * if the printfilter is muted. */ void -pf_buffer_tag (sc_filterref_t filter, sc_int tag) -{ - const sc_html_tags_t *entry; - assert (pf_is_valid (filter)); - - /* Search the tags table for this tag. */ - for (entry = HTML_TAGS_TABLE; entry->name; entry++) - { - if (tag == entry->tag) - break; - } - - /* If found, output the equivalent string, enclosed in '<>' characters. */ - if (entry->name) - { - pf_buffer_character (filter, LESSTHAN); - pf_buffer_string (filter, entry->name); - pf_buffer_character (filter, GREATERTHAN); - } - else - sc_error ("pf_buffer_tag: invalid tag, %ld\n", tag); +pf_buffer_tag(sc_filterref_t filter, sc_int tag) { + const sc_html_tags_t *entry; + assert(pf_is_valid(filter)); + + /* Search the tags table for this tag. */ + for (entry = HTML_TAGS_TABLE; entry->name; entry++) { + if (tag == entry->tag) + break; + } + + /* If found, output the equivalent string, enclosed in '<>' characters. */ + if (entry->name) { + pf_buffer_character(filter, LESSTHAN); + pf_buffer_string(filter, entry->name); + pf_buffer_character(filter, GREATERTHAN); + } else + sc_error("pf_buffer_tag: invalid tag, %ld\n", tag); } @@ -1253,34 +1146,31 @@ pf_buffer_tag (sc_filterref_t filter, sc_int tag) * a newline if requested by allow_newlines. */ static void -pf_strip_tags_common (sc_char *string, sc_bool allow_newlines) -{ - sc_char *marker, *cursor; - - /* Run through the string looking for <...> tags. */ - marker = string; - for (cursor = strchr (marker, LESSTHAN); - cursor; cursor = strchr (marker, LESSTHAN)) - { - sc_char *tag_end; - - /* Locate tag end, and break if unterminated. */ - tag_end = strchr (cursor, GREATERTHAN); - if (!tag_end) - break; - - /* If the tag is <br>, replace with newline if requested. */ - if (allow_newlines) - { - if (tag_end - cursor == 3 - && sc_strncasecmp (cursor + 1, "br", 2) == 0) - *cursor++ = '\n'; - } - - /* Remove the tag from the string, then advance input. */ - memmove (cursor, tag_end + 1, strlen (tag_end)); - marker = cursor; - } +pf_strip_tags_common(sc_char *string, sc_bool allow_newlines) { + sc_char *marker, *cursor; + + /* Run through the string looking for <...> tags. */ + marker = string; + for (cursor = strchr(marker, LESSTHAN); + cursor; cursor = strchr(marker, LESSTHAN)) { + sc_char *tag_end; + + /* Locate tag end, and break if unterminated. */ + tag_end = strchr(cursor, GREATERTHAN); + if (!tag_end) + break; + + /* If the tag is <br>, replace with newline if requested. */ + if (allow_newlines) { + if (tag_end - cursor == 3 + && sc_strncasecmp(cursor + 1, "br", 2) == 0) + *cursor++ = '\n'; + } + + /* Remove the tag from the string, then advance input. */ + memmove(cursor, tag_end + 1, strlen(tag_end)); + marker = cursor; + } } @@ -1292,15 +1182,13 @@ pf_strip_tags_common (sc_char *string, sc_bool allow_newlines) * allow <br> tags to map into newlines in hints strings. */ void -pf_strip_tags (sc_char *string) -{ - pf_strip_tags_common (string, FALSE); +pf_strip_tags(sc_char *string) { + pf_strip_tags_common(string, FALSE); } void -pf_strip_tags_for_hints (sc_char *string) -{ - pf_strip_tags_common (string, TRUE); +pf_strip_tags_for_hints(sc_char *string) { + pf_strip_tags_common(string, TRUE); } @@ -1315,78 +1203,71 @@ pf_strip_tags_for_hints (sc_char *string) * so the caller needs to remember to free it. */ sc_char * -pf_escape (const sc_char *string) -{ - const sc_char *marker, *cursor; - sc_char *buffer; - - /* Start with an empty return buffer. */ - buffer = (sc_char *)sc_malloc (strlen (string) + 1); - buffer[0] = NUL; - - /* Run through the string looking for <, >, %, or other escapes. */ - marker = string; - for (cursor = marker + strcspn (marker, ESCAPES); - cursor[0] != NUL; cursor = marker + strcspn (marker, ESCAPES)) - { - const sc_char *escape; - sc_char escape_buffer[3]; - - /* Extend buffer to hold the string so far. */ - if (cursor > marker) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - buffer[strlen (buffer) + cursor - marker] = NUL; - memcpy (buffer + strlen (buffer), marker, cursor - marker); - } - - /* Determine the appropriate character escape. */ - if (cursor[0] == LESSTHAN) - escape = ENTITY_LESSTHAN; - else if (cursor[0] == GREATERTHAN) - escape = ENTITY_GREATERTHAN; - else if (cursor[0] == PERCENT) - escape = ENTITY_PERCENT; - else - { - /* - * No real escape available, so fake, badly, by appending a space - * for cases where we've encountered a character entity; leave - * others untouched. - */ - escape_buffer[0] = cursor[0]; - if (sc_strncasecmp (cursor, - ENTITY_LESSTHAN, ENTITY_LENGTH) == 0 - || sc_strncasecmp (cursor, - ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0 - || sc_strncasecmp (cursor, - ENTITY_PERCENT, PERCENT_LENGTH) == 0) - { - escape_buffer[1] = ' '; - escape_buffer[2] = NUL; - } - else - escape_buffer[1] = NUL; - escape = escape_buffer; - } - - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + strlen (escape) + 1); - strcat (buffer, escape); - - /* Pass over character escaped and continue. */ - cursor++; - marker = cursor; - } - - /* Add all remaining characters to the buffer. */ - if (cursor > marker) - { - buffer = (sc_char *)sc_realloc (buffer, strlen (buffer) + cursor - marker + 1); - buffer[strlen (buffer) + cursor - marker] = NUL; - memcpy (buffer + strlen (buffer), marker, cursor - marker); - } - - return buffer; +pf_escape(const sc_char *string) { + const sc_char *marker, *cursor; + sc_char *buffer; + + /* Start with an empty return buffer. */ + buffer = (sc_char *)sc_malloc(strlen(string) + 1); + buffer[0] = NUL; + + /* Run through the string looking for <, >, %, or other escapes. */ + marker = string; + for (cursor = marker + strcspn(marker, ESCAPES); + cursor[0] != NUL; cursor = marker + strcspn(marker, ESCAPES)) { + const sc_char *escape; + sc_char escape_buffer[3]; + + /* Extend buffer to hold the string so far. */ + if (cursor > marker) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + buffer[strlen(buffer) + cursor - marker] = NUL; + memcpy(buffer + strlen(buffer), marker, cursor - marker); + } + + /* Determine the appropriate character escape. */ + if (cursor[0] == LESSTHAN) + escape = ENTITY_LESSTHAN; + else if (cursor[0] == GREATERTHAN) + escape = ENTITY_GREATERTHAN; + else if (cursor[0] == PERCENT) + escape = ENTITY_PERCENT; + else { + /* + * No real escape available, so fake, badly, by appending a space + * for cases where we've encountered a character entity; leave + * others untouched. + */ + escape_buffer[0] = cursor[0]; + if (sc_strncasecmp(cursor, + ENTITY_LESSTHAN, ENTITY_LENGTH) == 0 + || sc_strncasecmp(cursor, + ENTITY_GREATERTHAN, ENTITY_LENGTH) == 0 + || sc_strncasecmp(cursor, + ENTITY_PERCENT, PERCENT_LENGTH) == 0) { + escape_buffer[1] = ' '; + escape_buffer[2] = NUL; + } else + escape_buffer[1] = NUL; + escape = escape_buffer; + } + + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + strlen(escape) + 1); + strcat(buffer, escape); + + /* Pass over character escaped and continue. */ + cursor++; + marker = cursor; + } + + /* Add all remaining characters to the buffer. */ + if (cursor > marker) { + buffer = (sc_char *)sc_realloc(buffer, strlen(buffer) + cursor - marker + 1); + buffer[strlen(buffer) + cursor - marker] = NUL; + memcpy(buffer + strlen(buffer), marker, cursor - marker); + } + + return buffer; } @@ -1397,52 +1278,50 @@ pf_escape (const sc_char *string) * the match if the string matched, 0 otherwise. */ static sc_int -pf_compare_words (const sc_char *string, const sc_char *words) -{ - sc_int word_posn, posn; - - /* None expected, but skip leading space. */ - for (word_posn = 0; sc_isspace (words[word_posn]) && words[word_posn] != NUL;) - word_posn++; - - /* Match characters from words with the string at position. */ - posn = 0; - while (TRUE) - { - /* Any character mismatch means no words match. */ - if (sc_tolower (words[word_posn]) != sc_tolower (string[posn])) - return 0; - - /* Move to next character in each. */ - word_posn++; - posn++; - - /* - * If at space, advance over whitespace in words list. Stop when we - * hit the end of the words list. - */ - while (sc_isspace (words[word_posn]) && words[word_posn] != NUL) - word_posn++; - if (words[word_posn] == NUL) - break; - - /* - * About to match another word, so advance over whitespace in the - * current string too. - */ - while (sc_isspace (string[posn]) && string[posn] != NUL) - posn++; - } - - /* - * We reached the end of words. If we're at the end of the match string, - * or at spaces, we've matched. - */ - if (sc_isspace (string[posn]) || string[posn] == NUL) - return posn; - - /* More text after the match, so it's not quite a match. */ - return 0; +pf_compare_words(const sc_char *string, const sc_char *words) { + sc_int word_posn, posn; + + /* None expected, but skip leading space. */ + for (word_posn = 0; sc_isspace(words[word_posn]) && words[word_posn] != NUL;) + word_posn++; + + /* Match characters from words with the string at position. */ + posn = 0; + while (TRUE) { + /* Any character mismatch means no words match. */ + if (sc_tolower(words[word_posn]) != sc_tolower(string[posn])) + return 0; + + /* Move to next character in each. */ + word_posn++; + posn++; + + /* + * If at space, advance over whitespace in words list. Stop when we + * hit the end of the words list. + */ + while (sc_isspace(words[word_posn]) && words[word_posn] != NUL) + word_posn++; + if (words[word_posn] == NUL) + break; + + /* + * About to match another word, so advance over whitespace in the + * current string too. + */ + while (sc_isspace(string[posn]) && string[posn] != NUL) + posn++; + } + + /* + * We reached the end of words. If we're at the end of the match string, + * or at spaces, we've matched. + */ + if (sc_isspace(string[posn]) || string[posn] == NUL) + return posn; + + /* More text after the match, so it's not quite a match. */ + return 0; } @@ -1454,122 +1333,113 @@ pf_compare_words (const sc_char *string, const sc_char *words) * return string is malloc'ed, so the caller needs to remember to free it. */ sc_char * -pf_filter_input (const sc_char *string, sc_prop_setref_t bundle) -{ - sc_vartype_t vt_key[3]; - sc_int synonym_count, buffer_allocation; - sc_char *buffer; - const sc_char *current; - assert (string && bundle); - - if (pf_trace) - sc_trace ("Printfilter: input \"%s\"\n", string); - - /* Obtain a count of synonyms. */ - vt_key[0].string = "Synonyms"; - synonym_count = prop_get_child_count (bundle, "I<-s", vt_key); - - /* Begin with a NULL buffer for lazy allocation. */ - buffer_allocation = 0; - buffer = NULL; - - /* Loop over each word in the string. */ - current = string + strspn (string, WHITESPACE); - while (current[0] != NUL) - { - sc_int index_, extent; - - /* Search for a synonym match at this index into the buffer. */ - extent = 0; - for (index_ = 0; index_ < synonym_count; index_++) - { - const sc_char *original; - - /* Retrieve the synonym original string. */ - vt_key[0].string = "Synonyms"; - vt_key[1].integer = index_; - vt_key[2].string = "Original"; - original = prop_get_string (bundle, "S<-sis", vt_key); - - /* Compare the original at this point. */ - extent = pf_compare_words (current, original); - if (extent > 0) - break; - } - - /* - * If a synonym found was, index_ indicates it, and extent shows how - * much of the buffer to replace with it. - */ - if (index_ < synonym_count && extent > 0) - { - const sc_char *replacement; - sc_char *position; - sc_int length, final; - - /* - * If not yet allocated, allocate a buffer now, and copy the input - * string into it. Then switch current to the equivalent location - * in the allocated buffer. More basic copy-on-write. - */ - if (!buffer) - { - buffer_allocation = strlen (string) + 1; - buffer = (sc_char *)sc_malloc (buffer_allocation); - strcpy (buffer, string); - current = buffer + (current - string); - } - - /* Find the replacement text for this synonym. */ - vt_key[0].string = "Synonyms"; - vt_key[1].integer = index_; - vt_key[2].string = "Replacement"; - replacement = prop_get_string (bundle, "S<-sis", vt_key); - length = strlen (replacement); - - /* - * If necessary, grow the output buffer for the replacement, - * remembering to adjust current for the new buffer allocated. - * At the same time, note the last character index for the move. - */ - if (length > extent) - { - sc_int offset; - - offset = current - buffer; - buffer_allocation += length - extent; - buffer = (sc_char *)sc_realloc (buffer, buffer_allocation); - current = buffer + offset; - final = length; - } - else - final = extent; - - /* Insert the replacement string into the buffer. */ - position = buffer + (current - buffer); - memmove (position + length, - position + extent, - buffer_allocation - (current - buffer) - final); - memcpy (position, replacement, length); - - /* Adjust current to skip over the replacement. */ - current += length; - - if (pf_trace) - sc_trace ("Printfilter: synonym \"%s\"\n", buffer); - } - else - { - /* If no match, advance current over the unmatched word. */ - current += strcspn (current, WHITESPACE); - } - - /* Set current to the next word start. */ - current += strspn (current, WHITESPACE); - } - - /* Return the final string, or NULL if no synonym replacements. */ - return buffer; +pf_filter_input(const sc_char *string, sc_prop_setref_t bundle) { + sc_vartype_t vt_key[3]; + sc_int synonym_count, buffer_allocation; + sc_char *buffer; + const sc_char *current; + assert(string && bundle); + + if (pf_trace) + sc_trace("Printfilter: input \"%s\"\n", string); + + /* Obtain a count of synonyms. */ + vt_key[0].string = "Synonyms"; + synonym_count = prop_get_child_count(bundle, "I<-s", vt_key); + + /* Begin with a NULL buffer for lazy allocation. */ + buffer_allocation = 0; + buffer = NULL; + + /* Loop over each word in the string. */ + current = string + strspn(string, WHITESPACE); + while (current[0] != NUL) { + sc_int index_, extent; + + /* Search for a synonym match at this index into the buffer. */ + extent = 0; + for (index_ = 0; index_ < synonym_count; index_++) { + const sc_char *original; + + /* Retrieve the synonym original string. */ + vt_key[0].string = "Synonyms"; + vt_key[1].integer = index_; + vt_key[2].string = "Original"; + original = prop_get_string(bundle, "S<-sis", vt_key); + + /* Compare the original at this point. */ + extent = pf_compare_words(current, original); + if (extent > 0) + break; + } + + /* + * If a synonym found was, index_ indicates it, and extent shows how + * much of the buffer to replace with it. + */ + if (index_ < synonym_count && extent > 0) { + const sc_char *replacement; + sc_char *position; + sc_int length, final; + + /* + * If not yet allocated, allocate a buffer now, and copy the input + * string into it. Then switch current to the equivalent location + * in the allocated buffer. More basic copy-on-write. + */ + if (!buffer) { + buffer_allocation = strlen(string) + 1; + buffer = (sc_char *)sc_malloc(buffer_allocation); + strcpy(buffer, string); + current = buffer + (current - string); + } + + /* Find the replacement text for this synonym. */ + vt_key[0].string = "Synonyms"; + vt_key[1].integer = index_; + vt_key[2].string = "Replacement"; + replacement = prop_get_string(bundle, "S<-sis", vt_key); + length = strlen(replacement); + + /* + * If necessary, grow the output buffer for the replacement, + * remembering to adjust current for the new buffer allocated. + * At the same time, note the last character index for the move. + */ + if (length > extent) { + sc_int offset; + + offset = current - buffer; + buffer_allocation += length - extent; + buffer = (sc_char *)sc_realloc(buffer, buffer_allocation); + current = buffer + offset; + final = length; + } else + final = extent; + + /* Insert the replacement string into the buffer. */ + position = buffer + (current - buffer); + memmove(position + length, + position + extent, + buffer_allocation - (current - buffer) - final); + memcpy(position, replacement, length); + + /* Adjust current to skip over the replacement. */ + current += length; + + if (pf_trace) + sc_trace("Printfilter: synonym \"%s\"\n", buffer); + } else { + /* If no match, advance current over the unmatched word. */ + current += strcspn(current, WHITESPACE); + } + + /* Set current to the next word start. */ + current += strspn(current, WHITESPACE); + } + + /* Return the final string, or NULL if no synonym replacements. */ + return buffer; } @@ -1579,9 +1449,8 @@ pf_filter_input (const sc_char *string, sc_prop_setref_t bundle) * Set filter tracing on/off. */ void -pf_debug_trace (sc_bool flag) -{ - pf_trace = flag; +pf_debug_trace(sc_bool flag) { + pf_trace = flag; } } // End of namespace Adrift |