/* extra args -- marking if called from globals, and should mark lines, and fromscreen, if the searchpattern is on the screen, so we don't need to ask for it. */ int fsearch(int f, int n, int marking, int fromscreen) { int status = TRUE; int wrapok; MARK curpos; int didmark = FALSE; int didwrap; assert(curwp != 0); if (f && n < 0) return rsearch(f, -n, FALSE, FALSE); if (n == 0) n = 1; wrapok = marking || window_b_val(curwp, MDWRAPSCAN); last_srch_direc = FORWARD; /* ask the user for a regular expression to search for. if * "marking", then we were called to do line marking for the * global command. */ if (!marking) { status = readpattern("Search: ", &searchpat, &gregexp, lastkey, fromscreen); if (status != TRUE) return status; } ignorecase = window_b_val(curwp, MDIGNCASE); if (curwp == 0) return FALSE; curpos = DOT; scanboundry(wrapok, curpos, FORWARD); didwrap = FALSE; while (marking || n--) { movenext(&(DOT), FORWARD); status = scanner(gregexp, FORWARD, wrapok, &didwrap); if (status == ABORT) { mlwarn("[Aborted]"); DOT = curpos; return status; } /* if found, mark the line */ if (status && marking) { /* if we were on a match when we started, then scanner returns TRUE, even though it's on a boundary. quit if we find ourselves marking a line twice */ if (lismarked(DOT.l)) break; lsetmarked(DOT.l); /* and, so the next movenext gets to next line */ DOT.o = llength(DOT.l); didmark = TRUE; } if (!marking && didwrap) { mlwrite("[Search wrapped past end of buffer]"); didwrap = FALSE; } if (status != TRUE) break; } if (!marking && !status) movenext(&(DOT), REVERSE); if (marking) { /* restore dot and offset */ DOT = curpos; } else if (status) { savematch(DOT, gregexp->mlen); if (samepoint(DOT, curpos)) { mlwrite(onlyonemsg); } } /* Complain if not there. */ if ((marking && didmark == FALSE) || (!marking && status == FALSE)) { not_found_msg(wrapok, FORWARD); return FALSE; } attrib_matches(); return TRUE; }
/* * backhunt -- repeat previous forward search */ int backhunt(int f, int n) { int status = TRUE; int wrapok; MARK curpos; int didwrap; assert(curwp != 0); wrapok = window_b_val(curwp, MDWRAPSCAN); if (f && n < 0) /* search forwards */ return (forwhunt(f, -n)); if (n == 0) n = 1; /* Make sure a pattern exists */ if (tb_length(searchpat) == 0) { mlforce("[No pattern set]"); return FALSE; } ignorecase = window_b_val(curwp, MDIGNCASE); if (curwp == 0) return FALSE; /* find n'th occurrence of pattern */ curpos = DOT; scanboundry(wrapok, DOT, REVERSE); didwrap = FALSE; while (n--) { movenext(&(DOT), REVERSE); status = scanner(gregexp, REVERSE, wrapok, &didwrap); if (didwrap) { mlwrite("[Search wrapped past start of buffer]"); didwrap = FALSE; } if (status != TRUE) break; } if (status == TRUE) { savematch(DOT, gregexp->mlen); if (samepoint(DOT, curpos)) { mlwrite(onlyonemsg); } } else if (status == FALSE) { movenext(&(DOT), FORWARD); not_found_msg(wrapok, REVERSE); } else if (status == ABORT) { mlwarn("[Aborted]"); DOT = curpos; return status; } attrib_matches(); return status; }
/* Look for needle, starting at (current, current_x). begin is the line * where we first started searching, at column begin_x. The return * value specifies whether we found anything. If we did, set needle_len * to the length of the string we found if it isn't NULL. */ bool findnextstr( #ifndef DISABLE_SPELLER bool whole_word_only, #endif const filestruct *begin, size_t begin_x, const char *needle, size_t *needle_len) { size_t found_len; /* The length of the match we find. */ size_t current_x_find = 0; /* The location in the current line of the match we find. */ ssize_t current_y_find = openfile->current_y; filestruct *fileptr = openfile->current; const char *rev_start = fileptr->data, *found = NULL; time_t lastkbcheck = time(NULL); /* rev_start might end up 1 character before the start or after the * end of the line. This won't be a problem because strstrwrapper() * will return immediately and say that no match was found, and * rev_start will be properly set when the search continues on the * previous or next line. */ rev_start += #ifndef NANO_TINY ISSET(BACKWARDS_SEARCH) ? ((openfile->current_x == 0) ? -1 : move_mbleft(fileptr->data, openfile->current_x)) : #endif move_mbright(fileptr->data, openfile->current_x); /* Look for needle in the current line we're searching. */ enable_nodelay(); while (TRUE) { if (time(NULL) - lastkbcheck > 1) { int input = parse_kbinput(edit); lastkbcheck = time(NULL); if (input && func_from_key(&input) == do_cancel) { statusbar(_("Cancelled")); return FALSE; } } found = strstrwrapper(fileptr->data, needle, rev_start); /* We've found a potential match. */ if (found != NULL) { #ifndef DISABLE_SPELLER bool found_whole = FALSE; /* Is this potential match a whole word? */ #endif /* Set found_len to the length of the potential match. */ found_len = #ifdef HAVE_REGEX_H ISSET(USE_REGEXP) ? regmatches[0].rm_eo - regmatches[0].rm_so : #endif strlen(needle); #ifndef DISABLE_SPELLER /* If we're searching for whole words, see if this potential * match is a whole word. */ if (whole_word_only) { char *word = mallocstrncpy(NULL, found, found_len + 1); word[found_len] = '\0'; found_whole = is_whole_word(found - fileptr->data, fileptr->data, word); free(word); } /* If we're searching for whole words and this potential * match isn't a whole word, continue searching. */ if (!whole_word_only || found_whole) #endif break; } if (search_last_line) { /* We've finished processing the file, so get out. */ not_found_msg(needle); disable_nodelay(); return FALSE; } /* Move to the previous or next line in the file. */ #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = fileptr->prev; current_y_find--; } else { #endif fileptr = fileptr->next; current_y_find++; #ifndef NANO_TINY } #endif if (fileptr == NULL) { /* We've reached the start or end of the buffer, so wrap around. */ #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) { fileptr = openfile->filebot; current_y_find = editwinrows - 1; } else { #endif fileptr = openfile->fileage; current_y_find = 0; #ifndef NANO_TINY } #endif statusbar(_("Search Wrapped")); } if (fileptr == begin) /* We've reached the original starting line. */ search_last_line = TRUE; rev_start = fileptr->data; #ifndef NANO_TINY if (ISSET(BACKWARDS_SEARCH)) rev_start += strlen(fileptr->data); #endif } /* We found an instance. */ current_x_find = found - fileptr->data; /* Ensure we haven't wrapped around again! */ if (search_last_line && #ifndef NANO_TINY ((!ISSET(BACKWARDS_SEARCH) && current_x_find > begin_x) || (ISSET(BACKWARDS_SEARCH) && current_x_find < begin_x)) #else current_x_find > begin_x #endif ) { not_found_msg(needle); disable_nodelay(); return FALSE; } disable_nodelay(); /* We've definitely found something. */ openfile->current = fileptr; openfile->current_x = current_x_find; openfile->placewewant = xplustabs(); openfile->current_y = current_y_find; /* needle_len holds the length of needle. */ if (needle_len != NULL) *needle_len = found_len; return TRUE; }
/* ARGSUSED */ static int rsearch(int f, int n, int dummy GCC_UNUSED, int fromscreen) { int status; int wrapok; MARK curpos; int didwrap; assert(curwp != 0); if (f && n < 0) /* reverse direction */ return fsearch(f, -n, FALSE, fromscreen); if (n == 0) n = 1; wrapok = window_b_val(curwp, MDWRAPSCAN); last_srch_direc = REVERSE; /* ask the user for the regular expression to search for, and * find n'th occurrence. */ status = readpattern("Reverse search: ", &searchpat, &gregexp, EOS, fromscreen); if (status != TRUE) return status; ignorecase = window_b_val(curwp, MDIGNCASE); if (curwp == 0) return FALSE; curpos = DOT; scanboundry(wrapok, DOT, REVERSE); didwrap = FALSE; while (n--) { movenext(&(DOT), REVERSE); status = scanner(gregexp, REVERSE, wrapok, &didwrap); if (didwrap) { mlwrite( "[Search wrapped past start of buffer]"); didwrap = FALSE; } if (status != TRUE) break; } if (status == TRUE) { savematch(DOT, gregexp->mlen); if (samepoint(DOT, curpos)) { mlwrite(onlyonemsg); } } else if (status == FALSE) { movenext(&(DOT), FORWARD); not_found_msg(wrapok, REVERSE); } else if (status == ABORT) { mlwarn("[Aborted]"); DOT = curpos; return status; } attrib_matches(); return status; }
/* Step through each replace word and prompt user before replacing. * Parameters real_current and real_current_x are needed in order to * allow the cursor position to be updated when a word before the cursor * is replaced by a shorter word. * * needle is the string to seek. We replace it with answer. Return -1 * if needle isn't found, else the number of replacements performed. If * canceled isn't NULL, set it to TRUE if we canceled. */ ssize_t do_replace_loop( #ifndef DISABLE_SPELLER bool whole_word_only, #endif bool *canceled, const linestruct *real_current, size_t *real_current_x, const char *needle) { ssize_t numreplaced = -1; size_t match_len; bool replaceall = FALSE; #ifndef NANO_TINY bool old_mark_set = openfile->mark_set; linestruct *top, *bot; size_t top_x, bot_x; bool right_side_up = FALSE; /* TRUE if (mark_begin, mark_begin_x) is the top of the mark, * FALSE if (current, current_x) is. */ if (old_mark_set) { /* If the mark is on, frame the region, and turn the mark off. */ mark_order((const linestruct **)&top, &top_x, (const linestruct **)&bot, &bot_x, &right_side_up); openfile->mark_set = FALSE; /* Start either at the top or the bottom of the marked region. */ if (!ISSET(BACKWARDS_SEARCH)) { openfile->current = top; openfile->current_x = (top_x == 0 ? 0 : top_x - 1); } else { openfile->current = bot; openfile->current_x = bot_x; } } #endif /* !NANO_TINY */ if (canceled != NULL) *canceled = FALSE; findnextstr_wrap_reset(); while (findnextstr( #ifndef DISABLE_SPELLER whole_word_only, #endif real_current, *real_current_x, needle, &match_len)) { int i = 0; #ifndef NANO_TINY if (old_mark_set) { /* When we've found an occurrence outside of the marked region, * stop the fanfare. */ if (openfile->current->lineno > bot->lineno || openfile->current->lineno < top->lineno || (openfile->current == bot && openfile->current_x > bot_x) || (openfile->current == top && openfile->current_x < top_x)) break; } #endif /* Indicate that we found the search string. */ if (numreplaced == -1) numreplaced = 0; if (!replaceall) { size_t xpt = xplustabs(); char *exp_word = display_string(openfile->current->data, xpt, strnlenpt(openfile->current->data, openfile->current_x + match_len) - xpt, FALSE); edit_refresh(); curs_set(0); do_replace_highlight(TRUE, exp_word); /* TRANSLATORS: This is a prompt. */ i = do_yesno_prompt(TRUE, _("Replace this instance?")); do_replace_highlight(FALSE, exp_word); free(exp_word); curs_set(1); if (i == -1) { /* We canceled the replace. */ if (canceled != NULL) *canceled = TRUE; break; } } if (i > 0 || replaceall) { /* Yes, replace it!!!! */ char *copy; size_t length_change; #ifndef NANO_TINY add_undo(REPLACE); #endif if (i == 2) replaceall = TRUE; copy = replace_line(needle); length_change = strlen(copy) - strlen(openfile->current->data); #ifndef NANO_TINY /* If the mark was on and (mark_begin, mark_begin_x) was the * top of it, don't change mark_begin_x. */ if (!old_mark_set || !right_side_up) { /* Keep mark_begin_x in sync with the text changes. */ if (openfile->current == openfile->mark_begin && openfile->mark_begin_x > openfile->current_x) { if (openfile->mark_begin_x < openfile->current_x + match_len) openfile->mark_begin_x = openfile->current_x; else openfile->mark_begin_x += length_change; bot_x = openfile->mark_begin_x; } } /* If the mark was on and (current, current_x) was the top * of it, don't change real_current_x. */ if (!old_mark_set || right_side_up) { #endif /* Keep real_current_x in sync with the text changes. */ if (openfile->current == real_current && openfile->current_x <= *real_current_x) { if (*real_current_x < openfile->current_x + match_len) *real_current_x = openfile->current_x + match_len; *real_current_x += length_change; #ifndef NANO_TINY bot_x = *real_current_x; } #endif } /* Set the cursor at the last character of the replacement * text, so searching will resume after the replacement * text. Note that current_x might be set to (size_t)-1 * here. */ #ifndef NANO_TINY if (!ISSET(BACKWARDS_SEARCH)) #endif openfile->current_x += match_len + length_change - 1; /* Clean up. */ openfile->totsize += mbstrlen(copy) - mbstrlen(openfile->current->data); free(openfile->current->data); openfile->current->data = copy; #ifndef DISABLE_COLOR /* Reset the precalculated multiline-regex hints only when * the first replacement has been made. */ if (numreplaced == 0) reset_multis(openfile->current, TRUE); #endif if (!replaceall) { #ifndef DISABLE_COLOR /* If color syntaxes are available and turned on, we * need to call edit_refresh(). */ if (openfile->colorstrings != NULL && !ISSET(NO_COLOR_SYNTAX)) edit_refresh(); else #endif update_line(openfile->current, openfile->current_x); } set_modified(); numreplaced++; } } if (numreplaced == -1) not_found_msg(needle); #ifndef NANO_TINY if (old_mark_set) openfile->mark_set = TRUE; #endif /* If the NO_NEWLINES flag isn't set, and text has been added to the * magicline, make a new magicline. */ if (!ISSET(NO_NEWLINES) && openfile->filebot->data[0] != '\0') new_magicline(); return numreplaced; }