PageRenderTime 56ms CodeModel.GetById 20ms RepoModel.GetById 0ms app.codeStats 0ms

/src/string.cc

https://github.com/snmsts/xyzzy
C++ | 1304 lines | 1181 code | 123 blank | 0 comment | 251 complexity | 1d64e80f956bb363b2c49c309e17b9d5 MD5 | raw file
Possible License(s): BSD-3-Clause
  1. #include "stdafx.h"
  2. #include "ed.h"
  3. #include "byte-stream.h"
  4. #include "sequence.h"
  5. #include "StrBuf.h"
  6. int
  7. update_column (int column, Char c)
  8. {
  9. if (c == '\n')
  10. column = 0;
  11. else if (c == '\t')
  12. column = ((column + app.default_tab_columns)
  13. / app.default_tab_columns * app.default_tab_columns);
  14. else
  15. column += char_width (c);
  16. return column;
  17. }
  18. int
  19. update_column (int column, const Char *s, int size)
  20. {
  21. for (const Char *se = s + size; s < se; s++)
  22. column = update_column (column, *s);
  23. return column;
  24. }
  25. int
  26. update_column (int column, Char c, int size)
  27. {
  28. if (size)
  29. {
  30. if (c == '\n')
  31. column = 0;
  32. else if (c == '\t')
  33. column = ((column + app.default_tab_columns) / app.default_tab_columns
  34. * app.default_tab_columns
  35. + (size - 1) * app.default_tab_columns);
  36. else
  37. column += char_width (c) * size;
  38. }
  39. return column;
  40. }
  41. size_t
  42. s2wl (const char *string)
  43. {
  44. size_t l = 0;
  45. const u_char *s = (const u_char *)string;
  46. while (*s)
  47. {
  48. if (SJISP (*s))
  49. {
  50. if (!s[1])
  51. {
  52. s++;
  53. break;
  54. }
  55. l++;
  56. s += 2;
  57. }
  58. else
  59. s++;
  60. }
  61. return s - (const u_char *)string - l;
  62. }
  63. Char *
  64. s2w (Char *b, size_t size, const char **string)
  65. {
  66. Char *be = b + size;
  67. const u_char *s = (const u_char *)*string;
  68. while (b < be && *s)
  69. {
  70. if (SJISP (*s))
  71. {
  72. if (!s[1])
  73. {
  74. *b++ = *s++;
  75. break;
  76. }
  77. *b++ = (*s << 8) | s[1];
  78. s += 2;
  79. }
  80. else
  81. *b++ = *s++;
  82. }
  83. *string = (const char *)s;
  84. return b;
  85. }
  86. Char *
  87. s2w (Char *b, const char *string)
  88. {
  89. const u_char *s = (const u_char *)string;
  90. while (*s)
  91. {
  92. if (SJISP (*s))
  93. {
  94. if (!s[1])
  95. {
  96. *b = *s;
  97. break;
  98. }
  99. *b++ = (*s << 8) | s[1];
  100. s += 2;
  101. }
  102. else
  103. *b++ = *s++;
  104. }
  105. return b;
  106. }
  107. Char *
  108. s2w (const char *string, size_t size)
  109. {
  110. Char *b = (Char *)xmalloc (sizeof (Char) * size);
  111. s2w (b, string);
  112. return b;
  113. }
  114. void
  115. a2w (Char *b, const char *string, size_t size)
  116. {
  117. const u_char *s = (const u_char *)string;
  118. const u_char *se = s + size;
  119. while (s < se)
  120. *b++ = *s++;
  121. }
  122. Char *
  123. a2w (Char *b, size_t size, const char **string)
  124. {
  125. Char *be = b + size;
  126. const u_char *s = (const u_char *)*string;
  127. while (b < be && *s)
  128. *b++ = *s++;
  129. *string = (const char *)s;
  130. return b;
  131. }
  132. Char *
  133. a2w (Char *b, const char *string)
  134. {
  135. for (const u_char *s = (const u_char *)string; *s;)
  136. *b++ = *s++;
  137. return b;
  138. }
  139. Char *
  140. a2w (const char *string, size_t size)
  141. {
  142. Char *b = (Char *)xmalloc (sizeof (Char) * size);
  143. a2w (b, string, size);
  144. return b;
  145. }
  146. size_t
  147. w2sl (const Char *s, size_t size)
  148. {
  149. size_t l = 0;
  150. for (const Char *se = s + size; s < se; s++)
  151. if (DBCP (*s))
  152. l++;
  153. return size + l;
  154. }
  155. char *
  156. w2s (char *b, const Char *s, size_t size)
  157. {
  158. for (const Char *se = s + size; s < se; s++)
  159. {
  160. if (DBCP (*s))
  161. *b++ = *s >> 8;
  162. *b++ = char (*s);
  163. }
  164. *b = 0;
  165. return b;
  166. }
  167. char *
  168. w2s (const Char *s, size_t size)
  169. {
  170. char *b = (char *)xmalloc (w2sl (s, size) + 1);
  171. w2s (b, s, size);
  172. return b;
  173. }
  174. char *
  175. w2s (char *b, char *be, const Char *s, size_t size)
  176. {
  177. be--;
  178. for (const Char *se = s + size; s < se && b < be; s++)
  179. {
  180. if (DBCP (*s))
  181. {
  182. if (b == be - 1)
  183. break;
  184. *b++ = *s >> 8;
  185. }
  186. *b++ = char (*s);
  187. }
  188. *b = 0;
  189. return b;
  190. }
  191. char *
  192. w2s_quote (char *b, char *be, const Char *s, size_t size, int qc, int qe)
  193. {
  194. be--;
  195. for (const Char *se = s + size; s < se && b < be; s++)
  196. {
  197. if (DBCP (*s))
  198. {
  199. if (b == be - 1)
  200. break;
  201. *b++ = *s >> 8;
  202. }
  203. else if (*s == qc)
  204. {
  205. if (b == be - 1)
  206. break;
  207. *b++ = qe;
  208. }
  209. *b++ = char (*s);
  210. }
  211. *b = 0;
  212. return b;
  213. }
  214. size_t
  215. s2wl (const char *string, const char *se, int zero_term)
  216. {
  217. size_t l = 0;
  218. const u_char *s = (const u_char *)string;
  219. while (s < (const u_char *)se && (!zero_term || *s))
  220. {
  221. if (SJISP (*s))
  222. {
  223. if (s + 1 >= (const u_char *)se || (zero_term && !s[1]))
  224. {
  225. s++;
  226. break;
  227. }
  228. l++;
  229. s += 2;
  230. }
  231. else
  232. s++;
  233. }
  234. return s - (const u_char *)string - l;
  235. }
  236. Char *
  237. s2w (Char *b, const char *string, const char *se, int zero_term)
  238. {
  239. const u_char *s = (const u_char *)string;
  240. while (s < (const u_char *)se && (!zero_term || *s))
  241. {
  242. if (SJISP (*s))
  243. {
  244. if (s + 1 >= (const u_char *)se || (zero_term && !s[1]))
  245. {
  246. *b = *s;
  247. break;
  248. }
  249. *b++ = (*s << 8) | s[1];
  250. s += 2;
  251. }
  252. else
  253. *b++ = *s++;
  254. }
  255. return b;
  256. }
  257. void
  258. w2s_chunk (char *b, char *be, const Char *s, size_t size)
  259. {
  260. for (const Char *se = s + size; s < se && b < be; s++)
  261. {
  262. if (DBCP (*s))
  263. {
  264. if (b == be - 1)
  265. break;
  266. *b++ = *s >> 8;
  267. }
  268. *b++ = char (*s);
  269. }
  270. if (b < be)
  271. *b = 0;
  272. }
  273. lisp
  274. make_string (const u_char *string)
  275. {
  276. return make_string ((const char *)string);
  277. }
  278. lisp
  279. make_string (const char *string)
  280. {
  281. lisp p = make_simple_string ();
  282. size_t size = s2wl (string);
  283. xstring_contents (p) = s2w (string, size);
  284. xstring_length (p) = size;
  285. return p;
  286. }
  287. lisp
  288. make_string (const char *string, size_t size)
  289. {
  290. lisp p = make_simple_string ();
  291. Char *b = (Char *)xmalloc (size * sizeof (Char));
  292. xstring_contents (p) = b;
  293. xstring_length (p) = size;
  294. s2w (b, size, &string);
  295. return p;
  296. }
  297. lisp
  298. make_string_simple (const char *string, size_t size)
  299. {
  300. lisp p = make_simple_string ();
  301. xstring_contents (p) = a2w (string, size);
  302. xstring_length (p) = size;
  303. return p;
  304. }
  305. lisp
  306. make_string (const Char *string, size_t size)
  307. {
  308. lisp p = make_simple_string ();
  309. xstring_contents (p) = (Char *)xmemdup (string, size * sizeof (Char));
  310. xstring_length (p) = size;
  311. return p;
  312. }
  313. lisp
  314. copy_string (lisp p)
  315. {
  316. assert (stringp (p));
  317. return make_string (xstring_contents (p), xstring_length (p));
  318. }
  319. lisp
  320. make_string (Char c, size_t size)
  321. {
  322. lisp p = make_simple_string ();
  323. Char *d = (Char *)xmalloc (size * sizeof (Char));
  324. xstring_contents (p) = d;
  325. xstring_length (p) = size;
  326. bfill (d, int (size), c);
  327. return p;
  328. }
  329. lisp
  330. make_complex_string (Char c, int fillp, int size, int adjustable)
  331. {
  332. assert (fillp <= size);
  333. lisp p = make_complex_string ();
  334. Char *d = (Char *)xmalloc (size * sizeof (Char));
  335. xstring_contents (p) = d;
  336. xstring_length (p) = fillp >= 0 ? fillp : size;
  337. xstring_dimension (p) = size;
  338. xarray_adjustable (p) = adjustable;
  339. xarray_has_fillp (p) = fillp >= 0;
  340. bfill (d, size, c);
  341. return p;
  342. }
  343. lisp
  344. make_string (size_t size)
  345. {
  346. lisp p = make_simple_string ();
  347. xstring_contents (p) = (Char *)xmalloc (size * sizeof (Char));
  348. xstring_length (p) = size;
  349. return p;
  350. }
  351. lisp
  352. make_string_from_list (lisp list)
  353. {
  354. int l = 0;
  355. for (lisp x = list; consp (x); x = xcdr (x), l++)
  356. check_char (xcar (x));
  357. lisp string = make_string (l);
  358. Char *s = xstring_contents (string);
  359. for (lisp x = list; consp (x); x = xcdr (x))
  360. *s++ = xchar_code (xcar (x));
  361. return string;
  362. }
  363. lisp
  364. make_string_from_vector (lisp vector)
  365. {
  366. assert (general_vector_p (vector));
  367. lisp *p, *pe;
  368. for (p = xvector_contents (vector), pe = p + xvector_length (vector); p < pe; p++)
  369. check_char (*p);
  370. lisp string = make_string (xvector_length (vector));
  371. Char *s = xstring_contents (string);
  372. for (p = xvector_contents (vector); p < pe; p++)
  373. *s++ = xchar_code (*p);
  374. return string;
  375. }
  376. int
  377. string_equalp (const Char *p1, int l1, const char *p2, int l2)
  378. {
  379. if (l1 != l2)
  380. return 0;
  381. for (const Char *pe = p1 + l1; p1 < pe; p1++, p2++)
  382. if (char_upcase (*p1) != char_upcase (*p2))
  383. return 0;
  384. return 1;
  385. }
  386. int
  387. string_equalp (const Char *p1, int l1, const Char *p2, int l2)
  388. {
  389. if (l1 != l2)
  390. return 0;
  391. for (const Char *pe = p1 + l1; p1 < pe; p1++, p2++)
  392. if (char_upcase (*p1) != char_upcase (*p2))
  393. return 0;
  394. return 1;
  395. }
  396. int
  397. string_equalp (lisp x, int xo, lisp y, int yo, int l)
  398. {
  399. if (xo + l > xstring_length (x) || yo + l > xstring_length (y))
  400. return 0;
  401. return string_equalp (xstring_contents (x) + xo, l,
  402. xstring_contents (y) + yo, l);
  403. }
  404. lisp
  405. coerce_to_string (lisp x, int copy)
  406. {
  407. if (immediatep (x))
  408. {
  409. if (charp (x))
  410. {
  411. Char c = xchar_code (x);
  412. return make_string (&c, 1);
  413. }
  414. }
  415. else
  416. {
  417. switch (object_typeof (x))
  418. {
  419. case Tsimple_string:
  420. case Tcomplex_string:
  421. return copy ? copy_string (x) : x;
  422. case Tsymbol:
  423. return copy ? Fcopy_string (xsymbol_name (x)) : xsymbol_name (x);
  424. case Tsimple_vector:
  425. case Tcomplex_vector:
  426. return make_string_from_vector (x);
  427. }
  428. }
  429. return FEtype_error (x, Qstring);
  430. }
  431. void
  432. string_start_end (lisp string, int &start, int &end, lisp lstart, lisp lend)
  433. {
  434. check_string (string);
  435. seq_start_end (xstring_length (string), start, end, lstart, lend);
  436. }
  437. lisp
  438. Fcopy_string (lisp string)
  439. {
  440. check_string (string);
  441. return copy_string (string);
  442. }
  443. lisp
  444. Fchar (lisp string, lisp index)
  445. {
  446. check_string (string);
  447. int i = fixnum_value (index);
  448. if (i < 0 || i >= xstring_length (string))
  449. FErange_error (index);
  450. return make_char (xstring_contents (string) [i]);
  451. }
  452. lisp
  453. Fsi_set_char (lisp string, lisp index, lisp value)
  454. {
  455. check_string (string);
  456. check_char (value);
  457. int i = fixnum_value (index);
  458. if (i < 0 || i >= xstring_length (string))
  459. FErange_error (index);
  460. xstring_contents (string) [i] = xchar_code (value);
  461. return value;
  462. }
  463. lisp
  464. Fschar (lisp string, lisp index)
  465. {
  466. check_simple_string (string);
  467. int i = fixnum_value (index);
  468. if (i < 0 || i >= xstring_length (string))
  469. FErange_error (index);
  470. return make_char (xstring_contents (string) [i]);
  471. }
  472. lisp
  473. Fsi_set_schar (lisp string, lisp index, lisp value)
  474. {
  475. check_simple_string (string);
  476. check_char (value);
  477. int i = fixnum_value (index);
  478. if (i < 0 || i >= xstring_length (string))
  479. FErange_error (index);
  480. xstring_contents (string) [i] = xchar_code (value);
  481. return value;
  482. }
  483. static const Char *
  484. string_compare1 (lisp string1, lisp string2, lisp keys,
  485. const Char *&p, const Char *&pe,
  486. const Char *&q, const Char *&qe)
  487. {
  488. string1 = coerce_to_string (string1, 0);
  489. int start1, end1;
  490. string_start_end (string1, start1, end1,
  491. find_keyword (Kstart1, keys, make_fixnum (0)),
  492. find_keyword (Kend1, keys, Qnil));
  493. string2 = coerce_to_string (string2, 0);
  494. int start2, end2;
  495. string_start_end (string2, start2, end2,
  496. find_keyword (Kstart2, keys, make_fixnum (0)),
  497. find_keyword (Kend2, keys, Qnil));
  498. p = xstring_contents (string1) + start1;
  499. pe = xstring_contents (string1) + end1;
  500. q = xstring_contents (string2) + start2;
  501. qe = xstring_contents (string2) + end2;
  502. return xstring_contents (string1);
  503. }
  504. static int
  505. string_compare (lisp string1, lisp string2, lisp keys, int &l)
  506. {
  507. const Char *p, *pe, *q, *qe;
  508. const Char *p0 = string_compare1 (string1, string2, keys, p, pe, q, qe);
  509. while (1)
  510. {
  511. if (p == pe)
  512. {
  513. l = p - p0;
  514. return q == qe ? 0 : -1;
  515. }
  516. if (q == qe)
  517. {
  518. l = p - p0;
  519. return 1;
  520. }
  521. if (*p != *q)
  522. {
  523. l = p - p0;
  524. return *p - *q;
  525. }
  526. p++;
  527. q++;
  528. }
  529. }
  530. static int
  531. string_comparep (lisp string1, lisp string2, lisp keys, int &l)
  532. {
  533. const Char *p, *pe, *q, *qe;
  534. const Char *p0 = string_compare1 (string1, string2, keys, p, pe, q, qe);
  535. while (1)
  536. {
  537. if (p == pe)
  538. {
  539. l = p - p0;
  540. return q == qe ? 0 : -1;
  541. }
  542. if (q == qe)
  543. {
  544. l = p - p0;
  545. return 1;
  546. }
  547. Char c1 = char_upcase (*p);
  548. Char c2 = char_upcase (*q);
  549. if (c1 != c2)
  550. {
  551. l = p - p0;
  552. return c1 - c2;
  553. }
  554. p++;
  555. q++;
  556. }
  557. }
  558. lisp
  559. Fstring_equal (lisp x, lisp y, lisp keys)
  560. {
  561. const Char *p, *pe, *q, *qe;
  562. string_compare1 (x, y, keys, p, pe, q, qe);
  563. return boole (pe - p == qe - q && !bcmp (p, q, pe - p));
  564. }
  565. lisp
  566. Fstring_equalp (lisp x, lisp y, lisp keys)
  567. {
  568. const Char *p, *pe, *q, *qe;
  569. string_compare1 (x, y, keys, p, pe, q, qe);
  570. return boole (string_equalp (p, pe - p, q, qe - q));
  571. }
  572. lisp
  573. Fstring_not_equal (lisp x, lisp y, lisp keys)
  574. {
  575. int l;
  576. return string_compare (x, y, keys, l) ? make_fixnum (l) : Qnil;
  577. }
  578. lisp
  579. Fstring_not_equalp (lisp x, lisp y, lisp keys)
  580. {
  581. int l;
  582. return string_comparep (x, y, keys, l) ? make_fixnum (l) : Qnil;
  583. }
  584. lisp
  585. Fstring_less (lisp x, lisp y, lisp keys)
  586. {
  587. int l;
  588. return string_compare (x, y, keys, l) < 0 ? make_fixnum (l) : Qnil;
  589. }
  590. lisp
  591. Fstring_lessp (lisp x, lisp y, lisp keys)
  592. {
  593. int l;
  594. return string_comparep (x, y, keys, l) < 0 ? make_fixnum (l) : Qnil;
  595. }
  596. lisp
  597. Fstring_greater (lisp x, lisp y, lisp keys)
  598. {
  599. int l;
  600. return string_compare (x, y, keys, l) > 0 ? make_fixnum (l) : Qnil;
  601. }
  602. lisp
  603. Fstring_greaterp (lisp x, lisp y, lisp keys)
  604. {
  605. int l;
  606. return string_comparep (x, y, keys, l) > 0 ? make_fixnum (l) : Qnil;
  607. }
  608. lisp
  609. Fstring_not_greater (lisp x, lisp y, lisp keys)
  610. {
  611. int l;
  612. return string_compare (x, y, keys, l) <= 0 ? make_fixnum (l) : Qnil;
  613. }
  614. lisp
  615. Fstring_not_greaterp (lisp x, lisp y, lisp keys)
  616. {
  617. int l;
  618. return string_comparep (x, y, keys, l) <= 0 ? make_fixnum (l) : Qnil;
  619. }
  620. lisp
  621. Fstring_not_less (lisp x, lisp y, lisp keys)
  622. {
  623. int l;
  624. return string_compare (x, y, keys, l) >= 0 ? make_fixnum (l) : Qnil;
  625. }
  626. lisp
  627. Fstring_not_lessp (lisp x, lisp y, lisp keys)
  628. {
  629. int l;
  630. return string_comparep (x, y, keys, l) >= 0 ? make_fixnum (l) : Qnil;
  631. }
  632. lisp
  633. subseq_string (lisp string, lisp lstart, lisp lend)
  634. {
  635. int start, end;
  636. string_start_end (string, start, end, lstart, lend);
  637. return make_string (xstring_contents (string) + start, end - start);
  638. }
  639. lisp
  640. Fsubstring (lisp string, lisp lstart, lisp lend)
  641. {
  642. check_string (string);
  643. int len = xstring_length (string);
  644. int start = fixnum_value (lstart);
  645. int end = lend && lend != Qnil ? fixnum_value (lend) : len;
  646. if (start < 0)
  647. start += len;
  648. if (end < 0)
  649. end += len;
  650. if (start < 0 || start > end)
  651. FErange_error (lstart);
  652. if (end > len)
  653. FErange_error (lend);
  654. return make_string (xstring_contents (string) + start, end - start);
  655. }
  656. static inline int
  657. match_char_bag (Char c, lisp bag)
  658. {
  659. assert (stringp (bag));
  660. for (const Char *p = xstring_contents (bag), *pe = p + xstring_length (bag);
  661. p < pe; p++)
  662. if (c == *p)
  663. return 1;
  664. return 0;
  665. }
  666. static const Char *
  667. left_trim (const Char *p0, int l, lisp bag)
  668. {
  669. const Char *p, *pe;
  670. for (p = p0, pe = p + l; p < pe; p++)
  671. if (!match_char_bag (*p, bag))
  672. break;
  673. return p;
  674. }
  675. static const Char *
  676. right_trim (const Char *p0, int l, lisp bag)
  677. {
  678. const Char *p;
  679. for (p = p0 + l; p > p0; p--)
  680. if (!match_char_bag (p[-1], bag))
  681. break;
  682. return p;
  683. }
  684. static inline int
  685. left_trim (lisp string, lisp bag)
  686. {
  687. assert (stringp (string));
  688. return (left_trim (xstring_contents (string), xstring_length (string), bag)
  689. - xstring_contents (string));
  690. }
  691. static inline int
  692. right_trim (lisp string, lisp bag)
  693. {
  694. assert (stringp (string));
  695. return (right_trim (xstring_contents (string), xstring_length (string), bag)
  696. - xstring_contents (string));
  697. }
  698. lisp
  699. Fstring_left_trim (lisp char_bag, lisp string)
  700. {
  701. string = Fstring (string);
  702. int start = left_trim (string, seq_to_string (char_bag));
  703. return !start ? string : subseq_string (string, make_fixnum (start), Qnil);
  704. }
  705. lisp
  706. Fstring_right_trim (lisp char_bag, lisp string)
  707. {
  708. string = Fstring (string);
  709. int end = right_trim (string, seq_to_string (char_bag));
  710. return (end == xstring_length (string)
  711. ? string
  712. : subseq_string (string, make_fixnum (0), make_fixnum (end)));
  713. }
  714. lisp
  715. Fstring_trim (lisp char_bag, lisp string)
  716. {
  717. string = Fstring (string);
  718. char_bag = seq_to_string (char_bag);
  719. int start = left_trim (string, char_bag);
  720. int end = right_trim (string, char_bag);
  721. if (start >= end)
  722. return make_string ("");
  723. return ((!start && end == xstring_length (string))
  724. ? string
  725. : subseq_string (string, make_fixnum (start), make_fixnum (end)));
  726. }
  727. lisp
  728. Fstring_upcase (lisp string, lisp keys)
  729. {
  730. return Fnstring_upcase (coerce_to_string (string, 1), keys);
  731. }
  732. lisp
  733. Fstring_downcase (lisp string, lisp keys)
  734. {
  735. return Fnstring_downcase (coerce_to_string (string, 1), keys);
  736. }
  737. lisp
  738. Fstring_capitalize (lisp string, lisp keys)
  739. {
  740. return Fnstring_capitalize (coerce_to_string (string, 1), keys);
  741. }
  742. lisp
  743. Fnstring_upcase (lisp string, lisp keys)
  744. {
  745. int start, end;
  746. string_start_end (string, start, end,
  747. find_keyword (Kstart, keys, make_fixnum (0)),
  748. find_keyword (Kend, keys, Qnil));
  749. for (Char *p = xstring_contents (string) + start, *pe = xstring_contents (string) + end;
  750. p < pe; p++)
  751. *p = char_upcase (*p);
  752. return string;
  753. }
  754. lisp
  755. Fnstring_downcase (lisp string, lisp keys)
  756. {
  757. int start, end;
  758. string_start_end (string, start, end,
  759. find_keyword (Kstart, keys, make_fixnum (0)),
  760. find_keyword (Kend, keys, Qnil));
  761. for (Char *p = xstring_contents (string) + start, *pe = xstring_contents (string) + end;
  762. p < pe; p++)
  763. *p = char_downcase (*p);
  764. return string;
  765. }
  766. lisp
  767. Fnstring_capitalize (lisp string, lisp keys)
  768. {
  769. int start, end;
  770. string_start_end (string, start, end,
  771. find_keyword (Kstart, keys, make_fixnum (0)),
  772. find_keyword (Kend, keys, Qnil));
  773. int f = 1;
  774. for (Char *p = xstring_contents (string) + start, *pe = xstring_contents (string) + end;
  775. p < pe; p++)
  776. {
  777. if (alphanumericp (*p))
  778. {
  779. if (f)
  780. *p = char_upcase (*p);
  781. else
  782. *p = char_downcase (*p);
  783. f = 0;
  784. }
  785. else
  786. f = 1;
  787. }
  788. return string;
  789. }
  790. lisp
  791. Fstring (lisp x)
  792. {
  793. return coerce_to_string (x, symbolp (x));
  794. }
  795. static void
  796. trim (const Char *&p0, const Char *&pe, lisp bag)
  797. {
  798. if (p0 != pe)
  799. {
  800. p0 = left_trim (p0, pe - p0, bag);
  801. pe = right_trim (p0, pe - p0, bag);
  802. }
  803. }
  804. lisp
  805. Fsplit_string (lisp string, lisp lsep, lisp ignore_empty, lisp char_bag)
  806. {
  807. string = Fstring (string);
  808. if (!charp (lsep) && !stringp (lsep))
  809. FEtype_error (lsep, xsymbol_value (Qor_string_character));
  810. int empty_ok = ignore_empty && ignore_empty != Qnil;
  811. if (char_bag == Qnil)
  812. char_bag = 0;
  813. else if (char_bag)
  814. {
  815. char_bag = Fstring (char_bag);
  816. if (!xstring_length (char_bag))
  817. char_bag = 0;
  818. }
  819. const Char *p = xstring_contents (string);
  820. const Char *pe = p + xstring_length (string);
  821. if (p == pe)
  822. return Qnil;
  823. lisp result = Qnil;
  824. if (charp (lsep) || xstring_length (lsep) == 1)
  825. {
  826. Char sep = charp (lsep) ? xchar_code (lsep) : *xstring_contents (lsep);
  827. do
  828. {
  829. const Char *p0 = p;
  830. for (; p < pe && *p != sep; p++)
  831. ;
  832. const Char *pe = p;
  833. if (char_bag)
  834. trim (p0, pe, char_bag);
  835. if (p0 != pe || empty_ok)
  836. result = xcons (make_string (p0, pe - p0), result);
  837. }
  838. while (++p < pe);
  839. }
  840. else
  841. {
  842. if (!xstring_length (lsep))
  843. return char_bag ? Fstring_trim (char_bag, string) : string;
  844. do
  845. {
  846. const Char *p0 = p;
  847. for (; p < pe && !match_char_bag (*p, lsep); p++)
  848. ;
  849. const Char *pe = p;
  850. if (char_bag)
  851. trim (p0, pe, char_bag);
  852. if (p0 != pe || empty_ok)
  853. result = xcons (make_string (p0, pe - p0), result);
  854. }
  855. while (++p < pe);
  856. }
  857. return Fnreverse (result);
  858. }
  859. lisp
  860. Fquote_string (lisp string, lisp search, lisp quote)
  861. {
  862. check_string (string);
  863. const Char *s = xstring_contents (string);
  864. const Char *se = s + xstring_length (string);
  865. check_char (search);
  866. Char sch = xchar_code (search);
  867. check_char (quote);
  868. Char qch = xchar_code (quote);
  869. int count = 0;
  870. while (s < se)
  871. if (*s++ == sch)
  872. count++;
  873. if (!count)
  874. return string;
  875. s = xstring_contents (string);
  876. lisp string2 = make_string (xstring_length (string) + count);
  877. Char *d = xstring_contents (string2);
  878. while (s < se)
  879. {
  880. Char c = *s++;
  881. if (c == sch)
  882. *d++ = qch;
  883. *d++ = c;
  884. }
  885. return string2;
  886. }
  887. lisp
  888. parse_integer (lisp string, int start, int &end, int radix, int junk_allowed)
  889. {
  890. const Char *p = xstring_contents (string) + start;
  891. const Char *pe = xstring_contents (string) + end;
  892. if (junk_allowed)
  893. {
  894. const readtab_rep *readtab = xreadtable_rep (current_readtable ());
  895. for (; p < pe && stdchar_whitespace_p (readtab, *p); p++)
  896. ;
  897. for (; pe > p && stdchar_whitespace_p (readtab, pe[-1]); pe--)
  898. ;
  899. }
  900. if (p == pe)
  901. return Qnil;
  902. bignum_rep *rep;
  903. p = ato_bignum_rep (rep, p, pe - p, radix);
  904. end = p - xstring_contents (string);
  905. return p == pe ? make_integer (rep) : Qnil;
  906. }
  907. lisp
  908. Fparse_integer (lisp string, lisp keys)
  909. {
  910. int start, end;
  911. string_start_end (string, start, end,
  912. find_keyword (Kstart, keys, make_fixnum (0)),
  913. find_keyword (Kend, keys, Qnil));
  914. lisp junk_allowed = find_keyword (Kjunk_allowed, keys, Qnil);
  915. int radix;
  916. lisp r = find_keyword (Kradix, keys);
  917. if (r == Qnil)
  918. radix = 10;
  919. else
  920. {
  921. radix = fixnum_value (r);
  922. if (radix < 2 || radix > 36)
  923. FErange_error (r);
  924. }
  925. lisp result = parse_integer (string, start, end, radix, junk_allowed != Qnil);
  926. if (result == Qnil && junk_allowed == Qnil)
  927. FEprogram_error (Einvalid_integer_format, string);
  928. multiple_value::count () = 2;
  929. multiple_value::value (1) = make_fixnum (end);
  930. return result;
  931. }
  932. int WINAPI
  933. abbreviate_string (HDC hdc, char *buf, int maxpxl, int is_pathname)
  934. {
  935. SIZE sz;
  936. int l = strlen (buf);
  937. GetTextExtentPoint32 (hdc, buf, l, &sz);
  938. if (sz.cx <= maxpxl)
  939. return 0;
  940. GetTextExtentPoint32 (hdc, "...", 3, &sz);
  941. maxpxl = (maxpxl - sz.cx);
  942. char *lb, *le;
  943. char *rb, *re;
  944. if (is_pathname)
  945. {
  946. lb = le = buf;
  947. re = buf + l;
  948. rb = find_last_slash (buf);
  949. if (rb)
  950. {
  951. GetTextExtentPoint32 (hdc, rb, re - rb, &sz);
  952. if (sz.cx > maxpxl)
  953. {
  954. rb++;
  955. goto trim_tail;
  956. }
  957. int pxl = sz.cx;
  958. int dev = 0;
  959. if (alpha_char_p (*lb & 255) && lb[1] == ':')
  960. dev = dir_separator_p (lb[2]) ? 3 : 2;
  961. else if (dir_separator_p (*lb) && dir_separator_p (lb[1]))
  962. {
  963. char *sl = find_slash (lb + 2);
  964. if (sl)
  965. sl = find_slash (sl + 1);
  966. if (sl && sl < rb)
  967. dev = sl - lb + 1;
  968. }
  969. if (dev)
  970. {
  971. GetTextExtentPoint32 (hdc, lb, dev, &sz);
  972. if (pxl + sz.cx > maxpxl)
  973. goto done;
  974. pxl += sz.cx;
  975. le = lb + dev;
  976. }
  977. while (rb > le)
  978. {
  979. char c = *rb;
  980. *rb = 0;
  981. char *slash = find_last_slash (buf);
  982. *rb = c;
  983. if (!slash)
  984. break;
  985. GetTextExtentPoint32 (hdc, slash, rb - slash, &sz);
  986. if (sz.cx + pxl > maxpxl)
  987. break;
  988. rb = slash;
  989. pxl += sz.cx;
  990. }
  991. }
  992. else
  993. {
  994. rb = buf;
  995. trim_tail:
  996. for (; re > rb; re = CharPrev (rb, re))
  997. {
  998. GetTextExtentPoint32 (hdc, rb, re - rb, &sz);
  999. if (sz.cx <= maxpxl)
  1000. {
  1001. if (re - rb + 3 > l)
  1002. return 0;
  1003. *re = 0;
  1004. strcpy (stpcpy (buf, rb), "...");
  1005. return 1;
  1006. }
  1007. }
  1008. }
  1009. }
  1010. else
  1011. {
  1012. maxpxl /= 2;
  1013. for (lb = buf, le = buf + l / 2; le > lb; le = CharPrev (lb, le))
  1014. {
  1015. GetTextExtentPoint32 (hdc, lb, le - lb, &sz);
  1016. if (sz.cx <= maxpxl)
  1017. break;
  1018. }
  1019. for (rb = buf + l / 2, re = buf + l; rb < re; rb = CharNext (rb))
  1020. {
  1021. GetTextExtentPoint32 (hdc, rb, re - rb, &sz);
  1022. if (sz.cx <= maxpxl)
  1023. break;
  1024. }
  1025. }
  1026. done:
  1027. if ((le - lb) + (re - rb) + 3 > l)
  1028. return 0;
  1029. for (int i = 0; i < 3; i++)
  1030. le[i] = '.';
  1031. strcpy (le + 3, rb);
  1032. return 1;
  1033. }
  1034. static int
  1035. abbrev_string (char *buf, int maxl, int pathname_p)
  1036. {
  1037. HDC hdc (GetDC (0));
  1038. HGDIOBJ of (SelectObject (hdc, sysdep.ui_font ()));
  1039. TEXTMETRIC tm;
  1040. GetTextMetrics (hdc, &tm);
  1041. int maxpxl = tm.tmAveCharWidth * maxl;
  1042. int r = abbreviate_string (hdc, buf, maxpxl, pathname_p);
  1043. SelectObject (hdc, of);
  1044. ReleaseDC (0, hdc);
  1045. return r;
  1046. }
  1047. lisp
  1048. Fabbreviate_display_string (lisp string, lisp maxlen, lisp pathname_p)
  1049. {
  1050. check_string (string);
  1051. int l = fixnum_value (maxlen);
  1052. if (l <= 0)
  1053. return make_string ("");
  1054. char *buf = (char *)alloca (xstring_length (string) * 2 + 1);
  1055. w2s (buf, string);
  1056. if (!abbrev_string (buf, l, pathname_p && pathname_p != Qnil))
  1057. return string;
  1058. return make_string (buf);
  1059. }
  1060. lisp
  1061. Fabbreviate_string_column (lisp string, lisp column)
  1062. {
  1063. check_string (string);
  1064. int n = fixnum_value (column);
  1065. const Char *const p0 = xstring_contents (string);
  1066. const Char *const pe = p0 + xstring_length (string);
  1067. const Char *p = p0;
  1068. for (int c = 0; c < n && p < pe; p++)
  1069. {
  1070. c += char_width (*p);
  1071. if (c > n)
  1072. break;
  1073. }
  1074. return p == pe ? string : make_string (p0, p - p0);
  1075. }
  1076. static int
  1077. escseq_p (const Char *&p, const Char *pe)
  1078. {
  1079. if (p == pe)
  1080. return -1;
  1081. switch (*p)
  1082. {
  1083. default:
  1084. return -1;
  1085. case 'f':
  1086. p++;
  1087. return CC_FF;
  1088. case 'n':
  1089. p++;
  1090. return CC_NL;
  1091. case 'r':
  1092. p++;
  1093. return CC_CR;
  1094. case 't':
  1095. p++;
  1096. return CC_HT;
  1097. case 'v':
  1098. p++;
  1099. return CC_VT;
  1100. case 'x':
  1101. pe = min (p + 3, pe);
  1102. break;
  1103. case 'X':
  1104. pe = min (p + 5, pe);
  1105. break;
  1106. }
  1107. const Char *p1 = p + 1;
  1108. if (p1 == pe)
  1109. return -1;
  1110. int n = digit_char (*p1);
  1111. if (n >= 16)
  1112. return -1;
  1113. for (p1++; p1 < pe; p1++)
  1114. {
  1115. int x = digit_char (*p1);
  1116. if (x >= 16)
  1117. break;
  1118. n = n * 16 + x;
  1119. }
  1120. p = p1;
  1121. return n;
  1122. }
  1123. lisp
  1124. Fdecode_escape_sequence (lisp string, lisp regexpp)
  1125. {
  1126. check_string (string);
  1127. const Char *p = xstring_contents (string);
  1128. const Char *const pe = p + xstring_length (string);
  1129. char tem[1024];
  1130. StrBuf sb (tem, sizeof tem);
  1131. int mod = 0;
  1132. while (p < pe)
  1133. {
  1134. Char c = *p++;
  1135. if (c == '\\' && p < pe)
  1136. {
  1137. if (*p == '\\')
  1138. {
  1139. p++;
  1140. if (regexpp != Qnil)
  1141. sb.add (c);
  1142. else
  1143. mod = 1;
  1144. }
  1145. else
  1146. {
  1147. int n = escseq_p (p, pe);
  1148. if (n >= 0)
  1149. {
  1150. c = n;
  1151. mod = 1;
  1152. }
  1153. }
  1154. }
  1155. sb.add (c);
  1156. }
  1157. return mod ? sb.make_string () : string;
  1158. }
  1159. lisp
  1160. Fsi_octet_length (lisp string, lisp keys)
  1161. {
  1162. check_string (string);
  1163. int start, end;
  1164. string_start_end (string, start, end,
  1165. find_keyword (Kstart, keys, make_fixnum (0)),
  1166. find_keyword (Kend, keys, Qnil));
  1167. lisp encoding = find_keyword (Kencoding, keys);
  1168. if (encoding == Qnil)
  1169. return make_fixnum (w2sl (xstring_contents (string) + start, end - start));
  1170. check_char_encoding (encoding);
  1171. if (xchar_encoding_type (encoding) == encoding_auto_detect)
  1172. FEtype_error (encoding, Qchar_encoding);
  1173. if (start != 0 || end != xstring_length (string))
  1174. string = make_string (xstring_contents (string) + start, end - start);
  1175. xstream_iChar_helper is (string);
  1176. encoding_output_stream_helper s (encoding, is, eol_noconv);
  1177. int r = 0;
  1178. while (s->get () != xstream::eof)
  1179. r++;
  1180. return make_fixnum (r);
  1181. }