commit 34ceded0c1eb35f37364b9b3562c2b1044e2ab05 Author: Gavin Smith Date: Tue Mar 11 17:17:36 2014 +0000 info-utils.c (input_start, inptr, anchor_to_adjust, nodestart): New file-level variables. (write_and_advance, skip_input, write_extra_bytes_to_output) (copy_input_to_output): Three new functions to replace write_and_advance. All callers changed. (scan_node_contents): Function argument changed. Adjust offsets of anchors in tag table if we are rewriting the node. Output a newline wherever a newline occurs in a reference node description. diff --git a/info-utils.c b/info-utils.c index d33197a..7e748c9 100644 --- a/info-utils.c +++ b/info-utils.c @@ -445,42 +445,99 @@ printed_representation (const char *character, size_t len, size_t hpos, /* Whether to strip syntax from the text of nodes. */ int preprocess_nodes_p; +static char *input_start, *inptr; + static size_t output_allocated; static size_t output_length; static char **output_start; +static NODE **anchor_to_adjust; +static int nodestart; + +/* Difference between the number of bytes input in the file and + bytes output. */ +static long int output_bytes_difference; + static void init_output_stream (char **o_s) { output_allocated = 0; output_length = 0; output_start = o_s; + output_bytes_difference = 0; } static void -write_and_advance (char **output, char *input, size_t n) +reallocate_output (char **output, size_t n) { - if (preprocess_nodes_p) + output_length += n; + while (output_allocated < output_length) { - output_length += n; - while (output_allocated < output_length) + size_t offset; + if (output_allocated == 0) { - size_t offset; - if (output_allocated == 0) - { - output_allocated = 8; /* Initial allocation */ - offset = 0; - } - else - { - offset = *output - *output_start; - } + output_allocated = 8; /* Initial allocation */ + offset = 0; + } + else + { + offset = *output - *output_start; + } + + *output_start = x2realloc (*output_start, &output_allocated); + *output = *output_start + offset; + } +} - *output_start = x2realloc (*output_start, &output_allocated); - *output = *output_start + offset; - } +static void +skip_input (size_t n) +{ + inptr += n; + output_bytes_difference += n; +} + +static void +write_extra_bytes_to_output (char **output, char *input, size_t n) +{ + if (preprocess_nodes_p) + { + reallocate_output (output, n); memmove (*output, input, n); *output += n; + output_bytes_difference -= n; + } +} + +static void +copy_input_to_output (char **output, size_t n) +{ + if (preprocess_nodes_p) + { + reallocate_output (output, n); + memmove (*output, inptr, n); + inptr += n; + *output += n; + + /* Check if we have gone past any anchors and + adjust with output_bytes_difference. */ + if (anchor_to_adjust) + { + while ((*anchor_to_adjust)->nodestart - nodestart + <= inptr - input_start) + { + (*anchor_to_adjust)->nodestart -= output_bytes_difference; + anchor_to_adjust++; + if (!*anchor_to_adjust || (*anchor_to_adjust)->nodelen != 0) + { + anchor_to_adjust = 0; + break; + } + } + } + } + else + { + inptr += n; } } @@ -492,23 +549,21 @@ write_and_advance (char **output, char *input, size_t n) static void underlining_off (char **output) { - write_and_advance (output, ANSI_UNDERLINING_OFF, - strlen (ANSI_UNDERLINING_OFF)); + write_extra_bytes_to_output (output, ANSI_UNDERLINING_OFF, + strlen (ANSI_UNDERLINING_OFF)); } static void underlining_on (char **output) { - write_and_advance (output, ANSI_UNDERLINING_ON, - strlen (ANSI_UNDERLINING_ON)); + write_extra_bytes_to_output (output, ANSI_UNDERLINING_ON, + strlen (ANSI_UNDERLINING_ON)); } -/* Read first line of node and set next, prev and up. Advance INPTR past - the first line. */ +/* Read first line of node and set next, prev and up. */ static void -parse_top_node_line (NODE *node, char **inptr) +parse_top_node_line (NODE *node) { - char *nodeptr = *inptr; char **store_in; int value_length; @@ -518,30 +573,30 @@ parse_top_node_line (NODE *node, char **inptr) { store_in = 0; - nodeptr += skip_whitespace (nodeptr); + skip_input (skip_whitespace (inptr)); /* Check what field we are looking at */ - if (!strncmp (nodeptr, INFO_FILE_LABEL, strlen(INFO_FILE_LABEL))) + if (!strncmp (inptr, INFO_FILE_LABEL, strlen(INFO_FILE_LABEL))) { - nodeptr += strlen(INFO_FILE_LABEL); + skip_input (strlen(INFO_FILE_LABEL)); } - else if (!strncmp (nodeptr, INFO_NODE_LABEL, strlen(INFO_NODE_LABEL))) + else if (!strncmp (inptr, INFO_NODE_LABEL, strlen(INFO_NODE_LABEL))) { - nodeptr += strlen(INFO_NODE_LABEL); + skip_input (strlen(INFO_NODE_LABEL)); } - else if (!strncmp (nodeptr, INFO_PREV_LABEL, strlen(INFO_PREV_LABEL))) + else if (!strncmp (inptr, INFO_PREV_LABEL, strlen(INFO_PREV_LABEL))) { - nodeptr += strlen(INFO_PREV_LABEL); + skip_input (strlen(INFO_PREV_LABEL)); store_in = &(node->prev); } - else if (!strncmp (nodeptr, INFO_NEXT_LABEL, strlen(INFO_NEXT_LABEL))) + else if (!strncmp (inptr, INFO_NEXT_LABEL, strlen(INFO_NEXT_LABEL))) { - nodeptr += strlen(INFO_NEXT_LABEL); + skip_input (strlen(INFO_NEXT_LABEL)); store_in = &(node->next); } - else if (!strncmp (nodeptr, INFO_UP_LABEL, strlen(INFO_UP_LABEL))) + else if (!strncmp (inptr, INFO_UP_LABEL, strlen(INFO_UP_LABEL))) { - nodeptr += strlen(INFO_UP_LABEL); + skip_input (strlen(INFO_UP_LABEL)); store_in = &(node->up); } else @@ -549,28 +604,27 @@ parse_top_node_line (NODE *node, char **inptr) /* Not recognized - code below will skip to next comma */ } - nodeptr += skip_whitespace (nodeptr); + skip_input (skip_whitespace (inptr)); /* PARSE_NODE_START separates at commas or newlines, so it will work for filenames including full stops. */ - value_length = skip_node_characters (nodeptr, PARSE_NODE_START); + value_length = skip_node_characters (inptr, PARSE_NODE_START); if (store_in) { (*store_in) = xmalloc (value_length + 1); - memmove (*store_in, nodeptr, value_length); + memmove (*store_in, inptr, value_length); (*store_in) [value_length] = '\0'; } - nodeptr += value_length; - if ((*nodeptr) == '\n') + skip_input (value_length); + if (*inptr == '\n') { - nodeptr++; + skip_input (1); break; } - nodeptr++; /* Point after field terminator */ + skip_input (1); /* Point after field terminator */ } - *inptr = nodeptr; } /* Check if there is a colon on the next line and return its offset. @@ -589,18 +643,18 @@ colon_after_newline (char *nodeptr) return -1; } -/* Remove syntax from NODE->contents and build list of references - in node. */ +/* Remove syntax from (*NODE)->contents and build list of references + in node. Adjust anchors in tag table that point into node text.*/ void -scan_node_contents (NODE *node) +scan_node_contents (NODE **tag) { SEARCH_BINDING s; char *search_string; - char *nodeptr; char *new_contents = 0, *outptr = 0; int found_menu_entry, in_index = 0; + NODE *node = *tag; REFERENCE **refs = NULL; size_t refs_index = 0, refs_slots = 0; @@ -612,6 +666,13 @@ scan_node_contents (NODE *node) init_output_stream (&new_contents); + /* Set anchor_to_adjust to first anchor in node, if any. */ + anchor_to_adjust = tag + 1; + if (!*anchor_to_adjust) + anchor_to_adjust = 0; + else if (*anchor_to_adjust && (*anchor_to_adjust)->nodelen != 0) + anchor_to_adjust = 0; + /* Initialize refs to point to array of one null pointer in case there are no results. This way we know if refs has been initialized even if it is empty. */ @@ -619,9 +680,13 @@ scan_node_contents (NODE *node) refs_slots = 1; - nodeptr = node->contents; + /* This should be the only time we assign to inptr in this function - + all other assignment should be done with the helper functions above. */ + inptr = node->contents; + input_start = node->contents; + nodestart = node->nodestart; - parse_top_node_line (node, &nodeptr); + parse_top_node_line (node); deleted_lines++; /* Search for menu items or cross references in buffer. @@ -630,7 +695,7 @@ scan_node_contents (NODE *node) search_string = "\n\\* Menu:|\\*Note"; s.buffer = node->contents; - s.start = nodeptr - node->contents; + s.start = inptr - node->contents; s.end = node->nodelen; search_again: @@ -672,11 +737,11 @@ search_again: /* Write out up to Menu label, and skip it */ copy_to -= 8; - write_and_advance (&outptr, nodeptr, copy_to - nodeptr); + copy_input_to_output (&outptr, copy_to - inptr); + skip_input (8); - nodeptr = copy_to + 8; deleted_lines++; - s.start = nodeptr - s.buffer; + s.start = inptr - s.buffer; continue; } @@ -696,29 +761,27 @@ search_again: } /* Write out up to current reference */ - write_and_advance (&outptr, nodeptr, copy_to - nodeptr); + copy_input_to_output (&outptr, copy_to - inptr); - /* Skip notation */ - if (found_menu_entry) - nodeptr = copy_to; - else - nodeptr = copy_to + 5; + /* Skip "*Note" */ + if (!found_menu_entry) + skip_input (5); - /* Search forward to ":" to get reference label. */ - nodeptr += skip_whitespace (nodeptr); - colon_offset = string_in_line (":", nodeptr); + /* Search forward to ":" to get label name */ + skip_input (skip_whitespace (inptr)); + colon_offset = string_in_line (":", inptr); /* Cross-references may have a newline in the middle. */ if (colon_offset == -1 && !found_menu_entry - && (colon_offset = colon_after_newline (nodeptr)) != -1) + && (colon_offset = colon_after_newline (inptr)) != -1) ; else if (colon_offset == -1) { /* This is not a menu entry or reference. */ - nodeptr++; + skip_input (1); - s.start = nodeptr - s.buffer; + s.start = inptr - s.buffer; continue; } colon_offset--; /* Offset of colon, not character after it. */ @@ -737,22 +800,23 @@ search_again: /* Save label as it appears in input. */ entry->label = xmalloc(colon_offset + 1); - strncpy (entry->label, nodeptr, colon_offset); + strncpy (entry->label, inptr, colon_offset); entry->label[colon_offset] = '\0'; + skip_input (colon_offset + 1); /* Output reference label and set location of reference. */ if (!found_menu_entry) { if (capital_s) - write_and_advance (&outptr, "See ", 4); + write_extra_bytes_to_output (&outptr, "See ", 4); else - write_and_advance (&outptr, "see ", 4); + write_extra_bytes_to_output (&outptr, "see ", 4); } /* Output any whitespace or newlines before reference label */ leading_whitespace = skip_whitespace_and_newlines (entry->label); - write_and_advance (&outptr, entry->label, leading_whitespace); + write_extra_bytes_to_output (&outptr, entry->label, leading_whitespace); underlining_on (&outptr); @@ -776,7 +840,7 @@ search_again: while (*labelptr != '\n' && *labelptr) labelptr++; newline_offset = labelptr - (entry->label + leading_whitespace); - write_and_advance(&outptr, entry->label + leading_whitespace, + write_extra_bytes_to_output (&outptr, entry->label + leading_whitespace, (*labelptr ? newline_offset : strlen(entry->label) - leading_whitespace)); @@ -792,13 +856,14 @@ search_again: underlining_off (&outptr); /* Output newline and any whitespace at start of line */ - write_and_advance (&outptr, labelptr, space_at_start_of_line); + write_extra_bytes_to_output (&outptr, labelptr, + space_at_start_of_line); labelptr += space_at_start_of_line; underlining_on (&outptr); /* Output rest of label */ - write_and_advance (&outptr, labelptr, + write_extra_bytes_to_output (&outptr, labelptr, entry->label + strlen(entry->label) - labelptr); /* Text of reference ends later in node because of terminal @@ -817,20 +882,17 @@ search_again: /* Now get target of reference. */ - /* Read from after ':' to get target of reference. */ - nodeptr += colon_offset; nodeptr++; - /* If this reference entry continues with another ':' then the nodename is the same as the label. */ - if (*nodeptr == ':') + if (*inptr == ':') { entry->nodename = xstrdup (entry->label); - nodeptr++; + skip_input (1); if (found_menu_entry) { /* Output two spaces to match the length of "::" */ - write_and_advance (&outptr, " ", 2); + write_extra_bytes_to_output (&outptr, " ", 2); } } else @@ -843,24 +905,38 @@ search_again: if (found_menu_entry) { - length = info_parse_node (nodeptr, PARSE_NODE_DFLT); + length = info_parse_node (inptr, PARSE_NODE_DFLT); + if (in_index) - { - /* For index nodes, output the destination as well, - which will be the name of the node the index entry - refers to. */ - write_and_advance (&outptr, nodeptr, length); - } - nodeptr += length; - } + /* For index nodes, output the destination as well, + which will be the name of the node the index entry + refers to. */ + copy_input_to_output (&outptr, length); + else + skip_input (length); + } else { char saved_char; - length = info_parse_node (nodeptr, PARSE_NODE_SKIP_NEWLINES); + length = info_parse_node (inptr, PARSE_NODE_SKIP_NEWLINES); - /* TODO: Check if there is a newline in node specifier. - If so, output a newline and skip whitespace. */ + /* Check if there is a newline in node specifier. If so, + output a newline and skip whitespace. */ + saved_char = inptr[length]; + inptr[length] = '\0'; + if (strchr (inptr, '\n')) + { + inptr[length] = saved_char; + write_extra_bytes_to_output (&outptr, "\n", 1); + skip_input (length); + skip_input (skip_whitespace (inptr)); + } + else + { + inptr[length] = saved_char; + skip_input (length); + } } if (info_parsed_filename) @@ -879,11 +955,11 @@ search_again: /* Output spaces the length of the node specifier to avoid messing up left edge of second column of menu. */ for (i = 0; i < length; i++) - write_and_advance (&outptr, " ", 1); + write_extra_bytes_to_output (&outptr, " ", 1); } add_pointer_to_array (entry, refs_index, refs, refs_slots, 50); - s.start = nodeptr - s.buffer; + s.start = inptr - s.buffer; if (s.start >= s.end) break; } @@ -892,7 +968,7 @@ search_again: ("address@hidden address@hidden"). Skip past these and try again. */ char *ptr_to_null_byte; - ptr_to_null_byte = nodeptr + strlen (nodeptr); + ptr_to_null_byte = inptr + strlen (inptr); /* Three byte sequence "address@hidden" starts tag. Check there is enough space for this in the rest of the node. */ @@ -911,24 +987,20 @@ search_again: if (ptr_to_null_byte <= node->contents + node->nodelen - 3) { /* Write out up to tag. */ - write_and_advance (&outptr, nodeptr, - ptr_to_null_byte + 3 - nodeptr); - - /* Point to first character after ']' */ - nodeptr = ptr_to_null_byte + 3; + copy_input_to_output (&outptr, ptr_to_null_byte + 3 - inptr); - s.buffer = nodeptr; + /* Update search to start after tag. */ + s.buffer = inptr; s.start = 0; - s.end = node->nodelen - (nodeptr - node->contents); + s.end = node->nodelen - (inptr - node->contents); goto search_again; } } /* If we haven't accidentally gone past the end of the node, write out the rest of it. */ - if (nodeptr < node->contents + node->nodelen) - write_and_advance (&outptr, nodeptr, - (node->contents + node->nodelen) - nodeptr); + if (inptr < node->contents + node->nodelen) + copy_input_to_output (&outptr, (node->contents + node->nodelen) - inptr); node->references = refs; diff --git a/info-utils.h b/info-utils.h index 0074c0a..60825bf 100644 --- a/info-utils.h +++ b/info-utils.h @@ -56,9 +56,10 @@ extern char *info_parsed_nodename; */ int info_parse_node (char *string, int flag); -/* If preprocess_nodes_p=On, remove syntax from NODE->contents. - Set NODE->references and other fields. */ -void scan_node_contents (NODE *node); +/* NODE points to a tag table entry. Scan (*NODE)->contents for references + and set (*NODE)->references. If preprocess_nodes_p=On, remove syntax + from NODE->contents. Adjust anchors in tag table in this node. */ +void scan_node_contents (NODE **node); /* Get the entry associated with LABEL in REFERENCES. Return a pointer to the reference if found, or NULL. */ diff --git a/nodes.c b/nodes.c index 0399ab9..f9a57cf 100644 --- a/nodes.c +++ b/nodes.c @@ -1059,7 +1059,7 @@ info_node_of_file_buffer_tags (FILE_BUFFER *file_buffer, char *nodename) /* Read locations of references in node and similar. Rewrite node from tag->contents if preprocess_nodes=On. */ - scan_node_contents (tag); + scan_node_contents (&file_buffer->tags[i]); /* Disabled - we will expand tags in scan_node_contents. */ #if 0