PUT ("POSIX");  PUT ("C");
write_locales (void){  char linebuf[80];  void *all_data = NULL;  struct dirent **dirents;  int ndirents;  int cnt;  char *alias_path;  size_t alias_path_len;  char *entry;  int first_locale = 1;#define PUT(name) tsearch (name, &all_data, \			   (int (*) (const void *, const void *)) strcoll)  /* Now read the locale.alias files.  */  if (argz_create_sep (LOCALE_ALIAS_PATH, ':', &alias_path, &alias_path_len))    error (1, errno, gettext ("while preparing output"));  entry = NULL;  while ((entry = argz_next (alias_path, alias_path_len, entry)))    {      static const char aliasfile[] = "/locale.alias";      FILE *fp;      char full_name[strlen (entry) + sizeof aliasfile];      stpcpy (stpcpy (full_name, entry), aliasfile);      fp = fopen (full_name, "r");      if (fp == NULL)	/* Ignore non-existing files.  */	continue;      /* No threads present.  */      __fsetlocking (fp, FSETLOCKING_BYCALLER);      while (! feof_unlocked (fp))	{	  /* It is a reasonable approach to use a fix buffer here	     because	     a) we are only interested in the first two fields	     b) these fields must be usable as file names and so must	        not be that long  */	  char buf[BUFSIZ];	  char *alias;	  char *value;	  char *cp;	  if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)	    /* EOF reached.  */	    break;	  cp = buf;	  /* Ignore leading white space.  */	  while (isspace (cp[0]) && cp[0] != '\n')	    ++cp;	  /* A leading '#' signals a comment line.  */	  if (cp[0] != '\0' && cp[0] != '#' && cp[0] != '\n')	    {	      alias = cp++;	      while (cp[0] != '\0' && !isspace (cp[0]))		++cp;	      /* Terminate alias name.  */	      if (cp[0] != '\0')		*cp++ = '\0';	      /* Now look for the beginning of the value.  */	      while (isspace (cp[0]))		++cp;	      if (cp[0] != '\0')		{		  value = cp++;		  while (cp[0] != '\0' && !isspace (cp[0]))		    ++cp;		  /* Terminate value.  */		  if (cp[0] == '\n')		    {		      /* This has to be done to make the following			 test for the end of line possible.  We are			 looking for the terminating '\n' which do not			 overwrite here.  */		      *cp++ = '\0';		      *cp = '\n';		    }		  else if (cp[0] != '\0')		    *cp++ = '\0';		  /* Add the alias.  */		  if (! verbose)		    PUT (xstrdup (alias));		}	    }	  /* Possibly not the whole line fits into the buffer.	     Ignore the rest of the line.  */	  while (strchr (cp, '\n') == NULL)	    {	      cp = buf;	      if (fgets_unlocked (buf, BUFSIZ, fp) == NULL)		/* Make sure the inner loop will be left.  The outer		   loop will exit at the `feof' test.  */		*cp = '\n';	    }	}      fclose (fp);    }  memset (linebuf, '-', sizeof (linebuf) - 1);  linebuf[sizeof (linebuf) - 1] = '\0';  /* Now we can look for all files in the directory.  */  ndirents = scandir (LOCALEDIR, &dirents, select_dirs, alphasort);  for (cnt = 0; cnt < ndirents; ++cnt)    {      /* Test whether at least the LC_CTYPE data is there.  Some	 directories only contain translations.  */      char buf[sizeof (LOCALEDIR) + strlen (dirents[cnt]->d_name)	      + sizeof "/LC_IDENTIFICATION"];      char *enddir;      struct stat64 st;      stpcpy (enddir = stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"),			       dirents[cnt]->d_name),	      "/LC_IDENTIFICATION");      if (stat64 (buf, &st) == 0 && S_ISREG (st.st_mode))	{	  if (verbose)	    {	      /* Provide some nice output of all kinds of		 information.  */	      int fd;	      if (! first_locale)		putchar_unlocked ('\n');	      first_locale = 0;	      printf ("locale: %-15.15s directory: %.*s\n%s\n",		      dirents[cnt]->d_name, (int) (enddir - buf), buf,		      linebuf);	      fd = open64 (buf, O_RDONLY);	      if (fd != -1)		{		  void *mapped = mmap64 (NULL, st.st_size, PROT_READ,					 MAP_SHARED, fd, 0);		  if (mapped != MAP_FAILED)		    {		      /* Read the information from the file.  */		      struct		      {			unsigned int magic;			unsigned int nstrings;			unsigned int strindex[0];		      } *filedata = mapped;		      if (filedata->magic == LIMAGIC (LC_IDENTIFICATION)			  && (sizeof *filedata			      + (filedata->nstrings				 * sizeof (unsigned int))			      <= (size_t) st.st_size))			{			  const char *str;#define HANDLE(idx, name) \  str = ((char *) mapped						      \	 + filedata->strindex[_NL_ITEM_INDEX (_NL_IDENTIFICATION_##idx)]);    \  if (*str != '\0')							      \    printf ("%9s | %s\n", name, str)			  HANDLE (TITLE, "title");			  HANDLE (SOURCE, "source");			  HANDLE (ADDRESS, "address");			  HANDLE (CONTACT, "contact");			  HANDLE (EMAIL, "email");			  HANDLE (TEL, "telephone");			  HANDLE (FAX, "fax");			  HANDLE (LANGUAGE, "language");			  HANDLE (TERRITORY, "territory");			  HANDLE (AUDIENCE, "audience");			  HANDLE (APPLICATION, "application");			  HANDLE (ABBREVIATION, "abbreviation");			  HANDLE (REVISION, "revision");			  HANDLE (DATE, "date");			}		      munmap (mapped, st.st_size);		    }		  close (fd);		  /* Now try to get the charset information.  */		  strcpy (enddir, "/LC_CTYPE");		  fd = open64 (buf, O_RDONLY);		  if (fd != -1 && fstat64 (fd, &st) >= 0		      && ((mapped = mmap64 (NULL, st.st_size, PROT_READ,					    MAP_SHARED, fd, 0))			  != MAP_FAILED))		    {		      struct		      {			unsigned int magic;			unsigned int nstrings;			unsigned int strindex[0];		      } *filedata = mapped;		      if (filedata->magic == LIMAGIC (LC_CTYPE)			  && (sizeof *filedata			      + (filedata->nstrings				 * sizeof (unsigned int))			      <= (size_t) st.st_size))			{			  const char *str;			  str = ((char *) mapped				 + filedata->strindex[_NL_ITEM_INDEX (_NL_CTYPE_CODESET_NAME)]);			  if (*str != '\0')			    printf ("  codeset | %s\n", str);			}		      munmap (mapped, st.st_size);		    }		  if (fd != -1)		    close (fd);		}	    }	  else	    /* If the verbose format is not selected we simply	       collect the names.  */	    PUT (xstrdup (dirents[cnt]->d_name));	}    }  if (ndirents > 0)    free (dirents);  if (! verbose)    {      /* `POSIX' locale is always available (POSIX.2 4.34.3).  */      PUT ("POSIX");      /* And so is the "C" locale.  */      PUT ("C");      twalk (all_data, print_names);    }}