strutilascii.c 17 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691
  1. /*
  2. ASCII strings utilities
  3. Copyright (C) 2007, 2011
  4. The Free Software Foundation, Inc.
  5. Written by:
  6. Rostislav Benes, 2007
  7. The file_date routine is mostly from GNU's fileutils package,
  8. written by Richard Stallman and David MacKenzie.
  9. This file is part of the Midnight Commander.
  10. The Midnight Commander is free software: you can redistribute it
  11. and/or modify it under the terms of the GNU General Public License as
  12. published by the Free Software Foundation, either version 3 of the License,
  13. or (at your option) any later version.
  14. The Midnight Commander is distributed in the hope that it will be useful,
  15. but WITHOUT ANY WARRANTY; without even the implied warranty of
  16. MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
  17. GNU General Public License for more details.
  18. You should have received a copy of the GNU General Public License
  19. along with this program. If not, see <http://www.gnu.org/licenses/>.
  20. */
  21. #include <config.h>
  22. #include <stdio.h>
  23. #include <ctype.h>
  24. #include <config.h>
  25. #include <errno.h>
  26. #include "lib/global.h"
  27. #include "lib/strutil.h"
  28. /* using g_ascii function from glib
  29. * on terminal are showed only ascii characters (lower then 0x80)
  30. */
  31. static const char replch = '?';
  32. static void
  33. str_ascii_insert_replace_char (GString * buffer)
  34. {
  35. g_string_append_c (buffer, replch);
  36. }
  37. static int
  38. str_ascii_is_valid_string (const char *text)
  39. {
  40. (void) text;
  41. return 1;
  42. }
  43. static int
  44. str_ascii_is_valid_char (const char *ch, size_t size)
  45. {
  46. (void) ch;
  47. (void) size;
  48. return 1;
  49. }
  50. static void
  51. str_ascii_cnext_char (const char **text)
  52. {
  53. (*text)++;
  54. }
  55. static void
  56. str_ascii_cprev_char (const char **text)
  57. {
  58. (*text)--;
  59. }
  60. static int
  61. str_ascii_cnext_noncomb_char (const char **text)
  62. {
  63. if (*text[0] != '\0')
  64. {
  65. (*text)++;
  66. return 1;
  67. }
  68. else
  69. return 0;
  70. }
  71. static int
  72. str_ascii_cprev_noncomb_char (const char **text, const char *begin)
  73. {
  74. if ((*text) != begin)
  75. {
  76. (*text)--;
  77. return 1;
  78. }
  79. else
  80. return 0;
  81. }
  82. static int
  83. str_ascii_isspace (const char *text)
  84. {
  85. return g_ascii_isspace ((gchar) text[0]);
  86. }
  87. static int
  88. str_ascii_ispunct (const char *text)
  89. {
  90. return g_ascii_ispunct ((gchar) text[0]);
  91. }
  92. static int
  93. str_ascii_isalnum (const char *text)
  94. {
  95. return g_ascii_isalnum ((gchar) text[0]);
  96. }
  97. static int
  98. str_ascii_isdigit (const char *text)
  99. {
  100. return g_ascii_isdigit ((gchar) text[0]);
  101. }
  102. static int
  103. str_ascii_isprint (const char *text)
  104. {
  105. return g_ascii_isprint ((gchar) text[0]);
  106. }
  107. static int
  108. str_ascii_iscombiningmark (const char *text)
  109. {
  110. (void) text;
  111. return 0;
  112. }
  113. static int
  114. str_ascii_toupper (const char *text, char **out, size_t * remain)
  115. {
  116. if (*remain <= 1)
  117. return 0;
  118. (*out)[0] = (char) g_ascii_toupper ((gchar) text[0]);
  119. (*out)++;
  120. (*remain)--;
  121. return 1;
  122. }
  123. static int
  124. str_ascii_tolower (const char *text, char **out, size_t * remain)
  125. {
  126. if (*remain <= 1)
  127. return 0;
  128. (*out)[0] = (char) g_ascii_tolower ((gchar) text[0]);
  129. (*out)++;
  130. (*remain)--;
  131. return 1;
  132. }
  133. static int
  134. str_ascii_length (const char *text)
  135. {
  136. return strlen (text);
  137. }
  138. static int
  139. str_ascii_length2 (const char *text, int size)
  140. {
  141. return (size >= 0) ? min (strlen (text), (gsize) size) : strlen (text);
  142. }
  143. static gchar *
  144. str_ascii_conv_gerror_message (GError * error, const char *def_msg)
  145. {
  146. /* the same as str_utf8_conv_gerror_message() */
  147. if ((error != NULL) && (error->message != NULL))
  148. return g_strdup (error->message);
  149. return g_strdup (def_msg != NULL ? def_msg : "");
  150. }
  151. static estr_t
  152. str_ascii_vfs_convert_to (GIConv coder, const char *string, int size, GString * buffer)
  153. {
  154. (void) coder;
  155. g_string_append_len (buffer, string, size);
  156. return ESTR_SUCCESS;
  157. }
  158. static const char *
  159. str_ascii_term_form (const char *text)
  160. {
  161. static char result[BUF_MEDIUM];
  162. char *actual;
  163. size_t remain;
  164. size_t length;
  165. size_t pos = 0;
  166. actual = result;
  167. remain = sizeof (result);
  168. length = strlen (text);
  169. /* go throw all characters and check, if they are ascii and printable */
  170. for (; pos < length && remain > 1; pos++, actual++, remain--)
  171. {
  172. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  173. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  174. }
  175. actual[0] = '\0';
  176. return result;
  177. }
  178. static const char *
  179. str_ascii_fit_to_term (const char *text, int width, align_crt_t just_mode)
  180. {
  181. static char result[BUF_MEDIUM];
  182. char *actual;
  183. size_t remain;
  184. int ident;
  185. size_t length;
  186. size_t pos = 0;
  187. length = strlen (text);
  188. actual = result;
  189. remain = sizeof (result);
  190. if ((int) length <= width)
  191. {
  192. ident = 0;
  193. switch (HIDE_FIT (just_mode))
  194. {
  195. case J_CENTER_LEFT:
  196. case J_CENTER:
  197. ident = (width - length) / 2;
  198. break;
  199. case J_RIGHT:
  200. ident = width - length;
  201. break;
  202. }
  203. /* add space before text */
  204. if ((int) remain <= ident)
  205. goto finally;
  206. memset (actual, ' ', ident);
  207. actual += ident;
  208. remain -= ident;
  209. /* copy all characters */
  210. for (; pos < (gsize) length && remain > 1; pos++, actual++, remain--)
  211. {
  212. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  213. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  214. }
  215. /* add space after text */
  216. if (width - length - ident > 0)
  217. {
  218. if (remain <= width - length - ident)
  219. goto finally;
  220. memset (actual, ' ', width - length - ident);
  221. actual += width - length - ident;
  222. remain -= width - length - ident;
  223. }
  224. }
  225. else
  226. {
  227. if (IS_FIT (just_mode))
  228. {
  229. /* copy prefix of text, that is not wider than width / 2 */
  230. for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
  231. {
  232. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  233. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  234. }
  235. if (remain <= 1)
  236. goto finally;
  237. actual[0] = '~';
  238. actual++;
  239. remain--;
  240. pos += length - width + 1;
  241. /* copy suffix of text */
  242. for (; pos < length && remain > 1; pos++, actual++, remain--)
  243. {
  244. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  245. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  246. }
  247. }
  248. else
  249. {
  250. ident = 0;
  251. switch (HIDE_FIT (just_mode))
  252. {
  253. case J_CENTER:
  254. ident = (length - width) / 2;
  255. break;
  256. case J_RIGHT:
  257. ident = length - width;
  258. break;
  259. }
  260. /* copy substring text, substring start from ident and take width
  261. * characters from text */
  262. pos += ident;
  263. for (; pos < (gsize) (ident + width) && remain > 1; pos++, actual++, remain--)
  264. {
  265. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  266. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  267. }
  268. }
  269. }
  270. finally:
  271. actual[0] = '\0';
  272. return result;
  273. }
  274. static const char *
  275. str_ascii_term_trim (const char *text, int width)
  276. {
  277. static char result[BUF_MEDIUM];
  278. size_t remain;
  279. char *actual;
  280. size_t pos = 0;
  281. size_t length;
  282. length = strlen (text);
  283. actual = result;
  284. remain = sizeof (result);
  285. if (width > 0)
  286. {
  287. if (width < (int) length)
  288. {
  289. if (width <= 3)
  290. {
  291. memset (actual, '.', width);
  292. actual += width;
  293. remain -= width;
  294. }
  295. else
  296. {
  297. memset (actual, '.', 3);
  298. actual += 3;
  299. remain -= 3;
  300. pos += length - width + 3;
  301. /* copy suffix of text */
  302. for (; pos < length && remain > 1; pos++, actual++, remain--)
  303. {
  304. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  305. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  306. }
  307. }
  308. }
  309. else
  310. {
  311. /* copy all characters */
  312. for (; pos < length && remain > 1; pos++, actual++, remain--)
  313. {
  314. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  315. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  316. }
  317. }
  318. }
  319. actual[0] = '\0';
  320. return result;
  321. }
  322. static int
  323. str_ascii_term_width2 (const char *text, size_t length)
  324. {
  325. return (length != (size_t) (-1)) ? min (strlen (text), length) : strlen (text);
  326. }
  327. static int
  328. str_ascii_term_width1 (const char *text)
  329. {
  330. return str_ascii_term_width2 (text, (size_t) (-1));
  331. }
  332. static int
  333. str_ascii_term_char_width (const char *text)
  334. {
  335. (void) text;
  336. return 1;
  337. }
  338. static const char *
  339. str_ascii_term_substring (const char *text, int start, int width)
  340. {
  341. static char result[BUF_MEDIUM];
  342. size_t remain;
  343. char *actual;
  344. size_t pos = 0;
  345. size_t length;
  346. actual = result;
  347. remain = sizeof (result);
  348. length = strlen (text);
  349. if (start < (int) length)
  350. {
  351. pos += start;
  352. /* copy at most width characters from text from start */
  353. for (; pos < length && width > 0 && remain > 1; pos++, width--, actual++, remain--)
  354. {
  355. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  356. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  357. }
  358. }
  359. /* if text is shorter then width, add space to the end */
  360. for (; width > 0 && remain > 1; actual++, remain--, width--)
  361. {
  362. actual[0] = ' ';
  363. }
  364. actual[0] = '\0';
  365. return result;
  366. }
  367. static const char *
  368. str_ascii_trunc (const char *text, int width)
  369. {
  370. static char result[MC_MAXPATHLEN];
  371. int remain;
  372. char *actual;
  373. size_t pos = 0;
  374. size_t length;
  375. actual = result;
  376. remain = sizeof (result);
  377. length = strlen (text);
  378. if ((int) length > width)
  379. {
  380. /* copy prefix of text */
  381. for (; pos + 1 <= (gsize) width / 2 && remain > 1; actual++, pos++, remain--)
  382. {
  383. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  384. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  385. }
  386. if (remain <= 1)
  387. goto finally;
  388. actual[0] = '~';
  389. actual++;
  390. remain--;
  391. pos += length - width + 1;
  392. /* copy suffix of text */
  393. for (; pos < length && remain > 1; pos++, actual++, remain--)
  394. {
  395. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  396. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  397. }
  398. }
  399. else
  400. {
  401. /* copy all characters */
  402. for (; pos < length && remain > 1; pos++, actual++, remain--)
  403. {
  404. actual[0] = isascii ((unsigned char) text[pos]) ? text[pos] : '?';
  405. actual[0] = g_ascii_isprint ((gchar) actual[0]) ? actual[0] : '.';
  406. }
  407. }
  408. finally:
  409. actual[0] = '\0';
  410. return result;
  411. }
  412. static int
  413. str_ascii_offset_to_pos (const char *text, size_t length)
  414. {
  415. (void) text;
  416. return (int) length;
  417. }
  418. static int
  419. str_ascii_column_to_pos (const char *text, size_t pos)
  420. {
  421. (void) text;
  422. return (int) pos;
  423. }
  424. static char *
  425. str_ascii_create_search_needle (const char *needle, int case_sen)
  426. {
  427. (void) case_sen;
  428. return (char *) needle;
  429. }
  430. static void
  431. str_ascii_release_search_needle (char *needle, int case_sen)
  432. {
  433. (void) case_sen;
  434. (void) needle;
  435. }
  436. static const char *
  437. str_ascii_search_first (const char *text, const char *search, int case_sen)
  438. {
  439. char *fold_text;
  440. char *fold_search;
  441. const char *match;
  442. size_t offset;
  443. fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
  444. fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
  445. match = g_strstr_len (fold_text, -1, fold_search);
  446. if (match != NULL)
  447. {
  448. offset = match - fold_text;
  449. match = text + offset;
  450. }
  451. if (!case_sen)
  452. {
  453. g_free (fold_text);
  454. g_free (fold_search);
  455. }
  456. return match;
  457. }
  458. static const char *
  459. str_ascii_search_last (const char *text, const char *search, int case_sen)
  460. {
  461. char *fold_text;
  462. char *fold_search;
  463. const char *match;
  464. size_t offset;
  465. fold_text = (case_sen) ? (char *) text : g_ascii_strdown (text, -1);
  466. fold_search = (case_sen) ? (char *) search : g_ascii_strdown (search, -1);
  467. match = g_strrstr_len (fold_text, -1, fold_search);
  468. if (match != NULL)
  469. {
  470. offset = match - fold_text;
  471. match = text + offset;
  472. }
  473. if (!case_sen)
  474. {
  475. g_free (fold_text);
  476. g_free (fold_search);
  477. }
  478. return match;
  479. }
  480. static int
  481. str_ascii_compare (const char *t1, const char *t2)
  482. {
  483. return strcmp (t1, t2);
  484. }
  485. static int
  486. str_ascii_ncompare (const char *t1, const char *t2)
  487. {
  488. return strncmp (t1, t2, min (strlen (t1), strlen (t2)));
  489. }
  490. static int
  491. str_ascii_casecmp (const char *t1, const char *t2)
  492. {
  493. return g_ascii_strcasecmp (t1, t2);
  494. }
  495. static int
  496. str_ascii_ncasecmp (const char *t1, const char *t2)
  497. {
  498. return g_ascii_strncasecmp (t1, t2, min (strlen (t1), strlen (t2)));
  499. }
  500. static void
  501. str_ascii_fix_string (char *text)
  502. {
  503. for (; text[0] != '\0'; text++)
  504. {
  505. text[0] = ((unsigned char) text[0] < 128) ? text[0] : '?';
  506. }
  507. }
  508. static char *
  509. str_ascii_create_key (const char *text, int case_sen)
  510. {
  511. (void) case_sen;
  512. return (char *) text;
  513. }
  514. static int
  515. str_ascii_key_collate (const char *t1, const char *t2, int case_sen)
  516. {
  517. return (case_sen) ? strcmp (t1, t2) : g_ascii_strcasecmp (t1, t2);
  518. }
  519. static void
  520. str_ascii_release_key (char *key, int case_sen)
  521. {
  522. (void) key;
  523. (void) case_sen;
  524. }
  525. static int
  526. str_ascii_prefix (const char *text, const char *prefix)
  527. {
  528. int result;
  529. for (result = 0; text[result] != '\0' && prefix[result] != '\0'
  530. && text[result] == prefix[result]; result++);
  531. return result;
  532. }
  533. static int
  534. str_ascii_caseprefix (const char *text, const char *prefix)
  535. {
  536. int result;
  537. for (result = 0; text[result] != '\0' && prefix[result] != '\0'
  538. && g_ascii_toupper (text[result]) == g_ascii_toupper (prefix[result]); result++);
  539. return result;
  540. }
  541. struct str_class
  542. str_ascii_init (void)
  543. {
  544. struct str_class result;
  545. result.conv_gerror_message = str_ascii_conv_gerror_message;
  546. result.vfs_convert_to = str_ascii_vfs_convert_to;
  547. result.insert_replace_char = str_ascii_insert_replace_char;
  548. result.is_valid_string = str_ascii_is_valid_string;
  549. result.is_valid_char = str_ascii_is_valid_char;
  550. result.cnext_char = str_ascii_cnext_char;
  551. result.cprev_char = str_ascii_cprev_char;
  552. result.cnext_char_safe = str_ascii_cnext_char;
  553. result.cprev_char_safe = str_ascii_cprev_char;
  554. result.cnext_noncomb_char = str_ascii_cnext_noncomb_char;
  555. result.cprev_noncomb_char = str_ascii_cprev_noncomb_char;
  556. result.isspace = str_ascii_isspace;
  557. result.ispunct = str_ascii_ispunct;
  558. result.isalnum = str_ascii_isalnum;
  559. result.isdigit = str_ascii_isdigit;
  560. result.isprint = str_ascii_isprint;
  561. result.iscombiningmark = str_ascii_iscombiningmark;
  562. result.toupper = str_ascii_toupper;
  563. result.tolower = str_ascii_tolower;
  564. result.length = str_ascii_length;
  565. result.length2 = str_ascii_length2;
  566. result.length_noncomb = str_ascii_length;
  567. result.fix_string = str_ascii_fix_string;
  568. result.term_form = str_ascii_term_form;
  569. result.fit_to_term = str_ascii_fit_to_term;
  570. result.term_trim = str_ascii_term_trim;
  571. result.term_width2 = str_ascii_term_width2;
  572. result.term_width1 = str_ascii_term_width1;
  573. result.term_char_width = str_ascii_term_char_width;
  574. result.term_substring = str_ascii_term_substring;
  575. result.trunc = str_ascii_trunc;
  576. result.offset_to_pos = str_ascii_offset_to_pos;
  577. result.column_to_pos = str_ascii_column_to_pos;
  578. result.create_search_needle = str_ascii_create_search_needle;
  579. result.release_search_needle = str_ascii_release_search_needle;
  580. result.search_first = str_ascii_search_first;
  581. result.search_last = str_ascii_search_last;
  582. result.compare = str_ascii_compare;
  583. result.ncompare = str_ascii_ncompare;
  584. result.casecmp = str_ascii_casecmp;
  585. result.ncasecmp = str_ascii_ncasecmp;
  586. result.prefix = str_ascii_prefix;
  587. result.caseprefix = str_ascii_caseprefix;
  588. result.create_key = str_ascii_create_key;
  589. result.create_key_for_filename = str_ascii_create_key;
  590. result.key_collate = str_ascii_key_collate;
  591. result.release_key = str_ascii_release_key;
  592. return result;
  593. }