/manedit-1.2.1/manedit/ca_string.c

# · C · 1208 lines · 829 code · 203 blank · 176 comment · 238 complexity · f83631a272ac719c045ea54f59a8f02f MD5 · raw file

  1. #include <glib.h>
  2. #include <string.h>
  3. #include "ca_string.h"
  4. /* New, Copy, Delete */
  5. CAString *CAStringNewFromString(
  6. const gchar *s,
  7. const gint len
  8. );
  9. CAString *CAStringCopy(const CAString *ca_string);
  10. void CAStringDelete(CAString *ca_string);
  11. /* Convert To Regular Single-Byte String */
  12. gchar *CAStringToRegularString(
  13. const CAString *ca_string,
  14. const gint len
  15. );
  16. /* Measuring */
  17. gint CAStringLengthPointers(
  18. const CAString *ca_string1_ptr,
  19. const CAString *ca_string2_ptr
  20. );
  21. gint CAStringLength(const CAString *ca_string);
  22. gboolean CAStringIsEmpty(const CAString *ca_string);
  23. /* Seek */
  24. CAString *CAStringSeekToIndex(
  25. CAString *ca_string,
  26. const gint i
  27. );
  28. CAString *CAStringSeekToCharacter(
  29. CAString *ca_string,
  30. const gchar c
  31. );
  32. CAString *CAStringSeekToNextCharacter(
  33. CAString *ca_string,
  34. const gchar c
  35. );
  36. CAString *CAStringSeekToNextCharacters(
  37. CAString *ca_string,
  38. const gchar *characters_list,
  39. const gint ncharacters
  40. );
  41. CAString *CAStringSeekToNextAttribute(CAString *ca_string);
  42. CAString *CAStringNextLine(CAString *ca_string);
  43. CAString *CAStringPreviousLine(
  44. CAString *ca_string,
  45. CAString *ca_string_i
  46. );
  47. CAString *CAStringCurrentLineStart(
  48. CAString *ca_string,
  49. CAString *ca_string_i
  50. );
  51. /* Add/Remove Attribute */
  52. void CAStringSegmentAddAttribute(
  53. CAString *ca_string,
  54. const gint start_i, const gint end_i,
  55. const CAStringAttributes attr
  56. );
  57. void CAStringSegmentRemoveAttribute(
  58. CAString *ca_string,
  59. const gint start_i, const gint end_i,
  60. const CAStringAttributes attr
  61. );
  62. /* Select/Unselect */
  63. void CAStringSelect(
  64. CAString *ca_string,
  65. const gint selection_start_pos,
  66. const gint selection_end_pos,
  67. const gboolean clear_existing_selection
  68. );
  69. void CAStringUnselectAll(CAString *ca_string);
  70. /* Insert/Remove Character */
  71. CAString *CAStringInsertCharacter(
  72. CAString *ca_string,
  73. const gint i,
  74. const gchar c,
  75. const CAStringAttributes attr
  76. );
  77. CAString *CAStringAppendCharacter(
  78. CAString *ca_string,
  79. const gchar c,
  80. const CAStringAttributes attr
  81. );
  82. CAString *CAStringInsertText(
  83. CAString *ca_string,
  84. const gint i,
  85. const CAString *ca_string2
  86. );
  87. CAString *CAStringRemoveCharacter(
  88. CAString *ca_string,
  89. const gint i
  90. );
  91. CAString *CAStringRemoveText(
  92. CAString *ca_string,
  93. const gint i,
  94. const gint len
  95. );
  96. /* Remove End Lines */
  97. void CAStringClearLineEnds(CAString *ca_string);
  98. /* Remove Spaces */
  99. CAString *CAStringChug(CAString *ca_string);
  100. CAString *CAStringChomp(CAString *ca_string);
  101. CAString *CAStringStrip(CAString *ca_string);
  102. #define ATOI(s) (((s) != NULL) ? atoi(s) : 0)
  103. #define ATOL(s) (((s) != NULL) ? atol(s) : 0)
  104. #define ATOF(s) (((s) != NULL) ? atof(s) : 0.0f)
  105. #define STRDUP(s) (((s) != NULL) ? g_strdup(s) : NULL)
  106. #define MAX(a,b) (((a) > (b)) ? (a) : (b))
  107. #define MIN(a,b) (((a) < (b)) ? (a) : (b))
  108. #define CLIP(a,l,h) (MIN(MAX((a),(l)),(h)))
  109. #define STRLEN(s) (((s) != NULL) ? strlen(s) : 0)
  110. #define STRISEMPTY(s) (((s) != NULL) ? (*(s) == '\0') : TRUE)
  111. /*
  112. * Creates a new CAString from a regular single-byte
  113. * null-terminated string.
  114. */
  115. CAString *CAStringNewFromString(
  116. const gchar *s,
  117. const gint len
  118. )
  119. {
  120. gint _len = len;
  121. const gchar *sp,
  122. *s_end;
  123. CAString *ca_string,
  124. *ca_string_ptr;
  125. if(s == NULL)
  126. return(NULL);
  127. if(_len < 0)
  128. _len = strlen(s);
  129. /* Create a new CAString */
  130. ca_string = (CAString *)g_malloc((_len + 1) * sizeof(CAString));
  131. if(ca_string == NULL)
  132. return(NULL);
  133. /* Copy/convert the specified single-byte string data to the
  134. * CAString
  135. */
  136. ca_string_ptr = ca_string;
  137. sp = s;
  138. s_end = s + _len;
  139. while((*sp != '\0') && (sp < s_end))
  140. {
  141. CA_STRING_SET_CHARACTER(ca_string_ptr, *sp);
  142. CA_STRING_SET_ATTRIBUTE(ca_string_ptr, 0);
  143. ca_string_ptr++;
  144. sp++;
  145. }
  146. /* Add the null-terminating character to the CAString */
  147. CA_STRING_SET_CHARACTER(ca_string_ptr, '\0');
  148. CA_STRING_SET_ATTRIBUTE(ca_string_ptr, 0);
  149. return(ca_string);
  150. }
  151. /*
  152. * Coppies the CAString.
  153. */
  154. CAString *CAStringCopy(const CAString *ca_string)
  155. {
  156. gint len;
  157. const CAString *ca_string_ptr;
  158. CAString *ca_string2,
  159. *ca_string2_ptr;
  160. if(ca_string == NULL)
  161. return(NULL);
  162. len = CAStringLength(ca_string);
  163. ca_string2 = (CAString *)g_malloc((len + 1) * sizeof(CAString));
  164. if(ca_string2 == NULL)
  165. return(NULL);
  166. ca_string_ptr = ca_string;
  167. ca_string2_ptr = ca_string2;
  168. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  169. {
  170. *ca_string2_ptr = *ca_string_ptr;
  171. ca_string_ptr++;
  172. ca_string2_ptr++;
  173. }
  174. *ca_string2_ptr = *ca_string_ptr;
  175. return(ca_string2);
  176. }
  177. /*
  178. * Deletes the CAString.
  179. */
  180. void CAStringDelete(CAString *ca_string)
  181. {
  182. g_free(ca_string);
  183. }
  184. /*
  185. * Copy/converts the CAString to a regular single-byte
  186. * null-terminated string.
  187. */
  188. gchar *CAStringToRegularString(
  189. const CAString *ca_string,
  190. const gint len
  191. )
  192. {
  193. gint _len = len;
  194. gchar *s,
  195. *sp,
  196. *s_end;
  197. const CAString *ca_string_ptr;
  198. if((ca_string == NULL) || (_len == 0))
  199. return(NULL);
  200. if(_len < 0)
  201. {
  202. _len = CAStringLength(ca_string);
  203. if(_len == 0)
  204. return(NULL);
  205. s = g_malloc((_len + 1) * sizeof(gchar));
  206. if(s == NULL)
  207. return(NULL);
  208. sp = s;
  209. s_end = sp + _len;
  210. ca_string_ptr = ca_string;
  211. while(sp < s_end)
  212. {
  213. *sp = CA_STRING_CHARACTER(ca_string_ptr);
  214. sp++;
  215. ca_string_ptr++;
  216. }
  217. *sp = '\0';
  218. }
  219. else
  220. {
  221. s = g_malloc((_len + 1) * sizeof(gchar));
  222. if(s == NULL)
  223. return(NULL);
  224. sp = s;
  225. s_end = sp + _len;
  226. ca_string_ptr = ca_string;
  227. while((sp < s_end) && (CA_STRING_CHARACTER(ca_string_ptr) != '\0'))
  228. {
  229. *sp = CA_STRING_CHARACTER(ca_string_ptr);
  230. sp++;
  231. ca_string_ptr++;
  232. }
  233. *sp = '\0';
  234. }
  235. return(s);
  236. }
  237. /*
  238. * Calculates the number of characters between two CAString
  239. * pointers.
  240. *
  241. * Returns the number of units between the two CAString
  242. * pointers. Never returns negative, but can return 0 on error.
  243. */
  244. gint CAStringLengthPointers(
  245. const CAString *ca_string1_ptr,
  246. const CAString *ca_string2_ptr
  247. )
  248. {
  249. if((ca_string1_ptr == NULL) || (ca_string2_ptr == NULL))
  250. return(0);
  251. if(ca_string1_ptr > ca_string2_ptr)
  252. return(0);
  253. return((gint)(ca_string2_ptr - ca_string1_ptr));
  254. }
  255. /*
  256. * Calculates the number of characters in the CAString.
  257. */
  258. gint CAStringLength(const CAString *ca_string)
  259. {
  260. gint len;
  261. const CAString *ca_string_ptr;
  262. if(ca_string == NULL)
  263. return(0);
  264. len = 0;
  265. ca_string_ptr = ca_string;
  266. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  267. {
  268. len++;
  269. ca_string_ptr++;
  270. }
  271. return(len);
  272. }
  273. /*
  274. * Checks if the string is empty or NULL.
  275. */
  276. gboolean CAStringIsEmpty(const CAString *ca_string)
  277. {
  278. if(ca_string == NULL)
  279. return(TRUE);
  280. if(CA_STRING_CHARACTER(ca_string) == '\0')
  281. return(TRUE);
  282. return(FALSE);
  283. }
  284. /*
  285. * Seeks to the index position or end of string.
  286. *
  287. * The i specifies the index position, if i is -1 or out of
  288. * bounds then it will seek to the end of the string.
  289. */
  290. CAString *CAStringSeekToIndex(
  291. CAString *ca_string,
  292. const gint i
  293. )
  294. {
  295. gint ci;
  296. if(ca_string == NULL)
  297. return(NULL);
  298. ci = 0;
  299. while(CA_STRING_CHARACTER(ca_string) != '\0')
  300. {
  301. if(ci == i)
  302. break;
  303. ci++;
  304. ca_string++;
  305. }
  306. return(ca_string);
  307. }
  308. /*
  309. * Seeks to the next occurance of the character, if no such
  310. * character is found then NULL is returned.
  311. */
  312. CAString *CAStringSeekToCharacter(
  313. CAString *ca_string,
  314. const gchar c
  315. )
  316. {
  317. if(ca_string == NULL)
  318. return(NULL);
  319. while(CA_STRING_CHARACTER(ca_string) != '\0')
  320. {
  321. if(CA_STRING_CHARACTER(ca_string) == c)
  322. return(ca_string);
  323. ca_string++;
  324. }
  325. return(NULL);
  326. }
  327. /*
  328. * Seeks to the next occurance of the character or end of string.
  329. */
  330. CAString *CAStringSeekToNextCharacter(
  331. CAString *ca_string,
  332. const gchar c
  333. )
  334. {
  335. if(ca_string == NULL)
  336. return(NULL);
  337. while(CA_STRING_CHARACTER(ca_string) != '\0')
  338. {
  339. if(CA_STRING_CHARACTER(ca_string) == c)
  340. break;
  341. ca_string++;
  342. }
  343. return(ca_string);
  344. }
  345. /*
  346. * Seeks to the next first occurance of any character in the
  347. * list.
  348. *
  349. * The characters_list and ncharacters specifies the list of
  350. * characters (it is treated as a data buffer and not a
  351. * null-terminated string).
  352. */
  353. CAString *CAStringSeekToNextCharacters(
  354. CAString *ca_string,
  355. const gchar *characters_list,
  356. const gint ncharacters
  357. )
  358. {
  359. gchar c;
  360. gint i;
  361. if(ca_string == NULL)
  362. return(NULL);
  363. if((characters_list == NULL) || (ncharacters <= 0))
  364. return(ca_string);
  365. while(CA_STRING_CHARACTER(ca_string) != '\0')
  366. {
  367. c = CA_STRING_CHARACTER(ca_string);
  368. for(i = 0; i < ncharacters; i++)
  369. {
  370. if(characters_list[i] == c)
  371. return(ca_string);
  372. }
  373. ca_string++;
  374. }
  375. return(ca_string);
  376. }
  377. /*
  378. * Seeks to the next position of the CAString that differs in
  379. * any attribute from the specified starting position or end of
  380. * string if no attributes differ.
  381. */
  382. CAString *CAStringSeekToNextAttribute(CAString *ca_string)
  383. {
  384. CAString start_attr;
  385. if(ca_string == NULL)
  386. return(NULL);
  387. start_attr = CA_STRING_ATTRIBUTE(ca_string);
  388. while(CA_STRING_CHARACTER(ca_string) != '\0')
  389. {
  390. if(CA_STRING_ATTRIBUTE(ca_string) != start_attr)
  391. break;
  392. ca_string++;
  393. }
  394. return(ca_string);
  395. }
  396. /*
  397. * Seeks to the start of the next line or end of string.
  398. */
  399. CAString *CAStringNextLine(CAString *ca_string)
  400. {
  401. gchar c;
  402. if(ca_string == NULL)
  403. return(NULL);
  404. while(CA_STRING_CHARACTER(ca_string) != '\0')
  405. {
  406. c = CA_STRING_CHARACTER(ca_string);
  407. if((c == CA_STRING_CHARACTER_LINE_END) ||
  408. (c == CA_STRING_CHARACTER_LINE_BREAK)
  409. )
  410. {
  411. ca_string++;
  412. break;
  413. }
  414. ca_string++;
  415. }
  416. return(ca_string);
  417. }
  418. /*
  419. * Seeks to the start of the previous line or start of string.
  420. */
  421. CAString *CAStringPreviousLine(
  422. CAString *ca_string,
  423. CAString *ca_string_i
  424. )
  425. {
  426. gchar c;
  427. if(ca_string == NULL)
  428. return(NULL);
  429. if(ca_string_i == NULL)
  430. return(ca_string);
  431. if(ca_string_i <= ca_string)
  432. return(ca_string);
  433. /* Go back one character */
  434. ca_string_i--;
  435. c = CA_STRING_CHARACTER(ca_string_i);
  436. if((c == CA_STRING_CHARACTER_LINE_END) ||
  437. (c == CA_STRING_CHARACTER_LINE_BREAK)
  438. )
  439. {
  440. if(ca_string_i <= ca_string)
  441. return(ca_string);
  442. c = CA_STRING_CHARACTER(ca_string_i - 1);
  443. if((c == CA_STRING_CHARACTER_LINE_END) ||
  444. (c == CA_STRING_CHARACTER_LINE_BREAK)
  445. )
  446. return(ca_string_i);
  447. }
  448. /* Seek to the end of the previous line or start of string */
  449. while(ca_string_i > ca_string)
  450. {
  451. c = CA_STRING_CHARACTER(ca_string_i);
  452. if((c == CA_STRING_CHARACTER_LINE_END) ||
  453. (c == CA_STRING_CHARACTER_LINE_BREAK)
  454. )
  455. break;
  456. ca_string_i--;
  457. }
  458. /* At the start of the string? */
  459. if(ca_string_i <= ca_string)
  460. return(ca_string);
  461. ca_string_i--;
  462. /* Seek to the start of the previous line */
  463. while(ca_string_i > ca_string)
  464. {
  465. c = CA_STRING_CHARACTER(ca_string_i);
  466. if((c == CA_STRING_CHARACTER_LINE_END) ||
  467. (c == CA_STRING_CHARACTER_LINE_BREAK)
  468. )
  469. {
  470. ca_string_i++;
  471. break;
  472. }
  473. ca_string_i--;
  474. }
  475. return(ca_string_i);
  476. }
  477. /*
  478. * Seeks to the start of the current line or start of string.
  479. */
  480. CAString *CAStringCurrentLineStart(
  481. CAString *ca_string,
  482. CAString *ca_string_i
  483. )
  484. {
  485. gchar c;
  486. if(ca_string == NULL)
  487. return(NULL);
  488. if(ca_string_i == NULL)
  489. return(ca_string);
  490. /* Already at the end of a line? */
  491. c = CA_STRING_CHARACTER(ca_string_i);
  492. if((c == CA_STRING_CHARACTER_LINE_END) ||
  493. (c == CA_STRING_CHARACTER_LINE_BREAK)
  494. )
  495. {
  496. /* Seek back before the line end character */
  497. if(ca_string_i > ca_string)
  498. ca_string_i--;
  499. /* Is the character before the line end character also a
  500. * line end character?
  501. */
  502. c = CA_STRING_CHARACTER(ca_string_i);
  503. if((c == CA_STRING_CHARACTER_LINE_END) ||
  504. (c == CA_STRING_CHARACTER_LINE_BREAK)
  505. )
  506. {
  507. ca_string_i++;
  508. return(ca_string_i);
  509. }
  510. }
  511. /* Seek to the start of the current line */
  512. while(ca_string_i > ca_string)
  513. {
  514. c = CA_STRING_CHARACTER(ca_string_i);
  515. if((c == CA_STRING_CHARACTER_LINE_END) ||
  516. (c == CA_STRING_CHARACTER_LINE_BREAK)
  517. )
  518. {
  519. ca_string_i++; /* Seek back from the newline */
  520. break;
  521. }
  522. ca_string_i--;
  523. }
  524. return(ca_string_i);
  525. }
  526. /*
  527. * Adds the attribute to the CAString region.
  528. */
  529. void CAStringSegmentAddAttribute(
  530. CAString *ca_string,
  531. const gint start_i, const gint end_i,
  532. const CAStringAttributes attr
  533. )
  534. {
  535. gint i;
  536. if((ca_string == NULL) || (attr == 0))
  537. return;
  538. i = 0;
  539. while(CA_STRING_CHARACTER(ca_string) != '\0')
  540. {
  541. if(i == start_i)
  542. break;
  543. i++;
  544. ca_string++;
  545. }
  546. while(CA_STRING_CHARACTER(ca_string) != '\0')
  547. {
  548. CA_STRING_ADD_ATTRIBUTE(ca_string, attr);
  549. if(i == end_i)
  550. break;
  551. i++;
  552. ca_string++;
  553. }
  554. }
  555. /*
  556. * Removes the attribute from the CAString region.
  557. */
  558. void CAStringSegmentRemoveAttribute(
  559. CAString *ca_string,
  560. const gint start_i, const gint end_i,
  561. const CAStringAttributes attr
  562. )
  563. {
  564. gint i;
  565. if((ca_string == NULL) || (attr == 0))
  566. return;
  567. i = 0;
  568. while(CA_STRING_CHARACTER(ca_string) != '\0')
  569. {
  570. if(i == start_i)
  571. break;
  572. i++;
  573. ca_string++;
  574. }
  575. while(CA_STRING_CHARACTER(ca_string) != '\0')
  576. {
  577. CA_STRING_REMOVE_ATTRIBUTE(ca_string, attr);
  578. if(i == end_i)
  579. break;
  580. i++;
  581. ca_string++;
  582. }
  583. }
  584. /*
  585. * Adds the CA_STRING_ATTRIBUTE_SELECTED attribute to the
  586. * CAString region and, if clear_existing_selection is TRUE,
  587. * removes the CA_STRING_ATTRIBUTE_SELECTED attribute from the
  588. * rest.
  589. */
  590. void CAStringSelect(
  591. CAString *ca_string,
  592. const gint selection_start_pos,
  593. const gint selection_end_pos,
  594. const gboolean clear_existing_selection
  595. )
  596. {
  597. const CAStringAttributes attr = CA_STRING_ATTRIBUTE_SELECTED;
  598. if(ca_string == NULL)
  599. return;
  600. if(clear_existing_selection)
  601. {
  602. gint i = 0;
  603. CAString *ca_string_ptr = ca_string;
  604. /* Unselect the first region */
  605. while((CA_STRING_CHARACTER(ca_string_ptr) != '\0') &&
  606. (i < selection_start_pos)
  607. )
  608. {
  609. CA_STRING_REMOVE_ATTRIBUTE(ca_string_ptr, attr);
  610. i++;
  611. ca_string_ptr++;
  612. }
  613. /* Select the specified region */
  614. while((CA_STRING_CHARACTER(ca_string_ptr) != '\0') &&
  615. (i <= selection_end_pos)
  616. )
  617. {
  618. CA_STRING_ADD_ATTRIBUTE(ca_string_ptr, attr);
  619. i++;
  620. ca_string_ptr++;
  621. }
  622. /* Unselect the remaining region */
  623. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  624. {
  625. CA_STRING_REMOVE_ATTRIBUTE(ca_string_ptr, attr);
  626. ca_string_ptr++;
  627. }
  628. }
  629. else
  630. {
  631. /* Select the specified region */
  632. CAString *ca_string_ptr = CAStringSeekToIndex(ca_string, selection_start_pos),
  633. *ca_string_end = CAStringSeekToIndex(ca_string, selection_end_pos);
  634. while((CA_STRING_CHARACTER(ca_string_ptr) != '\0') &&
  635. (ca_string_ptr <= ca_string_end)
  636. )
  637. {
  638. CA_STRING_ADD_ATTRIBUTE(ca_string_ptr, attr);
  639. ca_string_ptr++;
  640. }
  641. }
  642. }
  643. /*
  644. * Removes the CA_STRING_ATTRIBUTE_SELECTED attribute from the
  645. * CAString region.
  646. */
  647. void CAStringUnselectAll(CAString *ca_string)
  648. {
  649. const CAStringAttributes attr = CA_STRING_ATTRIBUTE_SELECTED;
  650. if(ca_string == NULL)
  651. return;
  652. while(CA_STRING_CHARACTER(ca_string) != '\0')
  653. {
  654. CA_STRING_REMOVE_ATTRIBUTE(ca_string, attr);
  655. ca_string++;
  656. }
  657. }
  658. /*
  659. * Inserts a character.
  660. *
  661. * The i specifies the insert position, if i is -1 or out of
  662. * bounds then the new character will be appended.
  663. */
  664. CAString *CAStringInsertCharacter(
  665. CAString *ca_string,
  666. const gint i,
  667. const gchar c,
  668. const CAStringAttributes attr
  669. )
  670. {
  671. gint len;
  672. CAString *ca_string_i,
  673. *ca_string_ptr,
  674. *ca_string_end;
  675. if(ca_string == NULL)
  676. {
  677. len = 1;
  678. ca_string = (CAString *)g_malloc((len + 1) * sizeof(CAString));
  679. if(ca_string == NULL)
  680. return(NULL);
  681. ca_string_i = ca_string;
  682. CA_STRING_SET_CHARACTER(ca_string_i, c);
  683. CA_STRING_SET_ATTRIBUTE(ca_string_i, attr);
  684. ca_string_i++;
  685. CA_STRING_SET_CHARACTER(ca_string_i, '\0');
  686. CA_STRING_SET_ATTRIBUTE(ca_string_i, 0);
  687. return(ca_string);
  688. }
  689. /* Get the current length of the string */
  690. len = CAStringLength(ca_string);
  691. /* Increase the allocation for the new character */
  692. len++;
  693. ca_string = (CAString *)g_realloc(
  694. ca_string,
  695. (len + 1) * sizeof(CAString)
  696. );
  697. if(ca_string == NULL)
  698. return(NULL);
  699. /* Seek to the insert position */
  700. ca_string_i = CAStringSeekToIndex(ca_string, i);
  701. /* Seek to the end of the string */
  702. ca_string_ptr = ca_string_i;
  703. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  704. ca_string_ptr++;
  705. /* Seek to the end of the string's allocation */
  706. ca_string_end = ca_string + len;
  707. /* Shift the data */
  708. while(ca_string_ptr >= ca_string_i)
  709. {
  710. *ca_string_end = *ca_string_ptr;
  711. ca_string_ptr--;
  712. ca_string_end--;
  713. }
  714. /* Insert the new character */
  715. CA_STRING_SET_CHARACTER(ca_string_i, c);
  716. CA_STRING_SET_ATTRIBUTE(ca_string_i, attr);
  717. return(ca_string);
  718. }
  719. /*
  720. * Appends a character.
  721. */
  722. CAString *CAStringAppendCharacter(
  723. CAString *ca_string,
  724. const gchar c,
  725. const CAStringAttributes attr
  726. )
  727. {
  728. gint i,
  729. len;
  730. CAString *ca_string_a;
  731. if(ca_string == NULL)
  732. {
  733. len = 1;
  734. ca_string = (CAString *)g_malloc((len + 1) * sizeof(CAString));
  735. if(ca_string == NULL)
  736. return(NULL);
  737. ca_string_a = ca_string;
  738. CA_STRING_SET_CHARACTER(ca_string_a, c);
  739. CA_STRING_SET_ATTRIBUTE(ca_string_a, attr);
  740. ca_string_a++;
  741. CA_STRING_SET_CHARACTER(ca_string_a, '\0');
  742. CA_STRING_SET_ATTRIBUTE(ca_string_a, 0);
  743. return(ca_string);
  744. }
  745. /* Get the current length of the string */
  746. len = CAStringLength(ca_string);
  747. /* Record the insert position */
  748. i = len;
  749. /* Increase the allocation for the new character */
  750. len++;
  751. ca_string = (CAString *)g_realloc(
  752. ca_string,
  753. (len + 1) * sizeof(CAString)
  754. );
  755. if(ca_string == NULL)
  756. return(NULL);
  757. /* Get the append position */
  758. ca_string_a = ca_string + i;
  759. /* Append the new character */
  760. CA_STRING_SET_CHARACTER(ca_string_a, c);
  761. CA_STRING_SET_ATTRIBUTE(ca_string_a, attr);
  762. ca_string_a++;
  763. CA_STRING_SET_CHARACTER(ca_string_a, '\0');
  764. CA_STRING_SET_ATTRIBUTE(ca_string_a, 0);
  765. return(ca_string);
  766. }
  767. /*
  768. * Inserts a section of text.
  769. *
  770. * The i specifies the insert position, if i is -1 or out of
  771. * bounds then the new text will be appended.
  772. */
  773. CAString *CAStringInsertText(
  774. CAString *ca_string,
  775. const gint i,
  776. const CAString *ca_string2
  777. )
  778. {
  779. gint len, len2;
  780. const CAString *ca_string2_ptr;
  781. CAString *ca_string_i,
  782. *ca_string_ptr,
  783. *ca_string_end;
  784. if(ca_string == NULL)
  785. return(CAStringCopy(ca_string2));
  786. if(ca_string2 == NULL)
  787. return(ca_string);
  788. /* Get the length of the text to insert */
  789. len2 = CAStringLength(ca_string2);
  790. if(len2 <= 0)
  791. return(ca_string);
  792. /* Get the current length of the string */
  793. len = CAStringLength(ca_string);
  794. /* Increase the allocation for the text to insert */
  795. len += len2;
  796. ca_string = (CAString *)g_realloc(
  797. ca_string,
  798. (len + 1) * sizeof(CAString)
  799. );
  800. if(ca_string == NULL)
  801. return(NULL);
  802. /* Seek to the insert position */
  803. ca_string_i = CAStringSeekToIndex(ca_string, i);
  804. /* Seek to the end of the string */
  805. ca_string_ptr = ca_string_i;
  806. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  807. ca_string_ptr++;
  808. /* Seek to the end of the string's allocation */
  809. ca_string_end = ca_string + len;
  810. /* Shift the data */
  811. while(ca_string_ptr >= ca_string_i)
  812. {
  813. *ca_string_end = *ca_string_ptr;
  814. ca_string_ptr--;
  815. ca_string_end--;
  816. }
  817. /* Insert the text */
  818. ca_string_ptr = ca_string_i;
  819. ca_string2_ptr = ca_string2;
  820. while(CA_STRING_CHARACTER(ca_string2_ptr) != '\0')
  821. {
  822. *ca_string_ptr = *ca_string2_ptr;
  823. ca_string_ptr++;
  824. ca_string2_ptr++;
  825. }
  826. return(ca_string);
  827. }
  828. /*
  829. * Removes a character.
  830. */
  831. CAString *CAStringRemoveCharacter(
  832. CAString *ca_string,
  833. const gint i
  834. )
  835. {
  836. gint new_len;
  837. CAString *ca_string_i,
  838. *ca_string_ptr,
  839. *ca_string_end;
  840. if(ca_string == NULL)
  841. return(NULL);
  842. /* Seek to the remove position */
  843. ca_string_i = CAStringSeekToIndex(ca_string, i);
  844. /* Shift the data at the removal position one unit down */
  845. ca_string_ptr = ca_string_i;
  846. ca_string_end = ca_string_ptr + 1;
  847. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  848. {
  849. *ca_string_ptr = *ca_string_end;
  850. ca_string_ptr++;
  851. ca_string_end++;
  852. }
  853. /* Update the allocation */
  854. new_len = CAStringLength(ca_string);
  855. ca_string = (CAString *)g_realloc(
  856. ca_string,
  857. (new_len + 1) * sizeof(CAString)
  858. );
  859. if(ca_string == NULL)
  860. return(NULL);
  861. return(ca_string);
  862. }
  863. /*
  864. * Removes a section of text.
  865. */
  866. CAString *CAStringRemoveText(
  867. CAString *ca_string,
  868. const gint i,
  869. const gint len
  870. )
  871. {
  872. gint new_len;
  873. CAString *ca_string_i,
  874. *ca_string_i2;
  875. if(ca_string == NULL)
  876. return(NULL);
  877. /* Nothing to remove? */
  878. if(len <= 0)
  879. return(ca_string);
  880. /* Seek to the remove position */
  881. ca_string_i = CAStringSeekToIndex(ca_string, i);
  882. ca_string_i2 = CAStringSeekToIndex(ca_string_i, len);
  883. if(ca_string_i == ca_string_i2)
  884. return(ca_string);
  885. /* Shift the data at the removal position one unit down */
  886. while(CA_STRING_CHARACTER(ca_string_i2) != '\0')
  887. {
  888. *ca_string_i = *ca_string_i2;
  889. ca_string_i++;
  890. ca_string_i2++;
  891. }
  892. *ca_string_i = *ca_string_i2;
  893. /* Update the allocation */
  894. new_len = CAStringLength(ca_string);
  895. ca_string = (CAString *)g_realloc(
  896. ca_string,
  897. (new_len + 1) * sizeof(CAString)
  898. );
  899. if(ca_string == NULL)
  900. return(NULL);
  901. return(ca_string);
  902. }
  903. /*
  904. * Removes all CA_STRING_CHARACTER_LINE_END characters and
  905. * replaces them with spaces.
  906. */
  907. void CAStringClearLineEnds(CAString *ca_string)
  908. {
  909. CAString *ca_string_ptr;
  910. if(ca_string == NULL)
  911. return;
  912. ca_string_ptr = ca_string;
  913. while(CA_STRING_CHARACTER(ca_string_ptr) != '\0')
  914. {
  915. if(CA_STRING_CHARACTER(ca_string_ptr) == CA_STRING_CHARACTER_LINE_END)
  916. CA_STRING_SET_CHARACTER(ca_string_ptr, ' ');
  917. ca_string_ptr++;
  918. }
  919. }
  920. /*
  921. * Removes any leading spaces.
  922. */
  923. CAString *CAStringChug(CAString *ca_string)
  924. {
  925. gint new_len;
  926. CAString *ca_string_i,
  927. *ca_string_i2;
  928. if(ca_string == NULL)
  929. return(NULL);
  930. /* Seek to the first non-space character */
  931. ca_string_i2 = ca_string;
  932. while(CA_STRING_CHARACTER(ca_string_i2) == ' ')
  933. ca_string_i2++;
  934. /* No leading spaces? */
  935. if(ca_string_i2 == ca_string)
  936. return(ca_string);
  937. /* Shift the data */
  938. ca_string_i = ca_string;
  939. while(CA_STRING_CHARACTER(ca_string_i2) != '\0')
  940. {
  941. *ca_string_i = *ca_string_i2;
  942. ca_string_i++;
  943. ca_string_i2++;
  944. }
  945. *ca_string_i = *ca_string_i2;
  946. /* Update the allocation */
  947. new_len = CAStringLength(ca_string);
  948. ca_string = (CAString *)g_realloc(
  949. ca_string,
  950. (new_len + 1) * sizeof(CAString)
  951. );
  952. if(ca_string == NULL)
  953. return(NULL);
  954. return(ca_string);
  955. }
  956. /*
  957. * Removes any tailing spaces.
  958. */
  959. CAString *CAStringChomp(CAString *ca_string)
  960. {
  961. gint new_len;
  962. CAString *ca_string_i;
  963. if(ca_string == NULL)
  964. return(NULL);
  965. /* Seek to the end of the string */
  966. ca_string_i = ca_string;
  967. while(CA_STRING_CHARACTER(ca_string_i) != '\0')
  968. ca_string_i++;
  969. /* Empty string? */
  970. if(ca_string_i == ca_string)
  971. return(ca_string);
  972. /* Seek back one character before the end of string */
  973. if(ca_string_i > ca_string)
  974. ca_string_i--;
  975. /* Seek back any spaces */
  976. while((ca_string_i > ca_string) &&
  977. (CA_STRING_CHARACTER(ca_string_i) == ' ')
  978. )
  979. ca_string_i--;
  980. if((CA_STRING_CHARACTER(ca_string_i) != '\0') &&
  981. (CA_STRING_CHARACTER(ca_string_i) != ' ')
  982. )
  983. ca_string_i++;
  984. CA_STRING_SET_CHARACTER(ca_string_i, '\0');
  985. /* Update the allocation */
  986. new_len = ca_string_i - ca_string;
  987. ca_string = (CAString *)g_realloc(
  988. ca_string,
  989. (new_len + 1) * sizeof(CAString)
  990. );
  991. if(ca_string == NULL)
  992. return(NULL);
  993. return(ca_string);
  994. }
  995. /*
  996. * Removes any leading and tailing spaces.
  997. */
  998. CAString *CAStringStrip(CAString *ca_string)
  999. {
  1000. if(CAStringIsEmpty(ca_string))
  1001. return(ca_string);
  1002. ca_string = CAStringChug(ca_string);
  1003. ca_string = CAStringChomp(ca_string);
  1004. return(ca_string);
  1005. }