/* Return the absolute position of the node named NODENAME in BINDING. This is a brute force search, and we wish to avoid it when possible. This function is called when a tag (indirect or otherwise) doesn't really point to the right node. It returns the absolute position of the separator preceding the node. */ long find_node_in_binding (char *nodename, SEARCH_BINDING *binding) { long position; int offset, namelen; SEARCH_BINDING tmp_search; namelen = strlen (nodename); tmp_search.buffer = binding->buffer; tmp_search.start = binding->start; tmp_search.end = binding->end; tmp_search.flags = 0; while ((position = find_node_separator (&tmp_search)) != -1) { tmp_search.start = position; tmp_search.start += skip_node_separator (tmp_search.buffer + tmp_search.start); offset = string_in_line (INFO_NODE_LABEL, tmp_search.buffer + tmp_search.start); if (offset == -1) continue; tmp_search.start += offset; tmp_search.start += skip_whitespace (tmp_search.buffer + tmp_search.start); offset = skip_node_characters (tmp_search.buffer + tmp_search.start, DONT_SKIP_NEWLINES); /* Notice that this is an exact match. You cannot grovel through the buffer with this function looking for random nodes. */ if ((offset == namelen) && (tmp_search.buffer[tmp_search.start] == nodename[0]) && (strncmp (tmp_search.buffer + tmp_search.start, nodename, offset) == 0)) return position; } return -1; }
/* Return the absolute position of the beginning of a tags table in this binding starting the search at binding->start. */ long find_tags_table (SEARCH_BINDING *binding) { SEARCH_BINDING tmp_search; long position; tmp_search.buffer = binding->buffer; tmp_search.start = binding->start; tmp_search.end = binding->end; tmp_search.flags = S_FoldCase; while ((position = find_node_separator (&tmp_search)) != -1 ) { tmp_search.start = position; tmp_search.start += skip_node_separator (tmp_search.buffer + tmp_search.start); if (looking_at (TAGS_TABLE_BEG_LABEL, &tmp_search)) return position; } return -1; }
/* Given CONTENTS and FB (a file buffer), add the menu found in CONTENTS to the menu found in FB->contents. Second argument SIZE is the total size of CONTENTS. */ static void add_menu_to_file_buffer (char *contents, size_t size, FILE_BUFFER *fb) { SEARCH_BINDING contents_binding, fb_binding; long contents_offset, fb_offset; contents_binding.buffer = contents; contents_binding.start = 0; contents_binding.end = size; contents_binding.flags = S_FoldCase | S_SkipDest; fb_binding.buffer = fb->contents; fb_binding.start = 0; fb_binding.end = fb->filesize; fb_binding.flags = S_FoldCase | S_SkipDest; /* Move to the start of the menus in CONTENTS and FB. */ if (search_forward (INFO_MENU_LABEL, &contents_binding, &contents_offset) != search_success) /* If there is no menu in CONTENTS, quit now. */ return; /* There is a menu in CONTENTS, and contents_offset points to the first character following the menu starter string. Skip all whitespace and newline characters. */ contents_offset += skip_whitespace_and_newlines (contents + contents_offset); /* If there is no menu in FB, make one. */ if (search_forward (INFO_MENU_LABEL, &fb_binding, &fb_offset) != search_success) { /* Find the start of the second node in this file buffer. If there is only one node, we will be adding the contents to the end of this node. */ fb_offset = find_node_separator (&fb_binding); /* If not even a single node separator, give up. */ if (fb_offset == -1) return; fb_binding.start = fb_offset; fb_binding.start += skip_node_separator (fb_binding.buffer + fb_binding.start); /* Try to find the next node separator. */ fb_offset = find_node_separator (&fb_binding); /* If found one, consider that the start of the menu. Otherwise, the start of this menu is the end of the file buffer (i.e., fb->size). */ if (fb_offset != -1) fb_binding.start = fb_offset; else fb_binding.start = fb_binding.end; insert_text_into_fb_at_binding (fb, &fb_binding, INFO_MENU_LABEL, strlen (INFO_MENU_LABEL)); fb_binding.buffer = fb->contents; fb_binding.start = 0; fb_binding.end = fb->filesize; if (search_forward (INFO_MENU_LABEL, &fb_binding, &fb_offset) != search_success) abort (); } /* CONTENTS_OFFSET and FB_OFFSET point to the starts of the menus that appear in their respective buffers. Add the remainder of CONTENTS to the end of FB's menu. */ fb_binding.start = fb_offset; fb_offset = find_node_separator (&fb_binding); if (fb_offset != -1) fb_binding.start = fb_offset; else fb_binding.start = fb_binding.end; /* Leave exactly one blank line between directory entries. */ { int num_found = 0; while ((fb_binding.start > 0) && (whitespace_or_newline (fb_binding.buffer[fb_binding.start - 1]))) { num_found++; fb_binding.start--; } /* Optimize if possible. */ if (num_found >= 2) { fb_binding.buffer[fb_binding.start++] = '\n'; fb_binding.buffer[fb_binding.start++] = '\n'; } else { /* Do it the hard way. */ insert_text_into_fb_at_binding (fb, &fb_binding, "\n\n", 2); fb_binding.start += 2; } } /* Insert the new menu. */ insert_text_into_fb_at_binding (fb, &fb_binding, contents + contents_offset, size - contents_offset); }