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