/* SPDX-License-Identifier: BSD-2-Clause */ #define _GNU_SOURCE #include #include #include #include #include #include #include #include struct lc_era_t { char locale[64]; char *date_fmt; char *d_fmt; char *d_t_fmt; char *t_fmt; char *t_fmt_ampm; char *era; char *era_d_fmt; char *era_d_t_fmt; char *era_t_fmt; char *alt_digits; } era[512]; int ecnt = 0; char * xfrm_utf (const wchar_t *ws, int slist) { static char xfrm[4096]; char *p = xfrm; int wconst = 0; while (*ws) { if (*ws < 0x80 && (!wconst || !wcschr (L"aAbBcCdDeEfF", *ws))) { *p++ = *ws; wconst = 0; } else { p += sprintf (p, "\\x%04lx", *ws); wconst = 1; } ++ws; if (!*ws && slist) { ++ws; if (*ws) p += sprintf (p, ";"); } } *p = '\0'; return xfrm; } char * xfrm_slist (const char *slist) { static wchar_t wxfrm[4096], *wp; char *xfrm, *p, *ret; wp = wxfrm; while (*slist) { size_t len = mbstowcs (wp, slist, wxfrm + 4096 - wp) + 1; slist += strlen (slist) + 1; wp += len; } *wp++ = L'\0'; xfrm = xfrm_utf (wxfrm, 1); p = xfrm; while (*p) p += strlen (p) + 1; ++p; ret = (char *) malloc (p - xfrm); memcpy (ret, xfrm, p - xfrm); return ret; } void read_locale_era (char *name) { char *nl, *nlera, *altd; char locale[64]; wchar_t nlbuf[256]; strcpy (locale, name); nl = strchr (locale, '@'); if (nl) stpcpy (stpcpy (nl, ".utf8"), strchr (name, '@')); else strcat (locale, ".utf8"); printf ("%s\n", locale); setlocale (LC_ALL, locale); nlera = nl_langinfo (ERA); altd = nl_langinfo (ALT_DIGITS); if (!*nlera && !*altd) return; strcpy (era[ecnt].locale, name); nl = nl_langinfo (_DATE_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].date_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (D_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].d_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (D_T_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].d_t_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (T_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].t_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (T_FMT_AMPM); mbstowcs (nlbuf, nl, 256); era[ecnt].t_fmt_ampm = strdup (xfrm_utf (nlbuf, 0)); era[ecnt].era = *nlera ? xfrm_slist (nlera) : "\0"; era[ecnt].alt_digits = *altd ? xfrm_slist (altd) : "\0"; nl = nl_langinfo (ERA_D_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].era_d_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (ERA_D_T_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].era_d_t_fmt = strdup (xfrm_utf (nlbuf, 0)); nl = nl_langinfo (ERA_T_FMT); mbstowcs (nlbuf, nl, 256); era[ecnt].era_t_fmt = strdup (xfrm_utf (nlbuf, 0)); /* Serbian locale rename weirdness */ if (!strncmp (era[ecnt].locale, "sr_RS", 5)) { /* Create additional equivalent entries for the old locale sr_SP. */ ++ecnt; memcpy (&era[ecnt], &era[ecnt - 1], sizeof era[ecnt]); era[ecnt].locale[3] = 'S'; era[ecnt].locale[4] = 'P'; /* Create additional equivalent entry for sr_ME@latin missing in Linux. */ if (!strcmp (era[ecnt].locale, "sr_SP@latin")) { ++ecnt; memcpy (&era[ecnt], &era[ecnt - 1], sizeof era[ecnt]); era[ecnt].locale[3] = 'M'; era[ecnt].locale[4] = 'E'; } } ++ecnt; } int locale_cmp (const void *a, const void *b) { struct lc_era_t *la = (struct lc_era_t *) a; struct lc_era_t *lb = (struct lc_era_t *) b; return strcmp (la->locale, lb->locale); } void create_list () { FILE *fp = fopen ("lc_era.h", "w"); FILE *pp = popen ("rpm -q glibc", "r"); char vers[64]; int i; struct tm *tm; time_t tim; char tstr[64]; fgets (vers, 64, pp); pclose (pp); if (strchr (vers, '\n')) *strchr (vers, '\n') = '\0'; tim = time (NULL); tm = gmtime (&tim); strftime (tstr, 64, "%F", tm); fprintf (fp, "/* This struct of LC_TIME ERA data has been generated by fetching locale\n" " data from a Linux system using %s on %s. */\n" "\n" "struct lc_era_t\n" "{\n" " const char *locale;\n" " const wchar_t *date_fmt;\n" " const wchar_t *d_fmt;\n" " const wchar_t *d_t_fmt;\n" " const wchar_t *t_fmt;\n" " const wchar_t *t_fmt_ampm;\n" " const wchar_t *era;\n" " const wchar_t *era_d_fmt;\n" " const wchar_t *era_d_t_fmt;\n" " const wchar_t *era_t_fmt;\n" " const wchar_t *alt_digits;\n" "};\n" "\n" "static struct lc_era_t lc_era[] =\n" "{\n", vers, tstr); qsort (era, ecnt, sizeof (struct lc_era_t), locale_cmp); for (i = 0; i < ecnt; ++i) fprintf (fp, " { \"%s\", L\"%s\", L\"%s\", L\"%s\", L\"%s\", L\"%s\", " "L\"%s\", L\"%s\", L\"%s\", L\"%s\", L\"%s\" },\n", era[i].locale, era[i].date_fmt, era[i].d_fmt, era[i].d_t_fmt, era[i].t_fmt, era[i].t_fmt_ampm, era[i].era, era[i].era_d_fmt, era[i].era_d_t_fmt, era[i].era_t_fmt, era[i].alt_digits); fputs ("};\n", fp); fclose (fp); } int main () { char name[32], *c; FILE *pp; pp = popen ("locale -a | grep -a '_' | grep -F -v .", "r"); if (!pp) { perror ("popen failed"); return 1; } while (fgets (name, 32, pp)) { c = strchr (name, '\n'); if (c) *c = '\0'; read_locale_era (name); } pclose (pp); create_list (); return 0; }