commit 4c35fa8e416d950cd5c72f9f240149bd4307a62e
Author: Tim Hentenaar <tim@hentenaar.com>
Date:   Sun, 29 Mar 2026 04:51:14 -0400

    fix: XmString: improve locale string handling (#16)

commit ec89134f090fc50a25dbcd77993de81ebe39e10a
Author: Tim Hentenaar <tim@hentenaar.com>
Date:   Sun, 29 Mar 2026 13:51:48 -0400

    XmString: ensure the locale string is null terminated

--- a/lib/Xm/XmString.c
+++ b/lib/Xm/XmString.c
@@ -5191,40 +5191,35 @@
   return(can_do);
 }
 
-static void _parse_locale(char *str, int *indx, int *len)
+/**
+ * Parse a locale string, yielding the index and length of the character
+ * set identifier therein.
+ */
+static void _parse_locale(char *str, int *idx, int *len)
 {
-    char     *temp;
-    int      start;
-    int      end;
-
-    /*
-     *  Set the return variables to zero.  If we find what we're looking
-     *  for, we reset them.
-     */
+	int end = 0;
+	char *tmp = str;
 
-    *indx = 0;
-    *len = 0;
-    if (!str) return;
+	*idx = 0;
+	*len = 0;
+	if (!str || !*str || *str == '@' || *str == ';')
+		return;
 
-    /*
-     *  The format of the locale string is:
-     *          language[_territory[.codeset]]
-     */
+	/**
+	 * Locale identifiers are formatted as:
+	 * language[_territory][.codeset][@modifier]
+	 */
+	while (tmp[end] && tmp[end] != '.' && tmp[end] != '@' && tmp[end] != ';')
+		end++;
 
-    temp = str;
-    end = 0;
-    while ((temp[end] != '.') && (temp[end] != 0))
-      end++;
+	/* Bail if we didn't get a codeset */
+	if (tmp[end++] != '.')
+		return;
 
-    if (temp[end] == '.')
-    {
-        start = end + 1;
-        *indx = start;
-	end = start;
-        while (temp[end] != 0)
-	  end++;
-        *len = end - start;
-    }
+	/* Look for the end of the codeset */
+	*idx = end;
+	while (tmp[end] && tmp[end] != '@' && tmp[end] != ';') end++;
+	*len = end - *idx;
 }
 
 void _XmStringSetLocaleTag(const char *lang)
@@ -5268,8 +5263,10 @@
 		len = 5;
 	}
 
-	locale.tag   = XtNewString(str);
-	locale.ctype = XtNewString(ct);
+	locale.tag   = XtCalloc(locale.taglen + 1, 1);
+	locale.ctype = XtCalloc(len + 1, 1);
+	memcpy(locale.tag, str, locale.taglen);
+	memcpy(locale.ctype, ct, len);
 	_XmProcessUnlock();
 }
 
