PageRenderTime 83ms CodeModel.GetById 33ms RepoModel.GetById 0ms app.codeStats 0ms

/src/insdel.cc

https://bitbucket.org/mumurik/xyzzy
C++ | 2002 lines | 1822 code | 180 blank | 0 comment | 411 complexity | 629072c27e42a45b29857bcc487c396c MD5 | raw file

Large files files are truncated, but you can click here to view the full file

  1. #include "ed.h"
  2. #include "syntaxinfo.h"
  3. #include "sequence.h"
  4. #include "byte-stream.h"
  5. #ifdef DEBUG
  6. void
  7. Buffer::check_valid () const
  8. {
  9. long nchars = 0;
  10. const Chunk *cp = b_chunkb;
  11. for (; cp; cp = cp->c_next)
  12. {
  13. nchars += cp->c_used;
  14. if (!cp->c_next)
  15. assert (cp == b_chunke);
  16. }
  17. assert (nchars == b_nchars);
  18. nchars = 0;
  19. for (cp = b_chunke; cp; cp = cp->c_prev)
  20. {
  21. nchars += cp->c_used;
  22. if (!cp->c_prev)
  23. assert (cp == b_chunkb);
  24. }
  25. assert (nchars == b_nchars);
  26. }
  27. #endif /* DEBUG */
  28. void
  29. Buffer::check_read_only () const
  30. {
  31. if (read_only_p ())
  32. FEread_only_buffer ();
  33. }
  34. void
  35. Buffer::prepare_modify_buffer ()
  36. {
  37. if (b_in_post_modified_hook)
  38. FEread_only_buffer ();
  39. if (!b_modified && !verify_modtime ()
  40. && !yes_or_no_p (Mfile_has_changed_on_disk))
  41. FEplain_error (Eedit_canceled);
  42. if (!file_locked_p () && symbol_value (Slock_file, this) != Qnil
  43. && lock_file () == Kshared && !yes_or_no_p (Mfile_has_already_locked))
  44. {
  45. unlock_file ();
  46. FEplain_error (Eedit_canceled);
  47. }
  48. }
  49. void
  50. Buffer::modify ()
  51. {
  52. if (!b_modified)
  53. {
  54. b_modified = 1;
  55. modify_mode_line ();
  56. maybe_modify_buffer_bar ();
  57. }
  58. b_modified_count++;
  59. b_nlines = -1;
  60. b_need_auto_save = 1;
  61. set_nfolded_all(-1);
  62. b_stream_cache.p_chunk = 0;
  63. }
  64. void
  65. Buffer::set_modified_region (point_t p1, point_t p2)
  66. {
  67. b_last_modified = p1;
  68. if (b_modified_region.p1 == -1)
  69. {
  70. b_modified_region.p1 = p1;
  71. b_modified_region.p2 = p2;
  72. }
  73. else
  74. {
  75. b_modified_region.p1 = min (b_modified_region.p1, p1);
  76. b_modified_region.p2 = max (b_modified_region.p2, p2);
  77. }
  78. }
  79. void
  80. Buffer::modify_chunk (Chunk *cp) const
  81. {
  82. cp->c_nlines = -1;
  83. cp->invalidate_fold_info();
  84. cp->c_bstate = syntax_state::SS_INVALID;
  85. }
  86. void
  87. Buffer::prepare_modify_region (Window *wp, point_t p1, point_t p2)
  88. {
  89. assert (p1 < p2);
  90. assert (p1 >= b_contents.p1);
  91. assert (p2 <= b_contents.p2);
  92. check_read_only ();
  93. prepare_modify_buffer ();
  94. goto_char (wp->w_point, p1);
  95. if (!save_modify_undo (wp->w_point, p2 - p1))
  96. FEstorage_error ();
  97. long size = p2 - p1;
  98. Chunk *cp = wp->w_point.p_chunk;
  99. modify_chunk (cp);
  100. size -= cp->c_used - wp->w_point.p_offset;
  101. for (cp = cp->c_next; cp && size > 0; cp = cp->c_next)
  102. {
  103. modify_chunk (cp);
  104. size -= cp->c_used;
  105. }
  106. modify ();
  107. set_modified_region (p1, p2);
  108. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  109. }
  110. point_t
  111. Buffer::prepare_modify_region (Window *wp, lisp from, lisp to)
  112. {
  113. point_t p1 = coerce_to_restricted_point (from);
  114. point_t p2 = coerce_to_restricted_point (to);
  115. if (p1 == p2)
  116. return -1;
  117. if (p1 > p2)
  118. swap (p1, p2);
  119. prepare_modify_region (wp, p1, p2);
  120. return p2;
  121. }
  122. void
  123. Buffer::set_point (Point &point, point_t goal) const
  124. {
  125. point.p_point = 0;
  126. point.p_chunk = b_chunkb;
  127. point.p_offset = 0;
  128. goto_char (point, goal);
  129. }
  130. void
  131. Buffer::set_point_no_restrictions (Point &point, point_t goal)
  132. {
  133. no_restrictions nr (this);
  134. set_point (point, goal);
  135. }
  136. inline void
  137. move_chunk (Chunk *cp, int src, int dst, int size)
  138. {
  139. if (src != dst)
  140. memmove (cp->c_text + dst, cp->c_text + src, sizeof (Char) * size);
  141. }
  142. inline void
  143. move_chunk (const Chunk *sp, int src, Chunk *dp, int dst, int size)
  144. {
  145. memmove (dp->c_text + dst, sp->c_text + src, sizeof (Char) * size);
  146. }
  147. static void
  148. adjust (/* const */ Chunk *&chunk, int &offset)
  149. {
  150. /* const */ Chunk *cp = chunk;
  151. int o = offset;
  152. while (o > cp->c_used)
  153. {
  154. o -= cp->c_used;
  155. cp = cp->c_next;
  156. assert (cp);
  157. }
  158. chunk = cp;
  159. offset = o;
  160. }
  161. void
  162. copy_chunk (const Char *src, Chunk *dst, int doff, int size)
  163. {
  164. while (1)
  165. {
  166. int n = min (dst->c_used - doff, size);
  167. bcopy (src, dst->c_text + doff, n);
  168. size -= n;
  169. if (!size)
  170. return;
  171. src += n;
  172. doff += n;
  173. if (doff == dst->c_used)
  174. {
  175. dst = dst->c_next;
  176. doff = 0;
  177. }
  178. }
  179. }
  180. void
  181. Buffer::move_before_gap (Point &w_point, int size) const
  182. {
  183. Chunk *cur = w_point.p_chunk;
  184. int rest = cur->rest ();
  185. int n = cur->c_used - w_point.p_offset;
  186. move_chunk (cur, w_point.p_offset, Chunk::TEXT_SIZE - n, n);
  187. cur->c_used = Chunk::TEXT_SIZE;
  188. modify_chunk (cur);
  189. Chunk *prev = cur->c_prev;
  190. int pused = prev->c_used;
  191. prev->c_used += size - rest;
  192. modify_chunk (prev);
  193. copy_chunk (cur->c_text, prev, pused, w_point.p_offset);
  194. pused += w_point.p_offset;
  195. adjust (prev, pused);
  196. if (pused == prev->c_used)
  197. {
  198. prev = prev->c_next;
  199. pused = 0;
  200. }
  201. w_point.p_chunk = prev;
  202. w_point.p_offset = pused;
  203. }
  204. static void
  205. adjust_dst (/* const */ Chunk *&chunk, int &offset)
  206. {
  207. /* const */ Chunk *cp = chunk;
  208. int o = offset;
  209. while (o > Chunk::TEXT_SIZE)
  210. {
  211. o -= Chunk::TEXT_SIZE;
  212. cp = cp->c_next;
  213. assert (cp);
  214. }
  215. chunk = cp;
  216. offset = o;
  217. }
  218. static void
  219. copy_chunk_reverse (const Chunk *src, int soff, Chunk *dst, int doff, int size)
  220. {
  221. if (!size)
  222. return;
  223. soff += size;
  224. doff += size;
  225. adjust_dst (dst, doff);
  226. while (1)
  227. {
  228. int n = min (soff, doff);
  229. if (n)
  230. {
  231. n = min (n, size);
  232. soff -= n;
  233. doff -= n;
  234. move_chunk (src, soff, dst, doff, n);
  235. size -= n;
  236. if (!size)
  237. return;
  238. }
  239. if (!doff)
  240. {
  241. dst = dst->c_prev;
  242. doff = Chunk::TEXT_SIZE;
  243. }
  244. if (!soff)
  245. {
  246. src = src->c_prev;
  247. soff = src->c_used;
  248. }
  249. }
  250. }
  251. void
  252. Buffer::move_after_gap (Point &w_point, int size) const
  253. {
  254. Chunk *cp = w_point.p_chunk;
  255. Chunk *next = cp->c_next;
  256. int n = size - cp->rest ();
  257. move_chunk (next, 0, n, next->c_used);
  258. next->c_used += n;
  259. modify_chunk (next);
  260. copy_chunk_reverse (cp, w_point.p_offset, cp, w_point.p_offset + size,
  261. cp->c_used - w_point.p_offset);
  262. cp->c_used = Chunk::TEXT_SIZE;
  263. modify_chunk (cp);
  264. }
  265. int
  266. Buffer::allocate_new_chunks (Point &w_point, int requested)
  267. {
  268. Chunk *chunk = w_point.p_chunk;
  269. int need = requested - chunk->rest ();
  270. Chunk *prev = chunk;
  271. Chunk *head = alloc_chunk ();
  272. for (Chunk *cp = head; cp; cp = cp->c_next)
  273. {
  274. cp->c_prev = prev;
  275. prev = cp;
  276. if (need > Chunk::TEXT_SIZE)
  277. {
  278. cp->c_used = Chunk::TEXT_SIZE;
  279. need -= Chunk::TEXT_SIZE;
  280. cp->c_next = alloc_chunk ();
  281. }
  282. else
  283. {
  284. cp->c_used = need;
  285. cp->c_next = chunk->c_next;
  286. if (cp->c_next)
  287. cp->c_next->c_prev = cp;
  288. else
  289. b_chunke = cp;
  290. chunk->c_next = head;
  291. copy_chunk_reverse (chunk, w_point.p_offset,
  292. chunk, w_point.p_offset + requested,
  293. chunk->c_used - w_point.p_offset);
  294. modify_chunk (chunk);
  295. chunk->c_used = Chunk::TEXT_SIZE;
  296. if (w_point.p_offset == chunk->c_used)
  297. {
  298. w_point.p_chunk = chunk->c_next;
  299. w_point.p_offset = 0;
  300. }
  301. return 1;
  302. }
  303. }
  304. free_all_chunks (head);
  305. return 0;
  306. }
  307. int
  308. Buffer::move_gap (Point &w_point, int requested)
  309. {
  310. Chunk *chunk = w_point.p_chunk;
  311. int rest = chunk->rest ();
  312. if (rest >= requested)
  313. {
  314. move_chunk (chunk, w_point.p_offset, w_point.p_offset + requested,
  315. chunk->c_used - w_point.p_offset);
  316. chunk->c_used += requested;
  317. modify_chunk (chunk);
  318. return 1;
  319. }
  320. Chunk *cp = chunk->c_next;
  321. if (cp && rest + cp->rest () >= requested)
  322. {
  323. move_after_gap (w_point, requested);
  324. return 1;
  325. }
  326. cp = chunk->c_prev;
  327. if (cp && rest + cp->rest () >= requested)
  328. {
  329. move_before_gap (w_point, requested);
  330. return 1;
  331. }
  332. return allocate_new_chunks (w_point, requested);
  333. }
  334. extern ApplicationFrame *first_app_frame();
  335. void
  336. Buffer::adjust_insertion (const Point &point, int size)
  337. {
  338. point_t opoint = point.p_point;
  339. #define ADJINS(P) if ((P) > opoint) (P) += size
  340. #define ADJINS2(P) if ((P) >= opoint) (P) += size
  341. ADJINS (b_point);
  342. ADJINS (b_mark);
  343. ADJINS (b_selection_point);
  344. ADJINS (b_selection_marker);
  345. ADJINS (b_reverse_region.p1);
  346. ADJINS (b_reverse_region.p2);
  347. ADJINS (b_disp);
  348. textprop_adjust_insertion (opoint, size);
  349. for (save_excursion *se = b_excursion; se; se = se->prev ())
  350. ADJINS (se->se_point);
  351. for (save_restriction *sr = b_restriction; sr; sr = sr->prev ())
  352. {
  353. ADJINS (sr->sr_contents.p1);
  354. ADJINS2 (sr->sr_contents.p2);
  355. }
  356. for (lisp marker = lmarkers; consp (marker); marker = xcdr (marker))
  357. {
  358. lisp x = xcar (marker);
  359. ADJINS (xmarker_point (x));
  360. }
  361. for (ApplicationFrame *app1 = first_app_frame(); app1; app1 = app1->a_next) {
  362. for (Window *wp = app1->active_frame.windows; wp; wp = wp->w_next)
  363. if (wp->w_bufp == this)
  364. {
  365. ADJINS (wp->w_point.p_point);
  366. if (&wp->w_point != &point)
  367. set_point_no_restrictions (wp->w_point, wp->w_point.p_point);
  368. ADJINS (wp->w_mark);
  369. ADJINS (wp->w_selection_point);
  370. ADJINS (wp->w_selection_marker);
  371. ADJINS (wp->w_reverse_region.p1);
  372. ADJINS (wp->w_reverse_region.p2);
  373. ADJINS (wp->w_disp);
  374. ADJINS (wp->w_last_disp);
  375. }
  376. }
  377. for (WindowConfiguration *wc = WindowConfiguration::wc_chain;
  378. wc; wc = wc->wc_prev)
  379. for (WindowConfiguration::Data *d = wc->wc_data, *de = d + wc->wc_nwindows;
  380. d < de; d++)
  381. if (d->bufp == this)
  382. {
  383. ADJINS (d->point);
  384. ADJINS (d->disp);
  385. ADJINS (d->mark);
  386. ADJINS (d->selection_point);
  387. ADJINS (d->selection_marker);
  388. ADJINS (d->reverse_region.p1);
  389. ADJINS (d->reverse_region.p2);
  390. }
  391. }
  392. int
  393. Buffer::pre_insert_chars (Point &point, int size)
  394. {
  395. UndoInfo *undo = setup_insert_undo (point.p_point, size);
  396. if (!undo)
  397. return 0;
  398. if (!move_gap (point, size))
  399. {
  400. discard_insert_undo (undo);
  401. return 0;
  402. }
  403. save_insert_undo (undo, point.p_point, size);
  404. return 1;
  405. }
  406. void
  407. Buffer::post_insert_chars (Point &point, int size)
  408. {
  409. modify ();
  410. set_modified_region (point.p_point, point.p_point);
  411. b_modified_region.p2 += size;
  412. b_nchars += size;
  413. b_contents.p2 += size;
  414. adjust_insertion (point, size);
  415. forward_char (point, size);
  416. b_stream_cache = point;
  417. #ifdef DEBUG
  418. check_valid ();
  419. #endif
  420. }
  421. int
  422. Buffer::insert_chars_internal (Point &point, const insertChars *ichars,
  423. int nargs, int repeat)
  424. {
  425. double total_length = 0;
  426. int i;
  427. for (i = 0; i < nargs; i++)
  428. total_length += ichars[i].length;
  429. total_length *= repeat;
  430. if (total_length > INT_MAX)
  431. return 0;
  432. int size = int (total_length);
  433. if (!size)
  434. return 1;
  435. if (!pre_insert_chars (point, size))
  436. return 0;
  437. Chunk *cp = point.p_chunk;
  438. int off = point.p_offset;
  439. for (i = 0; i < repeat; i++)
  440. for (int j = 0; j < nargs; j++)
  441. {
  442. int rest = ichars[j].length;
  443. const Char *s = ichars[j].string;
  444. while (rest > 0)
  445. {
  446. int n = min (cp->c_used - off, rest);
  447. bcopy (s, cp->c_text + off, n);
  448. s += n;
  449. off += n;
  450. rest -= n;
  451. if (off == cp->c_used)
  452. {
  453. cp = cp->c_next;
  454. off = 0;
  455. }
  456. }
  457. }
  458. post_insert_chars (point, size);
  459. return 1;
  460. }
  461. int
  462. Buffer::insert_chars_internal (Point &point, const Char *string,
  463. int length, int repeat)
  464. {
  465. insertChars ichars;
  466. ichars.string = string;
  467. ichars.length = length;
  468. return insert_chars_internal (point, &ichars, 1, repeat);
  469. }
  470. void
  471. Buffer::insert_chars (Window *wp, const insertChars *ic, int n, int repeat)
  472. {
  473. prepare_modify_buffer ();
  474. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  475. point_t opoint = wp->w_point.p_point;
  476. if (!insert_chars_internal (wp->w_point, ic, n, repeat))
  477. FEstorage_error ();
  478. post_buffer_modified (Kinsert, wp->w_point, opoint, wp->w_point.p_point);
  479. }
  480. void
  481. Buffer::insert_chars (Window *wp, const Char *string, int length, int repeat)
  482. {
  483. prepare_modify_buffer ();
  484. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  485. point_t opoint = wp->w_point.p_point;
  486. if (!insert_chars_internal (wp->w_point, string, length, repeat))
  487. FEstorage_error ();
  488. post_buffer_modified (Kinsert, wp->w_point, opoint, wp->w_point.p_point);
  489. }
  490. void
  491. Buffer::insert_chars (Point &point, const Char *string, int length)
  492. {
  493. prepare_modify_buffer ();
  494. point_t opoint = point.p_point;
  495. if (!insert_chars_internal (point, string, length, 1))
  496. FEstorage_error ();
  497. post_buffer_modified (Kinsert, point, opoint, point.p_point);
  498. }
  499. lisp
  500. Finsert (lisp args)
  501. {
  502. int nargs = xlist_length (args);
  503. if (!nargs)
  504. FEtoo_few_arguments ();
  505. Window *wp = selected_window ();
  506. Buffer *bp = wp->w_bufp;
  507. bp->check_read_only ();
  508. int repeat = 1;
  509. Char *tem;
  510. insertChars *ichars = (insertChars *)alloca ((sizeof *ichars + sizeof *tem)
  511. * nargs);
  512. tem = (Char *)(ichars + nargs);
  513. int i;
  514. for (i = 0; i < nargs; i++, args = xcdr (args))
  515. {
  516. lisp x = xcar (args);
  517. if (charp (x))
  518. {
  519. *tem = xchar_code (x);
  520. ichars[i].string = tem++;
  521. ichars[i].length = 1;
  522. }
  523. else if (stringp (x))
  524. {
  525. ichars[i].string = xstring_contents (x);
  526. ichars[i].length = xstring_length (x);
  527. }
  528. else if (i && i == nargs - 1)
  529. {
  530. repeat = fixnum_value (x);
  531. if (repeat < 0)
  532. FErange_error (x);
  533. break;
  534. }
  535. else
  536. FEtype_error (x, xsymbol_value (Qor_string_character));
  537. }
  538. bp->insert_chars (wp, ichars, i, repeat);
  539. return Qt;
  540. }
  541. void
  542. Buffer::insert_file_contents (Window *wp, lisp filename, lisp visit,
  543. lisp loffset, lisp lsize, ReadFileContext &rfc)
  544. {
  545. check_read_only ();
  546. if (!visit)
  547. visit = Qnil;
  548. if (visit == Qnil)
  549. prepare_modify_buffer ();
  550. char path[PATH_MAX + 1];
  551. pathname2cstr (filename, path);
  552. if (special_file_p (path))
  553. file_error (Eis_character_special_file, filename);
  554. int offset, size;
  555. if (!loffset || loffset == Qnil)
  556. offset = 0;
  557. else
  558. {
  559. offset = fixnum_value (loffset);
  560. if (offset < 0)
  561. FErange_error (loffset);
  562. }
  563. if (!lsize || lsize == Qnil)
  564. size = -1;
  565. else
  566. {
  567. size = fixnum_value (lsize);
  568. if (size < 0)
  569. FErange_error (lsize);
  570. }
  571. Chunk *t_chunk;
  572. if (!wp->w_point.p_offset
  573. || wp->w_point.p_offset == wp->w_point.p_chunk->c_used)
  574. t_chunk = 0;
  575. else
  576. {
  577. t_chunk = alloc_chunk ();
  578. if (!t_chunk)
  579. FEstorage_error ();
  580. }
  581. long n;
  582. if (!safe_fixnum_value (symbol_value (Vexpected_eol_code, this), &n)
  583. || !valid_eol_code_p (n))
  584. n = eol_guess;
  585. rfc.r_expect_eol = eol_code (n);
  586. rfc.r_expect_char_encoding = symbol_value (Vexpected_fileio_encoding, this);
  587. if (!char_encoding_p (rfc.r_expect_char_encoding))
  588. rfc.r_expect_char_encoding = Qnil;
  589. rfc.r_char_encoding = lchar_encoding;
  590. read_file_contents (rfc, path, offset, size);
  591. if (rfc.r_status == ReadFileContext::RFCS_IOERR)
  592. {
  593. if (t_chunk)
  594. free_chunk (t_chunk);
  595. if (rfc.r_chunk)
  596. free_all_chunks (rfc.r_chunk);
  597. file_error (rfc.r_errcode, filename);
  598. }
  599. if (!rfc.r_chunk)
  600. {
  601. if (t_chunk)
  602. free_chunk (t_chunk);
  603. switch (rfc.r_status)
  604. {
  605. case ReadFileContext::RFCS_MEM:
  606. FEstorage_error ();
  607. case ReadFileContext::RFCS_OPEN:
  608. file_error (rfc.r_errcode, filename);
  609. default:
  610. break;
  611. }
  612. }
  613. else
  614. {
  615. if (visit != Qnil)
  616. clear_undo_info ();
  617. else
  618. {
  619. UndoInfo *u = setup_insert_undo (wp->w_point.p_point, rfc.r_nchars);
  620. if (!u)
  621. {
  622. if (t_chunk)
  623. free_chunk (t_chunk);
  624. free_all_chunks (rfc.r_chunk);
  625. FEstorage_error ();
  626. }
  627. save_insert_undo (u, wp->w_point.p_point, rfc.r_nchars);
  628. }
  629. if (!b_nchars)
  630. {
  631. free_all_chunks (b_chunkb);
  632. b_chunkb = rfc.r_chunk;
  633. b_chunke = rfc.r_tail;
  634. }
  635. else
  636. {
  637. Chunk *cp = wp->w_point.p_chunk;
  638. if (!wp->w_point.p_offset)
  639. {
  640. rfc.r_chunk->c_prev = cp->c_prev;
  641. if (!cp->c_prev)
  642. b_chunkb = rfc.r_chunk;
  643. else
  644. cp->c_prev->c_next = rfc.r_chunk;
  645. rfc.r_tail->c_next = cp;
  646. cp->c_prev = rfc.r_tail;
  647. }
  648. else if (wp->w_point.p_offset == wp->w_point.p_chunk->c_used)
  649. {
  650. assert (!cp->c_next);
  651. cp->c_next = rfc.r_chunk;
  652. rfc.r_chunk->c_prev = cp;
  653. b_chunke = rfc.r_tail;
  654. }
  655. else
  656. {
  657. bcopy (cp->c_text + wp->w_point.p_offset, t_chunk->c_text,
  658. cp->c_used - wp->w_point.p_offset);
  659. t_chunk->c_used = cp->c_used - wp->w_point.p_offset;
  660. modify_chunk (t_chunk);
  661. t_chunk->c_next = cp->c_next;
  662. if (t_chunk->c_next)
  663. t_chunk->c_next->c_prev = t_chunk;
  664. else
  665. b_chunke = t_chunk;
  666. rfc.r_tail->c_next = t_chunk;
  667. t_chunk->c_prev = rfc.r_tail;
  668. rfc.r_chunk->c_prev = cp;
  669. cp->c_next = rfc.r_chunk;
  670. cp->c_used = wp->w_point.p_offset;
  671. modify_chunk (cp);
  672. }
  673. }
  674. wp->w_point.p_chunk = rfc.r_chunk;
  675. wp->w_point.p_offset = 0;
  676. }
  677. modify ();
  678. set_modified_region (wp->w_point.p_point, wp->w_point.p_point);
  679. b_modified_region.p2 += rfc.r_nchars;
  680. b_nchars += rfc.r_nchars;
  681. b_contents.p2 += rfc.r_nchars;
  682. adjust_insertion (wp->w_point, rfc.r_nchars);
  683. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  684. #ifdef DEBUG
  685. check_valid ();
  686. #endif
  687. if (visit != Qnil)
  688. {
  689. b_eol_code = exact_eol_code (rfc.r_eol_code);
  690. lchar_encoding = rfc.r_char_encoding;
  691. b_modified = 0;
  692. b_need_auto_save = 0;
  693. b_modtime = rfc.r_modtime;
  694. if (symbol_value (Slock_file, this) == Kedit)
  695. unlock_file ();
  696. save_modtime_undo (b_modtime);
  697. maybe_modify_buffer_bar ();
  698. }
  699. else
  700. post_buffer_modified (Kinsert, wp->w_point,
  701. wp->w_point.p_point,
  702. wp->w_point.p_point + rfc.r_nchars);
  703. }
  704. lisp
  705. Finsert_file_contents (lisp filename, lisp visit, lisp offset, lisp size)
  706. {
  707. Window *wp = selected_window ();
  708. Buffer *bp = wp->w_bufp;
  709. ReadFileContext rfc;
  710. bp->insert_file_contents (wp, filename, visit, offset, size, rfc);
  711. multiple_value::count () = 3;
  712. multiple_value::value (1) = boole (rfc.r_status == ReadFileContext::RFCS_NOERR);
  713. multiple_value::value (2) = make_fixnum (rfc.r_nchars);
  714. return make_fixnum (rfc.r_nlines);
  715. }
  716. void
  717. Buffer::delete_chunk (Chunk *cp)
  718. {
  719. Chunk *prev = cp->c_prev;
  720. Chunk *next = cp->c_next;
  721. if (!prev && !next)
  722. {
  723. cp->clear ();
  724. return;
  725. }
  726. if (prev)
  727. prev->c_next = next;
  728. else
  729. b_chunkb = next;
  730. if (next)
  731. next->c_prev = prev;
  732. else
  733. b_chunke = prev;
  734. free_chunk (cp);
  735. }
  736. void
  737. Buffer::adjust_deletion (const Point &point, int size)
  738. {
  739. point_t from = point.p_point;
  740. #define ADJDEL(P) \
  741. if ((P) > from) (P) = max (point_t ((P) - size), from)
  742. ADJDEL (b_point);
  743. ADJDEL (b_mark);
  744. ADJDEL (b_selection_point);
  745. ADJDEL (b_selection_marker);
  746. ADJDEL (b_reverse_region.p1);
  747. ADJDEL (b_reverse_region.p2);
  748. ADJDEL (b_disp);
  749. textprop_adjust_deletion (from, size);
  750. for (save_excursion *se = b_excursion; se; se = se->prev ())
  751. ADJDEL (se->se_point);
  752. for (save_restriction *sr = b_restriction; sr; sr = sr->prev ())
  753. {
  754. ADJDEL (sr->sr_contents.p1);
  755. ADJDEL (sr->sr_contents.p2);
  756. }
  757. for (lisp marker = lmarkers; consp (marker); marker = xcdr (marker))
  758. {
  759. lisp x = xcar (marker);
  760. ADJDEL (xmarker_point (x));
  761. }
  762. all_window_iterator itr;
  763. for (Window *wp = itr.begin(); wp; wp = itr.next())
  764. if (wp->w_bufp == this)
  765. {
  766. if (point.p_point < wp->w_disp && point.p_point + size > wp->w_disp)
  767. wp->w_disp_flags |= Window::WDF_DELETE_TOP;
  768. ADJDEL (wp->w_point.p_point);
  769. if (&wp->w_point != &point)
  770. set_point_no_restrictions (wp->w_point, wp->w_point.p_point);
  771. ADJDEL (wp->w_mark);
  772. ADJDEL (wp->w_selection_point);
  773. ADJDEL (wp->w_selection_marker);
  774. ADJDEL (wp->w_reverse_region.p1);
  775. ADJDEL (wp->w_reverse_region.p2);
  776. ADJDEL (wp->w_disp);
  777. ADJDEL (wp->w_last_disp);
  778. }
  779. for (WindowConfiguration *wc = WindowConfiguration::wc_chain;
  780. wc; wc = wc->wc_prev)
  781. for (WindowConfiguration::Data *d = wc->wc_data, *de = d + wc->wc_nwindows;
  782. d < de; d++)
  783. if (d->bufp == this)
  784. {
  785. ADJDEL (d->point);
  786. ADJDEL (d->disp);
  787. ADJDEL (d->mark);
  788. ADJDEL (d->selection_point);
  789. ADJDEL (d->selection_marker);
  790. ADJDEL (d->reverse_region.p1);
  791. ADJDEL (d->reverse_region.p2);
  792. }
  793. }
  794. int
  795. Buffer::delete_region_internal (Point &point, point_t from, point_t to)
  796. {
  797. from = min (max (from, b_contents.p1), b_contents.p2);
  798. to = min (max (to, b_contents.p1), b_contents.p2);
  799. if (from == to)
  800. return 1;
  801. if (from > to)
  802. swap (from, to);
  803. int size = to - from;
  804. goto_char (point, from);
  805. if (!save_delete_undo (point, size))
  806. return 0;
  807. Chunk *cp = point.p_chunk;
  808. int off = point.p_offset;
  809. while (1)
  810. {
  811. int rest = cp->c_used - off;
  812. if (size >= rest)
  813. {
  814. Chunk *next = cp->c_next;
  815. if (!off)
  816. delete_chunk (cp);
  817. else
  818. {
  819. cp->c_used = off;
  820. modify_chunk (cp);
  821. }
  822. size -= rest;
  823. if (!size)
  824. break;
  825. cp = next;
  826. off = 0;
  827. }
  828. else
  829. {
  830. cp->c_used -= size;
  831. modify_chunk (cp);
  832. bcopy (cp->c_text + off + size, cp->c_text + off, cp->c_used - off);
  833. break;
  834. }
  835. }
  836. size = to - from;
  837. modify ();
  838. set_modified_region (from, to);
  839. b_modified_region.p2 -= size;
  840. b_nchars -= size;
  841. b_contents.p2 -= size;
  842. set_point (point, from);
  843. adjust_deletion (point, size);
  844. #ifdef DEBUG
  845. check_valid ();
  846. #endif
  847. return 1;
  848. }
  849. void
  850. Buffer::delete_region (Window *wp, point_t from, point_t to)
  851. {
  852. prepare_modify_buffer ();
  853. wp->w_disp_flags |= Window::WDF_GOAL_COLUMN;
  854. if (!delete_region_internal (wp->w_point, from, to))
  855. FEstorage_error ();
  856. post_buffer_modified (Kdelete, wp->w_point,
  857. wp->w_point.p_point, wp->w_point.p_point);
  858. }
  859. lisp
  860. Fdelete_region (lisp from, lisp to)
  861. {
  862. Window *wp = selected_window ();
  863. Buffer *bp = wp->w_bufp;
  864. point_t p1 = bp->coerce_to_point (from);
  865. point_t p2 = bp->coerce_to_point (to);
  866. if (p1 != p2)
  867. {
  868. bp->check_read_only ();
  869. bp->delete_region (wp, p1, p2);
  870. }
  871. return Qt;
  872. }
  873. void
  874. Buffer::overwrite_chars (Window *wp, const Char *p, int size)
  875. {
  876. prepare_modify_region (wp, wp->w_point.p_point, wp->w_point.p_point + size);
  877. copy_chunk (p, wp->w_point.p_chunk, wp->w_point.p_offset, size);
  878. post_buffer_modified (Kmodify, wp->w_point,
  879. wp->w_point.p_point, wp->w_point.p_point + size);
  880. }
  881. void
  882. Buffer::substring (const Point &point, int size, Char *b) const
  883. {
  884. const Chunk *cp = point.p_chunk;
  885. int n = cp->c_used - point.p_offset;
  886. if (n >= size)
  887. bcopy (cp->c_text + point.p_offset, b, size);
  888. else
  889. {
  890. bcopy (cp->c_text + point.p_offset, b, n);
  891. b += n;
  892. size -= n;
  893. for (cp = cp->c_next; size > cp->c_used; cp = cp->c_next)
  894. {
  895. bcopy (cp->c_text, b, cp->c_used);
  896. b += cp->c_used;
  897. size -= cp->c_used;
  898. }
  899. bcopy (cp->c_text, b, size);
  900. }
  901. }
  902. void
  903. Buffer::substring (point_t point, int size, Char *b) const
  904. {
  905. Point p;
  906. set_point (p, point);
  907. substring (p, size, b);
  908. }
  909. lisp
  910. Buffer::substring (point_t p1, point_t p2) const
  911. {
  912. p1 = min (max (p1, b_contents.p1), b_contents.p2);
  913. p2 = min (max (p2, b_contents.p1), b_contents.p2);
  914. if (p1 > p2)
  915. swap (p1, p2);
  916. int size = p2 - p1;
  917. lisp x = make_string (size);
  918. substring (p1, size, xstring_contents (x));
  919. return x;
  920. }
  921. lisp
  922. Fbuffer_substring (lisp p1, lisp p2)
  923. {
  924. Buffer *bp = selected_buffer ();
  925. return bp->substring (bp->coerce_to_point (p1), bp->coerce_to_point (p2));
  926. }
  927. static int
  928. encoding_sjis_p (lisp encoding)
  929. {
  930. return (!char_encoding_p (encoding)
  931. || xchar_encoding_type (encoding) == encoding_auto_detect
  932. || xchar_encoding_type (encoding) == encoding_sjis);
  933. }
  934. static int
  935. encoding_utf16_p (lisp encoding)
  936. {
  937. return (char_encoding_p (encoding)
  938. && xchar_encoding_type (encoding) == encoding_utf16);
  939. }
  940. static void *
  941. galloc (CLIPBOARDTEXT &clp, int size)
  942. {
  943. clp.hgl = GlobalAlloc (GMEM_MOVEABLE, size);
  944. if (!clp.hgl)
  945. return 0;
  946. void *p = GlobalLock (clp.hgl);
  947. if (p)
  948. return p;
  949. GlobalFree (clp.hgl);
  950. clp.hgl = 0;
  951. return 0;
  952. }
  953. static int
  954. make_cf_text_sjis (CLIPBOARDTEXT &clp, lisp string)
  955. {
  956. const Char *s = xstring_contents (string);
  957. const Char *const se = s + xstring_length (string);
  958. int extra;
  959. for (extra = 0; s < se; s++)
  960. if (*s == '\n' || DBCP (*s))
  961. extra++;
  962. clp.fmt = CF_TEXT;
  963. char *b = (char *)galloc (clp, xstring_length (string) + extra + 1);
  964. if (!b)
  965. return 0;
  966. for (s = xstring_contents (string); s < se; s++)
  967. {
  968. Char cc = *s;
  969. if (DBCP (cc))
  970. {
  971. if (code_charset (cc) == ccs_cp932)
  972. *b++ = cc >> 8;
  973. else
  974. {
  975. Char c2 = wc2cp932 (i2w (cc));
  976. if (c2 != Char (-1))
  977. {
  978. cc = c2;
  979. if (DBCP (cc))
  980. *b++ = cc >> 8;
  981. }
  982. else
  983. cc = '?';
  984. }
  985. }
  986. else if (cc == '\n')
  987. *b++ = '\r';
  988. *b++ = char (cc);
  989. }
  990. *b = 0;
  991. GlobalUnlock (clp.hgl);
  992. return 1;
  993. }
  994. static int
  995. make_cf_text (CLIPBOARDTEXT &clp, lisp string, lisp encoding)
  996. {
  997. if (encoding_sjis_p (encoding))
  998. return make_cf_text_sjis (clp, string);
  999. Char_input_string_stream str1 (string);
  1000. encoding_output_stream_helper is1 (encoding, str1, eol_crlf);
  1001. int l = is1->total_length ();
  1002. clp.fmt = CF_TEXT;
  1003. char *b = (char *)galloc (clp, l + 1);
  1004. if (!b)
  1005. return 0;
  1006. Char_input_string_stream str2 (string);
  1007. encoding_output_stream_helper is2 (encoding, str2, eol_crlf);
  1008. is2->copyto ((u_char *)b, l + 1);
  1009. GlobalUnlock (clp.hgl);
  1010. return 1;
  1011. }
  1012. static int
  1013. make_cf_wtext (CLIPBOARDTEXT &clp, lisp string)
  1014. {
  1015. const Char *s = xstring_contents (string);
  1016. const Char *const se = s + xstring_length (string);
  1017. int extra;
  1018. for (extra = 0; s < se; s++)
  1019. if (*s == '\n')
  1020. extra++;
  1021. clp.fmt = CF_UNICODETEXT;
  1022. ucs2_t *b = (ucs2_t *)galloc (clp, (xstring_length (string) + extra + 1) * sizeof *b);
  1023. if (!b)
  1024. return 0;
  1025. for (s = xstring_contents (string); s < se; s++)
  1026. {
  1027. if (*s == '\n')
  1028. *b++ = '\r';
  1029. ucs2_t c = i2w (*s);
  1030. if (c == ucs2_t (-1))
  1031. {
  1032. if (utf16_undef_char_high_p (*s) && s < se - 1
  1033. && utf16_undef_char_low_p (s[1]))
  1034. {
  1035. c = utf16_undef_pair_to_ucs2 (*s, s[1]);
  1036. s++;
  1037. }
  1038. else
  1039. c = DEFCHAR;
  1040. }
  1041. *b++ = c;
  1042. }
  1043. *b = 0;
  1044. GlobalUnlock (clp.hgl);
  1045. return 1;
  1046. }
  1047. int
  1048. make_clipboard_text (CLIPBOARDTEXT &clp, lisp string, int req)
  1049. {
  1050. clp.hgl = 0;
  1051. clp.fmt = 0;
  1052. lisp encoding = symbol_value (Vclipboard_char_encoding, selected_buffer ());
  1053. if (req == CF_UNICODETEXT || encoding_utf16_p (encoding))
  1054. return make_cf_wtext (clp, string);
  1055. return make_cf_text (clp, string, encoding);
  1056. }
  1057. static int
  1058. open_clipboard (HWND hwnd)
  1059. {
  1060. for (int i = 0; i < 100; i++)
  1061. {
  1062. if (OpenClipboard (hwnd))
  1063. return 1;
  1064. Sleep (0);
  1065. }
  1066. return 0;
  1067. }
  1068. lisp
  1069. Fcopy_to_clipboard (lisp string)
  1070. {
  1071. check_string (string);
  1072. if (!xstring_length (string))
  1073. return Qnil;
  1074. CLIPBOARDTEXT clp[2];
  1075. bzero (clp, sizeof clp);
  1076. if (!make_clipboard_text (clp[0], string, 0))
  1077. FEstorage_error ();
  1078. if (clp[0].fmt == CF_UNICODETEXT && !sysdep.WinNTp ()
  1079. && !make_cf_text_sjis (clp[1], string))
  1080. {
  1081. GlobalFree (clp[0].hgl);
  1082. FEstorage_error ();
  1083. }
  1084. int result = 0;
  1085. if (open_clipboard (active_app_frame().toplev))
  1086. {
  1087. if (EmptyClipboard ())
  1088. for (int i = 0; i < numberof (clp) && clp[i].hgl; i++)
  1089. {
  1090. if (!SetClipboardData (clp[i].fmt, clp[i].hgl))
  1091. break;
  1092. result = 1;
  1093. clp[i].hgl = 0;
  1094. }
  1095. CloseClipboard ();
  1096. }
  1097. for (int i = 0; i < numberof (clp); i++)
  1098. if (clp[i].hgl)
  1099. GlobalFree (clp[i].hgl);
  1100. xsymbol_value (Vclipboard_newer_than_kill_ring_p) = Qnil;
  1101. xsymbol_value (Vkill_ring_newer_than_clipboard_p) = Qnil;
  1102. return boole (result);
  1103. }
  1104. static int
  1105. count_cf_text_length (const u_char *string)
  1106. {
  1107. int l = 0;
  1108. const u_char *s = string;
  1109. for (; *s;)
  1110. {
  1111. if (SJISP (*s))
  1112. {
  1113. if (!s[1])
  1114. {
  1115. s++;
  1116. break;
  1117. }
  1118. l++;
  1119. s += 2;
  1120. }
  1121. else
  1122. {
  1123. if (*s == '\r' && s[1] == '\n')
  1124. l++;
  1125. s++;
  1126. }
  1127. }
  1128. return s - string - l;
  1129. }
  1130. static int
  1131. make_string_from_cf_text_sjis (lisp lstring, const u_char *s)
  1132. {
  1133. int l = count_cf_text_length (s);
  1134. Char *b = (Char *)malloc (l * sizeof *b);
  1135. if (!b)
  1136. return 0;
  1137. xstring_contents (lstring) = b;
  1138. xstring_length (lstring) = l;
  1139. while (*s)
  1140. {
  1141. if (SJISP (*s))
  1142. {
  1143. if (!s[1])
  1144. {
  1145. *b = *s;
  1146. break;
  1147. }
  1148. *b++ = (*s << 8) | s[1];
  1149. s += 2;
  1150. }
  1151. else if (*s == '\r' && s[1] == '\n')
  1152. s++;
  1153. else
  1154. *b++ = *s++;
  1155. }
  1156. return 1;
  1157. }
  1158. static int
  1159. make_string_from_cf_text (lisp lstring, const u_char *s)
  1160. {
  1161. lisp encoding = symbol_value (Vclipboard_char_encoding, selected_buffer ());
  1162. if (encoding_sjis_p (encoding))
  1163. return make_string_from_cf_text_sjis (lstring, s);
  1164. int sl = strlen ((const char *)s);
  1165. xinput_strstream str1 ((const char *)s, sl);
  1166. encoding_input_stream_helper is1 (encoding, str1);
  1167. int l = is1->total_length ();
  1168. Char *b = (Char *)malloc (l * sizeof *b);
  1169. if (!b)
  1170. return 0;
  1171. xstring_contents (lstring) = b;
  1172. xinput_strstream str2 ((const char *)s, sl);
  1173. encoding_input_stream_helper is2 (encoding, str2);
  1174. int c;
  1175. while ((c = is2->get ()) != xstream::eof)
  1176. if (c != '\r')
  1177. *b++ = c;
  1178. else
  1179. while (1)
  1180. {
  1181. c = is2->get ();
  1182. if (c == '\n')
  1183. {
  1184. *b++ = c;
  1185. break;
  1186. }
  1187. *b++ = '\r';
  1188. if (c == xstream::eof)
  1189. goto eof;
  1190. if (c != '\r')
  1191. {
  1192. *b++ = c;
  1193. break;
  1194. }
  1195. }
  1196. eof:
  1197. xstring_length (lstring) = b - xstring_contents (lstring);
  1198. return 1;
  1199. }
  1200. static int
  1201. count_cf_wtext_length (const ucs2_t *string)
  1202. {
  1203. int l = 0;
  1204. const ucs2_t *s = string;
  1205. for (; *s; s++)
  1206. if (*s == '\r')
  1207. {
  1208. if (s[1] == '\n')
  1209. {
  1210. l--;
  1211. s++;
  1212. }
  1213. }
  1214. else if (w2i (*s) == Char (-1))
  1215. l++;
  1216. return s - string + l;
  1217. }
  1218. static int
  1219. make_string_from_cf_wtext (lisp lstring, const ucs2_t *s, int lang)
  1220. {
  1221. int l = count_cf_wtext_length (s);
  1222. Char *b = (Char *)malloc (l * sizeof *b);
  1223. if (!b)
  1224. return 0;
  1225. xstring_contents (lstring) = b;
  1226. xstring_length (lstring) = l;
  1227. const Char *const translate = cjk_translate_table (lang);
  1228. switch (lang)
  1229. {
  1230. case ENCODING_LANG_JP:
  1231. case ENCODING_LANG_JP2:
  1232. default:
  1233. {
  1234. int to_half = xsymbol_value (Vunicode_to_half_width) != Qnil;
  1235. for (; *s; s++)
  1236. if (*s != '\r' || s[1] != '\n')
  1237. {
  1238. Char cc;
  1239. if (to_half
  1240. || (cc = wc2cp932 (*s)) == Char (-1)
  1241. || ccs_1byte_94_charset_p (code_charset (cc)))
  1242. cc = w2i (*s);
  1243. if (cc == Char (-1))
  1244. {
  1245. *b++ = utf16_ucs2_to_undef_pair_high (*s);
  1246. *b++ = utf16_ucs2_to_undef_pair_low (*s);
  1247. }
  1248. else
  1249. *b++ = cc;
  1250. }
  1251. }
  1252. break;
  1253. case ENCODING_LANG_KR:
  1254. case ENCODING_LANG_CN_GB:
  1255. case ENCODING_LANG_CN_BIG5:
  1256. for (; *s; s++)
  1257. if (*s != '\r' || s[1] != '\n')
  1258. {
  1259. Char cc = w2i (*s);
  1260. if (cc == Char (-1))
  1261. {
  1262. *b++ = utf16_ucs2_to_undef_pair_high (*s);
  1263. *b++ = utf16_ucs2_to_undef_pair_low (*s);
  1264. }
  1265. else
  1266. {
  1267. if (!ccs_1byte_94_charset_p (code_charset (cc)))
  1268. {
  1269. Char t = translate[*s];
  1270. if (t != Char (-1))
  1271. cc = t;
  1272. }
  1273. *b++ = cc;
  1274. }
  1275. }
  1276. break;
  1277. case ENCODING_LANG_CN:
  1278. for (; *s; s++)
  1279. if (*s != '\r' || s[1] != '\n')
  1280. {
  1281. Char cc = w2i (*s);
  1282. if (cc == Char (-1))
  1283. {
  1284. *b++ = utf16_ucs2_to_undef_pair_high (*s);
  1285. *b++ = utf16_ucs2_to_undef_pair_low (*s);
  1286. }
  1287. else
  1288. {
  1289. if (!ccs_1byte_94_charset_p (code_charset (cc)))
  1290. {
  1291. Char t = wc2gb2312_table[*s];
  1292. if (t != Char (-1) || (t = wc2big5_table[*s]) != Char (-1))
  1293. cc = t;
  1294. }
  1295. *b++ = cc;
  1296. }
  1297. }
  1298. break;
  1299. }
  1300. return 1;
  1301. }
  1302. int
  1303. make_string_from_clipboard_text (lisp lstring, const void *data, UINT fmt, int lang)
  1304. {
  1305. switch (fmt)
  1306. {
  1307. case CF_TEXT:
  1308. return make_string_from_cf_text (lstring, (const u_char *)data);
  1309. case CF_UNICODETEXT:
  1310. return make_string_from_cf_wtext (lstring, (const ucs2_t *)data, lang);
  1311. default:
  1312. assert (0);
  1313. return 0;
  1314. }
  1315. }
  1316. static int
  1317. get_clipboatd_data (UINT fmt, lisp lstring, int lang)
  1318. {
  1319. HGLOBAL hgl = GetClipboardData (fmt);
  1320. if (!hgl)
  1321. return -1;
  1322. void *data = GlobalLock (hgl);
  1323. if (!data)
  1324. return 0;
  1325. int r = make_string_from_clipboard_text (lstring, data, fmt, lang);
  1326. GlobalUnlock (hgl);
  1327. return r;
  1328. }
  1329. lisp
  1330. Fget_clipboard_data ()
  1331. {
  1332. int result = -1;
  1333. lisp lstring = make_simple_string ();
  1334. if (open_clipboard (active_app_frame().toplev))
  1335. {
  1336. lisp encoding = symbol_value (Vclipboard_char_encoding,
  1337. selected_buffer ());
  1338. if (encoding_utf16_p (encoding))
  1339. result = get_clipboatd_data (CF_UNICODETEXT, lstring,
  1340. xchar_encoding_utf_cjk (encoding));
  1341. if (result == -1)
  1342. {
  1343. UINT fmt = 0;
  1344. while ((fmt = EnumClipboardFormats (fmt)))
  1345. if (fmt == CF_TEXT || fmt == CF_UNICODETEXT)
  1346. {
  1347. result = get_clipboatd_data (fmt, lstring, ENCODING_LANG_NIL);
  1348. break;
  1349. }
  1350. }
  1351. CloseClipboard ();
  1352. }
  1353. if (!result)
  1354. FEstorage_error ();
  1355. if (result == -1)
  1356. return Qnil;
  1357. return lstring;
  1358. }
  1359. lisp
  1360. Fclipboard_empty_p ()
  1361. {
  1362. return boole (!IsClipboardFormatAvailable (CF_TEXT)
  1363. && (sysdep.WinNTp ()
  1364. || !IsClipboardFormatAvailable (CF_UNICODETEXT)));
  1365. }
  1366. textprop *
  1367. Buffer::find_textprop (point_t point) const
  1368. {
  1369. for (textprop *p = textprop_head (point); p; p = p->t_next)
  1370. if (p->t_range.p2 > point)
  1371. return p;
  1372. return 0;
  1373. }
  1374. void
  1375. Buffer::textprop_adjust_insertion (point_t point, int size)
  1376. {
  1377. for (textprop *p = textprop_head (point); p; p = p->t_next)
  1378. if (p->t_range.p2 > point)
  1379. {
  1380. if (p->t_range.p1 > point)
  1381. p->t_range.p1 += size;
  1382. p->t_range.p2 += size;
  1383. while ((p = p->t_next))
  1384. {
  1385. p->t_range.p1 += size;
  1386. p->t_range.p2 += size;
  1387. }
  1388. break;
  1389. }
  1390. }
  1391. void
  1392. Buffer::textprop_adjust_deletion (point_t point, int size)
  1393. {
  1394. point_t pe = point + size;
  1395. for (textprop *p = textprop_head (point), *prev = 0, *next; p; prev = p, p = next)
  1396. {
  1397. next = p->t_next;
  1398. if (p->t_range.p1 >= pe)
  1399. {
  1400. do
  1401. {
  1402. p->t_range.p1 -= size;
  1403. p->t_range.p2 -= size;
  1404. }
  1405. while (p = p->t_next);
  1406. break;
  1407. }
  1408. if (p->t_range.p2 > point)
  1409. {
  1410. if (p->t_range.p1 > point)
  1411. p->t_range.p1 = max (point_t (p->t_range.p1 - size), point);
  1412. p->t_range.p2 = max (point_t (p->t_range.p2 - size), point);
  1413. if (p->t_range.p1 == p->t_range.p2)
  1414. {
  1415. free_textprop (p);
  1416. if (prev)
  1417. {
  1418. prev->t_next = next;
  1419. p = prev;
  1420. }
  1421. else
  1422. {
  1423. b_textprop = next;
  1424. p = 0;
  1425. }
  1426. }
  1427. }
  1428. }
  1429. }
  1430. static inline void
  1431. copy_textprop (const textprop *p, textprop *t)
  1432. {
  1433. t->t_attrib = p->t_attrib;
  1434. t->t_tag = p->t_tag;
  1435. }
  1436. textprop *
  1437. Buffer::add_textprop (point_t p1, point_t p2)
  1438. {
  1439. textprop *p , *prev;
  1440. for (p = textprop_head (p1), prev = 0; p; prev = p, p = p->t_next)
  1441. if (*p > p1)
  1442. break;
  1443. if (p && p->t_range.p1 == p1 && p->t_range.p2 == p2)
  1444. return p;
  1445. textprop *q = make_textprop ();
  1446. if (!q)
  1447. return 0;
  1448. q->t_range.p1 = p1;
  1449. q->t_range.p2 = p2;
  1450. textprop **pl = prev ? &prev->t_next : &b_textprop;
  1451. if (p)
  1452. {
  1453. if (p2 <= p->t_range.p1)
  1454. {
  1455. q->t_next = p;
  1456. *pl = q;
  1457. }
  1458. else if (p2 < p->t_range.p2)
  1459. {
  1460. if (p1 <= p->t_range.p1)
  1461. {
  1462. q->t_next = p;
  1463. p->t_range.p1 = p2;
  1464. *pl = q;
  1465. }
  1466. else
  1467. {
  1468. textprop *t = make_textprop ();
  1469. if (!t)
  1470. {
  1471. free_textprop (q);
  1472. return 0;
  1473. }
  1474. t->t_next = p->t_next;
  1475. q->t_next = t;
  1476. p->t_next = q;
  1477. t->t_range.p1 = p2;
  1478. t->t_range.p2 = p->t_range.p2;
  1479. p->t_range.p2 = p1;
  1480. copy_textprop (p, t);
  1481. }
  1482. }
  1483. else
  1484. {
  1485. if (p1 <= p->t_range.p1)
  1486. {
  1487. p->t_range.p1 = p1;
  1488. p->t_range.p2 = p2;
  1489. free_textprop (q);
  1490. q = p;
  1491. }
  1492. else
  1493. {
  1494. q->t_next = p->t_next;
  1495. p->t_next = q;
  1496. p->t_range.p2 = p1;
  1497. }
  1498. }
  1499. }
  1500. else
  1501. {
  1502. q->t_next = *pl;
  1503. *pl = q;
  1504. }
  1505. for (p = q->t_next; p && p->t_range.p1 < p2; p = q->t_next)
  1506. {
  1507. if (p->t_range.p2 > p2)
  1508. {
  1509. p->t_range.p1 = p2;
  1510. break;
  1511. }
  1512. q->t_next = p->t_next;
  1513. free_textprop (p);
  1514. }
  1515. return q;
  1516. }
  1517. static int
  1518. check_attrib (lisp lc1, lisp lc2, lisp bold, lisp underline, lisp strikeout, lisp lcc, lisp lextend)
  1519. {
  1520. int attrib = 0;
  1521. if (lc1 != Qnil)
  1522. attrib |= ((fixnum_value (lc1) & (GLYPH_TEXTPROP_NCOLORS - 1))
  1523. << GLYPH_TEXTPROP_FG_SHIFT_BITS);
  1524. if (lc2 != Qnil)
  1525. attrib |= ((fixnum_value (lc2) & (GLYPH_TEXTPROP_NCOLORS - 1))
  1526. << GLYPH_TEXTPROP_BG_SHIFT_BITS);
  1527. if (bold != Qnil)
  1528. attrib |= GLYPH_BOLD;
  1529. if (underline != Qnil)
  1530. attrib |= GLYPH_UNDERLINE;
  1531. if (strikeout != Qnil)
  1532. attrib |= GLYPH_STRIKEOUT;
  1533. if (lcc != Qnil)
  1534. {
  1535. check_char (lcc);
  1536. int cc = xchar_code (lcc);
  1537. if (cc > ' ' && cc < 0x7f)
  1538. attrib |= cc;
  1539. }
  1540. if (lextend != Qnil)
  1541. attrib |= TEXTPROP_EXTEND_EOL_BIT;
  1542. return attrib;
  1543. }
  1544. static int
  1545. attrib_value (lisp keys)
  1546. {
  1547. return check_attrib (find_keyword (Kforeground, keys, Qnil),
  1548. find_keyword (Kbackground, keys, Qnil),
  1549. find_keyword (Kbold, keys, Qnil),
  1550. find_keyword (Kunderline, keys, Qnil),
  1551. find_keyword (Kstrike_out, keys, Qnil),
  1552. find_keyword (Kprefix, keys, Qnil),
  1553. find_keyword (Kextend, keys, Qnil));
  1554. }
  1555. static lisp
  1556. set_text_attribute (lisp lp1, lisp lp2, lisp tag, int attrib)
  1557. {
  1558. Buffer *bp = selected_buffer ();
  1559. point_t p1 = bp->coerce_to_restricted_point (lp1);
  1560. point_t p2 = bp->coerce_to_restricted_point (lp2);
  1561. if (p1 > p2)
  1562. swap (p1, p2);
  1563. textprop *p = bp->add_textprop (p1, p2);
  1564. if (!p)
  1565. FEstorage_error ();
  1566. p->t_attrib = attrib;
  1567. p->t_tag = tag;
  1568. bp->b_textprop_cache = p;
  1569. bp->set_modified_region (p1, p2);
  1570. return Qt;
  1571. }
  1572. lisp
  1573. Fset_text_attribute (lisp lp1, lisp lp2, lisp tag, lisp keys)
  1574. {
  1575. return set_text_attribute (lp1, lp2, tag, attrib_value (keys));
  1576. }
  1577. lisp
  1578. Fclear_all_text_attributes ()
  1579. {
  1580. Buffer *bp = selected_buffer ();
  1581. if (bp->b_textprop)
  1582. {
  1583. bp->b_textprop_heap.free_all ();
  1584. bp->b_textprop = 0;
  1585. bp->b_textprop_cache = 0;
  1586. bp->refresh_buffer ();
  1587. }
  1588. return Qt;
  1589. }
  1590. static lisp
  1591. delete_text_attributes (test_proc &test)
  1592. {
  1593. Buffer *bp = selected_buffer ();
  1594. for (textprop *t = bp->b_textprop, *prev = 0, *next; t; t = next)
  1595. {
  1596. next = t->t_next;
  1597. if (test.test (t->t_tag))
  1598. {
  1599. if (prev)
  1600. {
  1601. prev->t_next = next;
  1602. bp->b_textprop_cache = prev;
  1603. }
  1604. else
  1605. {
  1606. bp->b_textprop = next;
  1607. if (bp->b_textprop_cache == t)
  1608. bp->b_textprop_cache = 0;
  1609. }
  1610. bp->free_textprop (t);
  1611. }
  1612. else
  1613. prev = t;
  1614. }
  1615. bp->refresh_buffer ();
  1616. return Qt;
  1617. }
  1618. lisp
  1619. Fdelete_text_attributes (lisp tag, lisp keys)
  1620. {
  1621. seq_testproc test (tag, keys);
  1622. return delete_text_attributes (test);
  1623. }
  1624. lisp
  1625. Fdelete_text_attributes_if (lisp pred, lisp keys)
  1626. {
  1627. seq_testproc_if test (pred, keys);
  1628. return delete_text_attributes (test);
  1629. }
  1630. lisp
  1631. Fdelete_text_attributes_if_not (lisp pred, lisp keys)
  1632. {
  1633. seq_testproc_if_not test (pred, keys);
  1634. return delete_text_attributes (test);
  1635. }
  1636. lisp
  1637. Fdelete_text_attribute_point (lisp lpoint)
  1638. {
  1639. Buffer *bp = selected_buffer ();
  1640. point_t point = bp->coerce_to_point (lpoint);
  1641. for (textprop *t = bp->b_textprop, *prev = 0;
  1642. t && t->t_range.p1 <= point; prev = t, t = t->t_next)
  1643. if (*t > point)
  1644. {
  1645. if (prev)
  1646. {
  1647. prev->t_next = t->t_next;
  1648. bp->b_textprop_cache = prev;
  1649. }
  1650. else
  1651. {
  1652. bp->b_textprop = t->t_next;
  1653. if (bp->b_textprop_cache == t)
  1654. bp->b_textprop_cache = 0;
  1655. }
  1656. bp->set_modified_region (t->t_range.p1, t->t_range.p2);
  1657. bp->free_textprop (t);
  1658. return Qt;
  1659. }
  1660. return Qnil;
  1661. }
  1662. lisp
  1663. Ffind_text_attribute_point (lisp lpoint)
  1664. {
  1665. Buffer *bp = selected_buffer ();
  1666. point_t point = bp->coerce_to_point (lpoint);
  1667. for (textprop *t = bp->textprop_head (point);
  1668. t && t->t_range.p1 <= point; t = t->t_next)
  1669. if (*t > point)
  1670. {
  1671. int attrib = t->t_attrib;
  1672. multiple_value::count () = 10;
  1673. multiple_value::value (9) = boole (attrib & TEXTPROP_EXTEND_EOL_BIT);
  1674. multiple_value::value (8) = attrib & 0xff ? make_char (attrib & 0xff) : Qnil;
  1675. multiple_value::value (7) = boole (attrib & GLYPH_STRIKEOUT);
  1676. multiple_value::value (6) = boole (attrib & GLYPH_UNDERLINE);
  1677. multiple_value::value (5) = boole (attrib & GLYPH_BOLD);
  1678. multiple_value::value (4) = (attrib & ((GLYPH_TEXTPROP_NCOLORS - 1)
  1679. << GLYPH_TEXTPROP_BG_SHIFT_BITS)
  1680. ? make_fixnum ((attrib >> GLYPH_TEXTPROP_BG_SHIFT_BITS)
  1681. & (GLYPH_TEXTPROP_NCOLORS - 1))
  1682. : Qnil);
  1683. multiple_value::value (3) = (attrib & ((GLYPH_TEXTPROP_NCOLORS - 1)
  1684. << GLYPH_TEXTPROP_FG_SHIFT_BITS)
  1685. ? make_fixnum ((attrib >> GLYPH_TEXTPROP_FG_SHIFT_BITS)
  1686. & (GLYPH_TEXTPROP_NCOLORS - 1))
  1687. : Qnil);
  1688. multiple_value::value (2) = t->t_tag;
  1689. multiple_value::value (1) = make_fixnum (t->t_range.p2);
  1690. return make_fixnum (t->t_range.p1);
  1691. }
  1692. return Qnil;
  1693. }
  1694. static lisp
  1695. find_text_attribute (test_proc &test, lisp keys)
  1696. {
  1697. Buffer *bp = selected_buffer ();
  1698. lisp lstart = find_keyword (Kstart, keys, Qnil);
  1699. lisp lend = find_keyword (Kend, keys, Qnil);
  1700. lisp from_end = find_keyword (Kfrom_end, keys, Qnil);
  1701. point_t start = lstart == Qnil ? bp->b_contents.p1 : bp->coerce_to_point (lstart);
  1702. point_t end = lend == Qnil ? bp->b_contents.p2: bp->coerce_to_point (lend);
  1703. textprop *match = 0;
  1704. if (from_end == Qnil)
  1705. {
  1706. for (textprop *t = bp->textprop_head (start); t && *t < end; t = t->t_next)
  1707. if (t->t_range.p1 >= start && test.test (t->t_tag))
  1708. {
  1709. match = t;
  1710. break;
  1711. }
  1712. }
  1713. else
  1714. {
  1715. for (textprop *t = bp->textprop_head (start); t && *t < end; t = t->t_next)
  1716. if (t->t_range.p1 >= start && test.test (t->t_tag))
  1717. match = t;
  1718. }
  1719. if (!match)
  1720. return Qnil;
  1721. multiple_value::count () = 3;
  1722. multiple_value::value (2) = match->t_tag;
  1723. multiple_value::value (1) = make_fixnum (match->t_range.p2);
  1724. return make_fixnum (match->t_range.p1);
  1725. }
  1726. lisp
  1727. Ffind_text_attribute (lisp tag, lisp keys)
  1728. {
  1729. seq_testproc test (tag, keys);
  1730. return find_text_attribute (test, keys);
  1731. }
  1732. lisp
  1733. Ffind_text_attribute_if (lisp pred, lisp keys)
  1734. {
  1735. seq_testproc_if test (pred, keys);
  1736. return find_text_attribute (test, keys);
  1737. }
  1738. lisp
  1739. Ffind_text_attribute_if_not (lisp pred, lisp keys)
  1740. {
  1741. seq_testproc_if_not test (pred, keys);
  1742. return find_text_attribute (test, keys);
  1743. }
  1744. static lisp
  1745. modify_text_attributes (test_proc &test, lisp keys)
  1746. {
  1747. int attrib = attrib_value (keys);
  1748. Buffer *bp = selected_buffer ();
  1749. lisp lstart = find_keyword (Kstart, keys, Qnil);
  1750. lisp lend = find_keyword (Kend, keys, Qnil);
  1751. point_t start = lstart == Qnil ? bp->b_contents.p1 : bp->coerce_to_point (lstart);
  1752. point_t end = lend == Qnil ? bp->b_contents.p2: bp->coerce_to_point (lend);
  1753. for (textprop *t = bp->textprop_head (start); t && *t < end; t = t->t_next)
  1754. if (t->t_range.p1 >= start && test.test (t->t_tag))
  1755. t->t_attrib = attrib;
  1756. bp->refresh_buffer ();
  1757. return Qt;
  1758. }
  1759. lisp
  1760. Fmodify_text_attributes (lisp tag, lisp keys)
  1761. {
  1762. seq_testproc test (tag, keys);
  1763. return modify_text_attributes (test, keys);
  1764. }
  1765. lisp
  1766. Fmodify_text_attributes_if (lisp pred, lisp keys)
  1767. {
  1768. seq_testproc_if test (pred, keys);
  1769. return modify_text_attributes (test, keys);
  1770. }
  1771. lisp
  1772. Fmodify_text_attributes_if_not (lisp pred, lisp keys)
  1773. {
  1774. seq_testproc_if_not test (pred, keys);
  1775. return modify_text_attributes (test, keys);
  1776. }
  1777. static lisp
  1778. push_attrib (lisp x, lisp key, lisp value)
  1779. {
  1780. return xcons (key, xcons (value, x));
  1781. }
  1782. lisp
  1783. Flist_text_attributes (lisp lstart, lisp lend)
  1784. {
  1785. Buffer *bp = selected_buffer ();
  1786. point_t start = (lstart && lstart != Qnil
  1787. ? bp->coerce_to_point (lstart)
  1788. : bp->b_contents.p1);
  1789. point_t end = (lend && lend != Qnil
  1790. ? bp->coerce_to_point (lend)
  1791. : bp->b_contents.p2);
  1792. lisp r = Qnil;
  1793. for (const textprop *t = bp->b_textprop; t && *t < end; t = t->t_next)
  1794. if (*t > start)
  1795. {
  1796. lisp x = Qnil;
  1797. int attrib = t->t_attrib;

Large files files are truncated, but you can click here to view the full file