Commit | Line | Data |
---|---|---|
bfe13c81 KB |
1 | /* |
2 | * Copyright (c) 1988 Mark Nudleman | |
1e3ab5ee KB |
3 | * Copyright (c) 1988, 1993 |
4 | * The Regents of the University of California. All rights reserved. | |
bfe13c81 | 5 | * |
f15db449 | 6 | * %sccs.include.redist.c% |
bfe13c81 KB |
7 | */ |
8 | ||
9 | #ifndef lint | |
1e3ab5ee | 10 | static char sccsid[] = "@(#)prim.c 8.1 (Berkeley) %G%"; |
bfe13c81 KB |
11 | #endif /* not lint */ |
12 | ||
13 | /* | |
14 | * Primitives for displaying the file on the screen. | |
15 | */ | |
16 | ||
966c6ec0 KB |
17 | #include <sys/types.h> |
18 | #include <stdio.h> | |
19 | #include <ctype.h> | |
20 | #include <less.h> | |
bfe13c81 | 21 | |
966c6ec0 KB |
22 | int back_scroll = -1; |
23 | int hit_eof; /* keeps track of how many times we hit end of file */ | |
24 | int screen_trashed; | |
bfe13c81 KB |
25 | |
26 | static int squished; | |
27 | ||
bfe13c81 | 28 | extern int sigs; |
bfe13c81 | 29 | extern int top_scroll; |
bfe13c81 | 30 | extern int sc_width, sc_height; |
bfe13c81 KB |
31 | extern int caseless; |
32 | extern int linenums; | |
bfe13c81 | 33 | extern int tagoption; |
966c6ec0 | 34 | extern char *line; |
441de7b4 | 35 | extern int retain_below; |
bfe13c81 | 36 | |
966c6ec0 KB |
37 | off_t position(), forw_line(), back_line(), forw_raw_line(), back_raw_line(); |
38 | off_t ch_length(), ch_tell(); | |
bfe13c81 KB |
39 | |
40 | /* | |
41 | * Check to see if the end of file is currently "displayed". | |
42 | */ | |
bfe13c81 KB |
43 | eof_check() |
44 | { | |
966c6ec0 | 45 | off_t pos; |
bfe13c81 KB |
46 | |
47 | if (sigs) | |
48 | return; | |
49 | /* | |
50 | * If the bottom line is empty, we are at EOF. | |
51 | * If the bottom line ends at the file length, | |
52 | * we must be just at EOF. | |
53 | */ | |
54 | pos = position(BOTTOM_PLUS_ONE); | |
55 | if (pos == NULL_POSITION || pos == ch_length()) | |
56 | hit_eof++; | |
57 | } | |
58 | ||
59 | /* | |
60 | * If the screen is "squished", repaint it. | |
61 | * "Squished" means the first displayed line is not at the top | |
62 | * of the screen; this can happen when we display a short file | |
63 | * for the first time. | |
64 | */ | |
bfe13c81 KB |
65 | squish_check() |
66 | { | |
966c6ec0 KB |
67 | if (squished) { |
68 | squished = 0; | |
69 | repaint(); | |
70 | } | |
bfe13c81 KB |
71 | } |
72 | ||
73 | /* | |
966c6ec0 | 74 | * Display n lines, scrolling forward, starting at position pos in the |
4a7551ea KB |
75 | * input file. "only_last" means display only the last screenful if |
76 | * n > screen size. | |
bfe13c81 | 77 | */ |
4a7551ea | 78 | forw(n, pos, only_last) |
bfe13c81 | 79 | register int n; |
966c6ec0 | 80 | off_t pos; |
bfe13c81 KB |
81 | int only_last; |
82 | { | |
4a7551ea | 83 | extern int short_file; |
bfe13c81 | 84 | static int first_time = 1; |
966c6ec0 | 85 | int eof = 0, do_repaint; |
bfe13c81 KB |
86 | |
87 | squish_check(); | |
88 | ||
89 | /* | |
90 | * do_repaint tells us not to display anything till the end, | |
91 | * then just repaint the entire screen. | |
92 | */ | |
93 | do_repaint = (only_last && n > sc_height-1); | |
94 | ||
966c6ec0 KB |
95 | if (!do_repaint) { |
96 | if (top_scroll && n >= sc_height - 1) { | |
bfe13c81 KB |
97 | /* |
98 | * Start a new screen. | |
99 | * {{ This is not really desirable if we happen | |
100 | * to hit eof in the middle of this screen, | |
101 | * but we don't yet know if that will happen. }} | |
102 | */ | |
966c6ec0 | 103 | clear(); |
bfe13c81 | 104 | home(); |
966c6ec0 | 105 | } else { |
bfe13c81 KB |
106 | lower_left(); |
107 | clear_eol(); | |
108 | } | |
109 | ||
966c6ec0 KB |
110 | /* |
111 | * This is not contiguous with what is currently displayed. | |
112 | * Clear the screen image (position table) and start a new | |
113 | * screen. | |
114 | */ | |
115 | if (pos != position(BOTTOM_PLUS_ONE)) { | |
bfe13c81 KB |
116 | pos_clear(); |
117 | add_forw_pos(pos); | |
966c6ec0 KB |
118 | if (top_scroll) { |
119 | clear(); | |
bfe13c81 KB |
120 | home(); |
121 | } else if (!first_time) | |
bfe13c81 | 122 | putstr("...skipping...\n"); |
bfe13c81 KB |
123 | } |
124 | } | |
125 | ||
4a7551ea | 126 | for (short_file = 0; --n >= 0;) { |
bfe13c81 KB |
127 | /* |
128 | * Read the next line of input. | |
129 | */ | |
130 | pos = forw_line(pos); | |
966c6ec0 | 131 | if (pos == NULL_POSITION) { |
bfe13c81 | 132 | /* |
4a7551ea KB |
133 | * end of file; copy the table if the file was |
134 | * too small for an entire screen. | |
bfe13c81 KB |
135 | */ |
136 | eof = 1; | |
4a7551ea KB |
137 | if (position(TOP) == NULL_POSITION) { |
138 | copytable(); | |
139 | if (!position(TOP)) | |
140 | short_file = 1; | |
141 | } | |
142 | break; | |
bfe13c81 KB |
143 | } |
144 | /* | |
145 | * Add the position of the next line to the position table. | |
146 | * Display the current line on the screen. | |
147 | */ | |
148 | add_forw_pos(pos); | |
bfe13c81 KB |
149 | if (do_repaint) |
150 | continue; | |
151 | /* | |
966c6ec0 KB |
152 | * If this is the first screen displayed and we hit an early |
153 | * EOF (i.e. before the requested number of lines), we | |
154 | * "squish" the display down at the bottom of the screen. | |
155 | * But don't do this if a -t option was given; it can cause | |
156 | * us to start the display after the beginning of the file, | |
bfe13c81 KB |
157 | * and it is not appropriate to squish in that case. |
158 | */ | |
966c6ec0 | 159 | if (first_time && line == NULL && !top_scroll && !tagoption) { |
bfe13c81 KB |
160 | squished = 1; |
161 | continue; | |
162 | } | |
bfe13c81 KB |
163 | put_line(); |
164 | } | |
165 | ||
166 | if (eof && !sigs) | |
167 | hit_eof++; | |
168 | else | |
169 | eof_check(); | |
966c6ec0 | 170 | if (do_repaint) |
bfe13c81 KB |
171 | repaint(); |
172 | first_time = 0; | |
173 | (void) currline(BOTTOM); | |
174 | } | |
175 | ||
176 | /* | |
177 | * Display n lines, scrolling backward. | |
178 | */ | |
4a7551ea | 179 | back(n, pos, only_last) |
bfe13c81 | 180 | register int n; |
966c6ec0 | 181 | off_t pos; |
bfe13c81 KB |
182 | int only_last; |
183 | { | |
bfe13c81 KB |
184 | int do_repaint; |
185 | ||
186 | squish_check(); | |
187 | do_repaint = (n > get_back_scroll() || (only_last && n > sc_height-1)); | |
188 | hit_eof = 0; | |
189 | while (--n >= 0) | |
190 | { | |
191 | /* | |
192 | * Get the previous line of input. | |
193 | */ | |
194 | pos = back_line(pos); | |
195 | if (pos == NULL_POSITION) | |
4a7551ea | 196 | break; |
bfe13c81 KB |
197 | /* |
198 | * Add the position of the previous line to the position table. | |
199 | * Display the line on the screen. | |
200 | */ | |
201 | add_back_pos(pos); | |
bfe13c81 KB |
202 | if (!do_repaint) |
203 | { | |
441de7b4 EW |
204 | if (retain_below) |
205 | { | |
206 | lower_left(); | |
207 | clear_eol(); | |
208 | } | |
bfe13c81 KB |
209 | home(); |
210 | add_line(); | |
211 | put_line(); | |
212 | } | |
213 | } | |
214 | ||
215 | eof_check(); | |
966c6ec0 | 216 | if (do_repaint) |
bfe13c81 KB |
217 | repaint(); |
218 | (void) currline(BOTTOM); | |
219 | } | |
220 | ||
221 | /* | |
222 | * Display n more lines, forward. | |
223 | * Start just after the line currently displayed at the bottom of the screen. | |
224 | */ | |
bfe13c81 KB |
225 | forward(n, only_last) |
226 | int n; | |
227 | int only_last; | |
228 | { | |
966c6ec0 | 229 | off_t pos; |
bfe13c81 | 230 | |
966c6ec0 | 231 | if (hit_eof) { |
bfe13c81 | 232 | /* |
966c6ec0 KB |
233 | * If we're trying to go forward from end-of-file, |
234 | * go on to the next file. | |
bfe13c81 KB |
235 | */ |
236 | next_file(1); | |
237 | return; | |
238 | } | |
239 | ||
240 | pos = position(BOTTOM_PLUS_ONE); | |
241 | if (pos == NULL_POSITION) | |
242 | { | |
bfe13c81 KB |
243 | hit_eof++; |
244 | return; | |
245 | } | |
4a7551ea | 246 | forw(n, pos, only_last); |
bfe13c81 KB |
247 | } |
248 | ||
249 | /* | |
250 | * Display n more lines, backward. | |
251 | * Start just before the line currently displayed at the top of the screen. | |
252 | */ | |
bfe13c81 KB |
253 | backward(n, only_last) |
254 | int n; | |
255 | int only_last; | |
256 | { | |
966c6ec0 | 257 | off_t pos; |
bfe13c81 KB |
258 | |
259 | pos = position(TOP); | |
966c6ec0 KB |
260 | /* |
261 | * This will almost never happen, because the top line is almost | |
262 | * never empty. | |
263 | */ | |
bfe13c81 | 264 | if (pos == NULL_POSITION) |
bfe13c81 | 265 | return; |
4a7551ea | 266 | back(n, pos, only_last); |
bfe13c81 KB |
267 | } |
268 | ||
269 | /* | |
270 | * Repaint the screen, starting from a specified position. | |
271 | */ | |
966c6ec0 KB |
272 | prepaint(pos) |
273 | off_t pos; | |
bfe13c81 KB |
274 | { |
275 | hit_eof = 0; | |
4a7551ea | 276 | forw(sc_height-1, pos, 0); |
bfe13c81 KB |
277 | screen_trashed = 0; |
278 | } | |
279 | ||
280 | /* | |
281 | * Repaint the screen. | |
282 | */ | |
bfe13c81 KB |
283 | repaint() |
284 | { | |
285 | /* | |
286 | * Start at the line currently at the top of the screen | |
287 | * and redisplay the screen. | |
288 | */ | |
289 | prepaint(position(TOP)); | |
290 | } | |
291 | ||
292 | /* | |
293 | * Jump to the end of the file. | |
294 | * It is more convenient to paint the screen backward, | |
295 | * from the end of the file toward the beginning. | |
296 | */ | |
bfe13c81 KB |
297 | jump_forw() |
298 | { | |
966c6ec0 | 299 | off_t pos; |
bfe13c81 KB |
300 | |
301 | if (ch_end_seek()) | |
302 | { | |
303 | error("Cannot seek to end of file"); | |
304 | return; | |
305 | } | |
306 | lastmark(); | |
307 | pos = ch_tell(); | |
308 | clear(); | |
309 | pos_clear(); | |
310 | add_back_pos(pos); | |
4a7551ea | 311 | back(sc_height - 1, pos, 0); |
bfe13c81 KB |
312 | } |
313 | ||
314 | /* | |
315 | * Jump to line n in the file. | |
316 | */ | |
bfe13c81 KB |
317 | jump_back(n) |
318 | register int n; | |
319 | { | |
966c6ec0 | 320 | register int c, nlines; |
bfe13c81 KB |
321 | |
322 | /* | |
323 | * This is done the slow way, by starting at the beginning | |
324 | * of the file and counting newlines. | |
325 | * | |
326 | * {{ Now that we have line numbering (in linenum.c), | |
327 | * we could improve on this by starting at the | |
328 | * nearest known line rather than at the beginning. }} | |
329 | */ | |
966c6ec0 | 330 | if (ch_seek((off_t)0)) { |
bfe13c81 KB |
331 | /* |
332 | * Probably a pipe with beginning of file no longer buffered. | |
333 | * If he wants to go to line 1, we do the best we can, | |
334 | * by going to the first line which is still buffered. | |
335 | */ | |
336 | if (n <= 1 && ch_beg_seek() == 0) | |
337 | jump_loc(ch_tell()); | |
338 | error("Cannot get to beginning of file"); | |
339 | return; | |
340 | } | |
341 | ||
342 | /* | |
343 | * Start counting lines. | |
344 | */ | |
345 | for (nlines = 1; nlines < n; nlines++) | |
bfe13c81 | 346 | while ((c = ch_forw_get()) != '\n') |
966c6ec0 | 347 | if (c == EOI) { |
bfe13c81 | 348 | char message[40]; |
79a08ff0 | 349 | (void)sprintf(message, "File has only %d lines", |
966c6ec0 | 350 | nlines - 1); |
bfe13c81 KB |
351 | error(message); |
352 | return; | |
353 | } | |
bfe13c81 KB |
354 | jump_loc(ch_tell()); |
355 | } | |
356 | ||
357 | /* | |
358 | * Jump to a specified percentage into the file. | |
359 | * This is a poor compensation for not being able to | |
360 | * quickly jump to a specific line number. | |
361 | */ | |
bfe13c81 KB |
362 | jump_percent(percent) |
363 | int percent; | |
364 | { | |
966c6ec0 | 365 | off_t pos, len, ch_length(); |
bfe13c81 KB |
366 | register int c; |
367 | ||
368 | /* | |
369 | * Determine the position in the file | |
370 | * (the specified percentage of the file's length). | |
371 | */ | |
372 | if ((len = ch_length()) == NULL_POSITION) | |
373 | { | |
374 | error("Don't know length of file"); | |
375 | return; | |
376 | } | |
377 | pos = (percent * len) / 100; | |
378 | ||
379 | /* | |
380 | * Back up to the beginning of the line. | |
381 | */ | |
382 | if (ch_seek(pos) == 0) | |
383 | { | |
384 | while ((c = ch_back_get()) != '\n' && c != EOI) | |
385 | ; | |
386 | if (c == '\n') | |
387 | (void) ch_forw_get(); | |
388 | pos = ch_tell(); | |
389 | } | |
390 | jump_loc(pos); | |
391 | } | |
392 | ||
393 | /* | |
394 | * Jump to a specified position in the file. | |
395 | */ | |
bfe13c81 | 396 | jump_loc(pos) |
966c6ec0 | 397 | off_t pos; |
bfe13c81 KB |
398 | { |
399 | register int nline; | |
966c6ec0 | 400 | off_t tpos; |
bfe13c81 | 401 | |
966c6ec0 | 402 | if ((nline = onscreen(pos)) >= 0) { |
bfe13c81 KB |
403 | /* |
404 | * The line is currently displayed. | |
405 | * Just scroll there. | |
406 | */ | |
4a7551ea | 407 | forw(nline, position(BOTTOM_PLUS_ONE), 0); |
bfe13c81 KB |
408 | return; |
409 | } | |
410 | ||
411 | /* | |
412 | * Line is not on screen. | |
413 | * Seek to the desired location. | |
414 | */ | |
966c6ec0 | 415 | if (ch_seek(pos)) { |
bfe13c81 KB |
416 | error("Cannot seek to that position"); |
417 | return; | |
418 | } | |
419 | ||
420 | /* | |
966c6ec0 KB |
421 | * See if the desired line is BEFORE the currently displayed screen. |
422 | * If so, then move forward far enough so the line we're on will be | |
423 | * at the bottom of the screen, in order to be able to call back() | |
424 | * to make the screen scroll backwards & put the line at the top of | |
425 | * the screen. | |
bfe13c81 KB |
426 | * {{ This seems inefficient, but it's not so bad, |
427 | * since we can never move forward more than a | |
428 | * screenful before we stop to redraw the screen. }} | |
429 | */ | |
430 | tpos = position(TOP); | |
966c6ec0 KB |
431 | if (tpos != NULL_POSITION && pos < tpos) { |
432 | off_t npos = pos; | |
bfe13c81 KB |
433 | /* |
434 | * Note that we can't forw_line() past tpos here, | |
435 | * so there should be no EOI at this stage. | |
436 | */ | |
437 | for (nline = 0; npos < tpos && nline < sc_height - 1; nline++) | |
438 | npos = forw_line(npos); | |
439 | ||
966c6ec0 | 440 | if (npos < tpos) { |
bfe13c81 KB |
441 | /* |
442 | * More than a screenful back. | |
443 | */ | |
444 | lastmark(); | |
445 | clear(); | |
446 | pos_clear(); | |
447 | add_back_pos(npos); | |
448 | } | |
449 | ||
450 | /* | |
451 | * Note that back() will repaint() if nline > back_scroll. | |
452 | */ | |
4a7551ea | 453 | back(nline, npos, 0); |
bfe13c81 KB |
454 | return; |
455 | } | |
456 | /* | |
457 | * Remember where we were; clear and paint the screen. | |
458 | */ | |
966c6ec0 KB |
459 | lastmark(); |
460 | prepaint(pos); | |
bfe13c81 KB |
461 | } |
462 | ||
463 | /* | |
464 | * The table of marks. | |
465 | * A mark is simply a position in the file. | |
466 | */ | |
467 | #define NMARKS (27) /* 26 for a-z plus one for quote */ | |
468 | #define LASTMARK (NMARKS-1) /* For quote */ | |
966c6ec0 | 469 | static off_t marks[NMARKS]; |
bfe13c81 KB |
470 | |
471 | /* | |
472 | * Initialize the mark table to show no marks are set. | |
473 | */ | |
bfe13c81 KB |
474 | init_mark() |
475 | { | |
476 | int i; | |
477 | ||
478 | for (i = 0; i < NMARKS; i++) | |
479 | marks[i] = NULL_POSITION; | |
480 | } | |
481 | ||
482 | /* | |
483 | * See if a mark letter is valid (between a and z). | |
484 | */ | |
485 | static int | |
486 | badmark(c) | |
487 | int c; | |
488 | { | |
489 | if (c < 'a' || c > 'z') | |
490 | { | |
491 | error("Choose a letter between 'a' and 'z'"); | |
492 | return (1); | |
493 | } | |
494 | return (0); | |
495 | } | |
496 | ||
497 | /* | |
498 | * Set a mark. | |
499 | */ | |
bfe13c81 KB |
500 | setmark(c) |
501 | int c; | |
502 | { | |
503 | if (badmark(c)) | |
504 | return; | |
505 | marks[c-'a'] = position(TOP); | |
506 | } | |
507 | ||
bfe13c81 KB |
508 | lastmark() |
509 | { | |
510 | marks[LASTMARK] = position(TOP); | |
511 | } | |
512 | ||
513 | /* | |
514 | * Go to a previously set mark. | |
515 | */ | |
bfe13c81 KB |
516 | gomark(c) |
517 | int c; | |
518 | { | |
966c6ec0 | 519 | off_t pos; |
bfe13c81 | 520 | |
148d5db7 | 521 | if (c == '\'') { |
bfe13c81 | 522 | pos = marks[LASTMARK]; |
148d5db7 KB |
523 | if (pos == NULL_POSITION) |
524 | pos = 0; | |
525 | } | |
526 | else { | |
527 | if (badmark(c)) | |
528 | return; | |
bfe13c81 | 529 | pos = marks[c-'a']; |
148d5db7 KB |
530 | if (pos == NULL_POSITION) { |
531 | error("mark not set"); | |
532 | return; | |
533 | } | |
534 | } | |
535 | jump_loc(pos); | |
bfe13c81 KB |
536 | } |
537 | ||
538 | /* | |
539 | * Get the backwards scroll limit. | |
540 | * Must call this function instead of just using the value of | |
541 | * back_scroll, because the default case depends on sc_height and | |
542 | * top_scroll, as well as back_scroll. | |
543 | */ | |
bfe13c81 KB |
544 | get_back_scroll() |
545 | { | |
546 | if (back_scroll >= 0) | |
547 | return (back_scroll); | |
548 | if (top_scroll) | |
549 | return (sc_height - 2); | |
550 | return (sc_height - 1); | |
551 | } | |
552 | ||
553 | /* | |
554 | * Search for the n-th occurence of a specified pattern, | |
555 | * either forward or backward. | |
556 | */ | |
bfe13c81 KB |
557 | search(search_forward, pattern, n, wantmatch) |
558 | register int search_forward; | |
559 | register char *pattern; | |
560 | register int n; | |
561 | int wantmatch; | |
562 | { | |
966c6ec0 | 563 | off_t pos, linepos; |
bfe13c81 KB |
564 | register char *p; |
565 | register char *q; | |
566 | int linenum; | |
567 | int linematch; | |
966c6ec0 | 568 | #ifdef RECOMP |
bfe13c81 KB |
569 | char *re_comp(); |
570 | char *errmsg; | |
571 | #else | |
966c6ec0 | 572 | #ifdef REGCMP |
bfe13c81 KB |
573 | char *regcmp(); |
574 | static char *cpattern = NULL; | |
575 | #else | |
576 | static char lpbuf[100]; | |
577 | static char *last_pattern = NULL; | |
79a08ff0 | 578 | char *strcpy(); |
bfe13c81 KB |
579 | #endif |
580 | #endif | |
581 | ||
966c6ec0 KB |
582 | /* |
583 | * For a caseless search, convert any uppercase in the pattern to | |
584 | * lowercase. | |
585 | */ | |
bfe13c81 | 586 | if (caseless && pattern != NULL) |
966c6ec0 KB |
587 | for (p = pattern; *p; p++) |
588 | if (isupper(*p)) | |
589 | *p = tolower(*p); | |
590 | #ifdef RECOMP | |
bfe13c81 KB |
591 | |
592 | /* | |
593 | * (re_comp handles a null pattern internally, | |
594 | * so there is no need to check for a null pattern here.) | |
595 | */ | |
596 | if ((errmsg = re_comp(pattern)) != NULL) | |
597 | { | |
598 | error(errmsg); | |
966c6ec0 | 599 | return(0); |
bfe13c81 KB |
600 | } |
601 | #else | |
966c6ec0 | 602 | #ifdef REGCMP |
bfe13c81 KB |
603 | if (pattern == NULL || *pattern == '\0') |
604 | { | |
605 | /* | |
606 | * A null pattern means use the previous pattern. | |
607 | * The compiled previous pattern is in cpattern, so just use it. | |
608 | */ | |
609 | if (cpattern == NULL) | |
610 | { | |
611 | error("No previous regular expression"); | |
966c6ec0 | 612 | return(0); |
bfe13c81 KB |
613 | } |
614 | } else | |
615 | { | |
616 | /* | |
617 | * Otherwise compile the given pattern. | |
618 | */ | |
619 | char *s; | |
620 | if ((s = regcmp(pattern, 0)) == NULL) | |
621 | { | |
622 | error("Invalid pattern"); | |
966c6ec0 | 623 | return(0); |
bfe13c81 KB |
624 | } |
625 | if (cpattern != NULL) | |
626 | free(cpattern); | |
627 | cpattern = s; | |
628 | } | |
629 | #else | |
630 | if (pattern == NULL || *pattern == '\0') | |
631 | { | |
632 | /* | |
633 | * Null pattern means use the previous pattern. | |
634 | */ | |
635 | if (last_pattern == NULL) | |
636 | { | |
637 | error("No previous regular expression"); | |
966c6ec0 | 638 | return(0); |
bfe13c81 KB |
639 | } |
640 | pattern = last_pattern; | |
641 | } else | |
642 | { | |
79a08ff0 | 643 | (void)strcpy(lpbuf, pattern); |
bfe13c81 KB |
644 | last_pattern = lpbuf; |
645 | } | |
646 | #endif | |
647 | #endif | |
648 | ||
649 | /* | |
650 | * Figure out where to start the search. | |
651 | */ | |
652 | ||
966c6ec0 | 653 | if (position(TOP) == NULL_POSITION) { |
bfe13c81 | 654 | /* |
966c6ec0 KB |
655 | * Nothing is currently displayed. Start at the beginning |
656 | * of the file. (This case is mainly for searches from the | |
657 | * command line. | |
bfe13c81 | 658 | */ |
966c6ec0 KB |
659 | pos = (off_t)0; |
660 | } else if (!search_forward) { | |
bfe13c81 KB |
661 | /* |
662 | * Backward search: start just before the top line | |
663 | * displayed on the screen. | |
664 | */ | |
665 | pos = position(TOP); | |
966c6ec0 | 666 | } else { |
bfe13c81 KB |
667 | /* |
668 | * Start at the second screen line displayed on the screen. | |
669 | */ | |
670 | pos = position(TOP_PLUS_ONE); | |
671 | } | |
672 | ||
673 | if (pos == NULL_POSITION) | |
674 | { | |
675 | /* | |
676 | * Can't find anyplace to start searching from. | |
677 | */ | |
678 | error("Nothing to search"); | |
966c6ec0 | 679 | return(0); |
bfe13c81 KB |
680 | } |
681 | ||
682 | linenum = find_linenum(pos); | |
683 | for (;;) | |
684 | { | |
685 | /* | |
686 | * Get lines until we find a matching one or | |
687 | * until we hit end-of-file (or beginning-of-file | |
688 | * if we're going backwards). | |
689 | */ | |
690 | if (sigs) | |
691 | /* | |
692 | * A signal aborts the search. | |
693 | */ | |
966c6ec0 | 694 | return(0); |
bfe13c81 KB |
695 | |
696 | if (search_forward) | |
697 | { | |
698 | /* | |
699 | * Read the next line, and save the | |
700 | * starting position of that line in linepos. | |
701 | */ | |
702 | linepos = pos; | |
703 | pos = forw_raw_line(pos); | |
704 | if (linenum != 0) | |
705 | linenum++; | |
706 | } else | |
707 | { | |
708 | /* | |
709 | * Read the previous line and save the | |
710 | * starting position of that line in linepos. | |
711 | */ | |
712 | pos = back_raw_line(pos); | |
713 | linepos = pos; | |
714 | if (linenum != 0) | |
715 | linenum--; | |
716 | } | |
717 | ||
718 | if (pos == NULL_POSITION) | |
719 | { | |
720 | /* | |
721 | * We hit EOF/BOF without a match. | |
722 | */ | |
723 | error("Pattern not found"); | |
966c6ec0 | 724 | return(0); |
bfe13c81 KB |
725 | } |
726 | ||
727 | /* | |
728 | * If we're using line numbers, we might as well | |
729 | * remember the information we have now (the position | |
730 | * and line number of the current line). | |
731 | */ | |
732 | if (linenums) | |
733 | add_lnum(linenum, pos); | |
734 | ||
966c6ec0 KB |
735 | /* |
736 | * If this is a caseless search, convert uppercase in the | |
737 | * input line to lowercase. | |
738 | */ | |
bfe13c81 | 739 | if (caseless) |
966c6ec0 KB |
740 | for (p = q = line; *p; p++, q++) |
741 | *q = isupper(*p) ? tolower(*p) : *p; | |
742 | ||
743 | /* | |
744 | * Remove any backspaces along with the preceeding char. | |
745 | * This allows us to match text which is underlined or | |
746 | * overstruck. | |
747 | */ | |
748 | for (p = q = line; *p; p++, q++) | |
749 | if (q > line && *p == '\b') | |
750 | /* Delete BS and preceeding char. */ | |
751 | q -= 2; | |
752 | else | |
753 | /* Otherwise, just copy. */ | |
754 | *q = *p; | |
bfe13c81 KB |
755 | |
756 | /* | |
757 | * Test the next line to see if we have a match. | |
758 | * This is done in a variety of ways, depending | |
759 | * on what pattern matching functions are available. | |
760 | */ | |
966c6ec0 | 761 | #ifdef REGCMP |
bfe13c81 KB |
762 | linematch = (regex(cpattern, line) != NULL); |
763 | #else | |
966c6ec0 | 764 | #ifdef RECOMP |
bfe13c81 KB |
765 | linematch = (re_exec(line) == 1); |
766 | #else | |
767 | linematch = match(pattern, line); | |
768 | #endif | |
769 | #endif | |
770 | /* | |
771 | * We are successful if wantmatch and linematch are | |
772 | * both true (want a match and got it), | |
773 | * or both false (want a non-match and got it). | |
774 | */ | |
775 | if (((wantmatch && linematch) || (!wantmatch && !linematch)) && | |
776 | --n <= 0) | |
777 | /* | |
778 | * Found the line. | |
779 | */ | |
780 | break; | |
781 | } | |
bfe13c81 | 782 | jump_loc(linepos); |
966c6ec0 | 783 | return(1); |
bfe13c81 KB |
784 | } |
785 | ||
966c6ec0 | 786 | #if !defined(REGCMP) && !defined(RECOMP) |
bfe13c81 KB |
787 | /* |
788 | * We have neither regcmp() nor re_comp(). | |
789 | * We use this function to do simple pattern matching. | |
790 | * It supports no metacharacters like *, etc. | |
791 | */ | |
966c6ec0 | 792 | static |
bfe13c81 KB |
793 | match(pattern, buf) |
794 | char *pattern, *buf; | |
795 | { | |
796 | register char *pp, *lp; | |
797 | ||
798 | for ( ; *buf != '\0'; buf++) | |
799 | { | |
800 | for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++) | |
801 | if (*pp == '\0' || *lp == '\0') | |
802 | break; | |
803 | if (*pp == '\0') | |
804 | return (1); | |
805 | } | |
806 | return (0); | |
807 | } | |
808 | #endif |