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