void search() { int cpos = 0; int c; point_t o_point = curbp->b_point; point_t found; searchtext[0] = '\0'; display_prompt_and_response(m_sprompt, searchtext); cpos = strlen(searchtext); for (;;) { c = getch(); /* ignore control keys other than C-g, backspace, CR, C-s, C-R, ESC */ if (c < 32 && c != 07 && c != 0x08 && c != 0x13 && c != 0x12 && c != 0x1b) continue; switch(c) { case 0x1b: /* esc */ searchtext[cpos] = '\0'; flushinp(); /* discard any escape sequence without writing in buffer */ return; case 0x07: /* ctrl-g */ curbp->b_point = o_point; return; case 0x13: /* ctrl-s, do the search */ found = search_forward(searchtext); display_search_result(found, FWD_SEARCH, m_sprompt, searchtext); break; case 0x12: /* ctrl-r, do the search */ found = search_backwards(searchtext); display_search_result(found, REV_SEARCH, m_sprompt, searchtext); break; case 0x7f: /* del, erase */ case 0x08: /* backspace */ if (cpos == 0) continue; searchtext[--cpos] = '\0'; display_prompt_and_response(m_sprompt, searchtext); break; default: if (cpos < STRBUF_M - 1) { searchtext[cpos++] = c; searchtext[cpos] = '\0'; display_prompt_and_response(m_sprompt, searchtext); } break; } } }
/* Search forwards or backwards for the text delimited by BINDING. The search is forwards if BINDING->start is greater than BINDING->end. */ long search (char *string, SEARCH_BINDING *binding) { long result; /* If the search is backwards, then search backwards, otherwise forwards. */ if (binding->start > binding->end) result = search_backward (string, binding); else result = search_forward (string, binding); return result; }
/* Find STRING in LINE, returning the offset of the end of the string. Return an offset of -1 if STRING does not appear in LINE. The search is bound by the end of the line (i.e., either NEWLINE or 0). */ int string_in_line (char *string, char *line) { register int end; SEARCH_BINDING binding; /* Find the end of the line. */ for (end = 0; line[end] && line[end] != '\n'; end++); /* Search for STRING within these confines. */ binding.buffer = line; binding.start = 0; binding.end = end; binding.flags = S_FoldCase | S_SkipDest; return search_forward (string, &binding); }
/*search for a string and replace it with another string */ void query_replace(void) { point_t o_point = curbp->b_point; point_t l_point = -1; point_t found; char question[STRBUF_L]; int slen, rlen; /* length of search and replace strings */ int numsub = 0; /* number of substitutions */ int ask = TRUE; int c; searchtext[0] = '\0'; replace[0] = '\0'; if (!getinput("Query replace: ", (char*)searchtext, STRBUF_M)) return; if (!getinput("With: ", (char*)replace, STRBUF_M)) return; slen = strlen(searchtext); rlen = strlen(replace); /* build query replace question string */ sprintf(question, "Replace '%s' with '%s' ? ", searchtext, replace); /* scan through the file, from point */ numsub = 0; while(TRUE) { found = search_forward(searchtext); /* if not found set the point to the last point of replacement, or where we started */ if (found == -1) { curbp->b_point = (l_point == -1 ? o_point : l_point); break; } curbp->b_point = found; /* search_forward places point at end of search, move to start of search */ curbp->b_point -= slen; if (ask == TRUE) { msg(question); clrtoeol(); qprompt: display(curwp, TRUE); c = getch(); switch (c) { case 'y': /* yes, substitute */ break; case 'n': /* no, find next */ curbp->b_point = found; /* set to end of search string */ continue; case '!': /* yes/stop asking, do the lot */ ask = FALSE; break; case 0x1B: /* esc */ flushinp(); /* discard any escape sequence without writing in buffer */ case 'q': /* controlled exit */ return; default: /* help me */ msg("(y)es, (n)o, (!)do the rest, (q)uit"); goto qprompt; } } if (rlen > slen) { movegap(curbp, found); /*check enough space in gap left */ if (rlen - slen < curbp->b_egap - curbp->b_gap) growgap(curbp, rlen - slen); /* shrink gap right by r - s */ curbp->b_gap = curbp->b_gap + (rlen - slen); } else if (slen > rlen) { movegap(curbp, found); /* stretch gap left by s - r, no need to worry about space */ curbp->b_gap = curbp->b_gap - (slen - rlen); } else { /* if rlen = slen, we just overwrite the chars, no need to move gap */ } /* now just overwrite the chars at point in the buffer */ l_point = curbp->b_point; memcpy(ptr(curbp, curbp->b_point), replace, rlen * sizeof (char_t)); curbp->b_flags |= B_MODIFIED; curbp->b_point = found - (slen - rlen); /* end of replcement */ numsub++; } msg("%d substitutions", numsub); }
/* 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); }
static int pdf_insert_bookmark( PDF *p, const char *hypertext, pdf_outline *outline, int jndex) { static const char fn[] = "pdf_insert_bookmark"; pdf_outline *root, *self; int parent; int self_idx; int pageno = pdf_current_page(p); /* allocation */ if (p->outline_count == 0) { p->outline_capacity = OUTLINE_CHUNKSIZE; p->outlines = (pdf_outline *) pdc_calloc(p->pdc, sizeof(pdf_outline) * p->outline_capacity, fn); /* populate the root outline object */ root = &p->outlines[0]; pdf_init_outline(p, root); root->obj_id = pdc_alloc_id(p->out); root->open = pdc_true; /* set the open mode show bookmarks if we have at least one, * and the client didn't already set his own open mode. */ pdf_fix_openmode(p); } else if (p->outline_count + 1 >= p->outline_capacity) { p->outline_capacity *= 2; p->outlines = (pdf_outline *) pdc_realloc(p->pdc, p->outlines, sizeof(pdf_outline) * p->outline_capacity, fn); } /* copy */ self_idx = ++p->outline_count; self = &p->outlines[self_idx]; memcpy(self, outline, sizeof(pdf_outline)); self->obj_id = pdc_alloc_id(p->out); self->text = (char *) hypertext; self->page_id = pdf_get_page_id(p, 0); parent = self->parent; /* default destination */ if (self->action == NULL && self->dest == NULL) self->dest = pdf_init_destination(p); /* no destination */ if (self->dest != NULL && self->dest->name != NULL && !strlen(self->dest->name)) { pdf_cleanup_destination(p, self->dest); self->dest = NULL; } /* current page */ if (self->dest) { /* this ugly code is for compatibility with the ** obsolete "bookmarkdest" parameter. */ if (self->dest->pgnum == 0) self->dest->pgnum = pdf_current_page(p); if (self->dest->pgnum == 0) { self->dest->pgnum = 1; } else if (self->dest->page == PDC_BAD_ID) { self->dest->page = pdf_get_page_id(p, self->dest->pgnum); } } /* special case: empty list. */ if (FIRST(parent) == 0) { if (jndex > 0) pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", pdc_errprintf(p->pdc, "%d", jndex), 0, 0); FIRST(parent) = LAST(parent) = self_idx; self->in_order = pdc_true; } else switch (jndex) { case -2: /* insert "in order" */ { /* the "natural" case: append to the end if appropriate. */ if (pageno >= search_backward(p, -1, LAST(parent))) { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; } else { int idx; int curr_pg = 1; int next_pg; for (idx = FIRST(parent); idx != 0; idx = NEXT(idx)) { if (!IN_ORDER(idx)) continue; next_pg = pdf_search_page_fwd(p, curr_pg, PAGE_ID(idx)); /* TODO: understand why this can happen. */ if (next_pg < 1) { idx = 0; break; } if (next_pg > pageno) { self->next = idx; self->prev = PREV(idx); PREV(idx) = self_idx; if (self->prev == 0) FIRST(parent) = self_idx; else NEXT(self->prev) = self_idx; break; } curr_pg = next_pg; } /* if there are no "in order" bookmarks yet, ** we simply append this one to the end. */ if (idx == 0) { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; } } self->in_order = pdc_true; break; } case -1: /* append to the end */ { self->prev = LAST(parent); NEXT(LAST(parent)) = self_idx; LAST(parent) = self_idx; self->in_order = (pageno >= search_backward(p, pageno, self->prev)); break; } case 0: /* insert at the beginning */ { self->next = FIRST(parent); PREV(FIRST(parent)) = self_idx; FIRST(parent) = self_idx; self->in_order = (pageno <= search_forward(p, pageno, self->next)); break; } default: /* insert before [1..LAST] */ { int i; int target = FIRST(parent); for (i = 0; i < jndex; ++i) { if (target == LAST(parent)) pdc_error(p->pdc, PDC_E_OPT_ILLINTEGER, "index", pdc_errprintf(p->pdc, "%d", jndex), 0, 0); target = NEXT(target); } self->next = target; self->prev = PREV(target); NEXT(self->prev) = PREV(self->next) = self_idx; self->in_order = ((pageno >= search_backward(p, pageno, self->prev)) && (pageno <= search_forward(p, pageno, self->next))); break; } } /* else switch */ /* increase the number of open sub-entries for all relevant ancestors */ do { COUNT(parent)++; } while (OPEN(parent) && (parent = PARENT(parent)) != 0); return (self_idx); /* caller may use this as handle */ }
/* Treat this just like @unnumbered. The only difference is in node defaulting. */ void cm_top (void) { /* It is an error to have more than one @top. */ if (top_node_seen && strcmp (current_node, "Top") != 0) { TAG_ENTRY *tag = tag_table; line_error (_("Node with %ctop as a section already exists"), COMMAND_PREFIX); while (tag) { if (tag->flags & TAG_FLAG_IS_TOP) { file_line_error (tag->filename, tag->line_no, _("Here is the %ctop node"), COMMAND_PREFIX); return; } tag = tag->next_ent; } } else { top_node_seen = 1; /* It is an error to use @top before using @node. */ if (!tag_table) { char *top_name; get_rest_of_line (0, &top_name); line_error (_("%ctop used before %cnode, defaulting to %s"), COMMAND_PREFIX, COMMAND_PREFIX, top_name); execute_string ("@node Top, , (dir), (dir)\n@top %s\n", top_name); free (top_name); return; } cm_unnumbered (); /* The most recently defined node is the top node. */ tag_table->flags |= TAG_FLAG_IS_TOP; /* Now set the logical hierarchical level of the Top node. */ { int orig_offset = input_text_offset; input_text_offset = search_forward (node_search_string, orig_offset); if (input_text_offset > 0) { int this_section; /* We have encountered a non-top node, so mark that one exists. */ non_top_node_seen = 1; /* Move to the end of this line, and find out what the sectioning command is here. */ while (input_text[input_text_offset] != '\n') input_text_offset++; if (input_text_offset < input_text_length) input_text_offset++; this_section = what_section (input_text + input_text_offset, NULL); /* If we found a sectioning command, then give the top section a level of this section - 1. */ if (this_section != -1) set_top_section_level (this_section - 1); } input_text_offset = orig_offset; } } }