about summary refs log tree commit diff
path: root/locale/programs/locale.c
diff options
context:
space:
mode:
authorUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
committerUlrich Drepper <drepper@redhat.com>1997-02-19 04:43:53 +0000
commit1fb05e3db1891142410bc58c320dfe281749fffe (patch)
tree46299dbecec282055e3493787910444e77099fe7 /locale/programs/locale.c
parentc84142e8fe3cbcce43ae35ac957a74ac8216d11d (diff)
downloadglibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.gz
glibc-1fb05e3db1891142410bc58c320dfe281749fffe.tar.xz
glibc-1fb05e3db1891142410bc58c320dfe281749fffe.zip
update from main archive 970218 cvs/libc-970221 cvs/libc-970220 cvs/libc-970219
1997-02-19 03:28  Miles Bader  <miles@gnu.ai.mit.edu>

	* argp/argp-help.c: Add support for user provided filter of help
	messages.
	* argp/argp-parse.c: Likewise.
	* argp/argp.h: Likewise.
	* argp/argp-namefrob.h: Define __argp_input.

	* argp/argp-test.c: Add example for filter.

1997-02-19 02:58  Ulrich Drepper  <drepper@cygnus.com>

	* argp.h: New file.
	* locale/programs/locale.c: Switch to use argp.

	* errno.h: Make it possible to get definition of error_t even
	after having errno.h already.

	* elf/dl-hash.h: New file.  ELF hashing function.  Extracted
	from dl-lookup.c.
	* elf/dl-lookup.c (_dl_elf_hash): Remove definition.

	* elf/dl-load.c: Rename _dl_does_name_match_p to _dl_name_match_p.
	* elf/dl-version.c: Likewise.

	* elf/dl-lookup.c: Implement new versioning lookup scheme.
	* elf/dl-version.c (_dl_check_map_versions): Initialize new field
	in l_versions member.

	* elf/dlvsym.c: Correct call of _dl_lookup_versioned_symbol_skip
	and _dl_lookup_versioned_symbol.

	* elf/link.h: Rename hash_name_pair to struct r_found_version.
	* sysdeps/alpha/dl-machine.h: Likewise.
	* sysdeps/i386/dl-machine.h: Likewise.
	* sysdeps/m68k/dl-machine.h: Likewise.
	* sysdeps/mips/dl-machine.h: Likewise.

	* intl/l10nflist.c: (_nl_make_l10nflist): Fix bug in computation of
	length of abs_filename.

	* locale/Makefile (CPPFLAGS): Define LOCALE_ALIAS_PATH.

	* locale/programs/ld-monetary.c (monetary_add): Allow value 0
	in mon_grouping information.  This means no more grouping.
	* locale/programs/ld-numeric.c (numeric_add): Write value \377
	when seein value 0 in grouping information.
	* locale/programs/linereader.c (lr_close): Don't free fname since
	it might be used in error messages.

	* locale/programs/locale.c: Check whether output of `locale -a'
	really is locale directory.  Also print locale aliases.

	* misc/search.h (__action_fn_t): Parameters VALUE and LEVEL cannot
	be const.

1997-02-19 02:16  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/bsd/sun/sunos4/resourcebits.h: Correct #defin to
	#define.  Reported by Rick Flower <FLOWER@sdvax2.sdd.TRW.COM>.

1997-02-19 01:37  Erik Troan  <ewt@redhat.com>

	* shadow/sgetspent_r.c: Accept empty third, fourth and fifth fields.

1997-02-19 01:02  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/mman/syscalls.list: msync takes 3 arguments.
	Reported by Andreas Jaeger <aj@arthur.pfalz.de>.

	* sysdeps/stub/msync.c (msync): Add missing third parameter.

1997-02-19 00:29  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/bsd/sigsuspend.c: Call __sigpause with needed
	additional argument.

1997-02-18 22:13  Ulrich Drepper  <drepper@cygnus.com>

	* inet/net/ethernet.h: New file.
	* sysdeps/unix/sysv/linux/netinet/if_ether.c: Add BSD compatibility.
	* sysdeps/unix/sysv/linux/net/if_slip.h: New file.
	Contributed by a sun <asun@zoology.washington.edu>.

	* sysdeps/unix/sysv/linux/net/if_arp.h: Include <sys/socket.h>.
	* sunrpc/rpc/rpc_msg.h: Include <rpc/clnt.h>.
	Reported by a sun <asun@zoology.washington.edu>.

1997-02-16 14:25  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* Makerules ((common-objpfx)distinfo-$(subdir)): Depend on sysdep
	makefiles which may change the distinfo variables.

1997-02-16 14:03  Andreas Schwab  <schwab@issan.informatik.uni-dortmund.de>

	* sysdeps/unix/sysv/linux/Makefile (sysdep_headers)
	[$(subdir)=misc]: Add sys/quota.h.
	(sysdep_headers) [$(subdir)=inet]: Add netinet/udp.h.

1997-02-17 13:12  aleph1@dfw.net

	* sunrpc/clnt_simp.c (callrpc): Prevent buffer overflow by using
	strncpy.

1997-02-18 03:28  Ulrich Drepper  <drepper@cygnus.com>

	* stdio-common/bug10.c (main): Correct parameter.

1997-02-17 02:51  Ulrich Drepper  <drepper@cygnus.com>

	* malloc/obstack.h: Add `extern "C"' protection.
	* posix/regex.h: Likewise.
	* io/ftw.h: Likewise.
	* misc/libgen.h: Likewise.
	* login/utmp.h: Likewise.
	* sysdeps/unix/sysv/linux/sys/reboot.h: Likewise.
	* sysdeps/unix/sysv/linux/netinet/in.h: Likewise.
	* sunrpc/rpc/pmap_rmt.h: Likewise.
	* sunrpc/rpc/auth_des.h: Likewise.
	* elf/link.h: Likewise.
	Reported by HJ Lu.

1997-02-17 01:45  a sun  <asun@zoology.washington.edu>

	Linux specific network headers.
	* sysdeps/unix/sysv/linux/netinet/if_fddi.h: New file.
	* sysdeps/unix/sysv/linux/netinet/if_tr.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip_icmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip_fw.h: New file.
	* sysdeps/unix/sysv/linux/netinet/igmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/icmp.h: New file.
	* sysdeps/unix/sysv/linux/netinet/ip.h: New file.
	* sysdeps/unix/sysv/linux/netinet/tcp.h: New file.
	* sysdeps/unix/sysv/linux/netipx/ipx.h: New file.
	* sysdeps/unix/sysv/linux/netatalk/atalk.h: New file.
	* sysdeps/unix/sysv/linux/Dist: Add new network headers.
	* sysdeps/unix/sysv/linux/Makefile [$(subdir)=misc] (sysdep_headers):
	Add sys/quota.h.
	[$(subdir)=inet] (sysdep_headers): Add new network header.

	* sysdeps/unix/sysv/linux/netinet/udp.h: Add Linux specific changes.

	* inet/netinet/ip.h: Move to sysdeps/generic.
	* inet/netinet/tcp.h: Likewise.
	* sysdeps/generic/netinet/ip.h: Moved to here from inet/netinet.
	* sysdeps/generic/netinet/tcp.h: Likewise.

1997-02-17 01:18  Ulrich Drepper  <drepper@cygnus.com>

	* misc/sys/syslog.h (prioritynames): Correct definition to use
	braces where necessary.
	(facilitynames): Likewise.
	Patch by Ronald F. Guilmette <rfg@monkeys.com>.
	Comment and beautify declarations.

1997-02-16 19:54 1997  Philip Blundell  <Philip.Blundell@pobox.com>

	* inet/Makefile (routines): Add in6_addr, getnameinfo.
	* inet/getnameinfo.c: New file.  Implementation of getnameinfo()
	by Craig Metz.
	* inet/in6_addr.c: New file.  IPv6 addressing constants.
	* posix/Makefile (routines): Add gai_strerror.
	* resolv/netdb.h: Add more constants for IPv6 basic API.
	* sysdeps/posix/gai_strerror.c: New file.
	* sysdeps/stub/gai_strerror.c New file.
	* sysdeps/unix/sysv/linux/netinet/in.h: Add definitions for IPv6
	basic API.

	* sysdeps/posix/getaddrinfo.c: Update from latest version by
	Craig Metz and use reentrant getXXbyYY functions.

1997-02-15 14:32 Andreas Jaeger  <aj@arthur.pfalz.de>

	* argp/argp.h: Declare argp_program_version as const char.
	* argp/argp-test.c: Likewise

	* stdlib/testrand.c (main): Declare main prototype.
	* stdlib/testdiv.c (main): Likewise.
	* string/testcopy.c (main): Likewise.
	* string/test-ffs.c (main): Likewise.
	* time/test_time.c (main): Likewise.

	* locale/duplocale.c (__duplocale): Return result.

1997-02-16 03:54  Ulrich Drepper  <drepper@cygnus.com>

	* sysdeps/unix/sysv/linux/netinet/in.h: Declare bindresvport.
	Reported by fabsoft@fabserver1.zarm.uni-bremen.de.

	* nss/nss.h: Remove declaration of __nss_shlib_revision.
	* nss/nsswitch.c: Don't use NSS_SHLIB_VERSION macro.

1997-02-16 03:48  Thorsten Kukuk  <kukuk@weber.uni-paderborn.de>

	* nis/nss_nis/nis-ethers.c (_nss_nis_getethernam_r): Rename to
	_nss_nis_gethostton_r.
	(_nss_nis_getetherbyaddr_r): Rename to _nss_nis_getntohost_r.

1997-02-15 22:37  Andy Berkheimer  <andy@tho.org>

	* resolv/gethnamaddr.c (gethostbyname2): Test for ':' in name before
	trying to resolv name as numeric IPv6 address.
	* nss/digits_dots.c: Likewise.

Sat Feb 15 04:51:08 1997  Ulrich Drepper  <drepper@cygnus.com>

	* locale/setlocale.c (setlocale): Don't try to be clever about
	unused locales.  When the existence of the locale files isn't
	tested the result of setlocale might be different.

1997-02-15 03:34  Ulrich Drepper  <drepper@cygnus.com>

	* locale/setlocale.c (setlocale): Don't increment usage_count of
	new locale if it already has the value MAX_USAGE_COUNT (it might
	be the C locale data which is read-only).
Diffstat (limited to 'locale/programs/locale.c')
-rw-r--r--locale/programs/locale.c353
1 files changed, 258 insertions, 95 deletions
diff --git a/locale/programs/locale.c b/locale/programs/locale.c
index 8587345bf2..5a68c562ef 100644
--- a/locale/programs/locale.c
+++ b/locale/programs/locale.c
@@ -1,4 +1,4 @@
-/* locale - Implementation of the locale program according to POSIX 1003.2
+/* Implementation of the locale program according to POSIX 1003.2.
    Copyright (C) 1995, 1996, 1997 Free Software Foundation, Inc.
    This file is part of the GNU C Library.
    Contributed by Ulrich Drepper <drepper@gnu.ai.mit.edu>, 1995.
@@ -22,18 +22,21 @@
 # include <config.h>
 #endif
 
+#include <argp.h>
+#include <argz.h>
 #include <dirent.h>
+#include <errno.h>
 #include <error.h>
-#include <getopt.h>
 #include <langinfo.h>
 #include <libintl.h>
 #include <limits.h>
 #include <locale.h>
+#include <search.h>
 #include <stdio.h>
 #include <stdlib.h>
-#include <unistd.h>
-#include <errno.h>
 #include <string.h>
+#include <unistd.h>
+#include <sys/stat.h>
 
 #include "localeinfo.h"
 
@@ -44,16 +47,44 @@ static int show_category_name;
 /* If set print the name of the item.  */
 static int show_keyword_name;
 
-/* Long options.  */
-static const struct option long_options[] =
+/* Print names of all available locales.  */
+static int do_all;
+
+/* Print names of all available character maps.  */
+static int do_charmaps = 0;
+
+/* Name and version of program.  */
+static void print_version (FILE *stream, struct argp_state *state);
+void (*argp_program_version_hook) (FILE *, struct argp_state *) = print_version;
+
+/* Definitions of arguments for argp functions.  */
+static struct argp_option options[] =
 {
-  { "all-locales", no_argument, NULL, 'a' },
-  { "category-name", no_argument, &show_category_name, 1 },
-  { "charmaps", no_argument, NULL, 'm' },
-  { "help", no_argument, NULL, 'h' },
-  { "keyword-name", no_argument, &show_keyword_name, 1 },
-  { "version", no_argument, NULL, 'V' },
-  { NULL, 0, NULL, 0 }
+  { NULL, 0, NULL, 0, "System information:" },
+  { "all-locales", 'a', NULL, 0, "Write names of available locales" },
+  { "charmaps", 'm', NULL, 0, "Write names of available charmaps" },
+  { NULL, 0, NULL, 0, "Modify output format:" },
+  { "category-name", 'c', NULL, 0, "Write names of selected categories" },
+  { "keyword-name", 'k', NULL, 0, "Write names of selected keywords" },
+  { NULL, 0, NULL, 0, NULL }
+};
+
+/* Short description of program.  */
+static const char doc[] = "Get locale-specific information.";
+
+/* Strings for arguments in help texts.  */
+static const char args_doc[] = "NAME\n[-a|-m]";
+
+/* Prototype for option handler.  */
+static error_t parse_opt (int key, char *arg, struct argp_state *state);
+
+/* Function to print some extra text in the help message.  */
+static char *more_help (int key, const char *text, void *input);
+
+/* Data structure to communicate with argp functions.  */
+static struct argp argp =
+{
+  options, parse_opt, args_doc, doc, NULL, more_help
 };
 
 
@@ -124,7 +155,6 @@ extern void locale_special (const char *name, int show_category_name,
 			    int show_keyword_name);
 
 /* Prototypes for local functions.  */
-static void usage (int status) __attribute__ ((noreturn));
 static void write_locales (void);
 static void write_charmaps (void);
 static void show_locale_vars (void);
@@ -134,12 +164,6 @@ static void show_info (const char *name);
 int
 main (int argc, char *argv[])
 {
-  int optchar;
-  int do_all = 0;
-  int do_help = 0;
-  int do_version = 0;
-  int do_charmaps = 0;
-
   /* Set initial values for global variables.  */
   show_category_name = 0;
   show_keyword_name = 0;
@@ -152,55 +176,13 @@ main (int argc, char *argv[])
   /* Initialize the message catalog.  */
   textdomain (PACKAGE);
 
-  while ((optchar = getopt_long (argc, argv, "achkmV", long_options, NULL))
-         != -1)
-    switch (optchar)
-      {
-      case '\0':		/* Long option.  */
-	break;
-      case 'a':
-	do_all = 1;
-	break;
-      case 'c':
-	show_category_name = 1;
-	break;
-      case 'h':
-	do_help = 1;
-	break;
-      case 'k':
-	show_keyword_name = 1;
-	break;
-      case 'm':
-	do_charmaps = 1;
-	break;
-      case 'V':
-	do_version = 1;
-	break;
-      default:
-	usage (EXIT_FAILURE);
-      }
-
-  /* Version information is requested.  */
-  if (do_version)
-    {
-      printf ("locale (GNU %s) %s\n", PACKAGE, VERSION);
-      printf (_("\
-Copyright (C) %s Free Software Foundation, Inc.\n\
-This is free software; see the source for copying conditions.  There is NO\n\
-warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
-"), "1995, 1996, 1997");
-      printf (_("Written by %s.\n"), "Ulrich Drepper");
-
-      exit (EXIT_SUCCESS);
-    }
-
-  /* Help is requested.  */
-  if (do_help)
-    usage (EXIT_SUCCESS);
+  /* Parse and process arguments.  */
+  argp_parse (&argp, argc, argv, 0, 0, NULL);
 
   /* `-a' requests the names of all available locales.  */
   if (do_all != 0)
     {
+      setlocale (LC_COLLATE, "");
       write_locales ();
       exit (EXIT_SUCCESS);
     }
@@ -233,61 +215,219 @@ warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
 }
 
 
-/* Display usage information and exit.  */
-static void
-usage (int status)
+/* Handle program arguments.  */
+static error_t
+parse_opt (int key, char *arg, struct argp_state *state)
 {
-  if (status != EXIT_SUCCESS)
-    fprintf (stderr, gettext ("Try `%s --help' for more information.\n"),
-	     __progname);
-  else
+  switch (key)
     {
-      printf (gettext ("\
-Usage: %s [OPTION]... name\n\
-Mandatory arguments to long options are mandatory for short options too.\n\
-  -h, --help            display this help and exit\n\
-  -V, --version         output version information and exit\n\
-\n\
-  -a, --all-locales     write names of available locales\n\
-  -m, --charmaps        write names of available charmaps\n\
-\n\
-  -c, --category-name   write names of selected categories\n\
-  -k, --keyword-name    write names of selected keywords\n"),
-	      __progname);
-      fputs (gettext ("\
-Report bugs using the `glibcbug' script to <bugs@gnu.ai.mit.edu>.\n"),
-	     stdout);
+    case 'a':
+      do_all = 1;
+      break;
+    case 'c':
+      show_category_name = 1;
+      break;
+    case 'm':
+      do_charmaps = 1;
+      break;
+    case 'k':
+      show_keyword_name = 1;
+      break;
+    default:
+      return ARGP_ERR_UNKNOWN;
     }
+  return 0;
+}
+
+
+static char *
+more_help (int key, const char *text, void *input)
+{
+  switch (key)
+    {
+    case ARGP_KEY_HELP_EXTRA:
+      /* We print some extra information.  */
+      return strdup (gettext ("\
+Report bugs using the `glibcbug' script to <bugs@gnu.ai.mit.edu>.\n"));
+    default:
+      break;
+    }
+  return (char *) text;
+}
+
+/* Print the version information.  */
+static void
+print_version (FILE *stream, struct argp_state *state)
+{
+  fprintf (stream, "locale (GNU %s) %s\n", PACKAGE, VERSION);
+  fprintf (stream, gettext ("\
+Copyright (C) %s Free Software Foundation, Inc.\n\
+This is free software; see the source for copying conditions.  There is NO\n\
+warranty; not even for MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.\n\
+"), "1995, 1996, 1997");
+  fprintf (stream, gettext ("Written by %s.\n"), "Ulrich Drepper");
+}
 
-  exit (status);
+
+/* Simple action function which prints arguments as strings.  */
+static void
+print_names (const void *nodep, VISIT value, int level)
+{
+  if (value == postorder || value == leaf)
+    puts (*(char **) nodep);
 }
 
 
-/* Write the names of all available locales to stdout.  */
+/* Write the names of all available locales to stdout.  We have some
+   sources of the information: the contents of the locale directory
+   and the locale.alias file.  To avoid duplicates and print the
+   result is a reasonable order we put all entries is a search tree
+   and print them afterwards.  */
 static void
 write_locales (void)
 {
+  void *all_data = NULL;
   DIR *dir;
   struct dirent *dirent;
+  char *alias_path;
+  size_t alias_path_len;
+  char *entry;
 
-  /* `POSIX' locale is always available (POSIX.2 4.34.3).  */
-  puts ("POSIX");
+#define PUT(name) tsearch ((name), &all_data, \
+			   (int (*) (const void *, const void *)) strcoll)
 
-  dir = opendir (LOCALE_PATH);
+  dir = opendir (LOCALEDIR);
   if (dir == NULL)
     {
       error (1, errno, gettext ("cannot read locale directory `%s'"),
-	     LOCALE_PATH);
+	     LOCALEDIR);
       return;
     }
 
+  /* `POSIX' locale is always available (POSIX.2 4.34.3).  */
+  PUT ("POSIX");
+  /* And so is the "C" locale.  */
+  PUT ("C");
+
   /* Now we can look for all files in the directory.  */
   while ((dirent = readdir (dir)) != NULL)
     if (strcmp (dirent->d_name, ".") != 0
 	&& strcmp (dirent->d_name, "..") != 0)
-      puts (dirent->d_name);
+      {
+	mode_t mode;
+#ifdef _DIRENT_HAVE_D_TYPE
+	if (dirent->d_type != DT_UNKNOWN)
+	  mode = DTTOIF (dirent->d_type);
+	else
+#endif
+	  {
+	    struct stat st;
+	    char buf[sizeof (LOCALEDIR) + strlen (dirent->d_name) + 1];
+
+	    stpcpy (stpcpy (stpcpy (buf, LOCALEDIR), "/"), dirent->d_name);
+
+	    if (stat (buf, &st) < 0)
+	      continue;
+	    mode = st.st_mode;
+	  }
+
+	if (S_ISDIR (mode))
+	  PUT (strdup (dirent->d_name));
+      }
 
   closedir (dir);
+
+  /* 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;
+
+      while (! feof (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 (buf, BUFSIZ, fp) == NULL)
+	    /* EOF reached.  */
+	    break;
+
+	  cp = buf;
+	  /* Ignore leading white space.  */
+	  while (isspace (cp[0]))
+	    ++cp;
+
+	  /* A leading '#' signals a comment line.  */
+	  if (cp[0] != '\0' && cp[0] != '#')
+	    {
+	      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.  */
+		  PUT (strdup (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 (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);
+    }
+
+  twalk (all_data, print_names);
 }
 
 
@@ -295,6 +435,7 @@ write_locales (void)
 static void
 write_charmaps (void)
 {
+  void *all_data = NULL;
   DIR *dir;
   struct dirent *dirent;
 
@@ -310,9 +451,31 @@ write_charmaps (void)
   while ((dirent = readdir (dir)) != NULL)
     if (strcmp (dirent->d_name, ".") != 0
 	&& strcmp (dirent->d_name, "..") != 0)
-      puts (dirent->d_name);
+      {
+	mode_t mode;
+#ifdef _DIRENT_HAVE_D_TYPE
+	if (dirent->d_type != DT_UNKNOWN)
+	  mode = DTTOIF (dirent->d_type);
+	else
+#endif
+	  {
+	    struct stat st;
+	    char buf[sizeof (CHARMAP_PATH) + strlen (dirent->d_name) + 1];
+
+	    stpcpy (stpcpy (stpcpy (buf, CHARMAP_PATH), "/"), dirent->d_name);
+
+	    if (stat (buf, &st) < 0)
+	      continue;
+	    mode = st.st_mode;
+	  }
+
+	if (S_ISREG (mode))
+	  PUT (strdup (dirent->d_name));
+      }
 
   closedir (dir);
+
+  twalk (all_data, print_names);
 }