if (ctype == NULL) {  if (locale->copy_name[LC_CTYPE] != NULL) {  struct localedef_t *from = locale;  do from = find_locale (LC_CTYPE, from->copy_name[LC_CTYPE], from->repertoire_name, charmap); while (from->categories[LC_CTYPE].ctype == NULL && from->copy_name[LC_CTYPE] != NULL);  ctype = locale->categories[LC_CTYPE].ctype = from->categories[LC_CTYPE].ctype; }   if (ctype == NULL) { error (0, 0, _("No definition for %s category found"), "LC_CTYPE"); ctype_startup (NULL, locale, charmap, 0); ctype = locale->categories[LC_CTYPE].ctype; } }
ctype_finish (struct localedef_t *locale, struct charmap_t *charmap){  /* See POSIX.2, table 2-6 for the meaning of the following table.  */#define NCLASS 12  static const struct  {    const char *name;    const char allow[NCLASS];  }  valid_table[NCLASS] =  {    /* The order is important.  See token.h for more information.       M = Always, D = Default, - = Permitted, X = Mutually exclusive  */    { "upper",  "--MX-XDDXXX-" },    { "lower",  "--MX-XDDXXX-" },    { "alpha",  "---X-XDDXXX-" },    { "digit",  "XXX--XDDXXX-" },    { "xdigit", "-----XDDXXX-" },    { "space",  "XXXXX------X" },    { "print",  "---------X--" },    { "graph",  "---------X--" },    { "blank",  "XXXXXM-----X" },    { "cntrl",  "XXXXX-XX--XX" },    { "punct",  "XXXXX-DD-X-X" },    { "alnum",  "-----XDDXXX-" }  };  size_t cnt;  int cls1, cls2;  uint32_t space_value;  struct charseq *space_seq;  struct locale_ctype_t *ctype = locale->categories[LC_CTYPE].ctype;  int warned;  /* Set default value for classes not specified.  */  set_class_defaults (ctype, charmap, ctype->repertoire);  /* Check according to table.  */  for (cnt = 0; cnt < ctype->class_collection_max; ++cnt)    {      uint32_t tmp = ctype->class_collection[cnt];      if (tmp != 0)	{	  for (cls1 = 0; cls1 < NCLASS; ++cls1)	    if ((tmp & _ISwbit (cls1)) != 0)	      for (cls2 = 0; cls2 < NCLASS; ++cls2)		if (valid_table[cls1].allow[cls2] != '-')		  {		    int eq = (tmp & _ISwbit (cls2)) != 0;		    switch (valid_table[cls1].allow[cls2])		      {		      case 'M':			if (!eq)			  {			    uint32_t value = ctype->charnames[cnt];			    if (!be_quiet)			      error (0, 0, _("\character L'\\u%0*x' in class `%s' must be in class `%s'"),				     value > 0xffff ? 8 : 4, value,				     valid_table[cls1].name,				     valid_table[cls2].name);			  }			break;		      case 'X':			if (eq)			  {			    uint32_t value = ctype->charnames[cnt];			    if (!be_quiet)			      error (0, 0, _("\character L'\\u%0*x' in class `%s' must not be in class `%s'"),				     value > 0xffff ? 8 : 4, value,				     valid_table[cls1].name,				     valid_table[cls2].name);			  }			break;		      case 'D':			ctype->class_collection[cnt] |= _ISwbit (cls2);			break;		      default:			error (5, 0, _("internal error in %s, line %u"),			       __FUNCTION__, __LINE__);		      }		  }	}    }  for (cnt = 0; cnt < 256; ++cnt)    {      uint32_t tmp = ctype->class256_collection[cnt];      if (tmp != 0)	{	  for (cls1 = 0; cls1 < NCLASS; ++cls1)	    if ((tmp & _ISbit (cls1)) != 0)	      for (cls2 = 0; cls2 < NCLASS; ++cls2)		if (valid_table[cls1].allow[cls2] != '-')		  {		    int eq = (tmp & _ISbit (cls2)) != 0;		    switch (valid_table[cls1].allow[cls2])		      {		      case 'M':			if (!eq)			  {			    char buf[17];			    sprintf (buf, "\\%o", cnt);			    if (!be_quiet)			      error (0, 0, _("\character '%s' in class `%s' must be in class `%s'"),				     buf, valid_table[cls1].name,				     valid_table[cls2].name);			  }			break;		      case 'X':			if (eq)			  {			    char buf[17];			    sprintf (buf, "\\%o", cnt);			    if (!be_quiet)			      error (0, 0, _("\character '%s' in class `%s' must not be in class `%s'"),				     buf, valid_table[cls1].name,				     valid_table[cls2].name);			  }			break;		      case 'D':			ctype->class256_collection[cnt] |= _ISbit (cls2);			break;		      default:			error (5, 0, _("internal error in %s, line %u"),			       __FUNCTION__, __LINE__);		      }		  }	}    }  /* ... and now test <SP> as a special case.  */  space_value = repertoire_find_value (ctype->repertoire, "SP", 2);  if (space_value == ILLEGAL_CHAR_VALUE)    {      if (!be_quiet)	error (0, 0, _("character <SP> not defined in character map"));    }  else if (((cnt = BITPOS (tok_space),	     (ELEM (ctype, class_collection, , space_value)	      & BITw (tok_space)) == 0)	    || (cnt = BITPOS (tok_blank),		(ELEM (ctype, class_collection, , space_value)		 & BITw (tok_blank)) == 0)))    {      if (!be_quiet)	error (0, 0, _("<SP> character not in class `%s'"),	       valid_table[cnt].name);    }  else if (((cnt = BITPOS (tok_punct),	     (ELEM (ctype, class_collection, , space_value)	      & BITw (tok_punct)) != 0)	    || (cnt = BITPOS (tok_graph),		(ELEM (ctype, class_collection, , space_value)		 & BITw (tok_graph))		!= 0)))    {      if (!be_quiet)	error (0, 0, _("<SP> character must not be in class `%s'"),	       valid_table[cnt].name);    }  else    ELEM (ctype, class_collection, , space_value) |= BITw (tok_print);  space_seq = charmap_find_value (charmap, "SP", 2);  if (space_seq == NULL || space_seq->nbytes != 1)    {      if (!be_quiet)	error (0, 0, _("character <SP> not defined in character map"));    }  else if (((cnt = BITPOS (tok_space),	     (ctype->class256_collection[space_seq->bytes[0]]	      & BIT (tok_space)) == 0)	    || (cnt = BITPOS (tok_blank),		(ctype->class256_collection[space_seq->bytes[0]]		 & BIT (tok_blank)) == 0)))    {      if (!be_quiet)	error (0, 0, _("<SP> character not in class `%s'"),	       valid_table[cnt].name);    }  else if (((cnt = BITPOS (tok_punct),	     (ctype->class256_collection[space_seq->bytes[0]]	      & BIT (tok_punct)) != 0)	    || (cnt = BITPOS (tok_graph),		(ctype->class256_collection[space_seq->bytes[0]]		 & BIT (tok_graph)) != 0)))    {      if (!be_quiet)	error (0, 0, _("<SP> character must not be in class `%s'"),	       valid_table[cnt].name);    }  else    ctype->class256_collection[space_seq->bytes[0]] |= BIT (tok_print);  /* Now that the tests are done make sure the name array contains all     characters which are handled in the WIDTH section of the     character set definition file.  */  if (charmap->width_rules != NULL)    for (cnt = 0; cnt < charmap->nwidth_rules; ++cnt)      {#if 0	size_t inner;	for (inner = charmap->width_rules[cnt].from;	     inner <= charmap->width_rules[cnt].to; ++inner)	  (void) find_idx (ctype, NULL, NULL, NULL, inner);#else	/* XXX Handle width.  We must convert from the charseq to the           repertoire value */	abort ();#endif      }  /* There must be a multiple of 10 digits.  */  if (ctype->mbdigits_act % 10 != 0)    {      assert (ctype->mbdigits_act == ctype->wcdigits_act);      ctype->wcdigits_act -= ctype->mbdigits_act % 10;      ctype->mbdigits_act -= ctype->mbdigits_act % 10;      error (0, 0, _("`digit' category has not entries in groups of ten"));    }  /* Check the input digits.  There must be a multiple of ten available.     In each group I could be that one or the other character is missing.     In this case the whole group must be removed.  */  cnt = 0;  while (cnt < ctype->mbdigits_act)    {      size_t inner;      for (inner = 0; inner < 10; ++inner)	if (ctype->mbdigits[cnt + inner] == NULL)	  break;      if (inner == 10)	cnt += 10;      else	{	  /* Remove the group.  */	  memmove (&ctype->mbdigits[cnt], &ctype->mbdigits[cnt + 10],		   ((ctype->wcdigits_act - cnt - 10)		    * sizeof (ctype->mbdigits[0])));	  ctype->mbdigits_act -= 10;	}    }  /* If no input digits are given use the default.  */  if (ctype->mbdigits_act == 0)    {      if (ctype->mbdigits_max == 0)	{	  ctype->mbdigits = obstack_alloc (&charmap->mem_pool,					   10 * sizeof (struct charseq *));	  ctype->mbdigits_max = 10;	}      for (cnt = 0; cnt < 10; ++cnt)	{	  ctype->mbdigits[cnt] = charmap_find_symbol (charmap,						      digits + cnt, 1);	  if (ctype->mbdigits[cnt] == NULL)	    {	      ctype->mbdigits[cnt] = charmap_find_symbol (charmap,							  longnames[cnt],							  strlen (longnames[cnt]));	      if (ctype->mbdigits[cnt] == NULL)		{		  /* Hum, this ain't good.  */		  error (0, 0, _("\no input digits defined and none of the standard names in the charmap"));		  ctype->mbdigits[cnt] = obstack_alloc (&charmap->mem_pool,							sizeof (struct charseq) + 1);		  /* This is better than nothing.  */		  ctype->mbdigits[cnt]->bytes[0] = digits[cnt];		  ctype->mbdigits[cnt]->nbytes = 1;		}	    }	}      ctype->mbdigits_act = 10;    }  /* Check the wide character input digits.  There must be a multiple     of ten available.  In each group I could be that one or the other     character is missing.  In this case the whole group must be     removed.  */  cnt = 0;  while (cnt < ctype->wcdigits_act)    {      size_t inner;      for (inner = 0; inner < 10; ++inner)	if (ctype->wcdigits[cnt + inner] == ILLEGAL_CHAR_VALUE)	  break;      if (inner == 10)	cnt += 10;      else	{	  /* Remove the group.  */	  memmove (&ctype->wcdigits[cnt], &ctype->wcdigits[cnt + 10],		   ((ctype->wcdigits_act - cnt - 10)		    * sizeof (ctype->wcdigits[0])));	  ctype->wcdigits_act -= 10;	}    }  /* If no input digits are given use the default.  */  if (ctype->wcdigits_act == 0)    {      if (ctype->wcdigits_max == 0)	{	  ctype->wcdigits = obstack_alloc (&charmap->mem_pool,					   10 * sizeof (uint32_t));	  ctype->wcdigits_max = 10;	}      for (cnt = 0; cnt < 10; ++cnt)	ctype->wcdigits[cnt] = L'0' + cnt;      ctype->mbdigits_act = 10;    }  /* Check the outdigits.  */  warned = 0;  for (cnt = 0; cnt < 10; ++cnt)    if (ctype->mboutdigits[cnt] == NULL)      {	static struct charseq replace[2];	if (!warned)	  {	    error (0, 0, _("\not all characters used in `outdigit' are available in the charmap"));	    warned = 1;	  }	replace[0].nbytes = 1;	replace[0].bytes[0] = '?';	replace[0].bytes[1] = '\0';	ctype->mboutdigits[cnt] = &replace[0];      }  warned = 0;  for (cnt = 0; cnt < 10; ++cnt)    if (ctype->wcoutdigits[cnt] == 0)      {	if (!warned)	  {	    error (0, 0, _("\not all characters used in `outdigit' are available in the repertoire"));	    warned = 1;	  }	ctype->wcoutdigits[cnt] = L'?';      }}