123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998999100010011002100310041005100610071008100910101011101210131014101510161017101810191020102110221023102410251026102710281029103010311032103310341035103610371038103910401041104210431044104510461047104810491050105110521053105410551056105710581059106010611062106310641065106610671068106910701071107210731074107510761077107810791080108110821083108410851086108710881089109010911092109310941095109610971098109911001101110211031104110511061107110811091110111111121113111411151116111711181119112011211122112311241125112611271128112911301131113211331134113511361137113811391140114111421143114411451146114711481149115011511152 |
- /*
- * gstr.c: String Utility Functions.
- *
- * Author:
- * Miguel de Icaza (miguel@novell.com)
- * Aaron Bockover (abockover@novell.com)
- *
- * (C) 2006 Novell, Inc.
- *
- * Permission is hereby granted, free of charge, to any person obtaining
- * a copy of this software and associated documentation files (the
- * "Software"), to deal in the Software without restriction, including
- * without limitation the rights to use, copy, modify, merge, publish,
- * distribute, sublicense, and/or sell copies of the Software, and to
- * permit persons to whom the Software is furnished to do so, subject to
- * the following conditions:
- *
- * The above copyright notice and this permission notice shall be
- * included in all copies or substantial portions of the Software.
- *
- * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
- * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
- * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
- * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
- * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
- * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
- * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
- */
- #include <config.h>
- #include <stdio.h>
- #include <string.h>
- #include <ctype.h>
- #include <glib.h>
- #ifndef G_OS_WIN32
- #include <pthread.h>
- #endif
- #include <errno.h>
- /*
- * g_strndup and g_vasprintf need to allocate memory with g_malloc if
- * ENABLE_OVERRIDABLE_ALLOCATORS is defined so that it can be safely freed with g_free
- * rather than free.
- */
- /* This is not a macro, because I dont want to put _GNU_SOURCE in the glib.h header */
- gchar *
- g_strndup (const gchar *str, gsize n)
- {
- #if defined (HAVE_STRNDUP) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
- return strndup (str, n);
- #else
- if (str) {
- char *retval = g_malloc(n+1);
- if (retval) {
- strncpy(retval, str, n)[n] = 0;
- }
- return retval;
- }
- return NULL;
- #endif
- }
- gint g_vasprintf (gchar **ret, const gchar *fmt, va_list ap)
- {
- #if defined (HAVE_VASPRINTF) && !defined (ENABLE_OVERRIDABLE_ALLOCATORS)
- return vasprintf (ret, fmt, ap);
- #else
- char *buf;
- int len;
- size_t buflen;
- va_list ap2;
-
- #if defined(_MSC_VER) || defined(__MINGW64_VERSION_MAJOR)
- ap2 = ap;
- len = _vscprintf(fmt, ap2); // NOTE MS specific extension ( :-( )
- #else
- va_copy(ap2, ap);
- len = vsnprintf(NULL, 0, fmt, ap2);
- #endif
- if (len >= 0 && (buf = g_malloc ((buflen = (size_t) (len + 1)))) != NULL) {
- len = vsnprintf(buf, buflen, fmt, ap);
- *ret = buf;
- } else {
- *ret = NULL;
- len = -1;
- }
- va_end(ap2);
- return len;
- #endif
- }
- void
- g_strfreev (gchar **str_array)
- {
- gchar **orig = str_array;
- if (str_array == NULL)
- return;
- while (*str_array != NULL){
- g_free (*str_array);
- str_array++;
- }
- g_free (orig);
- }
- gchar **
- g_strdupv (gchar **str_array)
- {
- guint length;
- gchar **ret;
- guint i;
- if (!str_array)
- return NULL;
- length = g_strv_length(str_array);
- ret = g_new0(gchar *, length + 1);
- for (i = 0; str_array[i]; i++) {
- ret[i] = g_strdup(str_array[i]);
- }
- ret[length] = NULL;
- return ret;
- }
- guint
- g_strv_length(gchar **str_array)
- {
- gint length = 0;
- g_return_val_if_fail(str_array != NULL, 0);
- for(length = 0; str_array[length] != NULL; length++);
- return length;
- }
- gboolean
- g_str_has_suffix(const gchar *str, const gchar *suffix)
- {
- size_t str_length;
- size_t suffix_length;
-
- g_return_val_if_fail(str != NULL, FALSE);
- g_return_val_if_fail(suffix != NULL, FALSE);
- str_length = strlen(str);
- suffix_length = strlen(suffix);
- return suffix_length <= str_length ?
- strncmp(str + str_length - suffix_length, suffix, suffix_length) == 0 :
- FALSE;
- }
- gboolean
- g_str_has_prefix(const gchar *str, const gchar *prefix)
- {
- size_t str_length;
- size_t prefix_length;
-
- g_return_val_if_fail(str != NULL, FALSE);
- g_return_val_if_fail(prefix != NULL, FALSE);
- str_length = strlen(str);
- prefix_length = strlen(prefix);
- return prefix_length <= str_length ?
- strncmp(str, prefix, prefix_length) == 0 :
- FALSE;
- }
- gchar *
- g_strdup_vprintf (const gchar *format, va_list args)
- {
- int n;
- char *ret;
-
- n = g_vasprintf (&ret, format, args);
- if (n == -1)
- return NULL;
- return ret;
- }
- gchar *
- g_strdup_printf (const gchar *format, ...)
- {
- gchar *ret;
- va_list args;
- int n;
- va_start (args, format);
- n = g_vasprintf (&ret, format, args);
- va_end (args);
- if (n == -1)
- return NULL;
- return ret;
- }
- /*
- Max error number we support. It's empirically found by looking at our target OS.
- Last this was checked was June-2017.
- Apple is at 106.
- Android is at 133.
- Haiku starts numbering at 0x8000_7000 (like HRESULT on Win32) for POSIX errno,
- but errors from BeAPI or custom user libraries could be lower or higher.
- (Technically, this is C and old POSIX compliant, but not new POSIX compliant.)
- The big problem with this is that it effectively means errors start at a
- negative offset. As such, disable the whole strerror caching mechanism.
- */
- #define MONO_ERRNO_MAX 200
- #define str(s) #s
- #ifndef G_OS_WIN32
- static pthread_mutex_t strerror_lock = PTHREAD_MUTEX_INITIALIZER;
- #endif
- #if defined(__HAIKU__)
- const gchar *
- g_strerror (gint errnum)
- {
- /* returns a const char* on Haiku */
- return strerror(errnum);
- }
- #else
- static char *error_messages [MONO_ERRNO_MAX];
- const gchar *
- g_strerror (gint errnum)
- {
- if (errnum < 0)
- errnum = -errnum;
- if (errnum >= MONO_ERRNO_MAX)
- return ("Error number higher than " str (MONO_ERRNO_MAX));
- if (!error_messages [errnum]) {
- #ifndef G_OS_WIN32
- pthread_mutex_lock (&strerror_lock);
- #endif
- #ifdef HAVE_STRERROR_R
- char tmp_buff [128]; //Quite arbitrary, should be large enough
- char *buff = tmp_buff;
- size_t buff_len = sizeof (tmp_buff);
- buff [0] = 0;
- #ifndef STRERROR_R_CHAR_P
- int r;
- while ((r = strerror_r (errnum, buff, buff_len - 1))) {
- if (r != ERANGE) {
- buff = g_strdup_printf ("Invalid Error code '%d'", errnum);
- break;
- }
- if (buff == tmp_buff)
- buff = g_malloc (buff_len * 2);
- else
- buff = g_realloc (buff, buff_len * 2);
- buff_len *= 2;
- //Spec is not clean on whether size argument includes space for null terminator or not
- }
- if (!error_messages [errnum])
- error_messages [errnum] = g_strdup (buff);
- if (buff != tmp_buff)
- g_free (buff);
- #else /* STRERROR_R_CHAR_P */
- buff = strerror_r (errnum, buff, buff_len);
- if (!error_messages [errnum])
- error_messages [errnum] = g_strdup (buff);
- #endif /* STRERROR_R_CHAR_P */
- #else /* HAVE_STRERROR_R */
- if (!error_messages [errnum])
- error_messages [errnum] = g_strdup_printf ("Error code '%d'", errnum);
- #endif /* HAVE_STRERROR_R */
- #ifndef G_OS_WIN32
- pthread_mutex_unlock (&strerror_lock);
- #endif
- }
- return error_messages [errnum];
- }
- #endif
- gchar *
- g_strconcat (const gchar *first, ...)
- {
- va_list args;
- char *s, *ret;
- g_return_val_if_fail (first != NULL, NULL);
- size_t len = strlen (first);
- va_start (args, first);
- for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
- len += strlen (s);
- }
- va_end (args);
-
- ret = (char*)g_malloc (len + 1);
- if (ret == NULL)
- return NULL;
- ret [len] = 0;
- len = strlen (first);
- memcpy (ret, first, len);
- va_start (args, first);
- first = ret; // repurpose first as cursor
- for (s = va_arg (args, char *); s != NULL; s = va_arg(args, char *)){
- first += len;
- memcpy ((char*)first, s, len = strlen (s));
- }
- va_end (args);
- return ret;
- }
- static void
- add_to_vector (gchar ***vector, int size, gchar *token)
- {
- *vector = *vector == NULL ?
- (gchar **)g_malloc(2 * sizeof(*vector)) :
- (gchar **)g_realloc(*vector, (size + 1) * sizeof(*vector));
-
- (*vector)[size - 1] = token;
- }
- gchar **
- g_strsplit (const gchar *string, const gchar *delimiter, gint max_tokens)
- {
- const gchar *c;
- gchar *token, **vector;
- gint size = 1;
-
- g_return_val_if_fail (string != NULL, NULL);
- g_return_val_if_fail (delimiter != NULL, NULL);
- g_return_val_if_fail (delimiter[0] != 0, NULL);
-
- if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
- vector = (gchar **)g_malloc (2 * sizeof(vector));
- vector[0] = g_strdup ("");
- size++;
- string += strlen (delimiter);
- } else {
- vector = NULL;
- }
- while (*string && !(max_tokens > 0 && size >= max_tokens)) {
- c = string;
- if (strncmp (string, delimiter, strlen (delimiter)) == 0) {
- token = g_strdup ("");
- string += strlen (delimiter);
- } else {
- while (*string && strncmp (string, delimiter, strlen (delimiter)) != 0) {
- string++;
- }
- if (*string) {
- gsize toklen = (string - c);
- token = g_strndup (c, toklen);
- /* Need to leave a trailing empty
- * token if the delimiter is the last
- * part of the string
- */
- if (strcmp (string, delimiter) != 0) {
- string += strlen (delimiter);
- }
- } else {
- token = g_strdup (c);
- }
- }
-
- add_to_vector (&vector, size, token);
- size++;
- }
- if (*string) {
- if (strcmp (string, delimiter) == 0)
- add_to_vector (&vector, size, g_strdup (""));
- else {
- /* Add the rest of the string as the last element */
- add_to_vector (&vector, size, g_strdup (string));
- }
- size++;
- }
-
- if (vector == NULL) {
- vector = (gchar **) g_malloc (2 * sizeof (vector));
- vector [0] = NULL;
- } else if (size > 0) {
- vector[size - 1] = NULL;
- }
-
- return vector;
- }
- static gboolean
- charcmp (gchar testchar, const gchar *compare)
- {
- while(*compare) {
- if (*compare == testchar) {
- return TRUE;
- }
- compare++;
- }
-
- return FALSE;
- }
- gchar **
- g_strsplit_set (const gchar *string, const gchar *delimiter, gint max_tokens)
- {
- const gchar *c;
- gchar *token, **vector;
- gint size = 1;
-
- g_return_val_if_fail (string != NULL, NULL);
- g_return_val_if_fail (delimiter != NULL, NULL);
- g_return_val_if_fail (delimiter[0] != 0, NULL);
-
- if (charcmp (*string, delimiter)) {
- vector = (gchar **)g_malloc (2 * sizeof(vector));
- vector[0] = g_strdup ("");
- size++;
- string++;
- } else {
- vector = NULL;
- }
- c = string;
- while (*string && !(max_tokens > 0 && size >= max_tokens)) {
- if (charcmp (*string, delimiter)) {
- gsize toklen = (string - c);
- if (toklen == 0) {
- token = g_strdup ("");
- } else {
- token = g_strndup (c, toklen);
- }
-
- c = string + 1;
-
- add_to_vector (&vector, size, token);
- size++;
- }
- string++;
- }
-
- if (max_tokens > 0 && size >= max_tokens) {
- if (*string) {
- /* Add the rest of the string as the last element */
- add_to_vector (&vector, size, g_strdup (string));
- size++;
- }
- } else {
- if (*c) {
- /* Fill in the trailing last token */
- add_to_vector (&vector, size, g_strdup (c));
- size++;
- } else {
- /* Need to leave a trailing empty token if the
- * delimiter is the last part of the string
- */
- add_to_vector (&vector, size, g_strdup (""));
- size++;
- }
- }
-
- if (vector == NULL) {
- vector = (gchar **) g_malloc (2 * sizeof (vector));
- vector [0] = NULL;
- } else if (size > 0) {
- vector[size - 1] = NULL;
- }
-
- return vector;
- }
- gchar *
- g_strreverse (gchar *str)
- {
- size_t i, j;
- gchar c;
- if (str == NULL)
- return NULL;
- if (*str == 0)
- return str;
- for (i = 0, j = strlen (str) - 1; i < j; i++, j--) {
- c = str [i];
- str [i] = str [j];
- str [j] = c;
- }
- return str;
- }
- gchar *
- g_strjoin (const gchar *separator, ...)
- {
- va_list args;
- char *res, *s, *r;
- size_t len, slen;
- if (separator != NULL)
- slen = strlen (separator);
- else
- slen = 0;
-
- len = 0;
- va_start (args, separator);
- for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
- len += strlen (s);
- len += slen;
- }
- va_end (args);
- if (len == 0)
- return g_strdup ("");
-
- /* Remove the last separator */
- if (slen > 0 && len > 0)
- len -= slen;
- res = (char*)g_malloc (len + 1);
- va_start (args, separator);
- s = va_arg (args, char *);
- r = g_stpcpy (res, s);
- for (s = va_arg (args, char *); s != NULL; s = va_arg (args, char *)){
- if (separator != NULL)
- r = g_stpcpy (r, separator);
- r = g_stpcpy (r, s);
- }
- va_end (args);
- return res;
- }
- gchar *
- g_strjoinv (const gchar *separator, gchar **str_array)
- {
- char *res, *r;
- size_t slen, len, i;
-
- if (separator != NULL)
- slen = strlen (separator);
- else
- slen = 0;
-
- len = 0;
- for (i = 0; str_array [i] != NULL; i++){
- len += strlen (str_array [i]);
- len += slen;
- }
- if (len == 0)
- return g_strdup ("");
- if (slen > 0 && len > 0)
- len -= slen;
- res = g_malloc (len + 1);
- r = g_stpcpy (res, str_array [0]);
- for (i = 1; str_array [i] != NULL; i++){
- if (separator != NULL)
- r = g_stpcpy (r, separator);
- r = g_stpcpy (r, str_array [i]);
- }
- return res;
- }
- gchar *
- g_strchug (gchar *str)
- {
- size_t len;
- gchar *tmp;
- if (str == NULL)
- return NULL;
- tmp = str;
- while (*tmp && isspace (*tmp)) tmp++;
- if (str != tmp) {
- len = strlen (str) - (tmp - str - 1);
- memmove (str, tmp, len);
- }
- return str;
- }
- gchar *
- g_strchomp (gchar *str)
- {
- gchar *tmp;
- if (str == NULL)
- return NULL;
- tmp = str + strlen (str) - 1;
- while (*tmp && isspace (*tmp)) tmp--;
- *(tmp + 1) = '\0';
- return str;
- }
- gint
- g_fprintf(FILE *file, gchar const *format, ...)
- {
- va_list args;
- gint ret;
- va_start(args, format);
- ret = vfprintf(file, format, args);
- va_end(args);
- return ret;
- }
- gint
- g_sprintf(gchar *string, gchar const *format, ...)
- {
- va_list args;
- gint ret;
- va_start(args, format);
- ret = vsprintf(string, format, args);
- va_end(args);
- return ret;
- }
- gint
- g_snprintf(gchar *string, gulong n, gchar const *format, ...)
- {
- va_list args;
- gint ret;
-
- va_start(args, format);
- ret = vsnprintf(string, n, format, args);
- va_end(args);
- return ret;
- }
- static const char hx [] = { '0', '1', '2', '3', '4', '5', '6', '7',
- '8', '9', 'A', 'B', 'C', 'D', 'E', 'F' };
- static gboolean
- char_needs_encoding (char c)
- {
- if (((unsigned char)c) >= 0x80)
- return TRUE;
-
- if ((c >= '@' && c <= 'Z') ||
- (c >= 'a' && c <= 'z') ||
- (c >= '&' && c < 0x3b) ||
- (c == '!') || (c == '$') || (c == '_') || (c == '=') || (c == '~'))
- return FALSE;
- return TRUE;
- }
- gchar *
- g_filename_to_uri (const gchar *filename, const gchar *hostname, GError **gerror)
- {
- size_t n;
- char *ret, *rp;
- const char *p;
- #ifdef G_OS_WIN32
- const char *uriPrefix = "file:///";
- #else
- const char *uriPrefix = "file://";
- #endif
-
- g_return_val_if_fail (filename != NULL, NULL);
- if (hostname != NULL)
- g_warning ("%s", "eglib: g_filename_to_uri: hostname not handled");
- if (!g_path_is_absolute (filename)){
- if (gerror != NULL)
- *gerror = g_error_new (NULL, 2, "Not an absolute filename");
-
- return NULL;
- }
-
- n = strlen (uriPrefix) + 1;
- for (p = filename; *p; p++){
- #ifdef G_OS_WIN32
- if (*p == '\\') {
- n++;
- continue;
- }
- #endif
- if (char_needs_encoding (*p))
- n += 3;
- else
- n++;
- }
- ret = g_malloc (n);
- strcpy (ret, uriPrefix);
- for (p = filename, rp = ret + strlen (ret); *p; p++){
- #ifdef G_OS_WIN32
- if (*p == '\\') {
- *rp++ = '/';
- continue;
- }
- #endif
- if (char_needs_encoding (*p)){
- *rp++ = '%';
- *rp++ = hx [((unsigned char)(*p)) >> 4];
- *rp++ = hx [((unsigned char)(*p)) & 0xf];
- } else
- *rp++ = *p;
- }
- *rp = 0;
- return ret;
- }
- static int
- decode (char p)
- {
- if (p >= '0' && p <= '9')
- return p - '0';
- if (p >= 'A' && p <= 'F')
- return (p - 'A') + 10;
- if (p >= 'a' && p <= 'f')
- return (p - 'a') + 10;
- g_assert_not_reached ();
- return 0;
- }
- gchar *
- g_filename_from_uri (const gchar *uri, gchar **hostname, GError **gerror)
- {
- const char *p;
- char *r, *result;
- int flen = 0;
-
- g_return_val_if_fail (uri != NULL, NULL);
- if (hostname != NULL)
- g_warning ("%s", "eglib: g_filename_from_uri: hostname not handled");
- if (strncmp (uri, "file:///", 8) != 0){
- if (gerror != NULL)
- *gerror = g_error_new (NULL, 2, "URI does not start with the file: scheme");
- return NULL;
- }
- for (p = uri + 8; *p; p++){
- if (*p == '%'){
- if (p [1] && p [2] && isxdigit (p [1]) && isxdigit (p [2])){
- p += 2;
- } else {
- if (gerror != NULL)
- *gerror = g_error_new (NULL, 2, "URI contains an invalid escape sequence");
- return NULL;
- }
- }
- flen++;
- }
- #ifndef G_OS_WIN32
- flen++;
- #endif
- result = g_malloc (flen + 1);
- result [flen] = 0;
- #ifndef G_OS_WIN32
- *result = '/';
- r = result + 1;
- #else
- r = result;
- #endif
- for (p = uri + 8; *p; p++){
- if (*p == '%'){
- *r++ = (char)((decode (p [1]) << 4) | decode (p [2]));
- p += 2;
- } else
- *r++ = *p;
- flen++;
- }
- return result;
- }
- void
- g_strdown (gchar *string)
- {
- g_return_if_fail (string != NULL);
- while (*string){
- *string = (gchar)tolower (*string);
- string++;
- }
- }
- gchar
- g_ascii_tolower (gchar c)
- {
- return c >= 'A' && c <= 'Z' ? c + ('a' - 'A') : c;
- }
- void
- g_ascii_strdown_no_alloc (char* dst, const char* src, gsize len)
- {
- // dst can equal src. no_alloc means this function does no
- // allocation; caller may very well.
- for (gsize i = 0; i < len; ++i)
- dst [i] = g_ascii_tolower (src [i]);
- }
- gchar *
- g_ascii_strdown (const gchar *str, gssize len)
- {
- char *ret;
-
- g_return_val_if_fail (str != NULL, NULL);
- if (len == -1)
- len = strlen (str);
-
- ret = g_malloc (len + 1);
- g_ascii_strdown_no_alloc (ret, str, len);
- ret [len] = 0;
-
- return ret;
- }
- gchar
- g_ascii_toupper (gchar c)
- {
- return c >= 'a' && c <= 'z' ? c + ('A' - 'a') : c;
- }
- gchar *
- g_ascii_strup (const gchar *str, gssize len)
- {
- char *ret;
- int i;
-
- g_return_val_if_fail (str != NULL, NULL);
- if (len == -1)
- len = strlen (str);
-
- ret = g_malloc (len + 1);
- for (i = 0; i < len; i++)
- ret [i] = g_ascii_toupper (str [i]);
- ret [i] = 0;
-
- return ret;
- }
- static
- int
- g_ascii_charcmp (char c1, char c2)
- {
- // Do not subtract, to avoid overflow.
- // Use unsigned to mimic strcmp, and so
- // shorter strings compare as less.
- const guchar u1 = (guchar)c1;
- const guchar u2 = (guchar)c2;
- return (u1 < u2) ? -1 : (u1 > u2) ? 1 : 0;
- }
- static
- int
- g_ascii_charcasecmp (char c1, char c2)
- {
- return g_ascii_charcmp (g_ascii_tolower (c1), g_ascii_tolower (c2));
- }
- gint
- g_ascii_strncasecmp (const gchar *s1, const gchar *s2, gsize n)
- {
- // Unlike strncmp etc. this function does not stop at nul,
- // unless there is a mismatch.
- if (s1 == s2)
- return 0;
- gsize i;
- g_return_val_if_fail (s1 != NULL, 0);
- g_return_val_if_fail (s2 != NULL, 0);
- for (i = 0; i < n; i++) {
- const int j = g_ascii_charcasecmp (*s1++, *s2++);
- if (j)
- return j;
- }
-
- return 0;
- }
- gint
- g_ascii_strcasecmp (const gchar *s1, const gchar *s2)
- {
- if (s1 == s2)
- return 0;
- g_return_val_if_fail (s1 != NULL, 0);
- g_return_val_if_fail (s2 != NULL, 0);
- char c1;
- while ((c1 = *s1)) {
- ++s1;
- const int j = g_ascii_charcasecmp (c1, *s2++);
- if (j)
- return j;
- }
- return g_ascii_charcmp (0, *s2);
- }
- gboolean
- g_utf16_ascii_equal (const gunichar2 *utf16, size_t ulen, const char *ascii, size_t alen)
- {
- size_t i;
- if (ulen != alen)
- return FALSE;
- for (i = 0; i < ulen; ++i) {
- if (utf16[i] != ascii[i])
- return FALSE;
- }
- return TRUE;
- }
- gboolean
- g_utf16_asciiz_equal (const gunichar2 *utf16, const char *ascii)
- // z for zero means null terminated
- {
- while (1)
- {
- char a = *ascii++;
- gunichar2 u = *utf16++;
- if (a != u)
- return FALSE;
- if (a == 0)
- return TRUE;
- }
- }
- void
- g_strdelimit (gchar *string, gchar delimiter, gchar new_delimiter)
- {
- gchar *ptr;
- g_return_if_fail (string != NULL);
- for (ptr = string; *ptr; ptr++) {
- if (delimiter == *ptr)
- *ptr = new_delimiter;
- }
- }
- gsize
- g_strlcpy (gchar *dest, const gchar *src, gsize dest_size)
- {
- g_assert (src);
- g_assert (dest);
- #ifdef HAVE_STRLCPY
- return strlcpy (dest, src, dest_size);
- #else
- gchar *d;
- const gchar *s;
- gchar c;
- gsize len;
- len = dest_size;
- if (len == 0)
- return 0;
- s = src;
- d = dest;
- while (--len) {
- c = *s++;
- *d++ = c;
- if (c == '\0')
- return (dest_size - len - 1);
- }
- /* len is 0 i we get here */
- *d = '\0';
- /* we need to return the length of src here */
- while (*s++) ; /* instead of a plain strlen, we use 's' */
- return s - src - 1;
- #endif
- }
- gchar *
- g_stpcpy (gchar *dest, const char *src)
- {
- g_return_val_if_fail (dest != NULL, dest);
- g_return_val_if_fail (src != NULL, dest);
- #if HAVE_STPCPY
- return stpcpy (dest, src);
- #else
- while (*src)
- *dest++ = *src++;
-
- *dest = '\0';
-
- return dest;
- #endif
- }
- static const gchar escaped_dflt [256] = {
- 1, 1, 1, 1, 1, 1, 1, 1, 'b', 't', 'n', 1, 'f', 'r', 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 0, 0, '"', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, '\\', 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1,
- 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1
- };
- gchar *
- g_strescape (const gchar *source, const gchar *exceptions)
- {
- gchar escaped [256];
- const gchar *ptr;
- gchar c;
- gchar op;
- gchar *result;
- gchar *res_ptr;
- g_return_val_if_fail (source != NULL, NULL);
- memcpy (escaped, escaped_dflt, 256);
- if (exceptions != NULL) {
- for (ptr = exceptions; *ptr; ptr++)
- escaped [(int) *ptr] = 0;
- }
- result = g_malloc (strlen (source) * 4 + 1); /* Worst case: everything octal. */
- res_ptr = result;
- for (ptr = source; *ptr; ptr++) {
- c = *ptr;
- op = escaped [(int) c];
- if (op == 0) {
- *res_ptr++ = c;
- } else {
- *res_ptr++ = '\\';
- if (op != 1) {
- *res_ptr++ = op;
- } else {
- *res_ptr++ = '0' + ((c >> 6) & 3);
- *res_ptr++ = '0' + ((c >> 3) & 7);
- *res_ptr++ = '0' + (c & 7);
- }
- }
- }
- *res_ptr = '\0';
- return result;
- }
- gint
- g_ascii_xdigit_value (gchar c)
- {
- return ((isxdigit (c) == 0) ? -1 :
- ((c >= '0' && c <= '9') ? (c - '0') :
- ((c >= 'a' && c <= 'f') ? (c - 'a' + 10) :
- (c - 'A' + 10))));
- }
- gchar *
- g_strnfill (gsize length, gchar fill_char)
- {
- gchar *ret = g_new (gchar, length + 1);
- memset (ret, fill_char, length);
- ret [length] = 0;
- return ret;
- }
- size_t
- g_utf16_len (const gunichar2 *a)
- {
- #ifdef G_OS_WIN32
- return wcslen (a);
- #else
- size_t length = 0;
- while (a [length])
- ++length;
- return length;
- #endif
- }
- gsize
- g_strnlen (const char* s, gsize n)
- {
- gsize i;
- for (i = 0; i < n && s [i]; ++i) ;
- return i;
- }
- // This does not link on Xbox One - no lseek or read
- #ifndef RUNTIME_IL2CPP
- /**
- * Loads a chunk of data from the file pointed to by the
- * @fd starting at the file offset @offset for @size bytes
- * and returns an allocated version of that string, or NULL
- * on error.
- */
- char *
- g_str_from_file_region (int fd, guint64 offset, gsize size)
- {
- char *buffer;
- off_t loc;
- int status;
-
- do {
- loc = lseek (fd, offset, SEEK_SET);
- } while (loc == -1 && errno == EINTR);
- if (loc == -1)
- return NULL;
- buffer = (char *)g_malloc (size + 1);
- if (buffer == NULL)
- return NULL;
- buffer [size] = 0;
- do {
- status = read (fd, buffer, size);
- } while (status == -1 && errno == EINTR);
- if (status == -1){
- g_free (buffer);
- return NULL;
- }
- return buffer;
- }
- #endif // !RUNTIME_IL2CPP
|