PageRenderTime 25ms CodeModel.GetById 20ms RepoModel.GetById 1ms app.codeStats 0ms

/commands/less/less/search.c

http://github.com/vivekp/minix-nbsd
C | 1452 lines | 973 code | 93 blank | 386 comment | 290 complexity | 6e9d23aecb3326f8b2c75f9f31d38477 MD5 | raw file
Possible License(s): AGPL-1.0, BSD-3-Clause
  1. /* $NetBSD: search.c,v 1.10 2006/10/26 01:33:08 mrg Exp $ */
  2. /*
  3. * Copyright (C) 1984-2005 Mark Nudelman
  4. *
  5. * You may distribute under the terms of either the GNU General Public
  6. * License or the Less License, as specified in the README file.
  7. *
  8. * For more information about less, or for information on how to
  9. * contact the author, see the README file.
  10. */
  11. /*
  12. * Routines to search a file for a pattern.
  13. */
  14. #include "less.h"
  15. #include "position.h"
  16. #define MINPOS(a,b) (((a) < (b)) ? (a) : (b))
  17. #define MAXPOS(a,b) (((a) > (b)) ? (a) : (b))
  18. #if HAVE_POSIX_REGCOMP
  19. #include <regex.h>
  20. #ifdef REG_EXTENDED
  21. #define REGCOMP_FLAG (more_mode ? 0 : REG_EXTENDED)
  22. #else
  23. #define REGCOMP_FLAG 0
  24. #endif
  25. #endif
  26. #if HAVE_PCRE
  27. #include <pcre.h>
  28. #endif
  29. #if HAVE_RE_COMP
  30. char *re_comp();
  31. int re_exec();
  32. #endif
  33. #if HAVE_REGCMP
  34. char *regcmp();
  35. char *regex();
  36. extern char *__loc1;
  37. #endif
  38. #if HAVE_V8_REGCOMP
  39. #include "regexp.h"
  40. #endif
  41. static void cvt_text __P((char *, char *, int));
  42. static int is_ucase __P((char *));
  43. static int prev_pattern __P((void));
  44. static int compile_pattern __P((char *, int));
  45. static void uncompile_pattern __P((void));
  46. static int match_pattern __P((char *, char **, char **, int));
  47. struct hilite;
  48. static void add_hilite __P((struct hilite *, struct hilite *));
  49. static void adj_hilite __P((struct hilite *, POSITION, int));
  50. static void hilite_line __P((POSITION, char *, char *, char *, int));
  51. static void hilite_screen __P((void));
  52. static POSITION search_pos __P((int));
  53. static int search_range __P((POSITION, POSITION, int, int, int, POSITION *, POSITION *));
  54. static int match __P((char *, char *, char **, char **));
  55. extern int sigs;
  56. extern int how_search;
  57. extern int caseless;
  58. extern int linenums;
  59. extern int sc_height;
  60. extern int jump_sline;
  61. extern int bs_mode;
  62. extern int ctldisp;
  63. extern int status_col;
  64. extern int more_mode;
  65. extern POSITION start_attnpos;
  66. extern POSITION end_attnpos;
  67. #if HILITE_SEARCH
  68. extern int hilite_search;
  69. extern int screen_trashed;
  70. extern int size_linebuf;
  71. extern int squished;
  72. extern int can_goto_line;
  73. static int hide_hilite;
  74. static POSITION prep_startpos;
  75. static POSITION prep_endpos;
  76. struct hilite
  77. {
  78. struct hilite *hl_next;
  79. POSITION hl_startpos;
  80. POSITION hl_endpos;
  81. };
  82. static struct hilite hilite_anchor = { NULL, NULL_POSITION, NULL_POSITION };
  83. #define hl_first hl_next
  84. #endif
  85. /*
  86. * These are the static variables that represent the "remembered"
  87. * search pattern.
  88. */
  89. #if HAVE_POSIX_REGCOMP
  90. static regex_t *regpattern = NULL;
  91. #endif
  92. #if HAVE_PCRE
  93. pcre *regpattern = NULL;
  94. #endif
  95. #if HAVE_RE_COMP
  96. int re_pattern = 0;
  97. #endif
  98. #if HAVE_REGCMP
  99. static char *cpattern = NULL;
  100. #endif
  101. #if HAVE_V8_REGCOMP
  102. static struct regexp *regpattern = NULL;
  103. #endif
  104. static int is_caseless;
  105. static int is_ucase_pattern;
  106. static int last_search_type;
  107. static char *last_pattern = NULL;
  108. /*
  109. * Convert text. Perform one or more of these transformations:
  110. */
  111. #define CVT_TO_LC 01 /* Convert upper-case to lower-case */
  112. #define CVT_BS 02 /* Do backspace processing */
  113. #define CVT_CRLF 04 /* Remove CR after LF */
  114. #define CVT_ANSI 010 /* Remove ANSI escape sequences */
  115. static void
  116. cvt_text(odst, osrc, ops)
  117. char *odst;
  118. char *osrc;
  119. int ops;
  120. {
  121. register char *dst;
  122. register char *src;
  123. for (src = osrc, dst = odst; *src != '\0'; src++)
  124. {
  125. if ((ops & CVT_TO_LC) && IS_UPPER(*src))
  126. /* Convert uppercase to lowercase. */
  127. *dst++ = TO_LOWER(*src);
  128. else if ((ops & CVT_BS) && *src == '\b' && dst > odst)
  129. /* Delete BS and preceding char. */
  130. dst--;
  131. else if ((ops & CVT_ANSI) && *src == ESC)
  132. {
  133. /* Skip to end of ANSI escape sequence. */
  134. while (src[1] != '\0')
  135. if (!is_ansi_middle(*++src))
  136. break;
  137. } else
  138. /* Just copy. */
  139. *dst++ = *src;
  140. }
  141. if ((ops & CVT_CRLF) && dst > odst && dst[-1] == '\r')
  142. dst--;
  143. *dst = '\0';
  144. }
  145. /*
  146. * Determine which conversions to perform.
  147. */
  148. static int
  149. get_cvt_ops()
  150. {
  151. int ops = 0;
  152. if (is_caseless || bs_mode == BS_SPECIAL)
  153. {
  154. if (is_caseless)
  155. ops |= CVT_TO_LC;
  156. if (bs_mode == BS_SPECIAL)
  157. ops |= CVT_BS;
  158. if (bs_mode != BS_CONTROL)
  159. ops |= CVT_CRLF;
  160. } else if (bs_mode != BS_CONTROL)
  161. {
  162. ops |= CVT_CRLF;
  163. }
  164. if (ctldisp == OPT_ONPLUS)
  165. ops |= CVT_ANSI;
  166. return (ops);
  167. }
  168. /*
  169. * Are there any uppercase letters in this string?
  170. */
  171. static int
  172. is_ucase(s)
  173. char *s;
  174. {
  175. register char *p;
  176. for (p = s; *p != '\0'; p++)
  177. if (IS_UPPER(*p))
  178. return (1);
  179. return (0);
  180. }
  181. /*
  182. * Is there a previous (remembered) search pattern?
  183. */
  184. static int
  185. prev_pattern()
  186. {
  187. if (last_search_type & SRCH_NO_REGEX)
  188. return (last_pattern != NULL);
  189. #if HAVE_POSIX_REGCOMP
  190. return (regpattern != NULL);
  191. #endif
  192. #if HAVE_PCRE
  193. return (regpattern != NULL);
  194. #endif
  195. #if HAVE_RE_COMP
  196. return (re_pattern != 0);
  197. #endif
  198. #if HAVE_REGCMP
  199. return (cpattern != NULL);
  200. #endif
  201. #if HAVE_V8_REGCOMP
  202. return (regpattern != NULL);
  203. #endif
  204. #if NO_REGEX
  205. return (last_pattern != NULL);
  206. #endif
  207. }
  208. #if HILITE_SEARCH
  209. /*
  210. * Repaint the hilites currently displayed on the screen.
  211. * Repaint each line which contains highlighted text.
  212. * If on==0, force all hilites off.
  213. */
  214. public void
  215. repaint_hilite(on)
  216. int on;
  217. {
  218. int slinenum;
  219. POSITION pos;
  220. POSITION epos;
  221. int save_hide_hilite;
  222. if (squished)
  223. repaint();
  224. save_hide_hilite = hide_hilite;
  225. if (!on)
  226. {
  227. if (hide_hilite)
  228. return;
  229. hide_hilite = 1;
  230. }
  231. if (!can_goto_line)
  232. {
  233. repaint();
  234. hide_hilite = save_hide_hilite;
  235. return;
  236. }
  237. for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
  238. {
  239. pos = position(slinenum);
  240. if (pos == NULL_POSITION)
  241. continue;
  242. epos = position(slinenum+1);
  243. #if 0
  244. /*
  245. * If any character in the line is highlighted,
  246. * repaint the line.
  247. *
  248. * {{ This doesn't work -- if line is drawn with highlights
  249. * which should be erased (e.g. toggle -i with status column),
  250. * we must redraw the line even if it has no highlights.
  251. * For now, just repaint every line. }}
  252. */
  253. if (is_hilited(pos, epos, 1, NULL))
  254. #endif
  255. {
  256. (void) forw_line(pos);
  257. goto_line(slinenum);
  258. put_line();
  259. }
  260. }
  261. hide_hilite = save_hide_hilite;
  262. }
  263. /*
  264. * Clear the attn hilite.
  265. */
  266. public void
  267. clear_attn()
  268. {
  269. int slinenum;
  270. POSITION old_start_attnpos;
  271. POSITION old_end_attnpos;
  272. POSITION pos;
  273. POSITION epos;
  274. if (start_attnpos == NULL_POSITION)
  275. return;
  276. old_start_attnpos = start_attnpos;
  277. old_end_attnpos = end_attnpos;
  278. start_attnpos = end_attnpos = NULL_POSITION;
  279. if (!can_goto_line)
  280. {
  281. repaint();
  282. return;
  283. }
  284. if (squished)
  285. repaint();
  286. for (slinenum = TOP; slinenum < TOP + sc_height-1; slinenum++)
  287. {
  288. pos = position(slinenum);
  289. if (pos == NULL_POSITION)
  290. continue;
  291. epos = position(slinenum+1);
  292. if (pos < old_end_attnpos &&
  293. (epos == NULL_POSITION || epos > old_start_attnpos))
  294. {
  295. (void) forw_line(pos);
  296. goto_line(slinenum);
  297. put_line();
  298. }
  299. }
  300. }
  301. #endif
  302. /*
  303. * Hide search string highlighting.
  304. */
  305. public void
  306. undo_search()
  307. {
  308. if (!prev_pattern())
  309. {
  310. error("No previous regular expression", NULL_PARG);
  311. return;
  312. }
  313. #if HILITE_SEARCH
  314. hide_hilite = !hide_hilite;
  315. repaint_hilite(1);
  316. #endif
  317. }
  318. /*
  319. * Compile a search pattern, for future use by match_pattern.
  320. */
  321. static int
  322. compile_pattern(pattern, search_type)
  323. char *pattern;
  324. int search_type;
  325. {
  326. if ((search_type & SRCH_NO_REGEX) == 0)
  327. {
  328. #if HAVE_POSIX_REGCOMP
  329. regex_t *s = (regex_t *) ecalloc(1, sizeof(regex_t));
  330. if (regcomp(s, pattern, REGCOMP_FLAG))
  331. {
  332. free(s);
  333. error("Invalid pattern", NULL_PARG);
  334. return (-1);
  335. }
  336. if (regpattern != NULL)
  337. regfree(regpattern);
  338. regpattern = s;
  339. #endif
  340. #if HAVE_PCRE
  341. pcre *comp;
  342. const char *errstring;
  343. int erroffset;
  344. PARG parg;
  345. comp = pcre_compile(pattern, 0,
  346. &errstring, &erroffset, NULL);
  347. if (comp == NULL)
  348. {
  349. parg.p_string = (char *) errstring;
  350. error("%s", &parg);
  351. return (-1);
  352. }
  353. regpattern = comp;
  354. #endif
  355. #if HAVE_RE_COMP
  356. PARG parg;
  357. if ((parg.p_string = re_comp(pattern)) != NULL)
  358. {
  359. error("%s", &parg);
  360. return (-1);
  361. }
  362. re_pattern = 1;
  363. #endif
  364. #if HAVE_REGCMP
  365. char *s;
  366. if ((s = regcmp(pattern, 0)) == NULL)
  367. {
  368. error("Invalid pattern", NULL_PARG);
  369. return (-1);
  370. }
  371. if (cpattern != NULL)
  372. free(cpattern);
  373. cpattern = s;
  374. #endif
  375. #if HAVE_V8_REGCOMP
  376. struct regexp *s;
  377. if ((s = regcomp(pattern)) == NULL)
  378. {
  379. /*
  380. * regcomp has already printed an error message
  381. * via regerror().
  382. */
  383. return (-1);
  384. }
  385. if (regpattern != NULL)
  386. free(regpattern);
  387. regpattern = s;
  388. #endif
  389. }
  390. if (last_pattern != NULL)
  391. free(last_pattern);
  392. last_pattern = (char *) calloc(1, strlen(pattern)+1);
  393. if (last_pattern != NULL)
  394. strcpy(last_pattern, pattern);
  395. last_search_type = search_type;
  396. return (0);
  397. }
  398. /*
  399. * Forget that we have a compiled pattern.
  400. */
  401. static void
  402. uncompile_pattern()
  403. {
  404. #if HAVE_POSIX_REGCOMP
  405. if (regpattern != NULL)
  406. regfree(regpattern);
  407. regpattern = NULL;
  408. #endif
  409. #if HAVE_PCRE
  410. if (regpattern != NULL)
  411. pcre_free(regpattern);
  412. regpattern = NULL;
  413. #endif
  414. #if HAVE_RE_COMP
  415. re_pattern = 0;
  416. #endif
  417. #if HAVE_REGCMP
  418. if (cpattern != NULL)
  419. free(cpattern);
  420. cpattern = NULL;
  421. #endif
  422. #if HAVE_V8_REGCOMP
  423. if (regpattern != NULL)
  424. free(regpattern);
  425. regpattern = NULL;
  426. #endif
  427. last_pattern = NULL;
  428. }
  429. /*
  430. * Perform a pattern match with the previously compiled pattern.
  431. * Set sp and ep to the start and end of the matched string.
  432. */
  433. static int
  434. match_pattern(line, sp, ep, notbol)
  435. char *line;
  436. char **sp;
  437. char **ep;
  438. int notbol;
  439. {
  440. int matched;
  441. if (last_search_type & SRCH_NO_REGEX)
  442. return (match(last_pattern, line, sp, ep));
  443. #if HAVE_POSIX_REGCOMP
  444. {
  445. regmatch_t rm;
  446. int flags = (notbol) ? REG_NOTBOL : 0;
  447. matched = !regexec(regpattern, line, 1, &rm, flags);
  448. if (!matched)
  449. return (0);
  450. #ifndef __WATCOMC__
  451. *sp = line + rm.rm_so;
  452. *ep = line + rm.rm_eo;
  453. #else
  454. *sp = rm.rm_sp;
  455. *ep = rm.rm_ep;
  456. #endif
  457. }
  458. #endif
  459. #if HAVE_PCRE
  460. {
  461. int flags = (notbol) ? PCRE_NOTBOL : 0;
  462. int ovector[3];
  463. matched = pcre_exec(regpattern, NULL, line, strlen(line),
  464. 0, flags, ovector, 3) >= 0;
  465. if (!matched)
  466. return (0);
  467. *sp = line + ovector[0];
  468. *ep = line + ovector[1];
  469. }
  470. #endif
  471. #if HAVE_RE_COMP
  472. matched = (re_exec(line) == 1);
  473. /*
  474. * re_exec doesn't seem to provide a way to get the matched string.
  475. */
  476. *sp = *ep = NULL;
  477. #endif
  478. #if HAVE_REGCMP
  479. *ep = regex(cpattern, line);
  480. matched = (*ep != NULL);
  481. if (!matched)
  482. return (0);
  483. *sp = __loc1;
  484. #endif
  485. #if HAVE_V8_REGCOMP
  486. #if HAVE_REGEXEC2
  487. matched = regexec2(regpattern, line, notbol);
  488. #else
  489. matched = regexec(regpattern, line);
  490. #endif
  491. if (!matched)
  492. return (0);
  493. *sp = regpattern->startp[0];
  494. *ep = regpattern->endp[0];
  495. #endif
  496. #if NO_REGEX
  497. matched = match(last_pattern, line, sp, ep);
  498. #endif
  499. return (matched);
  500. }
  501. #if HILITE_SEARCH
  502. /*
  503. * Clear the hilite list.
  504. */
  505. public void
  506. clr_hilite()
  507. {
  508. struct hilite *hl;
  509. struct hilite *nexthl;
  510. for (hl = hilite_anchor.hl_first; hl != NULL; hl = nexthl)
  511. {
  512. nexthl = hl->hl_next;
  513. free((void*)hl);
  514. }
  515. hilite_anchor.hl_first = NULL;
  516. prep_startpos = prep_endpos = NULL_POSITION;
  517. }
  518. /*
  519. * Should any characters in a specified range be highlighted?
  520. */
  521. static int
  522. is_hilited_range(pos, epos)
  523. POSITION pos;
  524. POSITION epos;
  525. {
  526. struct hilite *hl;
  527. /*
  528. * Look at each highlight and see if any part of it falls in the range.
  529. */
  530. for (hl = hilite_anchor.hl_first; hl != NULL; hl = hl->hl_next)
  531. {
  532. if (hl->hl_endpos > pos &&
  533. (epos == NULL_POSITION || epos > hl->hl_startpos))
  534. return (1);
  535. }
  536. return (0);
  537. }
  538. /*
  539. * Should any characters in a specified range be highlighted?
  540. * If nohide is nonzero, don't consider hide_hilite.
  541. */
  542. public int
  543. is_hilited(pos, epos, nohide, p_matches)
  544. POSITION pos;
  545. POSITION epos;
  546. int nohide;
  547. int *p_matches;
  548. {
  549. int match;
  550. if (p_matches != NULL)
  551. *p_matches = 0;
  552. if (!status_col &&
  553. start_attnpos != NULL_POSITION &&
  554. pos < end_attnpos &&
  555. (epos == NULL_POSITION || epos > start_attnpos))
  556. /*
  557. * The attn line overlaps this range.
  558. */
  559. return (1);
  560. match = is_hilited_range(pos, epos);
  561. if (!match)
  562. return (0);
  563. if (p_matches != NULL)
  564. /*
  565. * Report matches, even if we're hiding highlights.
  566. */
  567. *p_matches = 1;
  568. if (hilite_search == 0)
  569. /*
  570. * Not doing highlighting.
  571. */
  572. return (0);
  573. if (!nohide && hide_hilite)
  574. /*
  575. * Highlighting is hidden.
  576. */
  577. return (0);
  578. return (1);
  579. }
  580. /*
  581. * Add a new hilite to a hilite list.
  582. */
  583. static void
  584. add_hilite(anchor, hl)
  585. struct hilite *anchor;
  586. struct hilite *hl;
  587. {
  588. struct hilite *ihl;
  589. /*
  590. * Hilites are sorted in the list; find where new one belongs.
  591. * Insert new one after ihl.
  592. */
  593. for (ihl = anchor; ihl->hl_next != NULL; ihl = ihl->hl_next)
  594. {
  595. if (ihl->hl_next->hl_startpos > hl->hl_startpos)
  596. break;
  597. }
  598. /*
  599. * Truncate hilite so it doesn't overlap any existing ones
  600. * above and below it.
  601. */
  602. if (ihl != anchor)
  603. hl->hl_startpos = MAXPOS(hl->hl_startpos, ihl->hl_endpos);
  604. if (ihl->hl_next != NULL)
  605. hl->hl_endpos = MINPOS(hl->hl_endpos, ihl->hl_next->hl_startpos);
  606. if (hl->hl_startpos >= hl->hl_endpos)
  607. {
  608. /*
  609. * Hilite was truncated out of existence.
  610. */
  611. free(hl);
  612. return;
  613. }
  614. hl->hl_next = ihl->hl_next;
  615. ihl->hl_next = hl;
  616. }
  617. static void
  618. adj_hilite_ansi(cvt_ops, line, npos)
  619. int cvt_ops;
  620. char **line;
  621. POSITION *npos;
  622. {
  623. if (cvt_ops & CVT_ANSI)
  624. while (**line == ESC)
  625. {
  626. /*
  627. * Found an ESC. The file position moves
  628. * forward past the entire ANSI escape sequence.
  629. */
  630. (*line)++;
  631. (*npos)++;
  632. while (**line != '\0')
  633. {
  634. (*npos)++;
  635. if (!is_ansi_middle(*(*line)++))
  636. break;
  637. }
  638. }
  639. }
  640. /*
  641. * Adjust hl_startpos & hl_endpos to account for backspace processing.
  642. */
  643. static void
  644. adj_hilite(anchor, linepos, cvt_ops)
  645. struct hilite *anchor;
  646. POSITION linepos;
  647. int cvt_ops;
  648. {
  649. char *line;
  650. struct hilite *hl;
  651. int checkstart;
  652. POSITION opos;
  653. POSITION npos;
  654. /*
  655. * The line was already scanned and hilites were added (in hilite_line).
  656. * But it was assumed that each char position in the line
  657. * correponds to one char position in the file.
  658. * This may not be true if there are backspaces in the line.
  659. * Get the raw line again. Look at each character.
  660. */
  661. (void) forw_raw_line(linepos, &line);
  662. opos = npos = linepos;
  663. hl = anchor->hl_first;
  664. checkstart = TRUE;
  665. while (hl != NULL)
  666. {
  667. /*
  668. * See if we need to adjust the current hl_startpos or
  669. * hl_endpos. After adjusting startpos[i], move to endpos[i].
  670. * After adjusting endpos[i], move to startpos[i+1].
  671. * The hilite list must be sorted thus:
  672. * startpos[0] < endpos[0] <= startpos[1] < endpos[1] <= etc.
  673. */
  674. if (checkstart && hl->hl_startpos == opos)
  675. {
  676. hl->hl_startpos = npos;
  677. checkstart = FALSE;
  678. continue; /* {{ not really necessary }} */
  679. } else if (!checkstart && hl->hl_endpos == opos)
  680. {
  681. hl->hl_endpos = npos;
  682. checkstart = TRUE;
  683. hl = hl->hl_next;
  684. continue; /* {{ necessary }} */
  685. }
  686. if (*line == '\0')
  687. break;
  688. adj_hilite_ansi(cvt_ops, &line, &npos);
  689. opos++;
  690. npos++;
  691. line++;
  692. if (cvt_ops & CVT_BS)
  693. {
  694. while (*line == '\b')
  695. {
  696. npos++;
  697. line++;
  698. adj_hilite_ansi(cvt_ops, &line, &npos);
  699. if (*line == '\0')
  700. {
  701. --npos;
  702. --line;
  703. break;
  704. }
  705. /*
  706. * Found a backspace. The file position moves
  707. * forward by 2 relative to the processed line
  708. * which was searched in hilite_line.
  709. */
  710. npos++;
  711. line++;
  712. }
  713. }
  714. }
  715. }
  716. /*
  717. * Make a hilite for each string in a physical line which matches
  718. * the current pattern.
  719. * sp,ep delimit the first match already found.
  720. */
  721. static void
  722. hilite_line(linepos, line, sp, ep, cvt_ops)
  723. POSITION linepos;
  724. char *line;
  725. char *sp;
  726. char *ep;
  727. int cvt_ops;
  728. {
  729. char *searchp;
  730. struct hilite *hl;
  731. struct hilite hilites;
  732. if (sp == NULL || ep == NULL)
  733. return;
  734. /*
  735. * sp and ep delimit the first match in the line.
  736. * Mark the corresponding file positions, then
  737. * look for further matches and mark them.
  738. * {{ This technique, of calling match_pattern on subsequent
  739. * substrings of the line, may mark more than is correct
  740. * if the pattern starts with "^". This bug is fixed
  741. * for those regex functions that accept a notbol parameter
  742. * (currently POSIX and V8-with-regexec2). }}
  743. */
  744. searchp = line;
  745. /*
  746. * Put the hilites into a temporary list until they're adjusted.
  747. */
  748. hilites.hl_first = NULL;
  749. do {
  750. if (ep > sp)
  751. {
  752. /*
  753. * Assume that each char position in the "line"
  754. * buffer corresponds to one char position in the file.
  755. * This is not quite true; we need to adjust later.
  756. */
  757. hl = (struct hilite *) ecalloc(1, sizeof(struct hilite));
  758. hl->hl_startpos = linepos + (sp-line);
  759. hl->hl_endpos = linepos + (ep-line);
  760. add_hilite(&hilites, hl);
  761. }
  762. /*
  763. * If we matched more than zero characters,
  764. * move to the first char after the string we matched.
  765. * If we matched zero, just move to the next char.
  766. */
  767. if (ep > searchp)
  768. searchp = ep;
  769. else if (*searchp != '\0')
  770. searchp++;
  771. else /* end of line */
  772. break;
  773. } while (match_pattern(searchp, &sp, &ep, 1));
  774. /*
  775. * If there were backspaces in the original line, they
  776. * were removed, and hl_startpos/hl_endpos are not correct.
  777. * {{ This is very ugly. }}
  778. */
  779. adj_hilite(&hilites, linepos, cvt_ops);
  780. /*
  781. * Now put the hilites into the real list.
  782. */
  783. while ((hl = hilites.hl_next) != NULL)
  784. {
  785. hilites.hl_next = hl->hl_next;
  786. add_hilite(&hilite_anchor, hl);
  787. }
  788. }
  789. #endif
  790. /*
  791. * Change the caseless-ness of searches.
  792. * Updates the internal search state to reflect a change in the -i flag.
  793. */
  794. public void
  795. chg_caseless()
  796. {
  797. if (!is_ucase_pattern)
  798. /*
  799. * Pattern did not have uppercase.
  800. * Just set the search caselessness to the global caselessness.
  801. */
  802. is_caseless = caseless;
  803. else
  804. /*
  805. * Pattern did have uppercase.
  806. * Discard the pattern; we can't change search caselessness now.
  807. */
  808. uncompile_pattern();
  809. }
  810. #if HILITE_SEARCH
  811. /*
  812. * Find matching text which is currently on screen and highlight it.
  813. */
  814. static void
  815. hilite_screen()
  816. {
  817. struct scrpos scrpos;
  818. get_scrpos(&scrpos);
  819. if (scrpos.pos == NULL_POSITION)
  820. return;
  821. prep_hilite(scrpos.pos, position(BOTTOM_PLUS_ONE), -1);
  822. repaint_hilite(1);
  823. }
  824. /*
  825. * Change highlighting parameters.
  826. */
  827. public void
  828. chg_hilite()
  829. {
  830. /*
  831. * Erase any highlights currently on screen.
  832. */
  833. clr_hilite();
  834. hide_hilite = 0;
  835. if (hilite_search == OPT_ONPLUS)
  836. /*
  837. * Display highlights.
  838. */
  839. hilite_screen();
  840. }
  841. #endif
  842. /*
  843. * Figure out where to start a search.
  844. */
  845. static POSITION
  846. search_pos(search_type)
  847. int search_type;
  848. {
  849. POSITION pos;
  850. int linenum;
  851. if (empty_screen())
  852. {
  853. /*
  854. * Start at the beginning (or end) of the file.
  855. * The empty_screen() case is mainly for
  856. * command line initiated searches;
  857. * for example, "+/xyz" on the command line.
  858. * Also for multi-file (SRCH_PAST_EOF) searches.
  859. */
  860. if (search_type & SRCH_FORW)
  861. {
  862. return (ch_zero());
  863. } else
  864. {
  865. pos = ch_length();
  866. if (pos == NULL_POSITION)
  867. {
  868. (void) ch_end_seek();
  869. pos = ch_length();
  870. }
  871. return (pos);
  872. }
  873. }
  874. if (how_search)
  875. {
  876. /*
  877. * Search does not include current screen.
  878. */
  879. if (search_type & SRCH_FORW)
  880. linenum = BOTTOM_PLUS_ONE;
  881. else
  882. linenum = TOP;
  883. pos = position(linenum);
  884. } else
  885. {
  886. /*
  887. * Search includes current screen.
  888. * It starts at the jump target (if searching backwards),
  889. * or at the jump target plus one (if forwards).
  890. */
  891. linenum = adjsline(jump_sline);
  892. pos = position(linenum);
  893. if (search_type & SRCH_FORW)
  894. {
  895. pos = forw_raw_line(pos, (char **)NULL);
  896. while (pos == NULL_POSITION)
  897. {
  898. if (++linenum >= sc_height)
  899. break;
  900. pos = position(linenum);
  901. }
  902. } else
  903. {
  904. while (pos == NULL_POSITION)
  905. {
  906. if (--linenum < 0)
  907. break;
  908. pos = position(linenum);
  909. }
  910. }
  911. }
  912. return (pos);
  913. }
  914. /*
  915. * Search a subset of the file, specified by start/end position.
  916. */
  917. static int
  918. search_range(pos, endpos, search_type, matches, maxlines, plinepos, pendpos)
  919. POSITION pos;
  920. POSITION endpos;
  921. int search_type;
  922. int matches;
  923. int maxlines;
  924. POSITION *plinepos;
  925. POSITION *pendpos;
  926. {
  927. char *line;
  928. LINENUM linenum;
  929. char *sp = NULL, *ep = NULL; /* XXX: GCC */
  930. int line_match;
  931. int cvt_ops;
  932. POSITION linepos, oldpos;
  933. linenum = find_linenum(pos);
  934. oldpos = pos;
  935. for (;;)
  936. {
  937. /*
  938. * Get lines until we find a matching one or until
  939. * we hit end-of-file (or beginning-of-file if we're
  940. * going backwards), or until we hit the end position.
  941. */
  942. if (ABORT_SIGS())
  943. {
  944. /*
  945. * A signal aborts the search.
  946. */
  947. return (-1);
  948. }
  949. if ((endpos != NULL_POSITION && pos >= endpos) || maxlines == 0)
  950. {
  951. /*
  952. * Reached end position without a match.
  953. */
  954. if (pendpos != NULL)
  955. *pendpos = pos;
  956. return (matches);
  957. }
  958. if (maxlines > 0)
  959. maxlines--;
  960. if (search_type & SRCH_FORW)
  961. {
  962. /*
  963. * Read the next line, and save the
  964. * starting position of that line in linepos.
  965. */
  966. linepos = pos;
  967. pos = forw_raw_line(pos, &line);
  968. if (linenum != 0)
  969. linenum++;
  970. } else
  971. {
  972. /*
  973. * Read the previous line and save the
  974. * starting position of that line in linepos.
  975. */
  976. pos = back_raw_line(pos, &line);
  977. linepos = pos;
  978. if (linenum != 0)
  979. linenum--;
  980. }
  981. if (pos == NULL_POSITION)
  982. {
  983. /*
  984. * Reached EOF/BOF without a match.
  985. */
  986. if (pendpos != NULL)
  987. *pendpos = oldpos;
  988. return (matches);
  989. }
  990. /*
  991. * If we're using line numbers, we might as well
  992. * remember the information we have now (the position
  993. * and line number of the current line).
  994. * Don't do it for every line because it slows down
  995. * the search. Remember the line number only if
  996. * we're "far" from the last place we remembered it.
  997. */
  998. if (linenums && abs((int)(pos - oldpos)) > 1024)
  999. add_lnum(linenum, pos);
  1000. oldpos = pos;
  1001. /*
  1002. * If it's a caseless search, convert the line to lowercase.
  1003. * If we're doing backspace processing, delete backspaces.
  1004. */
  1005. cvt_ops = get_cvt_ops();
  1006. cvt_text(line, line, cvt_ops);
  1007. /*
  1008. * Test the next line to see if we have a match.
  1009. * We are successful if we either want a match and got one,
  1010. * or if we want a non-match and got one.
  1011. */
  1012. line_match = match_pattern(line, &sp, &ep, 0);
  1013. line_match = (!(search_type & SRCH_NO_MATCH) && line_match) ||
  1014. ((search_type & SRCH_NO_MATCH) && !line_match);
  1015. if (!line_match)
  1016. continue;
  1017. /*
  1018. * Got a match.
  1019. */
  1020. if (search_type & SRCH_FIND_ALL)
  1021. {
  1022. #if HILITE_SEARCH
  1023. /*
  1024. * We are supposed to find all matches in the range.
  1025. * Just add the matches in this line to the
  1026. * hilite list and keep searching.
  1027. */
  1028. if (line_match)
  1029. hilite_line(linepos, line, sp, ep, cvt_ops);
  1030. #endif
  1031. } else if (--matches <= 0)
  1032. {
  1033. /*
  1034. * Found the one match we're looking for.
  1035. * Return it.
  1036. */
  1037. #if HILITE_SEARCH
  1038. if (hilite_search == OPT_ON)
  1039. {
  1040. /*
  1041. * Clear the hilite list and add only
  1042. * the matches in this one line.
  1043. */
  1044. clr_hilite();
  1045. if (line_match)
  1046. hilite_line(linepos, line, sp, ep, cvt_ops);
  1047. }
  1048. #endif
  1049. if (plinepos != NULL)
  1050. *plinepos = linepos;
  1051. return (0);
  1052. }
  1053. }
  1054. }
  1055. /*
  1056. * Search for the n-th occurrence of a specified pattern,
  1057. * either forward or backward.
  1058. * Return the number of matches not yet found in this file
  1059. * (that is, n minus the number of matches found).
  1060. * Return -1 if the search should be aborted.
  1061. * Caller may continue the search in another file
  1062. * if less than n matches are found in this file.
  1063. */
  1064. public int
  1065. search(search_type, pattern, n)
  1066. int search_type;
  1067. char *pattern;
  1068. int n;
  1069. {
  1070. POSITION pos;
  1071. int ucase;
  1072. if (pattern == NULL || *pattern == '\0')
  1073. {
  1074. /*
  1075. * A null pattern means use the previously compiled pattern.
  1076. */
  1077. if (!prev_pattern())
  1078. {
  1079. error("No previous regular expression", NULL_PARG);
  1080. return (-1);
  1081. }
  1082. if ((search_type & SRCH_NO_REGEX) !=
  1083. (last_search_type & SRCH_NO_REGEX))
  1084. {
  1085. error("Please re-enter search pattern", NULL_PARG);
  1086. return -1;
  1087. }
  1088. #if HILITE_SEARCH
  1089. if (hilite_search == OPT_ON)
  1090. {
  1091. /*
  1092. * Erase the highlights currently on screen.
  1093. * If the search fails, we'll redisplay them later.
  1094. */
  1095. repaint_hilite(0);
  1096. }
  1097. if (hilite_search == OPT_ONPLUS && hide_hilite)
  1098. {
  1099. /*
  1100. * Highlight any matches currently on screen,
  1101. * before we actually start the search.
  1102. */
  1103. hide_hilite = 0;
  1104. hilite_screen();
  1105. }
  1106. hide_hilite = 0;
  1107. #endif
  1108. } else
  1109. {
  1110. /*
  1111. * Compile the pattern.
  1112. */
  1113. ucase = is_ucase(pattern);
  1114. if (caseless == OPT_ONPLUS)
  1115. cvt_text(pattern, pattern, CVT_TO_LC);
  1116. if (compile_pattern(pattern, search_type) < 0)
  1117. return (-1);
  1118. /*
  1119. * Ignore case if -I is set OR
  1120. * -i is set AND the pattern is all lowercase.
  1121. */
  1122. is_ucase_pattern = ucase;
  1123. if (is_ucase_pattern && caseless != OPT_ONPLUS)
  1124. is_caseless = 0;
  1125. else
  1126. is_caseless = caseless;
  1127. #if HILITE_SEARCH
  1128. if (hilite_search)
  1129. {
  1130. /*
  1131. * Erase the highlights currently on screen.
  1132. * Also permanently delete them from the hilite list.
  1133. */
  1134. repaint_hilite(0);
  1135. hide_hilite = 0;
  1136. clr_hilite();
  1137. }
  1138. if (hilite_search == OPT_ONPLUS)
  1139. {
  1140. /*
  1141. * Highlight any matches currently on screen,
  1142. * before we actually start the search.
  1143. */
  1144. hilite_screen();
  1145. }
  1146. #endif
  1147. }
  1148. /*
  1149. * Figure out where to start the search.
  1150. */
  1151. pos = search_pos(search_type);
  1152. if (pos == NULL_POSITION)
  1153. {
  1154. /*
  1155. * Can't find anyplace to start searching from.
  1156. */
  1157. if (search_type & SRCH_PAST_EOF)
  1158. return (n);
  1159. /* repaint(); -- why was this here? */
  1160. error("Nothing to search", NULL_PARG);
  1161. return (-1);
  1162. }
  1163. n = search_range(pos, NULL_POSITION, search_type, n, -1,
  1164. &pos, (POSITION*)NULL);
  1165. if (n != 0)
  1166. {
  1167. /*
  1168. * Search was unsuccessful.
  1169. */
  1170. #if HILITE_SEARCH
  1171. if (hilite_search == OPT_ON && n > 0)
  1172. /*
  1173. * Redisplay old hilites.
  1174. */
  1175. repaint_hilite(1);
  1176. #endif
  1177. return (n);
  1178. }
  1179. if (!(search_type & SRCH_NO_MOVE))
  1180. {
  1181. /*
  1182. * Go to the matching line.
  1183. */
  1184. jump_loc(pos, jump_sline);
  1185. }
  1186. #if HILITE_SEARCH
  1187. if (hilite_search == OPT_ON)
  1188. /*
  1189. * Display new hilites in the matching line.
  1190. */
  1191. repaint_hilite(1);
  1192. #endif
  1193. return (0);
  1194. }
  1195. #if HILITE_SEARCH
  1196. /*
  1197. * Prepare hilites in a given range of the file.
  1198. *
  1199. * The pair (prep_startpos,prep_endpos) delimits a contiguous region
  1200. * of the file that has been "prepared"; that is, scanned for matches for
  1201. * the current search pattern, and hilites have been created for such matches.
  1202. * If prep_startpos == NULL_POSITION, the prep region is empty.
  1203. * If prep_endpos == NULL_POSITION, the prep region extends to EOF.
  1204. * prep_hilite asks that the range (spos,epos) be covered by the prep region.
  1205. */
  1206. public void
  1207. prep_hilite(spos, epos, maxlines)
  1208. POSITION spos;
  1209. POSITION epos;
  1210. int maxlines;
  1211. {
  1212. POSITION nprep_startpos = prep_startpos;
  1213. POSITION nprep_endpos = prep_endpos;
  1214. POSITION new_epos;
  1215. POSITION max_epos;
  1216. int result;
  1217. int i;
  1218. /*
  1219. * Search beyond where we're asked to search, so the prep region covers
  1220. * more than we need. Do one big search instead of a bunch of small ones.
  1221. */
  1222. #define SEARCH_MORE (3*size_linebuf)
  1223. if (!prev_pattern())
  1224. return;
  1225. /*
  1226. * If we're limited to a max number of lines, figure out the
  1227. * file position we should stop at.
  1228. */
  1229. if (maxlines < 0)
  1230. max_epos = NULL_POSITION;
  1231. else
  1232. {
  1233. max_epos = spos;
  1234. for (i = 0; i < maxlines; i++)
  1235. max_epos = forw_raw_line(max_epos, (char **)NULL);
  1236. }
  1237. /*
  1238. * Find two ranges:
  1239. * The range that we need to search (spos,epos); and the range that
  1240. * the "prep" region will then cover (nprep_startpos,nprep_endpos).
  1241. */
  1242. if (prep_startpos == NULL_POSITION ||
  1243. (epos != NULL_POSITION && epos < prep_startpos) ||
  1244. spos > prep_endpos)
  1245. {
  1246. /*
  1247. * New range is not contiguous with old prep region.
  1248. * Discard the old prep region and start a new one.
  1249. */
  1250. clr_hilite();
  1251. if (epos != NULL_POSITION)
  1252. epos += SEARCH_MORE;
  1253. nprep_startpos = spos;
  1254. } else
  1255. {
  1256. /*
  1257. * New range partially or completely overlaps old prep region.
  1258. */
  1259. if (epos == NULL_POSITION)
  1260. {
  1261. /*
  1262. * New range goes to end of file.
  1263. */
  1264. ;
  1265. } else if (epos > prep_endpos)
  1266. {
  1267. /*
  1268. * New range ends after old prep region.
  1269. * Extend prep region to end at end of new range.
  1270. */
  1271. epos += SEARCH_MORE;
  1272. } else /* (epos <= prep_endpos) */
  1273. {
  1274. /*
  1275. * New range ends within old prep region.
  1276. * Truncate search to end at start of old prep region.
  1277. */
  1278. epos = prep_startpos;
  1279. }
  1280. if (spos < prep_startpos)
  1281. {
  1282. /*
  1283. * New range starts before old prep region.
  1284. * Extend old prep region backwards to start at
  1285. * start of new range.
  1286. */
  1287. if (spos < SEARCH_MORE)
  1288. spos = 0;
  1289. else
  1290. spos -= SEARCH_MORE;
  1291. nprep_startpos = spos;
  1292. } else /* (spos >= prep_startpos) */
  1293. {
  1294. /*
  1295. * New range starts within or after old prep region.
  1296. * Trim search to start at end of old prep region.
  1297. */
  1298. spos = prep_endpos;
  1299. }
  1300. }
  1301. if (epos != NULL_POSITION && max_epos != NULL_POSITION &&
  1302. epos > max_epos)
  1303. /*
  1304. * Don't go past the max position we're allowed.
  1305. */
  1306. epos = max_epos;
  1307. if (epos == NULL_POSITION || epos > spos)
  1308. {
  1309. result = search_range(spos, epos, SRCH_FORW|SRCH_FIND_ALL, 0,
  1310. maxlines, (POSITION*)NULL, &new_epos);
  1311. if (result < 0)
  1312. return;
  1313. if (prep_endpos == NULL_POSITION || new_epos > prep_endpos)
  1314. nprep_endpos = new_epos;
  1315. }
  1316. prep_startpos = nprep_startpos;
  1317. prep_endpos = nprep_endpos;
  1318. }
  1319. #endif
  1320. /*
  1321. * Simple pattern matching function.
  1322. * It supports no metacharacters like *, etc.
  1323. */
  1324. static int
  1325. match(pattern, buf, pfound, pend)
  1326. char *pattern, *buf;
  1327. char **pfound, **pend;
  1328. {
  1329. register char *pp, *lp;
  1330. for ( ; *buf != '\0'; buf++)
  1331. {
  1332. for (pp = pattern, lp = buf; *pp == *lp; pp++, lp++)
  1333. if (*pp == '\0' || *lp == '\0')
  1334. break;
  1335. if (*pp == '\0')
  1336. {
  1337. if (pfound != NULL)
  1338. *pfound = buf;
  1339. if (pend != NULL)
  1340. *pend = lp;
  1341. return (1);
  1342. }
  1343. }
  1344. return (0);
  1345. }
  1346. #if HAVE_V8_REGCOMP
  1347. /*
  1348. * This function is called by the V8 regcomp to report
  1349. * errors in regular expressions.
  1350. */
  1351. void
  1352. regerror(s)
  1353. char *s;
  1354. {
  1355. PARG parg;
  1356. parg.p_string = s;
  1357. error("%s", &parg);
  1358. }
  1359. #endif