Prechádzať zdrojové kódy

SDL_GetPreferredLocales() follows the SDL_GetStringRule

Sam Lantinga 9 mesiacov pred
rodič
commit
4f8c348402

+ 6 - 3
include/SDL3/SDL_locale.h

@@ -94,13 +94,16 @@ typedef struct SDL_Locale
  * if possible, and you can call this function again to get an updated copy of
  * preferred locales.
  *
- * \returns array of locales, terminated with a locale with a NULL language
- *          field. Will return NULL on error; call SDL_GetError() for more
+ * The returned array follows the SDL_GetStringRule, and will be automatically freed later.
+ *
+ * \param count a pointer filled in with the number of locales returned, may
+ *              be NULL.
+ * \returns a NULL terminated array of locale pointers, or NULL on failure; call SDL_GetError() for more
  *          information.
  *
  * \since This function is available since SDL 3.0.0.
  */
-extern SDL_DECLSPEC SDL_Locale * SDLCALL SDL_GetPreferredLocales(void);
+extern SDL_DECLSPEC const SDL_Locale * const * SDLCALL SDL_GetPreferredLocales(int *count);
 
 /* Ends C function definitions when using C++ */
 #ifdef __cplusplus

+ 1 - 1
src/dynapi/SDL_dynapi_procs.h

@@ -416,7 +416,7 @@ SDL_DYNAPI_PROC(const char*,SDL_GetPlatform,(void),(),return)
 SDL_DYNAPI_PROC(void*,SDL_GetPointerProperty,(SDL_PropertiesID a, const char *b, void *c),(a,b,c),return)
 SDL_DYNAPI_PROC(SDL_PowerState,SDL_GetPowerInfo,(int *a, int *b),(a,b),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetPrefPath,(const char *a, const char *b),(a,b),return)
-SDL_DYNAPI_PROC(SDL_Locale*,SDL_GetPreferredLocales,(void),(),return)
+SDL_DYNAPI_PROC(const SDL_Locale* const*,SDL_GetPreferredLocales,(int *a),(a),return)
 SDL_DYNAPI_PROC(SDL_DisplayID,SDL_GetPrimaryDisplay,(void),(),return)
 SDL_DYNAPI_PROC(const char*,SDL_GetPrimarySelectionText,(void),(),return)
 SDL_DYNAPI_PROC(SDL_PropertyType,SDL_GetPropertyType,(SDL_PropertiesID a, const char *b),(a,b),return)

+ 30 - 17
src/locale/SDL_locale.c

@@ -22,39 +22,48 @@
 #include "SDL_internal.h"
 #include "SDL_syslocale.h"
 
-static SDL_Locale *build_locales_from_csv_string(char *csv)
+static const SDL_Locale * const *build_locales_from_csv_string(char *csv, int *count)
 {
-    size_t num_locales = 1; /* at least one */
+    int i, num_locales;
     size_t slen;
     size_t alloclen;
     char *ptr;
     SDL_Locale *loc;
-    SDL_Locale *retval;
+    const SDL_Locale **retval;
 
-    if (!csv || !csv[0]) {
+    if (count) {
+        *count = 0;
+    }
+
+    while (csv && *csv && SDL_isspace(*csv)) {
+        ++csv;
+    }
+    if (!csv || !*csv) {
         return NULL; /* nothing to report */
     }
 
+    num_locales = 1; /* at least one */
     for (ptr = csv; *ptr; ptr++) {
         if (*ptr == ',') {
             num_locales++;
         }
     }
 
-    num_locales++; /* one more for terminator */
-
     slen = ((size_t)(ptr - csv)) + 1; /* SDL_strlen(csv) + 1 */
-    alloclen = slen + (num_locales * sizeof(SDL_Locale));
+    alloclen = (num_locales * sizeof(SDL_Locale *)) + (num_locales * sizeof(SDL_Locale)) + slen;
 
-    loc = retval = (SDL_Locale *)SDL_calloc(1, alloclen);
+    retval = (const SDL_Locale **)SDL_calloc(1, alloclen);
     if (!retval) {
         return NULL; /* oh well */
     }
-    ptr = (char *)(retval + num_locales);
-    SDL_strlcpy(ptr, csv, slen);
+    loc = (SDL_Locale *)((Uint8 *)retval + ((num_locales + 1) * sizeof(SDL_Locale *)));
+    ptr = (char *)(loc + num_locales);
+    SDL_memcpy(ptr, csv, slen);
 
+    i = 0;
+    retval[i++] = loc;
     while (SDL_TRUE) { /* parse out the string */
-        while (*ptr == ' ') {
+        while (SDL_isspace(*ptr)) {
             ptr++; /* skip whitespace. */
         }
 
@@ -64,17 +73,17 @@ static SDL_Locale *build_locales_from_csv_string(char *csv)
         loc->language = ptr++;
         while (SDL_TRUE) {
             const char ch = *ptr;
-            if (ch == '_') {
+            if (ch == '_' || ch == '-') {
                 *(ptr++) = '\0';
                 loc->country = ptr;
-            } else if (ch == ' ') {
+            } else if (SDL_isspace(ch)) {
                 *(ptr++) = '\0'; /* trim ending whitespace and keep going. */
             } else if (ch == ',') {
                 *(ptr++) = '\0';
                 loc++;
+                retval[i++] = loc;
                 break;
             } else if (ch == '\0') {
-                loc++;
                 break;
             } else {
                 ptr++; /* just keep going, still a valid string */
@@ -82,10 +91,14 @@ static SDL_Locale *build_locales_from_csv_string(char *csv)
         }
     }
 
-    return retval;
+    if (count) {
+        *count = num_locales;
+    }
+
+    return SDL_FreeLater(retval);
 }
 
-SDL_Locale *SDL_GetPreferredLocales(void)
+const SDL_Locale * const *SDL_GetPreferredLocales(int *count)
 {
     char locbuf[128]; /* enough for 21 "xx_YY," language strings. */
     const char *hint = SDL_GetHint(SDL_HINT_PREFERRED_LOCALES);
@@ -95,5 +108,5 @@ SDL_Locale *SDL_GetPreferredLocales(void)
         SDL_zeroa(locbuf);
         SDL_SYS_GetPreferredLocales(locbuf, sizeof(locbuf));
     }
-    return build_locales_from_csv_string(locbuf);
+    return build_locales_from_csv_string(locbuf, count);
 }

+ 4 - 4
test/testlocale.c

@@ -15,20 +15,20 @@
 
 static void log_locales(void)
 {
-    SDL_Locale *locales = SDL_GetPreferredLocales();
+    const SDL_Locale * const *locales = SDL_GetPreferredLocales(NULL);
     if (!locales) {
         SDL_Log("Couldn't determine locales: %s", SDL_GetError());
     } else {
-        SDL_Locale *l;
+        int i;
         unsigned int total = 0;
         SDL_Log("Locales, in order of preference:");
-        for (l = locales; l->language; l++) {
+        for (i = 0; locales[i]; ++i) {
+            const SDL_Locale *l = locales[i];
             const char *c = l->country;
             SDL_Log(" - %s%s%s", l->language, c ? "_" : "", c ? c : "");
             total++;
         }
         SDL_Log("%u locales seen.", total);
-        SDL_free(locales);
     }
 }