1 /* -*- Mode: C; indent-tabs-mode: t; c-basic-offset: 8; tab-width: 8 -*-
2
3 eel-string.c: String routines to augment <string.h>.
4
5 Copyright (C) 2000 Eazel, Inc.
6
7 The Mate Library is free software; you can redistribute it and/or
8 modify it under the terms of the GNU Library General Public License as
9 published by the Free Software Foundation; either version 2 of the
10 License, or (at your option) any later version.
11
12 The Mate Library is distributed in the hope that it will be useful,
13 but WITHOUT ANY WARRANTY; without even the implied warranty of
14 MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
15 Library General Public License for more details.
16
17 You should have received a copy of the GNU Library General Public
18 License along with the Mate Library; see the file COPYING.LIB. If not,
19 write to the Free Software Foundation, Inc., 51 Franklin St, Fifth Floor,
20 Boston, MA 02110-1301, USA.
21
22 Authors: Darin Adler <darin@eazel.com>
23 */
24
25 #include <config.h>
26 #include "eel-glib-extensions.h"
27 #include "eel-string.h"
28
29 #include <errno.h>
30 #include <locale.h>
31 #include <stdlib.h>
32 #include <string.h>
33
34 #if !defined (EEL_OMIT_SELF_CHECK)
35 #include "eel-lib-self-check-functions.h"
36 #endif
37
38 size_t
eel_strlen(const char * string)39 eel_strlen (const char *string)
40 {
41 return string == NULL ? 0 : strlen (string);
42 }
43
44 char *
eel_strchr(const char * haystack,char needle)45 eel_strchr (const char *haystack, char needle)
46 {
47 return haystack == NULL ? NULL : strchr (haystack, needle);
48 }
49
50 int
eel_strcmp(const char * string_a,const char * string_b)51 eel_strcmp (const char *string_a, const char *string_b)
52 {
53 /* FIXME bugzilla.eazel.com 5450: Maybe we need to make this
54 * treat 'NULL < ""', or have a flavor that does that. If we
55 * didn't have code that already relies on 'NULL == ""', I
56 * would change it right now.
57 */
58 return strcmp (string_a == NULL ? "" : string_a,
59 string_b == NULL ? "" : string_b);
60 }
61
62 gboolean
eel_str_is_empty(const char * string_or_null)63 eel_str_is_empty (const char *string_or_null)
64 {
65 return eel_strcmp (string_or_null, NULL) == 0;
66 }
67
68 gboolean
eel_str_has_prefix(const char * haystack,const char * needle)69 eel_str_has_prefix (const char *haystack, const char *needle)
70 {
71 return g_str_has_prefix (haystack == NULL ? "" : haystack,
72 needle == NULL ? "" : needle);
73 }
74
75 gboolean
eel_istr_has_prefix(const char * haystack,const char * needle)76 eel_istr_has_prefix (const char *haystack, const char *needle)
77 {
78 const char *h, *n;
79 char hc, nc;
80
81 /* Eat one character at a time. */
82 h = haystack == NULL ? "" : haystack;
83 n = needle == NULL ? "" : needle;
84 do
85 {
86 if (*n == '\0')
87 {
88 return TRUE;
89 }
90 if (*h == '\0')
91 {
92 return FALSE;
93 }
94 hc = *h++;
95 nc = *n++;
96 hc = g_ascii_tolower (hc);
97 nc = g_ascii_tolower (nc);
98 }
99 while (hc == nc);
100 return FALSE;
101 }
102
103 /**
104 * eel_str_get_prefix:
105 * Get a new string containing the first part of an existing string.
106 *
107 * @source: The string whose prefix should be extracted.
108 * @delimiter: The string that marks the end of the prefix.
109 *
110 * Return value: A newly-allocated string that that matches the first part
111 * of @source, up to but not including the first occurrence of
112 * @delimiter. If @source is NULL, returns NULL. If
113 * @delimiter is NULL, returns a copy of @source.
114 * If @delimiter does not occur in @source, returns
115 * a copy of @source.
116 **/
117 char *
eel_str_get_prefix(const char * source,const char * delimiter)118 eel_str_get_prefix (const char *source,
119 const char *delimiter)
120 {
121 char *prefix_start;
122
123 if (source == NULL)
124 {
125 return NULL;
126 }
127
128 if (delimiter == NULL)
129 {
130 return g_strdup (source);
131 }
132
133 prefix_start = strstr (source, delimiter);
134
135 if (prefix_start == NULL)
136 {
137 return g_strdup ("");
138 }
139
140 return g_strndup (source, prefix_start - source);
141 }
142
143 char *
eel_str_double_underscores(const char * string)144 eel_str_double_underscores (const char *string)
145 {
146 int underscores;
147 const char *p;
148 char *q;
149 char *escaped;
150
151 if (string == NULL)
152 {
153 return NULL;
154 }
155
156 underscores = 0;
157 for (p = string; *p != '\0'; p++)
158 {
159 underscores += (*p == '_');
160 }
161
162 if (underscores == 0)
163 {
164 return g_strdup (string);
165 }
166
167 escaped = g_new (char, strlen (string) + underscores + 1);
168 for (p = string, q = escaped; *p != '\0'; p++, q++)
169 {
170 /* Add an extra underscore. */
171 if (*p == '_')
172 {
173 *q++ = '_';
174 }
175 *q = *p;
176 }
177 *q = '\0';
178
179 return escaped;
180 }
181
182 char *
eel_str_capitalize(const char * string)183 eel_str_capitalize (const char *string)
184 {
185 char *capitalized;
186
187 if (string == NULL)
188 {
189 return NULL;
190 }
191
192 capitalized = g_strdup (string);
193
194 capitalized[0] = g_ascii_toupper (capitalized[0]);
195
196 return capitalized;
197 }
198
199 /* Note: eel_string_ellipsize_* that use a length in pixels
200 * rather than characters can be found in eel_gdk_extensions.h
201 *
202 * FIXME bugzilla.eazel.com 5089:
203 * we should coordinate the names of eel_string_ellipsize_*
204 * and eel_str_*_truncate so that they match better and reflect
205 * their different behavior.
206 */
207 char *
eel_str_middle_truncate(const char * string,guint truncate_length)208 eel_str_middle_truncate (const char *string,
209 guint truncate_length)
210 {
211 char *truncated;
212 guint length;
213 guint num_left_chars;
214 guint num_right_chars;
215
216 const char delimter[] = "...";
217 const guint delimter_length = strlen (delimter);
218 const guint min_truncate_length = delimter_length + 2;
219
220 if (string == NULL)
221 {
222 return NULL;
223 }
224
225 /* It doesnt make sense to truncate strings to less than
226 * the size of the delimiter plus 2 characters (one on each
227 * side)
228 */
229 if (truncate_length < min_truncate_length)
230 {
231 return g_strdup (string);
232 }
233
234 length = g_utf8_strlen (string, -1);
235
236 /* Make sure the string is not already small enough. */
237 if (length <= truncate_length)
238 {
239 return g_strdup (string);
240 }
241
242 /* Find the 'middle' where the truncation will occur. */
243 num_left_chars = (truncate_length - delimter_length) / 2;
244 num_right_chars = truncate_length - num_left_chars - delimter_length;
245
246 truncated = g_new (char, strlen (string) + 1);
247
248 g_utf8_strncpy (truncated, string, num_left_chars);
249 g_strlcat (truncated, delimter, (truncate_length + 1));
250 g_strlcat (truncated, g_utf8_offset_to_pointer (string, length - num_right_chars), (truncate_length + 1));
251
252 return truncated;
253 }
254
255 char *
eel_str_strip_substring_and_after(const char * string,const char * substring)256 eel_str_strip_substring_and_after (const char *string,
257 const char *substring)
258 {
259 const char *substring_position;
260
261 g_return_val_if_fail (substring != NULL, g_strdup (string));
262 g_return_val_if_fail (substring[0] != '\0', g_strdup (string));
263
264 if (string == NULL)
265 {
266 return NULL;
267 }
268
269 substring_position = strstr (string, substring);
270 if (substring_position == NULL)
271 {
272 return g_strdup (string);
273 }
274
275 return g_strndup (string,
276 substring_position - string);
277 }
278
279 char *
eel_str_replace_substring(const char * string,const char * substring,const char * replacement)280 eel_str_replace_substring (const char *string,
281 const char *substring,
282 const char *replacement)
283 {
284 int substring_length, replacement_length, result_length, remaining_length;
285 const char *p, *substring_position;
286 char *result, *result_position;
287
288 g_return_val_if_fail (substring != NULL, g_strdup (string));
289 g_return_val_if_fail (substring[0] != '\0', g_strdup (string));
290
291 if (string == NULL)
292 {
293 return NULL;
294 }
295
296 if (replacement == NULL)
297 {
298 replacement = "";
299 }
300
301 substring_length = strlen (substring);
302 replacement_length = eel_strlen (replacement);
303
304 result_length = strlen (string);
305 for (p = string; ; p = substring_position + substring_length)
306 {
307 substring_position = strstr (p, substring);
308 if (substring_position == NULL)
309 {
310 break;
311 }
312 if (replacement_length > substring_length)
313 result_length += replacement_length - substring_length;
314 }
315
316 result = g_malloc (result_length + 1);
317
318 result_position = result;
319 for (p = string; ; p = substring_position + substring_length)
320 {
321 substring_position = strstr (p, substring);
322 if (substring_position == NULL)
323 {
324 remaining_length = strlen (p);
325 memcpy (result_position, p, remaining_length);
326 result_position += remaining_length;
327 break;
328 }
329 memcpy (result_position, p, substring_position - p);
330 result_position += substring_position - p;
331 memcpy (result_position, replacement, replacement_length);
332 result_position += replacement_length;
333 }
334
335 result_position[0] = '\0';
336
337 return result;
338 }
339
340 /**************** Custom printf ***********/
341
342 typedef struct
343 {
344 const char *start;
345 const char *end;
346 GString *format;
347 int arg_pos;
348 int width_pos;
349 int width_format_index;
350 int precision_pos;
351 int precision_format_index;
352 } ConversionInfo;
353
354 enum
355 {
356 ARG_TYPE_INVALID,
357 ARG_TYPE_INT,
358 ARG_TYPE_LONG,
359 ARG_TYPE_LONG_LONG,
360 ARG_TYPE_SIZE,
361 ARG_TYPE_LONG_DOUBLE,
362 ARG_TYPE_DOUBLE,
363 ARG_TYPE_POINTER
364 };
365
366 typedef int ArgType; /* An int, because custom are < 0 */
367
368
369 static const char *
get_position(const char * format,int * i)370 get_position (const char *format, int *i)
371 {
372 const char *p;
373
374 p = format;
375
376 if (g_ascii_isdigit (*p))
377 {
378 p++;
379
380 while (g_ascii_isdigit (*p))
381 {
382 p++;
383 }
384
385 if (*p == '$')
386 {
387 if (i != NULL)
388 {
389 *i = atoi (format) - 1;
390 }
391 return p + 1;
392 }
393 }
394
395 return format;
396 }
397
398 static gboolean
is_flag(char c)399 is_flag (char c)
400 {
401 return strchr ("#0- +'I", c) != NULL;
402 }
403
404 static gboolean
is_length_modifier(char c)405 is_length_modifier (char c)
406 {
407 return strchr ("hlLjzt", c) != NULL;
408 }
409
410
411 static ArgType
get_arg_type_from_format(EelPrintfHandler * custom_handlers,const char * format,int len)412 get_arg_type_from_format (EelPrintfHandler *custom_handlers,
413 const char *format,
414 int len)
415 {
416 char c;
417
418 c = format[len-1];
419
420 if (custom_handlers != NULL)
421 {
422 int i;
423
424 for (i = 0; custom_handlers[i].character != 0; i++)
425 {
426 if (custom_handlers[i].character == c)
427 {
428 return -(i + 1);
429 }
430 }
431 }
432
433 switch (c)
434 {
435 case 'd':
436 case 'i':
437 case 'o':
438 case 'u':
439 case 'x':
440 case 'X':
441 if (g_str_has_prefix (format, "ll"))
442 {
443 return ARG_TYPE_LONG_LONG;
444 }
445 if (g_str_has_prefix (format, "l"))
446 {
447 return ARG_TYPE_LONG;
448 }
449 if (g_str_has_prefix (format, "l"))
450 {
451 return ARG_TYPE_LONG;
452 }
453 if (g_str_has_prefix (format, "z"))
454 {
455 return ARG_TYPE_SIZE;
456 }
457 return ARG_TYPE_INT;
458 case 'e':
459 case 'E':
460 case 'f':
461 case 'F':
462 case 'g':
463 case 'G':
464 case 'a':
465 case 'A':
466 if (g_str_has_prefix (format, "L"))
467 {
468 return ARG_TYPE_LONG_DOUBLE;
469 }
470 return ARG_TYPE_DOUBLE;
471 case 'c':
472 return ARG_TYPE_INT;
473 case 's':
474 case 'p':
475 case 'n':
476 return ARG_TYPE_POINTER;
477 }
478 return ARG_TYPE_INVALID;
479 }
480
481 static void
skip_argv(va_list * va,ArgType type,EelPrintfHandler * custom_handlers)482 skip_argv (va_list *va,
483 ArgType type,
484 EelPrintfHandler *custom_handlers)
485 {
486 if (type < 0)
487 {
488 custom_handlers[-type - 1].skip (va);
489 return;
490 }
491
492 switch (type)
493 {
494 default:
495 case ARG_TYPE_INVALID:
496 return;
497
498 case ARG_TYPE_INT:
499 (void) va_arg (*va, int);
500 break;
501 case ARG_TYPE_LONG:
502 (void) va_arg (*va, long int);
503 break;
504 case ARG_TYPE_LONG_LONG:
505 (void) va_arg (*va, long long int);
506 break;
507 case ARG_TYPE_SIZE:
508 (void) va_arg (*va, gsize);
509 break;
510 case ARG_TYPE_LONG_DOUBLE:
511 (void) va_arg (*va, long double);
512 break;
513 case ARG_TYPE_DOUBLE:
514 (void) va_arg (*va, double);
515 break;
516 case ARG_TYPE_POINTER:
517 (void) va_arg (*va, void *);
518 break;
519 }
520 }
521
522 static void
skip_to_arg(va_list * va,ArgType * types,EelPrintfHandler * custom_handlers,int n)523 skip_to_arg (va_list *va,
524 ArgType *types,
525 EelPrintfHandler *custom_handlers,
526 int n)
527 {
528 int i;
529 for (i = 0; i < n; i++)
530 {
531 skip_argv (va, types[i], custom_handlers);
532 }
533 }
534
535 char *
eel_strdup_vprintf_with_custom(EelPrintfHandler * custom,const char * format,va_list va_orig)536 eel_strdup_vprintf_with_custom (EelPrintfHandler *custom,
537 const char *format,
538 va_list va_orig)
539 {
540 va_list va;
541 const char *p;
542 int num_args, i, j;
543 ArgType *args;
544 ConversionInfo *conversions;
545 GString *f, *str;
546 const char *flags, *width, *prec, *mod, *pos;
547 char *s;
548
549 num_args = 0;
550 for (p = format; *p != 0; p++)
551 {
552 if (*p == '%')
553 {
554 p++;
555 if (*p != '%')
556 {
557 num_args++;
558 }
559 }
560 }
561
562 args = g_new0 (ArgType, num_args * 3 + 1);
563 conversions = g_new0 (ConversionInfo, num_args);
564
565 /* i indexes conversions, j indexes args */
566 i = 0;
567 j = 0;
568 p = format;
569 while (*p != 0)
570 {
571 if (*p != '%')
572 {
573 p++;
574 continue;
575 }
576 p++;
577 if (*p == '%')
578 {
579 p++;
580 continue;
581 }
582
583 /* We got a real conversion: */
584 f = g_string_new ("%");
585 conversions[i].start = p - 1;
586
587 /* First comes the positional arg */
588
589 pos = p;
590 p = get_position (p, NULL);
591
592 /* Then flags */
593 flags = p;
594 while (is_flag (*p))
595 {
596 p++;
597 }
598 g_string_append_len (f, flags, p - flags);
599
600 /* Field width */
601
602 if (*p == '*')
603 {
604 p++;
605 p = get_position (p, &j);
606 args[j] = ARG_TYPE_INT;
607 conversions[i].width_pos = j++;
608 conversions[i].width_format_index = f->len;
609 }
610 else
611 {
612 conversions[i].width_pos = -1;
613 conversions[i].width_format_index = -1;
614 width = p;
615 while (g_ascii_isdigit (*p))
616 {
617 p++;
618 }
619 g_string_append_len (f, width, p - width);
620 }
621
622 /* Precision */
623 conversions[i].precision_pos = -1;
624 conversions[i].precision_format_index = -1;
625 if (*p == '.')
626 {
627 g_string_append_c (f, '.');
628 p++;
629
630 if (*p == '*')
631 {
632 p++;
633 p = get_position (p, &j);
634 args[j] = ARG_TYPE_INT;
635 conversions[i].precision_pos = j++;
636 conversions[i].precision_format_index = f->len;
637 }
638 else
639 {
640 prec = p;
641 while (g_ascii_isdigit (*p) || *p == '-')
642 {
643 p++;
644 }
645 g_string_append_len (f, prec, p - prec);
646 }
647 }
648
649 /* length modifier */
650
651 mod = p;
652
653 while (is_length_modifier (*p))
654 {
655 p++;
656 }
657
658 /* conversion specifier */
659 if (*p != 0)
660 p++;
661
662 g_string_append_len (f, mod, p - mod);
663
664 get_position (pos, &j);
665 args[j] = get_arg_type_from_format (custom, mod, p - mod);
666 conversions[i].arg_pos = j++;
667 conversions[i].format = f;
668 conversions[i].end = p;
669
670 i++;
671 }
672
673 g_assert (i == num_args);
674
675 str = g_string_new ("");
676
677 p = format;
678 for (i = 0; i < num_args; i++)
679 {
680 ArgType type;
681
682 g_string_append_len (str, p, conversions[i].start - p);
683 p = conversions[i].end;
684
685 if (conversions[i].precision_pos != -1)
686 {
687 char *val;
688
689 va_copy (va, va_orig);
690 skip_to_arg (&va, args, custom, conversions[i].precision_pos);
691 val = g_strdup_vprintf ("%d", va);
692 va_end (va);
693
694 g_string_insert (conversions[i].format,
695 conversions[i].precision_format_index,
696 val);
697
698 g_free (val);
699 }
700
701 if (conversions[i].width_pos != -1)
702 {
703 char *val;
704
705 va_copy (va, va_orig);
706 skip_to_arg (&va, args, custom, conversions[i].width_pos);
707 val = g_strdup_vprintf ("%d", va);
708 va_end (va);
709
710 g_string_insert (conversions[i].format,
711 conversions[i].width_format_index,
712 val);
713
714 g_free (val);
715 }
716
717 va_copy (va, va_orig);
718 skip_to_arg (&va, args, custom, conversions[i].arg_pos);
719 type = args[conversions[i].arg_pos];
720 if (type < 0)
721 {
722 s = custom[-type - 1].to_string (conversions[i].format->str, va);
723 g_string_append (str, s);
724 g_free (s);
725 }
726 else
727 {
728 g_string_append_vprintf (str, conversions[i].format->str, va);
729 }
730 va_end (va);
731
732 g_string_free (conversions[i].format, TRUE);
733 }
734 g_string_append (str, p);
735
736 g_free (args);
737 g_free (conversions);
738
739 return g_string_free (str, FALSE);
740 }
741
742 char *
eel_strdup_printf_with_custom(EelPrintfHandler * handlers,const char * format,...)743 eel_strdup_printf_with_custom (EelPrintfHandler *handlers,
744 const char *format,
745 ...)
746 {
747 va_list va;
748 char *res;
749
750 va_start (va, format);
751 res = eel_strdup_vprintf_with_custom (handlers, format, va);
752 va_end (va);
753
754 return res;
755 }
756
757 #if !defined (EEL_OMIT_SELF_CHECK)
758
759 static void
verify_printf(const char * format,...)760 verify_printf (const char *format, ...)
761 {
762 va_list va;
763 char *orig, *new;
764
765 va_start (va, format);
766 orig = g_strdup_vprintf (format, va);
767 va_end (va);
768
769 va_start (va, format);
770 new = eel_strdup_vprintf_with_custom (NULL, format, va);
771 va_end (va);
772
773 EEL_CHECK_STRING_RESULT (new, orig);
774
775 g_free (orig);
776 }
777
778 static char *
custom1_to_string(char * format,va_list va)779 custom1_to_string (char *format, va_list va)
780 {
781 int i;
782
783 i = va_arg (va, int);
784
785 return g_strdup_printf ("c1-%d-", i);
786 }
787
788 static void
custom1_skip(va_list * va)789 custom1_skip (va_list *va)
790 {
791 (void) va_arg (*va, int);
792 }
793
794 static char *
custom2_to_string(char * format,va_list va)795 custom2_to_string (char *format, va_list va)
796 {
797 char *s;
798
799 s = va_arg (va, char *);
800
801 return g_strdup_printf ("c2-%s-", s);
802 }
803
804 static void
custom2_skip(va_list * va)805 custom2_skip (va_list *va)
806 {
807 (void) va_arg (*va, char *);
808 }
809
810 static EelPrintfHandler handlers[] =
811 {
812 { 'N', custom1_to_string, custom1_skip },
813 { 'Y', custom2_to_string, custom2_skip },
814 { 0 }
815 };
816
817 static void
verify_custom(const char * orig,const char * format,...)818 verify_custom (const char *orig, const char *format, ...)
819 {
820 char *new;
821 va_list va;
822
823 va_start (va, format);
824 new = eel_strdup_vprintf_with_custom (handlers, format, va);
825 va_end (va);
826
827 EEL_CHECK_STRING_RESULT (new, orig);
828 }
829
830 void
eel_self_check_string(void)831 eel_self_check_string (void)
832 {
833 EEL_CHECK_INTEGER_RESULT (eel_strlen (NULL), 0);
834 EEL_CHECK_INTEGER_RESULT (eel_strlen (""), 0);
835 EEL_CHECK_INTEGER_RESULT (eel_strlen ("abc"), 3);
836
837 EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, NULL), 0);
838 EEL_CHECK_INTEGER_RESULT (eel_strcmp (NULL, ""), 0);
839 EEL_CHECK_INTEGER_RESULT (eel_strcmp ("", NULL), 0);
840 EEL_CHECK_INTEGER_RESULT (eel_strcmp ("a", "a"), 0);
841 EEL_CHECK_INTEGER_RESULT (eel_strcmp ("aaab", "aaab"), 0);
842 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp (NULL, "a") < 0, TRUE);
843 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", NULL) > 0, TRUE);
844 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("", "a") < 0, TRUE);
845 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "") > 0, TRUE);
846 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "b") < 0, TRUE);
847 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("a", "ab") < 0, TRUE);
848 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("ab", "a") > 0, TRUE);
849 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaa", "aaab") < 0, TRUE);
850 EEL_CHECK_BOOLEAN_RESULT (eel_strcmp ("aaab", "aaa") > 0, TRUE);
851
852 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, NULL), TRUE);
853 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, ""), TRUE);
854 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", NULL), TRUE);
855 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "a"), TRUE);
856 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaab"), TRUE);
857 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix (NULL, "a"), FALSE);
858 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", NULL), TRUE);
859 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("", "a"), FALSE);
860 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", ""), TRUE);
861 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "b"), FALSE);
862 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("a", "ab"), FALSE);
863 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("ab", "a"), TRUE);
864 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaa", "aaab"), FALSE);
865 EEL_CHECK_BOOLEAN_RESULT (eel_str_has_prefix ("aaab", "aaa"), TRUE);
866
867 EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, NULL), NULL);
868 EEL_CHECK_STRING_RESULT (eel_str_get_prefix (NULL, "foo"), NULL);
869 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", NULL), "foo");
870 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", ""), "");
871 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("", "foo"), "");
872 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", ""), "");
873 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo", "foo"), "");
874 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:", ":"), "foo");
875 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("foo:bar", ":"), "foo");
876 EEL_CHECK_STRING_RESULT (eel_str_get_prefix ("footle:bar", "tle:"), "foo");
877
878 EEL_CHECK_STRING_RESULT (eel_str_double_underscores (NULL), NULL);
879 EEL_CHECK_STRING_RESULT (eel_str_double_underscores (""), "");
880 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_"), "__");
881 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo"), "foo");
882 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar"), "foo__bar");
883 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_bar_2"), "foo__bar__2");
884 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("_foo"), "__foo");
885 EEL_CHECK_STRING_RESULT (eel_str_double_underscores ("foo_"), "foo__");
886
887 EEL_CHECK_STRING_RESULT (eel_str_capitalize (NULL), NULL);
888 EEL_CHECK_STRING_RESULT (eel_str_capitalize (""), "");
889 EEL_CHECK_STRING_RESULT (eel_str_capitalize ("foo"), "Foo");
890 EEL_CHECK_STRING_RESULT (eel_str_capitalize ("Foo"), "Foo");
891
892 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 0), "foo");
893 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 1), "foo");
894 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 3), "foo");
895 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 4), "foo");
896 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 5), "foo");
897 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 6), "foo");
898 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("foo", 7), "foo");
899 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 0), "a_much_longer_foo");
900 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 1), "a_much_longer_foo");
901 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 2), "a_much_longer_foo");
902 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 3), "a_much_longer_foo");
903 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 4), "a_much_longer_foo");
904 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 5), "a...o");
905 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 6), "a...oo");
906 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 7), "a_...oo");
907 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 8), "a_...foo");
908 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("a_much_longer_foo", 9), "a_m...foo");
909 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 8), "so...ven");
910 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 8), "so...odd");
911 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 9), "som...ven");
912 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 9), "som...odd");
913 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 10), "som...even");
914 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 10), "som..._odd");
915 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 11), "some...even");
916 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 11), "some..._odd");
917 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 12), "some..._even");
918 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 12), "some...g_odd");
919 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 13), "somet..._even");
920 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd");
921 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_even", 14), "something_even");
922 EEL_CHECK_STRING_RESULT (eel_str_middle_truncate ("something_odd", 13), "something_odd");
923
924 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after (NULL, "bar"), NULL);
925 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("", "bar"), "");
926 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo", "bar"), "foo");
927 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar", "bar"), "foo ");
928 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("foo bar xxx", "bar"), "foo ");
929 EEL_CHECK_STRING_RESULT (eel_str_strip_substring_and_after ("bar", "bar"), "");
930
931 EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", NULL), NULL);
932 EEL_CHECK_STRING_RESULT (eel_str_replace_substring (NULL, "foo", "bar"), NULL);
933 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", NULL), "bar");
934 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", ""), "");
935 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("", "foo", "bar"), "");
936 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("bar", "foo", ""), "bar");
937 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("xxx", "x", "foo"), "foofoofoo");
938 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("fff", "f", "foo"), "foofoofoo");
939 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "foo", "f"), "fff");
940 EEL_CHECK_STRING_RESULT (eel_str_replace_substring ("foofoofoo", "f", ""), "oooooo");
941
942 verify_printf ("%.*s", 2, "foo");
943 verify_printf ("%*.*s", 2, 4, "foo");
944 verify_printf ("before %5$*1$.*2$s between %6$*3$.*4$d after",
945 4, 5, 6, 7, "foo", G_PI);
946 verify_custom ("c1-42- c2-foo-","%N %Y", 42 ,"foo");
947 verify_custom ("c1-42- bar c2-foo-","%N %s %Y", 42, "bar" ,"foo");
948 verify_custom ("c1-42- bar c2-foo-","%3$N %2$s %1$Y","foo", "bar", 42);
949
950 }
951
952 #endif /* !EEL_OMIT_SELF_CHECK */
953