repertoire_name = locale->repertoire_name ?: repertoire_global; if (repertoire_name != NULL) ctype->repertoire = repertoire_read (repertoire_name);
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;  /* Now resolve copying and also handle completely missing definitions.  */  if (ctype == NULL)    {      /* First see whether we were supposed to copy.  If yes, find the	 actual definition.  */      if (locale->copy_name[LC_CTYPE] != NULL)	{	  /* Find the copying locale.  This has to happen transitively since	     the locale we are copying from might also copying another one.  */	  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 there is still no definition issue an warning and create an	 empty one.  */      if (ctype == NULL)	{	  if (! be_quiet)	    error (0, 0, _("No definition for %s category found"), "LC_CTYPE");	  ctype_startup (NULL, locale, charmap, 0);	  ctype = locale->categories[LC_CTYPE].ctype;	}    }  /* 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_act; ++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)      {	unsigned char bytes[charmap->mb_cur_max];	int nbytes = charmap->width_rules[cnt].from->nbytes;	/* We have the range of character for which the width is           specified described using byte sequences of the multibyte           charset.  We have to convert this to UCS4 now.  And we           cannot simply convert the beginning and the end of the           sequence, we have to iterate over the byte sequence and           convert it for every single character.  */	memcpy (bytes, charmap->width_rules[cnt].from->bytes, nbytes);	while (nbytes < charmap->width_rules[cnt].to->nbytes	       || memcmp (bytes, charmap->width_rules[cnt].to->bytes,			  nbytes) <= 0)	  {	    /* Find the UCS value for `bytes'.  */	    int inner;	    uint32_t wch;	    struct charseq *seq = charmap_find_symbol (charmap, bytes, nbytes);	    if (seq == NULL)	      wch = ILLEGAL_CHAR_VALUE;	    else if (seq->ucs4 != UNINITIALIZED_CHAR_VALUE)	      wch = seq->ucs4;	    else	      wch = repertoire_find_value (ctype->repertoire, seq->name,					   strlen (seq->name));	    if (wch != ILLEGAL_CHAR_VALUE)	      /* We are only interested in the side-effects of the		 `find_idx' call.  It will add appropriate entries in		 the name array if this is necessary.  */	      (void) find_idx (ctype, NULL, NULL, NULL, wch);	    /* "Increment" the bytes sequence.  */	    inner = nbytes - 1;	    while (inner >= 0 && bytes[inner] == 0xff)	      --inner;	    if (inner < 0)	      {		/* We have to extend the byte sequence.  */		if (nbytes >= charmap->width_rules[cnt].to->nbytes)		  break;		bytes[0] = 1;		memset (&bytes[1], 0, nbytes);		++nbytes;	      }	    else	      {		++bytes[inner];		while (++inner < nbytes)		  bytes[inner] = 0;	      }	  }      }  /* 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 it 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 it 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'?';      }}