now->val.str.startmb[now->val.str.lenmb] = '\0'; last_str = now->val.str.startmb;
if (last_token == tok_bsymbol) { now->val.str.startmb[now->val.str.lenmb] = '\0'; last_str = now->val.str.startmb; } else last_str = NULL;
ctype_read (struct linereader *ldfile, struct localedef_t *result,	    struct charmap_t *charmap, const char *repertoire_name,	    int ignore_content){  struct repertoire_t *repertoire = NULL;  struct locale_ctype_t *ctype;  struct token *now;  enum token_t nowtok;  size_t cnt;  struct charseq *last_seq;  uint32_t last_wch = 0;  enum token_t last_token;  enum token_t ellipsis_token;  char last_charcode[16];  size_t last_charcode_len = 0;  const char *last_str = NULL;  int mapidx;  /* Get the repertoire we have to use.  */  if (repertoire_name != NULL)    repertoire = repertoire_read (repertoire_name);  /* The rest of the line containing `LC_CTYPE' must be free.  */  lr_ignore_rest (ldfile, 1);  do    {      now = lr_token (ldfile, charmap, NULL);      nowtok = now->tok;    }  while (nowtok == tok_eol);  /* If we see `copy' now we are almost done.  */  if (nowtok == tok_copy)    {      handle_copy (ldfile, charmap, repertoire, result, tok_lc_ctype, LC_CTYPE,		   "LC_CTYPE", ignore_content);      return;    }  /* Prepare the data structures.  */  ctype_startup (ldfile, result, charmap, ignore_content);  ctype = result->categories[LC_CTYPE].ctype;  /* Remember the repertoire we use.  */  if (!ignore_content)    ctype->repertoire = repertoire;  while (1)    {      unsigned long int class_bit = 0;      unsigned long int class256_bit = 0;      int handle_digits = 0;      /* Of course we don't proceed beyond the end of file.  */      if (nowtok == tok_eof)	break;      /* Ingore empty lines.  */      if (nowtok == tok_eol)	{	  now = lr_token (ldfile, charmap, NULL);	  nowtok = now->tok;	  continue;	}      switch (nowtok)	{	case tok_charclass:	  now = lr_token (ldfile, charmap, NULL);	  while (now->tok == tok_ident || now->tok == tok_string)	    {	      ctype_class_new (ldfile, ctype, now->val.str.startmb);	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok != tok_semicolon)		break;	      now = lr_token (ldfile, charmap, NULL);	    }	  if (now->tok != tok_eol)	    SYNTAX_ERROR (_("\%s: syntax error in definition of new character class"), "LC_CTYPE");	  break;	case tok_charconv:	  now = lr_token (ldfile, charmap, NULL);	  while (now->tok == tok_ident || now->tok == tok_string)	    {	      ctype_map_new (ldfile, ctype, now->val.str.startmb, charmap);	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok != tok_semicolon)		break;	      now = lr_token (ldfile, charmap, NULL);	    }	  if (now->tok != tok_eol)	    SYNTAX_ERROR (_("\%s: syntax error in definition of new character map"), "LC_CTYPE");	  break;	case tok_class:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  /* We simply forget the `class' keyword and use the following	     operand to determine the bit.  */	  now = lr_token (ldfile, charmap, NULL);	  if (now->tok == tok_ident || now->tok == tok_string)	    {	      /* Must be one of the predefined class names.  */	      for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)		if (strcmp (ctype->classnames[cnt], now->val.str.startmb) == 0)		  break;	      if (cnt >= ctype->nr_charclass)		{#ifdef PREDEFINED_CLASSES		  if (now->val.str.lenmb == 8		      && memcmp ("special1", now->val.str.startmb, 8) == 0)		    class_bit = _ISwspecial1;		  else if (now->val.str.lenmb == 8		      && memcmp ("special2", now->val.str.startmb, 8) == 0)		    class_bit = _ISwspecial2;		  else if (now->val.str.lenmb == 8		      && memcmp ("special3", now->val.str.startmb, 8) == 0)		    class_bit = _ISwspecial3;		  else#endif		    {		      lr_error (ldfile, _("\unknown character class `%s' in category `LC_CTYPE'"),				now->val.str.startmb);		      free (now->val.str.startmb);		      lr_ignore_rest (ldfile, 0);		      continue;		    }		}	      else		class_bit = _ISwbit (cnt);	      free (now->val.str.startmb);	    }	  else if (now->tok == tok_digit)	    goto handle_tok_digit;	  else if (now->tok < tok_upper || now->tok > tok_blank)	    goto err_label;	  else	    {	      class_bit = BITw (now->tok);	      class256_bit = BIT (now->tok);	    }	  /* The next character must be a semicolon.  */	  now = lr_token (ldfile, charmap, NULL);	  if (now->tok != tok_semicolon)	    goto err_label;	  goto read_charclass;	case tok_upper:	case tok_lower:	case tok_alpha:	case tok_alnum:	case tok_space:	case tok_cntrl:	case tok_punct:	case tok_graph:	case tok_print:	case tok_xdigit:	case tok_blank:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  class_bit = BITw (now->tok);	  class256_bit = BIT (now->tok);	  handle_digits = 0;	read_charclass:	  ctype->class_done |= class_bit;	  last_token = tok_none;	  ellipsis_token = tok_none;	  now = lr_token (ldfile, charmap, NULL);	  while (now->tok != tok_eol && now->tok != tok_eof)	    {	      uint32_t wch;	      struct charseq *seq;	      if (now->tok != tok_bsymbol)		/* XXX Cannot be handled yet.  We will have support		   for tok_ucs4 soon.  */		goto err_label;	      if (ellipsis_token == tok_none)		{		  if (get_character (now, charmap, repertoire, &seq, &wch))		    goto err_label;		  if (!ignore_content && seq != NULL && seq->nbytes == 1)		    /* Yep, we can store information about this byte		       sequence.  */		    ctype->class256_collection[seq->bytes[0]] |= class256_bit;		  if (!ignore_content && wch != ILLEGAL_CHAR_VALUE		      && class_bit != 0)		    /* We have the UCS4 position.  */		    *find_idx (ctype, &ctype->class_collection,			       &ctype->class_collection_max,			       &ctype->class_collection_act, wch) |= class_bit;		  last_token = now->tok;		  /* Terminate the string.  */		  now->val.str.startmb[now->val.str.lenmb] = '\0';		  last_str = now->val.str.startmb;		  last_seq = seq;		  last_wch = wch;		  memcpy (last_charcode, now->val.charcode.bytes, 16);		  last_charcode_len = now->val.charcode.nbytes;		  if (!ignore_content && handle_digits == 1)		    {		      /* We must store the digit values.  */		      if (ctype->mbdigits_act == ctype->mbdigits_max)			{			  ctype->mbdigits_max += 10;			  ctype->mbdigits = xrealloc (ctype->mbdigits,						      (ctype->mbdigits_max						       * sizeof (char *)));			  ctype->wcdigits_max += 10;			  ctype->wcdigits = xrealloc (ctype->wcdigits,						      (ctype->wcdigits_max						       * sizeof (uint32_t)));			}		      ctype->mbdigits[ctype->mbdigits_act++] = seq;		      ctype->wcdigits[ctype->wcdigits_act++] = wch;		    }		  else if (!ignore_content && handle_digits == 2)		    {		      /* We must store the digit values.  */		      if (ctype->outdigits_act >= 10)			{			  lr_error (ldfile, _("\%s: field `%s' does not contain exactly ten entries"),			    "LC_CTYPE", "outdigit");			  goto err_label;			}		      ctype->mboutdigits[ctype->outdigits_act] = seq;		      ctype->wcoutdigits[ctype->outdigits_act] = wch;		      ++ctype->outdigits_act;		    }		}	      else		{		  /* Now it gets complicated.  We have to resolve the		     ellipsis problem.  First we must distinguish between		     the different kind of ellipsis and this must match the		     tokens we have seen.  */		  assert (last_token != tok_none);		  if (last_token != now->tok)		    {		      lr_error (ldfile, _("\ellipsis range must be marked by two operands of same type"));		      lr_ignore_rest (ldfile, 0);		      break;		    }		  if (last_token == tok_bsymbol)		    {		      if (ellipsis_token == tok_ellipsis3)			lr_error (ldfile, _("with symbolic name range values \the absolute ellipsis `...' must not be used"));		      charclass_symbolic_ellipsis (ldfile, ctype, charmap,						   repertoire, now, last_str,						   class256_bit, class_bit,						   (ellipsis_token						    == tok_ellipsis4						    ? 10 : 16),						   ignore_content,						   handle_digits);		    }		  else if (last_token == tok_ucs4)		    {		      if (ellipsis_token != tok_ellipsis2)			lr_error (ldfile, _("\with UCS range values one must use the hexadecimal symbolic ellipsis `..'"));		      charclass_ucs4_ellipsis (ldfile, ctype, charmap,					       repertoire, now, last_wch,					       class256_bit, class_bit,					       ignore_content, handle_digits);		    }		  else		    {		      assert (last_token == tok_charcode);		      if (ellipsis_token != tok_ellipsis3)			lr_error (ldfile, _("\with character code range values one must use the absolute ellipsis `...'"));		      charclass_charcode_ellipsis (ldfile, ctype, charmap,						   repertoire, now,						   last_charcode,						   last_charcode_len,						   class256_bit, class_bit,						   ignore_content,						   handle_digits);		    }		  /* Now we have used the last value.  */		  last_token = tok_none;		}	      /* Next we expect a semicolon or the end of the line.  */	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok == tok_eol || now->tok == tok_eof)		break;	      if (last_token != tok_none		  && now->tok >= tok_ellipsis2 && now->tok <= tok_ellipsis4)		{		  ellipsis_token = now->tok;		  now = lr_token (ldfile, charmap, NULL);		  continue;		}	      if (now->tok != tok_semicolon)		goto err_label;	      /* And get the next character.  */	      now = lr_token (ldfile, charmap, NULL);	      ellipsis_token = tok_none;	    }	  break;	case tok_digit:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	handle_tok_digit:	  class_bit = _ISwdigit;	  class256_bit = _ISdigit;	  handle_digits = 1;	  goto read_charclass;	case tok_outdigit:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  if (ctype->outdigits_act != 0)	    lr_error (ldfile, _("\%s: field `%s' declared more than once"),		      "LC_CTYPE", "outdigit");	  class_bit = 0;	  class256_bit = 0;	  handle_digits = 2;	  goto read_charclass;	case tok_toupper:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  mapidx = 0;	  goto read_mapping;	case tok_tolower:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  mapidx = 1;	  goto read_mapping;	case tok_map:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  /* We simply forget the `map' keyword and use the following	     operand to determine the mapping.  */	  now = lr_token (ldfile, charmap, NULL);	  if (now->tok == tok_ident || now->tok == tok_string)	    {	      size_t cnt;	      for (cnt = 2; cnt < ctype->map_collection_nr; ++cnt)		if (strcmp (now->val.str.startmb, ctype->mapnames[cnt]) == 0)		  break;	      if (cnt < ctype->map_collection_nr)		mapidx = cnt;	      else		{		  lr_error (ldfile, _("unknown map `%s'"),			    now->val.str.startmb);		  lr_ignore_rest (ldfile, 0);		  break;		}	    }	  else if (now->tok < tok_toupper || now->tok > tok_tolower)	    goto err_label;	  else	    mapidx = now->tok - tok_toupper;	  now = lr_token (ldfile, charmap, NULL);	  /* This better should be a semicolon.  */	  if (now->tok != tok_semicolon)	    goto err_label;	read_mapping:	  /* Test whether this mapping was already defined.  */	  if (ctype->tomap_done[mapidx])	    {	      lr_error (ldfile, _("duplicated definition for mapping `%s'"),			ctype->mapnames[mapidx]);	      lr_ignore_rest (ldfile, 0);	      break;	    }	  ctype->tomap_done[mapidx] = 1;	  now = lr_token (ldfile, charmap, NULL);	  while (now->tok != tok_eol && now->tok != tok_eof)	    {	      struct charseq *from_seq;	      uint32_t from_wch;	      struct charseq *to_seq;	      uint32_t to_wch;	      /* Every pair starts with an opening brace.  */	      if (now->tok != tok_open_brace)		goto err_label;	      /* Next comes the from-value.  */	      now = lr_token (ldfile, charmap, NULL);	      if (get_character (now, charmap, repertoire, &from_seq,				 &from_wch) != 0)		goto err_label;	      /* The next is a comma.  */	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok != tok_comma)		goto err_label;	      /* And the other value.  */	      now = lr_token (ldfile, charmap, NULL);	      if (get_character (now, charmap, repertoire, &to_seq,				 &to_wch) != 0)		goto err_label;	      /* And the last thing is the closing brace.  */	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok != tok_close_brace)		goto err_label;	      if (!ignore_content)		{		  if (mapidx < 2 && from_seq != NULL && to_seq != NULL		      && from_seq->nbytes == 1 && to_seq->nbytes == 1)		    /* We can use this value.  */		    ctype->map256_collection[mapidx][from_seq->bytes[0]]		      = to_seq->bytes[0];		  if (from_wch != ILLEGAL_CHAR_VALUE		      && to_wch != ILLEGAL_CHAR_VALUE)		    /* Both correct values.  */		    *find_idx (ctype, &ctype->map_collection[mapidx],			       &ctype->map_collection_max[mapidx],			       &ctype->map_collection_act[mapidx],			       from_wch) = to_wch;		}	      /* Now comes a semicolon or the end of the line/file.  */	      now = lr_token (ldfile, charmap, NULL);	      if (now->tok == tok_semicolon)		now = lr_token (ldfile, charmap, NULL);	    }	  break;	case tok_translit_start:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  /* The rest of the line better should be empty.  */	  lr_ignore_rest (ldfile, 1);	  /* We count here the number of allocated entries in the `translit'	     array.  */	  cnt = 0;	  /* We proceed until we see the `translit_end' token.  */	  while (now = lr_token (ldfile, charmap, repertoire),		 now->tok != tok_translit_end && now->tok != tok_eof)	    {	      if (now->tok == tok_eol)		/* Ignore empty lines.  */		continue;	      if (now->tok == tok_translit_end)		{		  lr_ignore_rest (ldfile, 0);		  break;		}	      if (now->tok == tok_include)		{		  /* We have to include locale.  */		  const char *locale_name;		  const char *repertoire_name;		  now = lr_token (ldfile, charmap, NULL);		  /* This should be a string or an identifier.  In any		     case something to name a locale.  */		  if (now->tok != tok_string && now->tok != tok_ident)		    {		    translit_syntax:		      lr_error (ldfile, _("%s: syntax error"), "LC_CTYPE");		      lr_ignore_rest (ldfile, 0);		      continue;		    }		  locale_name = now->val.str.startmb;		  /* Next should be a semicolon.  */		  now = lr_token (ldfile, charmap, NULL);		  if (now->tok != tok_semicolon)		    goto translit_syntax;		  /* Now the repertoire name.  */		  now = lr_token (ldfile, charmap, NULL);		  if ((now->tok != tok_string && now->tok != tok_ident)		      || now->val.str.startmb == NULL)		    goto translit_syntax;		  repertoire_name = now->val.str.startmb;		  /* We must not have more than one `include'.  */		  if (ctype->translit_copy_locale != NULL)		    {		      lr_error (ldfile, _("\%s: only one `include' instruction allowed"), "LC_CTYPE");		      lr_ignore_rest (ldfile, 0);		      continue;		    }		  ctype->translit_copy_locale = locale_name;		  ctype->translit_copy_repertoire = repertoire_name;		  /* The rest of the line must be empty.  */		  lr_ignore_rest (ldfile, 1);		  continue;		}	      read_translit_entry (ldfile, ctype, now, charmap, repertoire);	    }	  break;	case tok_ident:	  /* Ignore the rest of the line if we don't need the input of	     this line.  */	  if (ignore_content)	    {	      lr_ignore_rest (ldfile, 0);	      break;	    }	  /* This could mean one of several things.  First test whether	     it's a character class name.  */	  for (cnt = 0; cnt < ctype->nr_charclass; ++cnt)	    if (strcmp (now->val.str.startmb, ctype->classnames[cnt]) == 0)	      break;	  if (cnt < ctype->nr_charclass)	    {	      class_bit = _ISwbit (cnt);	      class256_bit = cnt <= 11 ? _ISbit (cnt) : 0;	      free (now->val.str.startmb);	      goto read_charclass;	    }	  for (cnt = 0; cnt < ctype->map_collection_nr; ++cnt)	    if (strcmp (now->val.str.startmb, ctype->mapnames[cnt]) == 0)	      break;	  if (cnt < ctype->map_collection_nr)	    {	      mapidx = cnt;	      free (now->val.str.startmb);	      goto read_mapping;            }#ifdef PREDEFINED_CLASSES	  if (strcmp (now->val.str.startmb, "special1") == 0)	    {	      class_bit = _ISwspecial1;	      free (now->val.str.startmb);	      goto read_charclass;	    }	  if (strcmp (now->val.str.startmb, "special2") == 0)	    {	      class_bit = _ISwspecial2;	      free (now->val.str.startmb);	      goto read_charclass;	    }	  if (strcmp (now->val.str.startmb, "special3") == 0)	    {	      class_bit = _ISwspecial3;	      free (now->val.str.startmb);	      goto read_charclass;	    }	  if (strcmp (now->val.str.startmb, "tosymmetric") == 0)	    {	      mapidx = 2;	      goto read_mapping;	    }#endif	  break;	case tok_end:	  /* Next we assume `LC_CTYPE'.  */	  now = lr_token (ldfile, charmap, NULL);	  if (now->tok == tok_eof)	    break;	  if (now->tok == tok_eol)	    lr_error (ldfile, _("%s: incomplete `END' line"),		      "LC_CTYPE");	  else if (now->tok != tok_lc_ctype)	    lr_error (ldfile, _("\%1$s: definition does not end with `END %1$s'"), "LC_CTYPE");	  lr_ignore_rest (ldfile, now->tok == tok_lc_ctype);	  return;	default:	err_label:	  if (now->tok != tok_eof)	    SYNTAX_ERROR (_("%s: syntax error"), "LC_CTYPE");	}      /* Prepare for the next round.  */      now = lr_token (ldfile, charmap, NULL);      nowtok = now->tok;    }  /* When we come here we reached the end of the file.  */  lr_error (ldfile, _("%s: premature end of file"), "LC_CTYPE");}