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