char path[strlen (i18npath) + sizeof ("/charmaps")];
const size_t pathlen = strlen (i18npath); char i18npathbuf[pathlen + 1]; char path[pathlen + sizeof ("/charmaps")];
charmap_read (const char *filename, int verbose, int be_quiet, int use_default){  struct charmap_t *result = NULL;  if (filename != NULL)    {      struct linereader *cmfile;      /* First try the name as found in the parameter.  */      cmfile = lr_open (filename, charmap_hash);      if (cmfile == NULL)	{	  /* No successful.  So start looking through the directories	     in the I18NPATH if this is a simple name.  */	  if (strchr (filename, '/') == NULL)	    {	      char *i18npath = getenv ("I18NPATH");	      if (i18npath != NULL && *i18npath != '\0')		{		  char path[strlen (i18npath) + sizeof ("/charmaps")];		  char *next;		  i18npath = strdupa (i18npath);		  while (cmfile == NULL			 && (next = strsep (&i18npath, ":")) != NULL)		    {		      stpcpy (stpcpy (path, next), "/charmaps");		      cmfile = cmlr_open (path, filename, charmap_hash);		      if (cmfile == NULL)			/* Try without the "/charmaps" part.  */			cmfile = cmlr_open (next, filename, charmap_hash);		    }		}	      if (cmfile == NULL)		/* Try the default directory.  */		cmfile = cmlr_open (CHARMAP_PATH, filename, charmap_hash);	    }	}      if (cmfile != NULL)	{	  result = parse_charmap (cmfile, verbose, be_quiet);	  if (result == NULL && !be_quiet)	    WITH_CUR_LOCALE (error (0, errno, _("\character map file `%s' not found"), filename));	}    }  if (result == NULL && filename != NULL && strchr (filename, '/') == NULL)    {      /* OK, one more try.  We also accept the names given to the	 character sets in the files.  Sometimes they differ from the	 file name.  */      CHARMAP_DIR *dir;      dir = charmap_opendir (CHARMAP_PATH);      if (dir != NULL)	{	  const char *dirent;	  while ((dirent = charmap_readdir (dir)) != NULL)	    {	      char **aliases;	      char **p;	      int found;	      aliases = charmap_aliases (CHARMAP_PATH, dirent);	      found = 0;	      for (p = aliases; *p; p++)		if (strcasecmp (*p, filename) == 0)		  {		    found = 1;		    break;		  }	      charmap_free_aliases (aliases);	      if (found)		{		  struct linereader *cmfile;		  cmfile = cmlr_open (CHARMAP_PATH, dirent, charmap_hash);		  if (cmfile != NULL)		    result = parse_charmap (cmfile, verbose, be_quiet);		  break;		}	    }	  charmap_closedir (dir);	}    }  if (result == NULL && DEFAULT_CHARMAP != NULL)    {      struct linereader *cmfile;      cmfile = cmlr_open (CHARMAP_PATH, DEFAULT_CHARMAP, charmap_hash);      if (cmfile != NULL)	result = parse_charmap (cmfile, verbose, be_quiet);      if (result == NULL)	WITH_CUR_LOCALE (error (4, errno, _("\default character map file `%s' not found"), DEFAULT_CHARMAP));    }  if (result != NULL && result->code_set_name == NULL)    /* The input file does not specify a code set name.  This       shouldn't happen but we should cope with it.  */    result->code_set_name = basename (filename);  /* Test of ASCII compatibility of locale encoding.     Verify that the encoding to be used in a locale is ASCII compatible,     at least for the graphic characters, excluding the control characters,     '$' and '@'.  This constraint comes from an ISO C 99 restriction.     ISO C 99 section 7.17.(2) (about wchar_t):       the null character shall have the code value zero and each member of       the basic character set shall have a code value equal to its value       when used as the lone character in an integer character constant.     ISO C 99 section 5.2.1.(3):       Both the basic source and basic execution character sets shall have       the following members: the 26 uppercase letters of the Latin alphabet            A B C D E F G H I J K L M N O P Q R S T U V W X Y Z       the 26 lowercase letters of the Latin alphabet            a b c d e f g h i j k l m n o p q r s t u v w x y z       the 10 decimal digits            0 1 2 3 4 5 6 7 8 9       the following 29 graphic characters            ! " # % & ' ( ) * + , - . / : ; < = > ? [ \ ] ^ _ { | } ~       the space character, and control characters representing horizontal       tab, vertical tab, and form feed.     Therefore, for all members of the "basic character set", the 'char' code     must have the same value as the 'wchar_t' code, which in glibc is the     same as the Unicode code, which for all of the enumerated characters     is identical to the ASCII code. */  if (result != NULL && use_default)    {      static const char basic_charset[] =	{	  'A', 'B', 'C', 'D', 'E', 'F', 'G', 'H', 'I', 'J', 'K', 'L', 'M',	  'N', 'O', 'P', 'Q', 'R', 'S', 'T', 'U', 'V', 'W', 'X', 'Y', 'Z',	  'a', 'b', 'c', 'd', 'e', 'f', 'g', 'h', 'i', 'j', 'k', 'l', 'm',	  'n', 'o', 'p', 'q', 'r', 's', 't', 'u', 'v', 'w', 'x', 'y', 'z',	  '0', '1', '2', '3', '4', '5', '6', '7', '8', '9',	  '!', '"', '#', '%', '&', '\'', '(', ')', '*', '+', ',', '-',	  '.', '/', ':', ';', '<', '=', '>', '?', '[', '\\', ']', '^',	  '_', '{', '|', '}', '~', ' ', '\t', '\v', '\f', '\0'	};      int failed = 0;      const char *p = basic_charset;      do	{	  struct charseq *seq = charmap_find_symbol (result, p, 1);	  if (seq == NULL || seq->ucs4 != (uint32_t) *p)	    failed = 1;	}      while (*p++ != '\0');      if (failed)	{	  WITH_CUR_LOCALE (fprintf (stderr, _("\character map `%s' is not ASCII compatible, locale not ISO C compliant\n"),				    result->code_set_name));	  enc_not_ascii_compatible = true;	}    }  return result;}