// lesson: search

Search

A file you can't search is a file you can only scroll. The good news after the last few lessons: search is easy โ€” plain C string work, no escape codes, no state machines. The design still deserves five minutes, because search UX has sharp conventions.

Find-next semantics

The operation that matters is not "find" but find next: given where I am, where is the following match? Repeat-invocations then walk match to match. Two conventions define it:

  • Start searching at a given position (inclusive), and let the caller pass "cursor + one column" for repeat-search โ€” else pressing find-next while standing on a match finds the same match forever. Keeping the +1 out of the search function keeps the function honest and the policy visible at the call site.
  • Wrap around. Hitting the last match then searching again jumps back to the first (vim flashes "search hit BOTTOM, continuing at TOP"). Implement by scanning position โ†’ end of buffer, then start of buffer โ†’ position.

Within a line, strstr(3) does the byte work โ€” find the first occurrence of a needle in a haystack. The only wrinkle: starting mid-line means searching the line's suffix (strstr(line + col, q)), then reporting the match's column relative to the whole line (add the offset back โ€” a classic pointer-arithmetic fencepost).

Real editors layer niceties on this core โ€” case folding, highlight-all, incremental search that jumps as you type, regex. All of them sit on exactly this function; incremental search, for instance, is just re-running find-next from the search's origin on every keystroke of the query.

โ€บ Find in Buffer

20 pts

Implement:

int editor_find_next(const struct editor *e, const char *query,
                     int from_row, int from_col,
                     int *match_row, int *match_col);
  • Search forward from (from_row, from_col) inclusive, wrapping past the end of the buffer, over all lines โ€” including the part of the starting line before from_col* on the wrapped pass (a match just left of the cursor must be reachable).
  • On a hit: store its position, return 1. No match anywhere (or empty/NULL query, or an out-of-range start): return 0.
  • Matches are byte-exact and case-sensitive.

Log in to submit a solution and earn points.