Remove some #if __cplusplus wrt inlining. (#18891)
[mono-project.git] / mono / eglib / gstr.c
blobc549b241894f145f9f79823e6e10d03a442815e3
1 /*
2 * gstr.c: String Utility Functions.
4 * Author:
5 * Miguel de Icaza (miguel@novell.com)
6 * Aaron Bockover (abockover@novell.com)
8 * (C) 2006 Novell, Inc.
10 * Permission is hereby granted, free of charge, to any person obtaining
11 * a copy of this software and associated documentation files (the
12 * "Software"), to deal in the Software without restriction, including
13 * without limitation the rights to use, copy, modify, merge, publish,
14 * distribute, sublicense, and/or sell copies of the Software, and to
15 * permit persons to whom the Software is furnished to do so, subject to
16 * the following conditions:
18 * The above copyright notice and this permission notice shall be
19 * included in all copies or substantial portions of the Software.
21 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
22 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
23 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
24 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
25 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
26 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
27 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
29 #include <config.h>
30 #include <stdio.h>
31 #include <string.h>
32 #include <ctype.h>
33 #include <glib.h>
35 #ifndef G_OS_WIN32
36 #include <pthread.h>
37 #endif
39 #include <errno.h>
41 /*
42 * g_strndup and g_vasprintf need to allocate memory with g_malloc if
43 * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free
44 * rather than free.
47 /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
48 gchar *
49 g_strndup (const gchar *str, gsize n)
51 #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
52 return strndup (str, n);
53 #else
54 if (str) {
55 char *retval = g_malloc(n+1);
56 if (retval) {
57 strncpy(retval, str, n)[n] = 0;
59 return retval;
61 return NULL;
62 #endif
65 gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
67 #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
68 return vasprintf (ret, fmt, ap);
69 #else
70 char *buf;
71 int len;
72 size_t buflen;
73 va_list ap2;
75 #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
76 ap2 = ap;
77 len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
78 #else
79 va_copy(ap2, ap);
80 len = vsnprintf(NULL, 0, fmt, ap2);
81 #endif
83 if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
84 len = vsnprintf(buf, buflen, fmt, ap);
85 *ret = buf;
86 } else {
87 *ret = NULL;
88 len = -1;
91 va_end(ap2);
92 return len;
93 #endif
96 void
97 g_strfreev (gchar **str_array)
99 gchar **orig = str_array;
100 if (str_array == NULL)
101 return;
102 while (*str_array != NULL){
103 g_free (*str_array);
104 str_array++;
106 g_free (orig);
109 gchar **
110 g_strdupv (gchar **str_array)
112 guint length;
113 gchar **ret;
114 guint i;
116 if (!str_array)
117 return NULL;
119 length = g_strv_length(str_array);
120 ret = g_new0(gchar *, length + 1);
121 for (i = 0; str_array[i]; i++) {
122 ret[i] = g_strdup(str_array[i]);
124 ret[length] = NULL;
125 return ret;
128 guint
129 g_strv_length(gchar **str_array)
131 gint length = 0;
132 g_return_val_if_fail(str_array != NULL, 0);
133 for(length = 0; str_array[length] != NULL; length++);
134 return length;
137 gboolean
138 g_str_has_suffix(const gchar *str, const gchar *suffix)
140 size_t str_length;
141 size_t suffix_length;
143 g_return_val_if_fail(str != NULL, FALSE);
144 g_return_val_if_fail(suffix != NULL, FALSE);
146 str_length = strlen(str);
147 suffix_length = strlen(suffix);
149 return suffix_length <= str_length ?
150 strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
151 FALSE;
154 gboolean
155 g_str_has_prefix(const gchar *str, const gchar *prefix)
157 size_t str_length;
158 size_t prefix_length;
160 g_return_val_if_fail(str != NULL, FALSE);
161 g_return_val_if_fail(prefix != NULL, FALSE);
163 str_length = strlen(str);
164 prefix_length = strlen(prefix);
166 return prefix_length <= str_length ?
167 strncmp(str, prefix, prefix_length) == 0 :
168 FALSE;
171 gchar *
172 g_strdup_vprintf (const gchar *format, va_list args)
174 int n;
175 char *ret;
177 n = g_vasprintf (&ret, format, args);
178 if (n == -1)
179 return NULL;
181 return ret;
184 gchar *
185 g_strdup_printf (const gchar *format, ...)
187 gchar *ret;
188 va_list args;
189 int n;
191 va_start (args, format);
192 n = g_vasprintf (&ret, format, args);
193 va_end (args);
194 if (n == -1)
195 return NULL;
197 return ret;
202 Max error number we support. It's empirically found by looking at our target OS.
204 Last this was checked was June-2017.
206 Apple is at 106.
207 Android is at 133.
209 Haiku starts numbering at 0x8000_7000 (like HRESULT on Win32) for POSIX errno,
210 but errors from BeAPI or custom user libraries could be lower or higher.
211 (Technically, this is C and old POSIX compliant, but not new POSIX compliant.)
212 The big problem with this is that it effectively means errors start at a
213 negative offset. As such, disable the whole strerror caching mechanism.
216 #define MONO_ERRNO_MAX 200
217 #define str(s) #s
219 #ifndef G_OS_WIN32
220 static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
221 #endif
223 #if defined(__HAIKU__)
224 const gchar *
225 g_strerror (gint errnum)
227 /* returns a const char* on Haiku */
228 return strerror(errnum);
230 #else
231 static char *error_messages [MONO_ERRNO_MAX];
233 const gchar *
234 g_strerror (gint errnum)
236 if (errnum < 0)
237 errnum = -errnum;
238 if (errnum >= MONO_ERRNO_MAX)
239 return ("Error number higher than " str (MONO_ERRNO_MAX));
241 if (!error_messages [errnum]) {
242 #ifndef G_OS_WIN32
243 pthread_mutex_lock (&strerror_lock);
244 #endif
246 #ifdef HAVE_STRERROR_R
247 char tmp_buff [128]; //Quite arbitrary, should be large enough
248 char *buff = tmp_buff;
249 size_t buff_len = sizeof (tmp_buff);
250 buff [0] = 0;
252 #ifndef STRERROR_R_CHAR_P
253 int r;
254 while ((r = strerror_r (errnum, buff, buff_len - 1))) {
255 if (r != ERANGE) {
256 buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
257 break;
259 if (buff == tmp_buff)
260 buff = g_malloc (buff_len * 2);
261 else
262 buff = g_realloc (buff, buff_len * 2);
263 buff_len *= 2;
264 //Spec is not clean on whether size argument includes space for null terminator or not
266 if (!error_messages [errnum])
267 error_messages [errnum] = g_strdup (buff);
268 if (buff != tmp_buff)
269 g_free (buff);
270 #else /* STRERROR_R_CHAR_P */
271 buff = strerror_r (errnum, buff, buff_len);
272 if (!error_messages [errnum])
273 error_messages [errnum] = g_strdup (buff);
274 #endif /* STRERROR_R_CHAR_P */
276 #else /* HAVE_STRERROR_R */
277 if (!error_messages [errnum])
278 error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
279 #endif /* HAVE_STRERROR_R */
282 #ifndef G_OS_WIN32
283 pthread_mutex_unlock (&strerror_lock);
284 #endif
287 return error_messages [errnum];
289 #endif
291 gchar *
292 g_strconcat (const gchar *first, ...)
294 va_list args;
295 char *s, *ret;
296 g_return_val_if_fail (first != NULL, NULL);
298 size_t len = strlen (first);
299 va_start (args, first);
300 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
301 len += strlen (s);
303 va_end (args);
305 ret = (char*)g_malloc (len + 1);
306 if (ret == NULL)
307 return NULL;
309 ret [len] = 0;
310 len = strlen (first);
311 memcpy (ret, first, len);
312 va_start (args, first);
313 first = ret; // repurpose first as cursor
314 for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
315 first += len;
316 memcpy ((char*)first, s, len = strlen (s));
318 va_end (args);
320 return ret;
323 static void
324 add_to_vector (gchar ***vector, int size, gchar *token)
326 *vector = *vector == NULL ?
327 (gchar **)g_malloc(2 * sizeof(*vector)) :
328 (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
330 (*vector)[size - 1] = token;
333 gchar **
334 g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
336 const gchar *c;
337 gchar *token, **vector;
338 gint size = 1;
340 g_return_val_if_fail (string != NULL, NULL);
341 g_return_val_if_fail (delimiter != NULL, NULL);
342 g_return_val_if_fail (delimiter[0] != 0, NULL);
344 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
345 vector = (gchar **)g_malloc (2 * sizeof(vector));
346 vector[0] = g_strdup ("");
347 size++;
348 string += strlen (delimiter);
349 } else {
350 vector = NULL;
353 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
354 c = string;
355 if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
356 token = g_strdup ("");
357 string += strlen (delimiter);
358 } else {
359 while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
360 string++;
363 if (*string) {
364 gsize toklen = (string - c);
365 token = g_strndup (c, toklen);
367 /* Need to leave a trailing empty
368 * token if the delimiter is the last
369 * part of the string
371 if (strcmp (string, delimiter) != 0) {
372 string += strlen (delimiter);
374 } else {
375 token = g_strdup (c);
379 add_to_vector (&vector, size, token);
380 size++;
383 if (*string) {
384 if (strcmp (string, delimiter) == 0)
385 add_to_vector (&vector, size, g_strdup (""));
386 else {
387 /* Add the rest of the string as the last element */
388 add_to_vector (&vector, size, g_strdup (string));
390 size++;
393 if (vector == NULL) {
394 vector = (gchar **) g_malloc (2 * sizeof (vector));
395 vector [0] = NULL;
396 } else if (size > 0) {
397 vector[size - 1] = NULL;
400 return vector;
403 static gboolean
404 charcmp (gchar testchar, const gchar *compare)
406 while(*compare) {
407 if (*compare == testchar) {
408 return TRUE;
410 compare++;
413 return FALSE;
416 gchar **
417 g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
419 const gchar *c;
420 gchar *token, **vector;
421 gint size = 1;
423 g_return_val_if_fail (string != NULL, NULL);
424 g_return_val_if_fail (delimiter != NULL, NULL);
425 g_return_val_if_fail (delimiter[0] != 0, NULL);
427 if (charcmp (*string, delimiter)) {
428 vector = (gchar **)g_malloc (2 * sizeof(vector));
429 vector[0] = g_strdup ("");
430 size++;
431 string++;
432 } else {
433 vector = NULL;
436 c = string;
437 while (*string && !(max_tokens > 0 && size >= max_tokens)) {
438 if (charcmp (*string, delimiter)) {
439 gsize toklen = (string - c);
440 if (toklen == 0) {
441 token = g_strdup ("");
442 } else {
443 token = g_strndup (c, toklen);
446 c = string + 1;
448 add_to_vector (&vector, size, token);
449 size++;
452 string++;
455 if (max_tokens > 0 && size >= max_tokens) {
456 if (*string) {
457 /* Add the rest of the string as the last element */
458 add_to_vector (&vector, size, g_strdup (string));
459 size++;
461 } else {
462 if (*c) {
463 /* Fill in the trailing last token */
464 add_to_vector (&vector, size, g_strdup (c));
465 size++;
466 } else {
467 /* Need to leave a trailing empty token if the
468 * delimiter is the last part of the string
470 add_to_vector (&vector, size, g_strdup (""));
471 size++;
475 if (vector == NULL) {
476 vector = (gchar **) g_malloc (2 * sizeof (vector));
477 vector [0] = NULL;
478 } else if (size > 0) {
479 vector[size - 1] = NULL;
482 return vector;
485 gchar *
486 g_strreverse (gchar *str)
488 size_t i, j;
489 gchar c;
491 if (str == NULL)
492 return NULL;
494 if (*str == 0)
495 return str;
497 for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
498 c = str [i];
499 str [i] = str [j];
500 str [j] = c;
503 return str;
506 gchar *
507 g_strjoin (const gchar *separator, ...)
509 va_list args;
510 char *res, *s, *r;
511 size_t len, slen;
513 if (separator != NULL)
514 slen = strlen (separator);
515 else
516 slen = 0;
518 len = 0;
519 va_start (args, separator);
520 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
521 len += strlen (s);
522 len += slen;
524 va_end (args);
526 if (len == 0)
527 return g_strdup ("");
529 /* Remove the last separator */
530 if (slen > 0 && len > 0)
531 len -= slen;
533 res = (char*)g_malloc (len + 1);
534 va_start (args, separator);
535 s = va_arg (args, char *);
536 r = g_stpcpy (res, s);
537 for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
538 if (separator != NULL)
539 r = g_stpcpy (r, separator);
540 r = g_stpcpy (r, s);
542 va_end (args);
544 return res;
547 gchar *
548 g_strjoinv (const gchar *separator, gchar **str_array)
550 char *res, *r;
551 size_t slen, len, i;
553 if (separator != NULL)
554 slen = strlen (separator);
555 else
556 slen = 0;
558 len = 0;
559 for (i = 0; str_array [i] != NULL; i++){
560 len += strlen (str_array [i]);
561 len += slen;
564 if (len == 0)
565 return g_strdup ("");
567 if (slen > 0 && len > 0)
568 len -= slen;
570 res = g_malloc (len + 1);
571 r = g_stpcpy (res, str_array [0]);
572 for (i = 1; str_array [i] != NULL; i++){
573 if (separator != NULL)
574 r = g_stpcpy (r, separator);
575 r = g_stpcpy (r, str_array [i]);
578 return res;
581 gchar *
582 g_strchug (gchar *str)
584 size_t len;
585 gchar *tmp;
587 if (str == NULL)
588 return NULL;
590 tmp = str;
591 while (*tmp && isspace (*tmp)) tmp++;
592 if (str != tmp) {
593 len = strlen (str) - (tmp - str - 1);
594 memmove (str, tmp, len);
596 return str;
599 gchar *
600 g_strchomp (gchar *str)
602 gchar *tmp;
604 if (str == NULL)
605 return NULL;
607 tmp = str + strlen (str) - 1;
608 while (*tmp && isspace (*tmp)) tmp--;
609 *(tmp + 1) = '\0';
610 return str;
613 gint
614 g_fprintf(FILE *file, gchar const *format, ...)
616 va_list args;
617 gint ret;
619 va_start(args, format);
620 ret = vfprintf(file, format, args);
621 va_end(args);
623 return ret;
626 gint
627 g_sprintf(gchar *string, gchar const *format, ...)
629 va_list args;
630 gint ret;
632 va_start(args, format);
633 ret = vsprintf(string, format, args);
634 va_end(args);
636 return ret;
639 gint
640 g_snprintf(gchar *string, gulong n, gchar const *format, ...)
642 va_list args;
643 gint ret;
645 va_start(args, format);
646 ret = vsnprintf(string, n, format, args);
647 va_end(args);
649 return ret;
652 static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
653 '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
655 static gboolean
656 char_needs_encoding (char c)
658 if (((unsigned char)c) >= 0x80)
659 return TRUE;
661 if ((c >= '@' && c <= 'Z') ||
662 (c >= 'a' && c <= 'z') ||
663 (c >= '&' && c < 0x3b) ||
664 (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
665 return FALSE;
666 return TRUE;
669 gchar *
670 g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **gerror)
672 size_t n;
673 char *ret, *rp;
674 const char *p;
675 #ifdef G_OS_WIN32
676 const char *uriPrefix = "file:///";
677 #else
678 const char *uriPrefix = "file://";
679 #endif
681 g_return_val_if_fail (filename != NULL, NULL);
683 if (hostname != NULL)
684 g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
686 if (!g_path_is_absolute (filename)){
687 if (gerror != NULL)
688 *gerror = g_error_new (NULL, 2, "Not an absolute filename");
690 return NULL;
693 n = strlen (uriPrefix) + 1;
694 for (p = filename; *p; p++){
695 #ifdef G_OS_WIN32
696 if (*p == '\\') {
697 n++;
698 continue;
700 #endif
701 if (char_needs_encoding (*p))
702 n += 3;
703 else
704 n++;
706 ret = g_malloc (n);
707 strcpy (ret, uriPrefix);
708 for (p = filename, rp = ret + strlen (ret); *p; p++){
709 #ifdef G_OS_WIN32
710 if (*p == '\\') {
711 *rp++ = '/';
712 continue;
714 #endif
715 if (char_needs_encoding (*p)){
716 *rp++ = '%';
717 *rp++ = hx [((unsigned char)(*p)) >> 4];
718 *rp++ = hx [((unsigned char)(*p)) & 0xf];
719 } else
720 *rp++ = *p;
722 *rp = 0;
723 return ret;
726 static int
727 decode (char p)
729 if (p >= '0' && p <= '9')
730 return p - '0';
731 if (p >= 'A' && p <= 'F')
732 return (p - 'A') + 10;
733 if (p >= 'a' && p <= 'f')
734 return (p - 'a') + 10;
735 g_assert_not_reached ();
736 return 0;
739 gchar *
740 g_filename_from_uri (const gchar *uri, gchar **hostname, GError **gerror)
742 const char *p;
743 char *r, *result;
744 int flen = 0;
746 g_return_val_if_fail (uri != NULL, NULL);
748 if (hostname != NULL)
749 g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
751 if (strncmp (uri, "file:///", 8) != 0){
752 if (gerror != NULL)
753 *gerror = g_error_new (NULL, 2, "URI does not start with the file: scheme");
754 return NULL;
757 for (p = uri + 8; *p; p++){
758 if (*p == '%'){
759 if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
760 p += 2;
761 } else {
762 if (gerror != NULL)
763 *gerror = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
764 return NULL;
767 flen++;
769 #ifndef G_OS_WIN32
770 flen++;
771 #endif
773 result = g_malloc (flen + 1);
774 result [flen] = 0;
776 #ifndef G_OS_WIN32
777 *result = '/';
778 r = result + 1;
779 #else
780 r = result;
781 #endif
783 for (p = uri + 8; *p; p++){
784 if (*p == '%'){
785 *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
786 p += 2;
787 } else
788 *r++ = *p;
789 flen++;
791 return result;
794 void
795 g_strdown (gchar *string)
797 g_return_if_fail (string != NULL);
799 while (*string){
800 *string = (gchar)tolower (*string);
801 string++;
805 gchar
806 g_ascii_tolower (gchar c)
808 return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
811 void
812 g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len)
814 // dst can equal src. no_alloc means this function does no
815 // allocation; caller may very well.
817 for (gsize i = 0; i < len; ++i)
818 dst [i] = g_ascii_tolower (src [i]);
821 gchar *
822 g_ascii_strdown (const gchar *str, gssize len)
824 char *ret;
826 g_return_val_if_fail (str != NULL, NULL);
828 if (len == -1)
829 len = strlen (str);
831 ret = g_malloc (len + 1);
832 g_ascii_strdown_no_alloc (ret, str, len);
833 ret [len] = 0;
835 return ret;
838 gchar
839 g_ascii_toupper (gchar c)
841 return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
844 gchar *
845 g_ascii_strup (const gchar *str, gssize len)
847 char *ret;
848 int i;
850 g_return_val_if_fail (str != NULL, NULL);
852 if (len == -1)
853 len = strlen (str);
855 ret = g_malloc (len + 1);
856 for (i = 0; i < len; i++)
857 ret [i] = g_ascii_toupper (str [i]);
858 ret [i] = 0;
860 return ret;
863 static
865 g_ascii_charcmp (char c1, char c2)
867 // Do not subtract, to avoid overflow.
868 // Use unsigned to mimic strcmp, and so
869 // shorter strings compare as less.
871 const guchar u1 = (guchar)c1;
872 const guchar u2 = (guchar)c2;
873 return (u1 < u2) ? -1 : (u1 > u2) ? 1 : 0;
876 static
878 g_ascii_charcasecmp (char c1, char c2)
880 return g_ascii_charcmp (g_ascii_tolower (c1), g_ascii_tolower (c2));
883 gint
884 g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
886 // Unlike strncmp etc. this function does not stop at nul,
887 // unless there is a mismatch.
889 if (s1 == s2)
890 return 0;
892 gsize i;
894 g_return_val_if_fail (s1 != NULL, 0);
895 g_return_val_if_fail (s2 != NULL, 0);
897 for (i = 0; i < n; i++) {
898 const int j = g_ascii_charcasecmp (*s1++, *s2++);
899 if (j)
900 return j;
903 return 0;
906 gint
907 g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
909 if (s1 == s2)
910 return 0;
912 g_return_val_if_fail (s1 != NULL, 0);
913 g_return_val_if_fail (s2 != NULL, 0);
915 char c1;
917 while ((c1 = *s1)) {
918 ++s1;
919 const int j = g_ascii_charcasecmp (c1, *s2++);
920 if (j)
921 return j;
924 return g_ascii_charcmp (0, *s2);
927 gboolean
928 g_utf16_ascii_equal (const gunichar2 *utf16, size_t ulen, const char *ascii, size_t alen)
930 size_t i;
931 if (ulen != alen)
932 return FALSE;
933 for (i = 0; i < ulen; ++i) {
934 if (utf16[i] != ascii[i])
935 return FALSE;
937 return TRUE;
940 gboolean
941 g_utf16_asciiz_equal (const gunichar2 *utf16, const char *ascii)
942 // z for zero means null terminated
944 while (1)
946 char a = *ascii++;
947 gunichar2 u = *utf16++;
948 if (a != u)
949 return FALSE;
950 if (a == 0)
951 return TRUE;
955 void
956 g_strdelimit (gchar *string, gchar delimiter, gchar new_delimiter)
958 gchar *ptr;
960 g_return_if_fail (string != NULL);
962 for (ptr = string; *ptr; ptr++) {
963 if (delimiter == *ptr)
964 *ptr = new_delimiter;
968 gsize
969 g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
971 g_assert (src);
972 g_assert (dest);
974 #ifdef HAVE_STRLCPY
975 return strlcpy (dest, src, dest_size);
976 #else
977 gchar *d;
978 const gchar *s;
979 gchar c;
980 gsize len;
982 len = dest_size;
983 if (len == 0)
984 return 0;
986 s = src;
987 d = dest;
988 while (--len) {
989 c = *s++;
990 *d++ = c;
991 if (c == '\0')
992 return (dest_size - len - 1);
995 /* len is 0 i we get here */
996 *d = '\0';
997 /* we need to return the length of src here */
998 while (*s++) ; /* instead of a plain strlen, we use 's' */
999 return s - src - 1;
1000 #endif
1003 gchar *
1004 g_stpcpy (gchar *dest, const char *src)
1006 g_return_val_if_fail (dest != NULL, dest);
1007 g_return_val_if_fail (src != NULL, dest);
1009 #if HAVE_STPCPY
1010 return stpcpy (dest, src);
1011 #else
1012 while (*src)
1013 *dest++ = *src++;
1015 *dest = '\0';
1017 return dest;
1018 #endif
1021 static const gchar escaped_dflt [256] = {
1022 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
1023 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1024 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1025 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1026 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1027 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
1028 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1029 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
1030 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1031 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1032 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1033 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1034 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1035 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1036 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
1037 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
1040 gchar *
1041 g_strescape (const gchar *source, const gchar *exceptions)
1043 gchar escaped [256];
1044 const gchar *ptr;
1045 gchar c;
1046 gchar op;
1047 gchar *result;
1048 gchar *res_ptr;
1050 g_return_val_if_fail (source != NULL, NULL);
1052 memcpy (escaped, escaped_dflt, 256);
1053 if (exceptions != NULL) {
1054 for (ptr = exceptions; *ptr; ptr++)
1055 escaped [(int) *ptr] = 0;
1057 result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
1058 res_ptr = result;
1059 for (ptr = source; *ptr; ptr++) {
1060 c = *ptr;
1061 op = escaped [(int) c];
1062 if (op == 0) {
1063 *res_ptr++ = c;
1064 } else {
1065 *res_ptr++ = '\\';
1066 if (op != 1) {
1067 *res_ptr++ = op;
1068 } else {
1069 *res_ptr++ = '0' + ((c >> 6) & 3);
1070 *res_ptr++ = '0' + ((c >> 3) & 7);
1071 *res_ptr++ = '0' + (c & 7);
1075 *res_ptr = '\0';
1076 return result;
1079 gint
1080 g_ascii_xdigit_value (gchar c)
1082 return ((isxdigit (c) == 0) ? -1 :
1083 ((c >= '0' && c <= '9') ? (c - '0') :
1084 ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
1085 (c - 'A' + 10))));
1088 gchar *
1089 g_strnfill (gsize length, gchar fill_char)
1091 gchar *ret = g_new (gchar, length + 1);
1093 memset (ret, fill_char, length);
1094 ret [length] = 0;
1095 return ret;
1098 size_t
1099 g_utf16_len (const gunichar2 *a)
1101 #ifdef G_OS_WIN32
1102 return wcslen (a);
1103 #else
1104 size_t length = 0;
1105 while (a [length])
1106 ++length;
1107 return length;
1108 #endif
1111 gsize
1112 g_strnlen (const char* s, gsize n)
1114 gsize i;
1115 for (i = 0; i < n && s [i]; ++i) ;
1116 return i;
1120 * Loads a chunk of data from the file pointed to by the
1121 * @fd starting at the file offset @offset for @size bytes
1122 * and returns an allocated version of that string, or NULL
1123 * on error.
1125 char *
1126 g_str_from_file_region (int fd, guint64 offset, gsize size)
1128 char *buffer;
1129 off_t loc;
1130 int status;
1132 do {
1133 loc = lseek (fd, offset, SEEK_SET);
1134 } while (loc == -1 && errno == EINTR);
1135 if (loc == -1)
1136 return NULL;
1137 buffer = (char *)g_malloc (size + 1);
1138 if (buffer == NULL)
1139 return NULL;
1140 buffer [size] = 0;
1141 do {
1142 status = read (fd, buffer, size);
1143 } while (status == -1 && errno == EINTR);
1144 if (status == -1){
1145 g_free (buffer);
1146 return NULL;
1148 return buffer;