Listing 3 (setlocal.c)

/* setlocale function */
#include <ctype.h>
#include <locale.h>
#include <stdlib.h>
#include <string.h>

#if _NCAT != 6
#error wrong number of categories
#endif
      /* static data */
static char *defname = NULL;/* name of "" locale */
static int namalloc = 0;/* _Locale. _Name allocated
*/
static const char * const nmcats[_NCAT] = {
   NULL, "collate:", "ctype:", "monetary:",
   "numeric:", "time:"};
static struct lconv *pcats[_NCAT] = {NULL};

/* set new locale */
#undef setlocale
char *setlocale(int cat, const char *lname)
   {
   if (cat < 0 || _NCAT <= cat)
      return (NULL); /* bad category */
   if (lname == NULL)
      return ((char *)_Locale._Name);
   if (lname[0] == '\0')
      { /* find name of default locale */
      char *sl, *s2;
      
      if (defname)
         lname = defname;
      else if ((sl = getenv("LOCALE")) != NULL
         && (s2 = malloc(strlen(sl) + 1)) != NULL)
         lname = defname = strcpy(s2, sl);
      else
         lname = "C";
      }
   if (_Clocale._Ctype == NULL)
      {  /* flesh out "C" locale */
      size_t i;
      
      for (i =  0; i < _NCAT; ++i)
         pcats[i] = & _Clocale;
      _Clocale._Ctype = _Ctype;
      _Clocale._Tolower = _Tolower;
      _Clocale._Toupper = _Toupper;
      }
    { /* set categories */
   struct lconv *p;
   int changed = 0;
   
   if (cat != LC_ALL)
      { /* set a single category */
      if ((p = _Getloc(nmcats[cat], lname)) == NULL)
         return (NULL);
      if (p != pcats[cat])
         pcats[cat] = _Setloc(cat, p), changed = 1;
      }
   else
      {  /* set all categories */
      size_t i;
      
      for (i = 0; ++i < _NCAT; )
         {  /* set a category */
         if ((p = _Getloc(nmcats[i], lname)) == NULL)
            {  /* revert all on any failure */
            setlocale(LC_ALL,_Locale._Name);
            return (NULL);
            }
         if (p != pcats[i])
            pcats[i] = _Setloc(i, p), changed = 1;
         }
      if ((p = _Getloc("", lname)) != NULL)
         pcats[0] = p; /* set only if LC_ALL
                         component */
      }
   if (changed)
      {  /* rebuild _Locale._Name */
      char *s;
      size_t i, n;
      size_t len = strlen(pcats[0]->_Name);
      
      for (i = 0, n = 0; ++i < _NCAT; )
         if (pcats[i] != pcats[0])
            {  /* count a changed subcategory */
            len += strlen(nmcats[i])
               + strlen(pcats[i]->_Name) + 1;
            ++n;
            }
      if (in == 1)
         {  /* uniform locale */
         if (namalloc)
            free((void *)_Locale._Name);
         Locale._Name = pcats[1]->_Name;
         namalloc = 0;
         }
      else if ((s = malloc(len + 1)) == NULL)
         {  /* may be rash to try to roll back */
         setlocale(LC_ALL, _Locale._Name);
         return (NULL);
         }
      else
         {  /* build complex name */
         if (namalloc)
            free((void *)_Locale._Name);
         _Locale. _Name = s;
         namalloc = 1;
         s += strlen(strcpy(s, pcats[0]->_Name));
         for (i = 0; ++i < _NCAT; )
      if (pcats[i] != pcats[0])
         { /* add a component */
         *s =  ';';
         s +=   strlen(strcpy(s, nmcats[i]));
         s +=   strlen(strcpy(s, pcats[i]->_Name));
         }
      }
   }
 }
return ((char *)_Locale._Name);
}