PageRenderTime 63ms CodeModel.GetById 24ms RepoModel.GetById 0ms app.codeStats 0ms

/src/search.cc

https://bitbucket.org/mumurik/xyzzy
C++ | 1582 lines | 1397 code | 184 blank | 1 comment | 344 complexity | b0e4e4fa3d34c4ee8f65e9cdf6522cfc MD5 | raw file
  1. #include "ed.h"
  2. #include "regex.h"
  3. #include "StrBuf.h"
  4. #define SF_CASE_FOLD 1
  5. #define SF_NO_DUP 2
  6. #define SF_REVERSE 4
  7. #define SF_TAIL 8
  8. #define SF_LWORD 16
  9. #define SF_RWORD 32
  10. #define SF_LSYMBOL 64
  11. #define SF_RSYMBOL 128
  12. #define SF_SMART_CASE_FOLD 256
  13. static Regexp::sregs re_regs = {-1, {-1, -1}};
  14. extern u_char char_no_translate_table[];
  15. extern u_char char_translate_upcase_table[];
  16. static inline void
  17. clear_regs ()
  18. {
  19. re_regs.nregs = -1;
  20. }
  21. static void
  22. copy_regs0 (Regexp::sregs &d, const Regexp::sregs &s)
  23. {
  24. d.nregs = s.nregs;
  25. for (int i = 0; i <= d.nregs; i++)
  26. {
  27. d.start[i] = s.start[i];
  28. d.end[i] = s.end[i];
  29. }
  30. }
  31. static void
  32. check_regs ()
  33. {
  34. int i = 0;
  35. for (; i <= re_regs.nregs; i++)
  36. {
  37. if (re_regs.start[i] < 0)
  38. re_regs.end[i] = -1;
  39. else if (re_regs.end[i] < 0)
  40. re_regs.start[i] = -1;
  41. else
  42. {
  43. if (re_regs.end[i] < re_regs.start[i])
  44. re_regs.end[i] = re_regs.start[i];
  45. if (i)
  46. {
  47. if (re_regs.start[i] < re_regs.start[0])
  48. re_regs.start[i] = re_regs.start[0];
  49. if (re_regs.end[i] > re_regs.end[0])
  50. re_regs.end[i] = re_regs.end[0];
  51. }
  52. }
  53. }
  54. for (; i < MAX_REGS; i++)
  55. {
  56. re_regs.start[i] = -1;
  57. re_regs.end[i] = -1;
  58. }
  59. }
  60. static inline void
  61. save_search (point_t start, point_t end)
  62. {
  63. re_regs.nregs = 0;
  64. re_regs.start[0] = start;
  65. re_regs.end[0] = end;
  66. xsymbol_value (Vlast_match_string) = Qnil;
  67. }
  68. static inline void
  69. save_match (const Regexp &re, lisp str)
  70. {
  71. copy_regs0 (re_regs, re.re_regs);
  72. check_regs ();
  73. xsymbol_value (Vlast_match_string) = str;
  74. }
  75. static void
  76. bm_compilef (int *BM, const Char *pattern, int patlen, int case_fold)
  77. {
  78. int i;
  79. for (i = 0; i < 256; i++)
  80. BM[i] = patlen;
  81. for (i = patlen - 1; i >= 0; i--)
  82. {
  83. Char cc = *pattern++;
  84. int c = DBCP (cc) ? cc >> 8 : cc;
  85. if (case_fold && alpha_char_p (cc))
  86. BM[_char_transpose_case (c)] = i;
  87. BM[c] = i;
  88. }
  89. }
  90. static void
  91. bm_compileb (int *BM, const Char *pattern, int patlen, int case_fold)
  92. {
  93. int i ;
  94. for (i = 0; i < 256; i++)
  95. BM[i] = patlen;
  96. for (i = patlen - 1, pattern += patlen; i >= 0; i--)
  97. {
  98. Char cc = *--pattern;
  99. int c = DBCP (cc) ? cc >> 8 : cc;
  100. if (case_fold && alpha_char_p (cc))
  101. BM[_char_transpose_case (c)] = i;
  102. BM[c] = i;
  103. }
  104. }
  105. int
  106. Buffer::word_bound (const Point &point) const
  107. {
  108. const syntax_table *tab = xsyntax_table (lsyntax_table);
  109. if (bobp (point) || eobp (point))
  110. return 1;
  111. Char c = point.ch ();
  112. if (!ascii_char_p (c) || xchar_syntax (tab, c) != SCword)
  113. return 1;
  114. c = point.prevch ();
  115. if (!ascii_char_p (c) || xchar_syntax (tab, c) != SCword)
  116. return 1;
  117. return 0;
  118. }
  119. int
  120. Buffer::symbol_bound (const Point &point) const
  121. {
  122. const syntax_table *tab = xsyntax_table (lsyntax_table);
  123. if (bobp (point) || eobp (point))
  124. return 1;
  125. Char c = point.ch ();
  126. if (!ascii_char_p (c)
  127. || (xchar_syntax (tab, c) != SCword
  128. && xchar_syntax (tab, c) != SCsymbol))
  129. return 1;
  130. c = point.prevch ();
  131. if (!ascii_char_p (c)
  132. || (xchar_syntax (tab, c) != SCword
  133. && xchar_syntax (tab, c) != SCsymbol))
  134. return 1;
  135. return 0;
  136. }
  137. int
  138. Buffer::bm_execf (Point &point, const Char *pattern, int patlen, const int *BM,
  139. point_t limit, int flags) const
  140. {
  141. const Char *pate = pattern + patlen - 1;
  142. Char c0 = (flags & SF_CASE_FOLD) ? char_upcase (*pate) : *pate;
  143. Chunk *cp = point.p_chunk;
  144. const Char *pe = cp->c_text + cp->c_used;
  145. const Char *p = cp->c_text + point.p_offset;
  146. Char c = *p;
  147. int delta = BM[DBCP (c) ? c >> 8 : c];
  148. while (1)
  149. {
  150. while (delta)
  151. {
  152. point.p_point += delta;
  153. if (point.p_point >= limit)
  154. return 0;
  155. while (pe - p <= delta)
  156. {
  157. delta -= pe - p;
  158. cp = cp->c_next;
  159. p = cp->c_text;
  160. pe = p + cp->c_used;
  161. }
  162. p += delta;
  163. c = *p;
  164. delta = BM[DBCP (c) ? c >> 8 : c];
  165. }
  166. if (((flags & SF_CASE_FOLD) ? char_upcase (c) : c) != c0)
  167. {
  168. delta = 1;
  169. continue;
  170. }
  171. point_t opoint (point.p_point);
  172. for (const Char *pat = pate; pat > pattern;)
  173. {
  174. point.p_point--;
  175. if (p == cp->c_text)
  176. {
  177. cp = cp->c_prev;
  178. p = pe = cp->c_text + cp->c_used;
  179. }
  180. c = *--p;
  181. Char c2 = *--pat;
  182. if ((flags & SF_CASE_FOLD)
  183. ? char_upcase (c) != char_upcase (c2)
  184. : c != c2)
  185. goto fail;
  186. }
  187. point.p_chunk = cp;
  188. point.p_offset = p - cp->c_text;
  189. if ((flags & SF_LWORD && !word_bound (point))
  190. || (flags & SF_LSYMBOL && !symbol_bound (point)))
  191. goto fail2;
  192. if (flags & (SF_RWORD | SF_RSYMBOL))
  193. {
  194. Point tem (point);
  195. goto_char (tem, opoint + 1);
  196. if (flags & SF_RWORD ? !word_bound (tem) : !symbol_bound (tem))
  197. goto fail2;
  198. }
  199. return 1;
  200. fail2:
  201. delta = opoint - point.p_point + 1;
  202. continue;
  203. fail:
  204. delta = max (BM[DBCP (c) ? c >> 8 : c], int (opoint - point.p_point + 1));
  205. }
  206. }
  207. int
  208. Buffer::bm_execb (Point &point, const Char *pattern, int patlen, const int *BM,
  209. point_t limit, int flags) const
  210. {
  211. const Char *pate = pattern + patlen;
  212. Char c0 = (flags & SF_CASE_FOLD) ? char_upcase (*pattern) : *pattern;
  213. pattern++;
  214. Chunk *cp = point.p_chunk;
  215. const Char *p = cp->c_text + point.p_offset;
  216. const Char *pe = cp->c_text + cp->c_used;
  217. Char c = *p;
  218. int delta = BM[DBCP (c) ? c >> 8 : c];
  219. while (1)
  220. {
  221. while (delta)
  222. {
  223. point.p_point -= delta;
  224. if (point.p_point < limit)
  225. return 0;
  226. while (p - cp->c_text < delta)
  227. {
  228. delta -= p - cp->c_text;
  229. cp = cp->c_prev;
  230. p = pe = cp->c_text + cp->c_used;
  231. }
  232. p -= delta;
  233. c = *p;
  234. delta = BM[DBCP (c) ? c >> 8 : c];
  235. }
  236. if (((flags & SF_CASE_FOLD) ? char_upcase (c) : c) != c0)
  237. {
  238. delta = 1;
  239. continue;
  240. }
  241. point_t opoint (point.p_point);
  242. for (const Char *pat = pattern; pat < pate; pat++)
  243. {
  244. point.p_point++;
  245. if (++p == pe)
  246. {
  247. cp = cp->c_next;
  248. p = cp->c_text;
  249. pe = p + cp->c_used;
  250. }
  251. c = *p;
  252. Char c2 = *pat;
  253. if ((flags & SF_CASE_FOLD)
  254. ? char_upcase (c) != char_upcase (c2)
  255. : c != c2)
  256. goto fail;
  257. }
  258. point.p_chunk = cp;
  259. point.p_offset = p - cp->c_text;
  260. if (flags & (SF_RWORD | SF_RSYMBOL))
  261. {
  262. Point tem (point);
  263. forward_char (tem, 1);
  264. if (flags & SF_RWORD ? !word_bound (tem) : !symbol_bound (tem))
  265. goto fail2;
  266. }
  267. if (flags & (SF_LWORD | SF_LSYMBOL))
  268. {
  269. Point tem (point);
  270. goto_char (tem, opoint);
  271. if (flags & SF_LWORD ? !word_bound (tem) : !symbol_bound (tem))
  272. goto fail2;
  273. }
  274. return 1;
  275. fail2:
  276. delta = point.p_point - opoint + 1;
  277. continue;
  278. fail:
  279. delta = max (BM[DBCP (c) ? c >> 8 : c], int (point.p_point - opoint + 1));
  280. }
  281. }
  282. int
  283. Buffer::scan_forward (Point &w_point, const Char *pattern, int patlen,
  284. const int *BM, point_t limit, int flags) const
  285. {
  286. int d = patlen - 1;
  287. if (flags & SF_NO_DUP)
  288. d++;
  289. if (w_point.p_point + d >= limit)
  290. return 0;
  291. Point point (w_point);
  292. forward_char (point, d);
  293. if (!bm_execf (point, pattern, patlen, BM, limit, flags))
  294. return 0;
  295. save_search (point.p_point, point.p_point + patlen);
  296. if (flags & SF_TAIL)
  297. forward_char (point, patlen);
  298. w_point = point;
  299. return 1;
  300. }
  301. int
  302. Buffer::scan_backward (Point &w_point, const Char *pattern, int patlen,
  303. const int *BM, point_t limit, int flags) const
  304. {
  305. point_t t = w_point.p_point;
  306. if (flags & SF_NO_DUP)
  307. t--;
  308. t = min (t, point_t (b_contents.p2 - patlen));
  309. if (t < limit)
  310. return 0;
  311. Point point (w_point);
  312. goto_char (point, t);
  313. if (!bm_execb (point, pattern, patlen, BM, limit, flags))
  314. return 0;
  315. save_search (point.p_point - (patlen - 1), point.p_point + 1);
  316. if (flags & SF_TAIL)
  317. forward_char (point, 1);
  318. else
  319. forward_char (point, -(patlen - 1));
  320. w_point = point;
  321. return 1;
  322. }
  323. int
  324. Buffer::re_scan_buffer (Point &w_point, lisp pattern, point_t limit,
  325. point_t last_match, lChar last_match_char,
  326. int flags) const
  327. {
  328. Point point (w_point);
  329. if (flags & SF_REVERSE)
  330. {
  331. if (flags & SF_NO_DUP && !forward_char (point, -1))
  332. return 0;
  333. if (point.p_point < limit || point.p_point > b_contents.p2)
  334. return 0;
  335. }
  336. else
  337. {
  338. if (flags & SF_NO_DUP && !forward_char (point, 1))
  339. return 0;
  340. if (point.p_point < b_contents.p1 || point.p_point > limit)
  341. return 0;
  342. }
  343. if (flags & SF_SMART_CASE_FOLD
  344. && stringp (pattern)
  345. && Regexp::smart_case_fold_p (xstring_contents (pattern),
  346. xstring_length (pattern)))
  347. flags |= SF_CASE_FOLD;
  348. Regexp re ((flags & SF_CASE_FOLD
  349. ? char_translate_upcase_table
  350. : char_no_translate_table),
  351. xsyntax_table (lsyntax_table));
  352. if (regexpp (pattern))
  353. re.compile (pattern, 1);
  354. else
  355. re.compile (xstring_contents (pattern), xstring_length (pattern), 1);
  356. if (flags & SF_REVERSE
  357. ? re.search_backward (this, point, limit, b_contents.p2,
  358. last_match, last_match_char)
  359. : re.search (this, point, b_contents.p1, limit,
  360. last_match, last_match_char))
  361. {
  362. save_match (re, Qnil);
  363. goto_char (w_point, flags & SF_TAIL ? re_regs.end[0] : re_regs.start[0]);
  364. return 1;
  365. }
  366. return 0;
  367. }
  368. static int
  369. scan_flags (lisp keys)
  370. {
  371. int flags = 0;
  372. lisp x = find_keyword (Kcase_fold, keys);
  373. if (x == Ksmart)
  374. flags |= SF_SMART_CASE_FOLD;
  375. else if (x != Qnil)
  376. flags |= SF_CASE_FOLD;
  377. if (find_keyword_bool (Kno_dup, keys))
  378. flags |= SF_NO_DUP;
  379. if (find_keyword_bool (Kreverse, keys))
  380. flags |= SF_REVERSE;
  381. if (find_keyword_bool (Ktail, keys))
  382. flags |= SF_TAIL;
  383. x = find_keyword (Kleft_bound, keys);
  384. if (x == Ksymbol)
  385. flags |= SF_LSYMBOL;
  386. else if (x != Qnil)
  387. flags |= SF_LWORD;
  388. x = find_keyword (Kright_bound, keys);
  389. if (x == Ksymbol)
  390. flags |= SF_RSYMBOL;
  391. else if (x != Qnil)
  392. flags |= SF_RWORD;
  393. return flags;
  394. }
  395. static point_t
  396. scan_limit (const Buffer *bp, int flags, lisp keys)
  397. {
  398. lisp t = find_keyword (Klimit, keys);
  399. return (t != Qnil
  400. ? bp->coerce_to_restricted_point (t)
  401. : flags & SF_REVERSE ? bp->b_contents.p1 : bp->b_contents.p2);
  402. }
  403. static point_t
  404. scan_last_match (const Buffer *bp, lisp keys, lChar &ch)
  405. {
  406. lisp t = find_keyword (Klast_match, keys);
  407. if (t != Qnil)
  408. {
  409. check_cons (t);
  410. lisp lpoint = xcar (t);
  411. if (lpoint != Qnil)
  412. {
  413. lisp lch = xcdr (t);
  414. if (lch == Qnil)
  415. ch = lChar_EOF;
  416. else
  417. {
  418. check_char (lch);
  419. ch = xchar_code (lch);
  420. }
  421. return bp->coerce_to_restricted_point (lpoint);
  422. }
  423. }
  424. ch = lChar_EOF;
  425. return -1;
  426. }
  427. static int
  428. smart_case_fold_string_p (lisp string)
  429. {
  430. const Char *s = xstring_contents (string);
  431. const Char *const se = s + xstring_length (string);
  432. for (; s < se; s++)
  433. if (upper_char_p (*s))
  434. return 0;
  435. return 1;
  436. }
  437. lisp
  438. Fscan_buffer (lisp pattern, lisp keys)
  439. {
  440. int flags = scan_flags (keys);
  441. Window *wp = selected_window ();
  442. Buffer *bp = wp->w_bufp;
  443. point_t limit = scan_limit (bp, flags, keys);
  444. clear_regs ();
  445. if (!regexpp (pattern))
  446. {
  447. check_string (pattern);
  448. if (!xstring_length (pattern))
  449. return Qnil;
  450. }
  451. int result;
  452. if (find_keyword_bool (Kregexp, keys) || regexpp (pattern))
  453. {
  454. lChar last_match_char;
  455. point_t last_match = scan_last_match (bp, keys, last_match_char);
  456. result = bp->re_scan_buffer (wp->w_point, pattern, limit,
  457. last_match, last_match_char, flags);
  458. }
  459. else
  460. {
  461. int BM[256];
  462. if (flags & SF_SMART_CASE_FOLD
  463. && smart_case_fold_string_p (pattern))
  464. flags |= SF_CASE_FOLD;
  465. if (flags & SF_REVERSE)
  466. {
  467. bm_compileb (BM, xstring_contents (pattern), xstring_length (pattern),
  468. flags & SF_CASE_FOLD);
  469. result = bp->scan_backward (wp->w_point, xstring_contents (pattern),
  470. xstring_length (pattern), BM, limit, flags);
  471. }
  472. else
  473. {
  474. bm_compilef (BM, xstring_contents (pattern), xstring_length (pattern),
  475. flags & SF_CASE_FOLD);
  476. result = bp->scan_forward (wp->w_point, xstring_contents (pattern),
  477. xstring_length (pattern), BM, limit, flags);
  478. }
  479. }
  480. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  481. return boole (result);
  482. }
  483. static int
  484. string_start_end (lisp string, lisp start, lisp end, int &offset, int &len)
  485. {
  486. if (start && start != Qnil)
  487. {
  488. offset = fixnum_value (start);
  489. if (offset < 0 || offset > xstring_length (string))
  490. return 0;
  491. }
  492. else
  493. offset = 0;
  494. if (end && end != Qnil)
  495. {
  496. len = fixnum_value (end);
  497. if (len < offset || len > xstring_length (string))
  498. return 0;
  499. }
  500. else
  501. len = xstring_length (string);
  502. return 1;
  503. }
  504. static lisp
  505. string_match (lisp regex, lisp string, lisp start, lisp end, const u_char *translate)
  506. {
  507. check_string (string);
  508. clear_regs ();
  509. Regexp re (translate, xsyntax_table (selected_buffer ()->lsyntax_table));
  510. if (regexpp (regex))
  511. re.compile (regex, 1);
  512. else
  513. {
  514. check_string (regex);
  515. if (!xstring_length (regex))
  516. return Qnil;
  517. re.compile (xstring_contents (regex), xstring_length (regex), 1);
  518. }
  519. int offset, len;
  520. if (!string_start_end (string, start, end, offset, len))
  521. return Qnil;
  522. if (!re.search (xstring_contents (string), len, offset))
  523. return Qnil;
  524. save_match (re, string);
  525. return make_fixnum (re.re_regs.start[0]);
  526. }
  527. lisp
  528. Fstring_match (lisp regexp, lisp string, lisp start, lisp end)
  529. {
  530. return string_match (regexp, string, start, end, char_no_translate_table);
  531. }
  532. lisp
  533. Fstring_matchp (lisp regexp, lisp string, lisp start, lisp end)
  534. {
  535. return string_match (regexp, string, start, end, char_translate_upcase_table);
  536. }
  537. lisp
  538. Fmatch_beginning (lisp regno)
  539. {
  540. int r = fixnum_value (regno);
  541. if (r < 0 || r >= MAX_REGS)
  542. FErange_error (regno);
  543. if (r > re_regs.nregs || re_regs.start[r] < 0)
  544. return Qnil;
  545. return make_fixnum (re_regs.start[r]);
  546. }
  547. lisp
  548. Fmatch_end (lisp regno)
  549. {
  550. int r = fixnum_value (regno);
  551. if (r < 0 || r >= MAX_REGS)
  552. FErange_error (regno);
  553. if (r > re_regs.nregs || re_regs.start[r] < 0)
  554. return Qnil;
  555. return make_fixnum (re_regs.end[r]);
  556. }
  557. lisp
  558. Fmatch_string (lisp regno)
  559. {
  560. int r = fixnum_value (regno);
  561. if (r < 0 || r >= MAX_REGS)
  562. FErange_error (regno);
  563. if (r > re_regs.nregs || re_regs.start[r] < 0)
  564. return Qnil;
  565. lisp string = xsymbol_value (Vlast_match_string);
  566. if (string != Qnil)
  567. {
  568. int start = min ((int)re_regs.start[r], xstring_length (string));
  569. int end = max (start, min ((int)re_regs.end[r], xstring_length (string)));
  570. return make_string (xstring_contents (string) + start, end - start);
  571. }
  572. return selected_buffer ()->substring (re_regs.start[r], re_regs.end[r]);
  573. }
  574. lisp
  575. Fcompile_regexp (lisp pattern, lisp case_fold)
  576. {
  577. if (regexpp (pattern))
  578. return pattern;
  579. check_string (pattern);
  580. if (!xstring_length (pattern))
  581. return Qnil;
  582. Regexp re (((case_fold == Ksmart
  583. ? Regexp::smart_case_fold_p (xstring_contents (pattern),
  584. xstring_length (pattern))
  585. : case_fold && case_fold != Qnil)
  586. ? char_translate_upcase_table
  587. : char_no_translate_table),
  588. xsyntax_table (selected_buffer ()->lsyntax_table));
  589. re.compile (xstring_contents (pattern), xstring_length (pattern), 1);
  590. return re.make_regexp (pattern);
  591. }
  592. lisp
  593. Fcompiled_regexp_source (lisp re)
  594. {
  595. check_regexp (re);
  596. return xregexp_source (re);
  597. }
  598. lisp
  599. Fcompiled_regexp_case_fold_p (lisp re)
  600. {
  601. check_regexp (re);
  602. return boole (xregexp_flags (re) & lregexp::TRANSLATE);
  603. }
  604. lisp
  605. Fregexp_quote (lisp string)
  606. {
  607. check_string (string);
  608. int count = 0;
  609. const Char *p = xstring_contents (string);
  610. const Char *pe = p + xstring_length (string);
  611. while (p < pe)
  612. switch (*p++)
  613. {
  614. case '^':
  615. case '$':
  616. case '.':
  617. case '[':
  618. case '*':
  619. case '+':
  620. case '?':
  621. case '\\':
  622. count++;
  623. break;
  624. default:
  625. break;
  626. }
  627. if (!count)
  628. return string;
  629. p = xstring_contents (string);
  630. lisp string2 = make_string (xstring_length (string) + count);
  631. Char *p2 = xstring_contents (string2);
  632. while (p < pe)
  633. {
  634. Char c = *p++;
  635. switch (c)
  636. {
  637. case '^':
  638. case '$':
  639. case '.':
  640. case '[':
  641. case '*':
  642. case '+':
  643. case '?':
  644. case '\\':
  645. *p2++ = '\\';
  646. /* fall thru... */
  647. default:
  648. *p2++ = c;
  649. break;
  650. }
  651. }
  652. return string2;
  653. }
  654. lisp
  655. Flooking_at (lisp regex, lisp case_fold)
  656. {
  657. Window *wp = selected_window ();
  658. Buffer *bp = wp->w_bufp;
  659. clear_regs ();
  660. Regexp re (((case_fold == Ksmart
  661. ? (stringp (regex)
  662. && Regexp::smart_case_fold_p (xstring_contents (regex),
  663. xstring_length (regex)))
  664. : case_fold && case_fold != Qnil)
  665. ? char_translate_upcase_table
  666. : char_no_translate_table),
  667. xsyntax_table (bp->lsyntax_table));
  668. if (regexpp (regex))
  669. re.compile (regex, 0);
  670. else
  671. {
  672. check_string (regex);
  673. if (!xstring_length (regex))
  674. return Qnil;
  675. re.compile (xstring_contents (regex), xstring_length (regex), 0);
  676. }
  677. if (!re.match (bp, wp->w_point, bp->b_contents.p1, bp->b_contents.p2))
  678. return Qnil;
  679. save_match (re, Qnil);
  680. return Qt;
  681. }
  682. lisp
  683. Flooking_for (lisp string, lisp case_fold)
  684. {
  685. check_string (string);
  686. Window *wp = selected_window ();
  687. if (wp->w_point.p_point + xstring_length (string) > wp->w_bufp->b_contents.p2)
  688. return Qnil;
  689. const Chunk *cp = wp->w_point.p_chunk;
  690. const Char *p = cp->c_text + wp->w_point.p_offset;
  691. const Char *pe = cp->c_text + cp->c_used;
  692. const Char *s = xstring_contents (string);
  693. const Char *se = s + xstring_length (string);
  694. int cf = (case_fold == Ksmart
  695. ? smart_case_fold_string_p (string)
  696. : case_fold && case_fold != Qnil);
  697. while (s < se)
  698. {
  699. if (p == pe)
  700. {
  701. cp = cp->c_next;
  702. p = cp->c_text;
  703. pe = p + cp->c_used;
  704. }
  705. Char c1 = *s++;
  706. Char c2 = *p++;
  707. if (cf ? char_upcase (c1) != char_upcase (c2) : c1 != c2)
  708. return Qnil;
  709. }
  710. return Qt;
  711. }
  712. lisp
  713. Flooking_back (lisp string, lisp case_fold)
  714. {
  715. check_string (string);
  716. Window *wp = selected_window ();
  717. if (wp->w_point.p_point - xstring_length (string) < wp->w_bufp->b_contents.p1)
  718. return Qnil;
  719. const Chunk *cp = wp->w_point.p_chunk;
  720. const Char *p = cp->c_text + wp->w_point.p_offset;
  721. const Char *s = xstring_contents (string);
  722. const Char *se = s + xstring_length (string);
  723. int cf = (case_fold == Ksmart
  724. ? smart_case_fold_string_p (string)
  725. : case_fold && case_fold != Qnil);
  726. while (se > s)
  727. {
  728. if (p == cp->c_text)
  729. {
  730. cp = cp->c_prev;
  731. p = cp->c_text + cp->c_used;
  732. }
  733. Char c1 = *--se;
  734. Char c2 = *--p;
  735. if (cf ? char_upcase (c1) != char_upcase (c2) : c1 != c2)
  736. return Qnil;
  737. }
  738. return Qt;
  739. }
  740. static lisp
  741. skip_chars (lisp chars, int dir)
  742. {
  743. check_string (chars);
  744. u_long hi[(256 + sizeof (u_long) - 1) / sizeof (u_long)];
  745. bzero (hi, sizeof hi);
  746. u_long lo[256][(256 + sizeof (u_long) - 1) / sizeof (u_long)];
  747. const Char *p = xstring_contents (chars);
  748. const Char *pe = p + xstring_length (chars);
  749. if (p == pe)
  750. return Qnil;
  751. int not = 0;
  752. if (*p == '^')
  753. {
  754. not = 1;
  755. if (p == pe)
  756. return Qnil;
  757. p++;
  758. }
  759. while (p < pe)
  760. {
  761. Char c = *p++;
  762. if (p < pe - 1 && *p == '-')
  763. {
  764. Char c2 = p[1];
  765. p += 2;
  766. for (; c <= c2; c++)
  767. {
  768. int h = c >> 8;
  769. if (!bitisset (hi, h))
  770. {
  771. bitset (hi, h);
  772. bzero (lo[h], sizeof lo[h]);
  773. }
  774. bitset (lo[h], c & 255);
  775. }
  776. }
  777. else
  778. {
  779. int h = c >> 8;
  780. if (!bitisset (hi, h))
  781. {
  782. bitset (hi, h);
  783. bzero (lo[h], sizeof lo[h]);
  784. }
  785. bitset (lo[h], c & 255);
  786. }
  787. }
  788. Window *wp = selected_window ();
  789. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  790. Buffer *bp = wp->w_bufp;
  791. Point &point = wp->w_point;
  792. if (dir < 0 && !bp->forward_char (point, -1))
  793. return Qnil;
  794. int nomatch = 1;
  795. if (!bp->eobp (point))
  796. while (1)
  797. {
  798. Char c = point.ch ();
  799. if (not == (bitisset (hi, c >> 8) && bitisset (lo[c >> 8], c & 255)))
  800. break;
  801. if (!bp->forward_char (point, dir) || bp->eobp (point))
  802. return Qt;
  803. nomatch = 0;
  804. }
  805. if (dir < 0)
  806. bp->forward_char (point, 1);
  807. return boole (!nomatch);
  808. }
  809. lisp
  810. Fskip_chars_forward (lisp chars)
  811. {
  812. return skip_chars (chars, 1);
  813. }
  814. lisp
  815. Fskip_chars_backward (lisp chars)
  816. {
  817. return skip_chars (chars, -1);
  818. }
  819. static lisp
  820. skip_syntax_spec (lisp syntax_spec, int dir)
  821. {
  822. u_char buf[SCmax];
  823. bzero (buf, sizeof buf);
  824. check_string (syntax_spec);
  825. const Char *p = xstring_contents (syntax_spec);
  826. const Char *pe = p + xstring_length (syntax_spec);
  827. if (p == pe)
  828. return Qnil;
  829. int not = 0;
  830. if (*p == '^')
  831. {
  832. not = 1;
  833. if (p == pe)
  834. return Qnil;
  835. p++;
  836. }
  837. while (p < pe)
  838. {
  839. Char c = *p++;
  840. if (!ascii_char_p (c) || syntax_spec_table[c] == -1)
  841. FEsimple_error (Einvalid_syntax_spec, syntax_spec);
  842. buf[syntax_spec_table[c]] = 1;
  843. }
  844. if (not)
  845. for (int i = 0; i < sizeof buf; i++)
  846. buf[i]--;
  847. Window *wp = selected_window ();
  848. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  849. Buffer *bp = wp->w_bufp;
  850. const syntax_table *tab = xsyntax_table (bp->lsyntax_table);
  851. Point &point = wp->w_point;
  852. if (dir < 0 && !bp->forward_char (point, -1))
  853. return Qnil;
  854. int nomatch = 1;
  855. if (!bp->eobp (point))
  856. while (1)
  857. {
  858. Char c = point.ch ();
  859. if (c >= 256)
  860. c >>= 8;
  861. if (!buf[xchar_syntax (tab, c)])
  862. break;
  863. if (!bp->forward_char (point, dir) || bp->eobp (point))
  864. return Qt;
  865. nomatch = 0;
  866. }
  867. if (dir < 0)
  868. bp->forward_char (point, 1);
  869. return boole (!nomatch);
  870. }
  871. lisp
  872. Fskip_syntax_spec_forward (lisp syntax_spec)
  873. {
  874. return skip_syntax_spec (syntax_spec, 1);
  875. }
  876. lisp
  877. Fskip_syntax_spec_backward (lisp syntax_spec)
  878. {
  879. return skip_syntax_spec (syntax_spec, -1);
  880. }
  881. static int
  882. re_tag_p (lisp string)
  883. {
  884. for (const Char *p = xstring_contents (string), *pe = p + xstring_length (string) - 1;
  885. p < pe; p++)
  886. if (*p == '\\')
  887. return 1;
  888. return 0;
  889. }
  890. #define NOCASECONV 'E'
  891. #define UPCASE_ONE 'u'
  892. #define DOWNCASE_ONE 'l'
  893. #define UPCASE_CHARS 'U'
  894. #define DOWNCASE_CHARS 'L'
  895. static void
  896. case_conversion (int fconv, Point &from, const Point &end, Buffer *bp)
  897. {
  898. switch (fconv)
  899. {
  900. case UPCASE_ONE:
  901. if (from.p_point < end.p_point)
  902. bp->upcase_region_internal (from, from.p_point + 1);
  903. break;
  904. case DOWNCASE_ONE:
  905. if (from.p_point < end.p_point)
  906. bp->downcase_region_internal (from, from.p_point + 1);
  907. break;
  908. case UPCASE_CHARS:
  909. bp->upcase_region_internal (from, end.p_point);
  910. break;
  911. case DOWNCASE_CHARS:
  912. bp->downcase_region_internal (from, end.p_point);
  913. break;
  914. }
  915. }
  916. static void
  917. replace_match (Window *wp, lisp string, int literal)
  918. {
  919. Buffer *bp = wp->w_bufp;
  920. if (literal)
  921. {
  922. int l = min (xstring_length (string), int (re_regs.end[0] - re_regs.start[0]));
  923. if (l)
  924. {
  925. bp->goto_char (wp->w_point, re_regs.start[0]);
  926. bp->overwrite_chars (wp, xstring_contents (string), l);
  927. }
  928. if (re_regs.start[0] + l != re_regs.end[0])
  929. bp->delete_region (wp, re_regs.start[0] + l, re_regs.end[0]);
  930. else if (l != xstring_length (string))
  931. {
  932. bp->goto_char (wp->w_point, re_regs.start[0] + l);
  933. bp->insert_chars (wp, xstring_contents (string) + l,
  934. xstring_length (string) - l, 1);
  935. }
  936. else
  937. bp->goto_char (wp->w_point, re_regs.end[0]);
  938. }
  939. else
  940. {
  941. int l = (min (max (re_regs.end[0], bp->b_contents.p1), bp->b_contents.p2)
  942. - min (max (re_regs.start[0], bp->b_contents.p1), bp->b_contents.p2));
  943. Char *b = (Char *)alloca (sizeof (Char) * l);
  944. bp->substring (re_regs.start[0], l, b);
  945. bp->delete_region (wp, re_regs.start[0], re_regs.end[0]);
  946. const Char *p = xstring_contents (string);
  947. const Char *pe = p + xstring_length (string);
  948. const Char *p0 = p;
  949. int fconv = NOCASECONV;
  950. Point conv_point;
  951. while (p < pe)
  952. {
  953. if (*p++ == '\\')
  954. {
  955. bp->insert_chars (wp, p0, p - p0 - 1, 1);
  956. if (p == pe)
  957. break;
  958. Char c = *p++;
  959. switch (c)
  960. {
  961. case '&':
  962. c = '0';
  963. case '0':
  964. case '1':
  965. case '2':
  966. case '3':
  967. case '4':
  968. case '5':
  969. case '6':
  970. case '7':
  971. case '8':
  972. case '9':
  973. c -= '0';
  974. if (re_regs.start[c] >= 0)
  975. bp->insert_chars (wp,
  976. b + min (int (re_regs.start[c] - re_regs.start[0]),
  977. l),
  978. min (int (re_regs.end[c] - re_regs.start[c]),
  979. l),
  980. 1);
  981. p0 = p;
  982. break;
  983. case NOCASECONV:
  984. case UPCASE_ONE:
  985. case DOWNCASE_ONE:
  986. case UPCASE_CHARS:
  987. case DOWNCASE_CHARS:
  988. case_conversion (fconv, conv_point, wp->w_point, bp);
  989. fconv = c;
  990. conv_point = wp->w_point;
  991. p0 = p;
  992. break;
  993. default:
  994. p0 = p - 1;
  995. break;
  996. }
  997. }
  998. }
  999. bp->insert_chars (wp, p0, p - p0, 1);
  1000. case_conversion (fconv, conv_point, wp->w_point, bp);
  1001. }
  1002. }
  1003. lisp
  1004. Freplace_match (lisp string, lisp keys)
  1005. {
  1006. check_string (string);
  1007. if (re_regs.start[0] < 0)
  1008. return Qnil;
  1009. Window *wp = selected_window ();
  1010. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  1011. wp->w_bufp->check_read_only ();
  1012. replace_match (wp, string, (find_keyword (Kliteral, keys) != Qnil
  1013. || !re_tag_p (string)));
  1014. return Qt;
  1015. }
  1016. static lChar
  1017. match_end_before (Buffer *bp, const Point &point)
  1018. {
  1019. Point p (point);
  1020. bp->goto_char (p, re_regs.end[0]);
  1021. if (bp->bobp (p))
  1022. return lChar_EOF;
  1023. return p.prevch ();
  1024. }
  1025. lisp
  1026. Freplace_buffer (lisp pattern, lisp replacement, lisp keys)
  1027. {
  1028. int flags = scan_flags (keys) & ~SF_REVERSE;
  1029. int once = find_keyword_bool (Konce, keys);
  1030. Window *wp = selected_window ();
  1031. Buffer *bp = wp->w_bufp;
  1032. point_t limit = scan_limit (bp, flags, keys);
  1033. lChar last_match_char;
  1034. point_t last_match = scan_last_match (bp, keys, last_match_char);
  1035. clear_regs ();
  1036. if (!regexpp (pattern))
  1037. {
  1038. check_string (pattern);
  1039. if (!xstring_length (pattern))
  1040. return make_fixnum (0);
  1041. }
  1042. check_string (replacement);
  1043. int regexp = find_keyword_bool (Kregexp, keys) || regexpp (pattern);
  1044. int literal = find_keyword (Kliteral, keys) != Qnil || !re_tag_p (replacement);
  1045. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  1046. wp->w_bufp->check_read_only ();
  1047. int delete_regexp = 0;
  1048. int BM[256];
  1049. if (!regexp)
  1050. {
  1051. if (flags & SF_SMART_CASE_FOLD
  1052. && smart_case_fold_string_p (pattern))
  1053. flags |= SF_CASE_FOLD;
  1054. bm_compilef (BM, xstring_contents (pattern), xstring_length (pattern),
  1055. flags & SF_CASE_FOLD);
  1056. }
  1057. else if (!regexpp (pattern))
  1058. {
  1059. pattern = Fcompile_regexp (pattern, (flags & SF_SMART_CASE_FOLD
  1060. ? Ksmart : boole (flags & SF_CASE_FOLD)));
  1061. delete_regexp = 1;
  1062. }
  1063. point_t last_pos = -1;
  1064. int count = 0;
  1065. while ((regexp
  1066. ? bp->re_scan_buffer (wp->w_point, pattern, limit,
  1067. last_match, last_match_char, flags)
  1068. : bp->scan_forward (wp->w_point, xstring_contents (pattern),
  1069. xstring_length (pattern), BM, limit, flags))
  1070. && re_regs.start[0] >= 0)
  1071. {
  1072. if (re_regs.start[0] != re_regs.end[0]
  1073. || last_match != re_regs.start[0])
  1074. {
  1075. long ochars = bp->b_nchars;
  1076. last_match_char = match_end_before (bp, wp->w_point);
  1077. replace_match (wp, replacement, literal);
  1078. last_match = wp->w_point.p_point;
  1079. limit += bp->b_nchars - ochars;
  1080. count++;
  1081. if (once)
  1082. {
  1083. last_pos = wp->w_point.p_point;
  1084. bp->goto_eol (wp->w_point);
  1085. flags |= SF_NO_DUP;
  1086. }
  1087. else if (re_regs.start[0] == re_regs.end[0])
  1088. flags |= SF_NO_DUP;
  1089. else
  1090. flags &= ~SF_NO_DUP;
  1091. }
  1092. else
  1093. flags |= SF_NO_DUP;
  1094. clear_regs ();
  1095. if (bp->eobp (wp->w_point))
  1096. break;
  1097. QUIT;
  1098. }
  1099. if (last_pos != -1)
  1100. bp->goto_char (wp->w_point, last_pos);
  1101. if (delete_regexp)
  1102. destruct_regexp (pattern);
  1103. return make_fixnum (count);
  1104. }
  1105. lisp
  1106. Fmatch_data (lisp v)
  1107. {
  1108. if (re_regs.start[0] < 0)
  1109. return Qnil;
  1110. if (!v || v == Qnil)
  1111. v = make_vector (2 * MAX_REGS + 1, Qnil);
  1112. else
  1113. {
  1114. check_general_vector (v);
  1115. if (xvector_length (v) != 2 * MAX_REGS + 1)
  1116. FEtype_error (v, Smatch_data);
  1117. }
  1118. lisp *p = xvector_contents (v);
  1119. for (int i = 0; i < MAX_REGS; i++)
  1120. if (re_regs.start[i] >= 0)
  1121. {
  1122. *p++ = make_fixnum (re_regs.start[i]);
  1123. *p++ = make_fixnum (re_regs.end[i]);
  1124. }
  1125. else
  1126. {
  1127. *p++ = Qnil;
  1128. *p++ = Qnil;
  1129. }
  1130. *p = xsymbol_value (Vlast_match_string);
  1131. return v;
  1132. }
  1133. lisp
  1134. Fstore_match_data (lisp data)
  1135. {
  1136. if (data == Qnil)
  1137. {
  1138. clear_regs ();
  1139. return Qnil;
  1140. }
  1141. check_general_vector (data);
  1142. if (xvector_length (data) != 2 * MAX_REGS + 1)
  1143. FEtype_error (data, Smatch_data);
  1144. Regexp::sregs r;
  1145. lisp *p = xvector_contents (data);
  1146. for (int i = 0; i < MAX_REGS; i++, p += 2)
  1147. if (*p == Qnil)
  1148. r.start[i] = r.end[i] = -1;
  1149. else
  1150. {
  1151. r.start[i] = fixnum_value (*p);
  1152. r.end[i] = fixnum_value (p[1]);
  1153. }
  1154. r.nregs = MAX_REGS - 1;
  1155. xsymbol_value (Vlast_match_string) = stringp (*p) ? *p : Qnil;
  1156. copy_regs0 (re_regs, r);
  1157. check_regs ();
  1158. return Qt;
  1159. }
  1160. static void
  1161. ss_add (StrBuf &sb, Char cc, int &fconv)
  1162. {
  1163. switch (fconv)
  1164. {
  1165. case UPCASE_ONE:
  1166. sb.add (char_upcase (cc));
  1167. fconv = NOCASECONV;
  1168. break;
  1169. case DOWNCASE_ONE:
  1170. sb.add (char_downcase (cc));
  1171. fconv = NOCASECONV;
  1172. break;
  1173. case UPCASE_CHARS:
  1174. sb.add (char_upcase (cc));
  1175. break;
  1176. case DOWNCASE_CHARS:
  1177. sb.add (char_downcase (cc));
  1178. break;
  1179. default:
  1180. sb.add (cc);
  1181. break;
  1182. }
  1183. }
  1184. static void
  1185. substitute_string (StrBuf &sb, lisp string, lisp replacement)
  1186. {
  1187. const Char *r = xstring_contents (replacement);
  1188. const Char *const re = r + xstring_length (replacement);
  1189. point_t l = xstring_length (string);
  1190. int fconv = NOCASECONV;
  1191. while (r < re)
  1192. {
  1193. Char c = *r++;
  1194. if (c != '\\')
  1195. ss_add (sb, c, fconv);
  1196. else
  1197. {
  1198. if (r == re)
  1199. break;
  1200. c = *r++;
  1201. switch (c)
  1202. {
  1203. case '&':
  1204. c = '0';
  1205. case '0':
  1206. case '1':
  1207. case '2':
  1208. case '3':
  1209. case '4':
  1210. case '5':
  1211. case '6':
  1212. case '7':
  1213. case '8':
  1214. case '9':
  1215. c -= '0';
  1216. if (re_regs.start[c] >= 0)
  1217. {
  1218. int start = min (re_regs.start[c], l);
  1219. int end = min (re_regs.end[c], l);
  1220. for (; start < end; start++)
  1221. ss_add (sb, xstring_contents (string)[start], fconv);
  1222. }
  1223. break;
  1224. case NOCASECONV:
  1225. case UPCASE_ONE:
  1226. case DOWNCASE_ONE:
  1227. case UPCASE_CHARS:
  1228. case DOWNCASE_CHARS:
  1229. fconv = c;
  1230. break;
  1231. default:
  1232. ss_add (sb, c, fconv);
  1233. break;
  1234. }
  1235. }
  1236. }
  1237. }
  1238. lisp
  1239. Fsubstitute_string (lisp string, lisp pattern, lisp replacement, lisp keys)
  1240. {
  1241. clear_regs ();
  1242. lisp case_fold = find_keyword (Kcase_fold, keys);
  1243. const u_char *const translate = ((case_fold == Ksmart
  1244. ? (stringp (pattern)
  1245. && Regexp::smart_case_fold_p (xstring_contents (pattern),
  1246. xstring_length (pattern)))
  1247. : case_fold != Qnil)
  1248. ? char_translate_upcase_table
  1249. : char_no_translate_table);
  1250. check_string (string);
  1251. check_string (replacement);
  1252. Regexp re (translate, xsyntax_table (selected_buffer ()->lsyntax_table));
  1253. if (regexpp (pattern))
  1254. re.compile (pattern, 1);
  1255. else
  1256. {
  1257. check_string (pattern);
  1258. if (!xstring_length (pattern))
  1259. return string;
  1260. re.compile (xstring_contents (pattern), xstring_length (pattern), 1);
  1261. }
  1262. int offset, len;
  1263. if (!string_start_end (string,
  1264. find_keyword (Kstart, keys, Qnil),
  1265. find_keyword (Kend, keys, Qnil),
  1266. offset, len))
  1267. return Qnil;
  1268. int count;
  1269. lisp lcount = find_keyword (Kcount, keys, Qnil);
  1270. if (lcount == Qnil)
  1271. count = -1;
  1272. else
  1273. {
  1274. count = fixnum_value (lcount);
  1275. if (!count)
  1276. return string;
  1277. }
  1278. lisp lskip = find_keyword (Kskip, keys, Qnil);
  1279. int skip = lskip == Qnil ? 0 : fixnum_value (lskip);
  1280. char tem[1024];
  1281. StrBuf sb (tem, sizeof tem);
  1282. if (offset)
  1283. sb.add (xstring_contents (string), offset);
  1284. int found = 0;
  1285. while (re.search (xstring_contents (string), len, offset))
  1286. {
  1287. save_match (re, Qnil);
  1288. if (skip > 0)
  1289. {
  1290. sb.add (xstring_contents (string) + offset, re_regs.end[0] - offset);
  1291. skip--;
  1292. }
  1293. else
  1294. {
  1295. sb.add (xstring_contents (string) + offset, re_regs.start[0] - offset);
  1296. substitute_string (sb, string, replacement);
  1297. count--;
  1298. found++;
  1299. }
  1300. offset = re_regs.end[0];
  1301. if (re_regs.start[0] == re_regs.end[0])
  1302. break;
  1303. if (offset == len)
  1304. break;
  1305. if (!count)
  1306. break;
  1307. clear_regs ();
  1308. }
  1309. sb.add (xstring_contents (string) + offset, xstring_length (string) - offset);
  1310. multiple_value::count () = 2;
  1311. multiple_value::value (1) = make_fixnum (found);
  1312. return sb.make_string ();
  1313. }
  1314. lisp
  1315. Fstring_replace_match (lisp string, lisp replacement)
  1316. {
  1317. check_string (string);
  1318. check_string (replacement);
  1319. if (re_regs.start[0] < 0)
  1320. return Qnil;
  1321. char tem[1024];
  1322. StrBuf sb (tem, sizeof tem);
  1323. substitute_string (sb, string, replacement);
  1324. return sb.make_string ();
  1325. }
  1326. lisp
  1327. Fstring_looking_at (lisp regex, lisp string, lisp keys)
  1328. {
  1329. check_string (string);
  1330. clear_regs ();
  1331. lisp case_fold = find_keyword (Kcase_fold, keys);
  1332. Regexp re (((case_fold == Ksmart
  1333. ? (stringp (regex)
  1334. && Regexp::smart_case_fold_p (xstring_contents (regex),
  1335. xstring_length (regex)))
  1336. : case_fold != Qnil)
  1337. ? char_translate_upcase_table
  1338. : char_no_translate_table),
  1339. xsyntax_table (selected_buffer ()->lsyntax_table));
  1340. if (regexpp (regex))
  1341. re.compile (regex, 0);
  1342. else
  1343. {
  1344. check_string (regex);
  1345. if (!xstring_length (regex))
  1346. return Qnil;
  1347. re.compile (xstring_contents (regex), xstring_length (regex), 0);
  1348. }
  1349. int offset, len;
  1350. if (!string_start_end (string,
  1351. find_keyword (Kstart, keys, Qnil),
  1352. find_keyword (Kend, keys, Qnil),
  1353. offset, len))
  1354. return Qnil;
  1355. if (!re.match (xstring_contents (string), len, offset))
  1356. return Qnil;
  1357. save_match (re, string);
  1358. return make_fixnum (re.re_regs.start[0]);
  1359. }
  1360. lisp
  1361. Fcompare_buffer_substrings (lisp buffer1, lisp start1, lisp end1,
  1362. lisp buffer2, lisp start2, lisp end2,
  1363. lisp case_fold)
  1364. {
  1365. Buffer *bp1 = Buffer::coerce_to_buffer (buffer1);
  1366. Buffer *bp2 = Buffer::coerce_to_buffer (buffer2);
  1367. point_t p1 = bp1->coerce_to_restricted_point (start1);
  1368. point_t pe1 = bp1->coerce_to_restricted_point (end1);
  1369. point_t p2 = bp2->coerce_to_restricted_point (start2);
  1370. point_t pe2 = bp2->coerce_to_restricted_point (end2);
  1371. if (p1 > pe1)
  1372. swap (p1, pe1);
  1373. if (p2 > pe2)
  1374. swap (p2, pe2);
  1375. if (case_fold == Qnil)
  1376. case_fold = 0;
  1377. Point point1, point2;
  1378. bp1->set_point (point1, p1);
  1379. bp2->set_point (point2, p2);
  1380. point_t end = p1 + min (pe1 - p1, pe2 - p2);
  1381. int diff = 0;
  1382. while (point1.p_point < end)
  1383. {
  1384. Char c1 = point1.ch ();
  1385. Char c2 = point2.ch ();
  1386. diff = case_fold ? char_upcase (c1) - char_upcase (c2) : c1 - c2;
  1387. if (diff)
  1388. break;
  1389. if (!bp1->forward_char (point1, 1)
  1390. || !bp2->forward_char (point2, 1))
  1391. break;
  1392. }
  1393. if (!diff)
  1394. diff = (pe1 - p1) - (pe2 - p2);
  1395. return make_fixnum (diff < 0
  1396. ? -1 - (point1.p_point - p1)
  1397. : 1 + (point1.p_point - p1));
  1398. }