if (state == 0)  lr_error (ldfile, _("%s: empty category description not allowed"), "LC_COLLATE"); else if (state == 1) lr_error (ldfile, _("%s: missing `order_end' keyword"), "LC_COLLATE"); else if (state == 3) error (0, 0, _("%s: missing `reorder-end' keyword"), "LC_COLLATE");
if (!ignore_content) { if (state == 0)  lr_error (ldfile, _("%s: empty category description not allowed"), "LC_COLLATE"); else if (state == 1) lr_error (ldfile, _("%s: missing `order_end' keyword"), "LC_COLLATE"); else if (state == 3) error (0, 0, _("%s: missing `reorder-end' keyword"), "LC_COLLATE"); }
collate_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_collate_t *collate;  struct token *now;  struct token *arg;  enum token_t nowtok;  int state = 0;  int was_ellipsis = 0;  /* Get the repertoire we have to use.  */  if (repertoire_name != NULL)    repertoire = repertoire_read (repertoire_name);  /* The rest of the line containing `LC_COLLATE' must be free.  */  lr_ignore_rest (ldfile, 1);  do    {      now = lr_token (ldfile, charmap, NULL);      nowtok = now->tok;    }  while (nowtok == tok_eol);  if (nowtok == tok_copy)    {      state = 2;      now = lr_token (ldfile, charmap, NULL);      if (now->tok != tok_string)	goto err_label;      /* XXX Use the name */      lr_ignore_rest (ldfile, 1);      now = lr_token (ldfile, charmap, NULL);      nowtok = now->tok;    }  /* Prepare the data structures.  */  collate_startup (ldfile, result, ignore_content);  collate = result->categories[LC_COLLATE].collate;  while (1)    {      /* 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_coll_weight_max:	  if (state != 0)	    goto err_label;	  arg = lr_token (ldfile, charmap, NULL);	  if (arg->tok != tok_number)	    goto err_label;	  if (collate->col_weight_max != -1)	    lr_error (ldfile, _("%s: duplicate definition of `%s'"),		      "LC_COLLATE", "col_weight_max");	  else	    collate->col_weight_max = arg->val.num;	  lr_ignore_rest (ldfile, 1);	  break;	case tok_section_symbol:	  if (state != 0)	    goto err_label;	  arg = lr_token (ldfile, charmap, repertoire);	  if (arg->tok != tok_bsymbol)	    goto err_label;	  else if (!ignore_content)	    {	      /* Check whether this section is already known.  */	      struct section_list *known = collate->sections;	      while (known != NULL)		if (strcmp (known->name, arg->val.str.startmb) == 0)		  break;	      if (known != NULL)		{		  lr_error (ldfile,			    _("%s: duplicate declaration of section `%s'"),			    "LC_COLLATE", arg->val.str.startmb);		  free (arg->val.str.startmb);		}	      else		collate->sections = make_seclist_elem (collate,						       arg->val.str.startmb,						       collate->sections);	      lr_ignore_rest (ldfile, known == NULL);	    }	  else	    {	      free (arg->val.str.startmb);	      lr_ignore_rest (ldfile, 1);	    }	  break;	case tok_collating_element:	  if (state != 0)	    goto err_label;	  arg = lr_token (ldfile, charmap, repertoire);	  if (arg->tok != tok_bsymbol)	    goto err_label;	  else	    {	      const char *symbol = arg->val.str.startmb;	      size_t symbol_len = arg->val.str.lenmb;	      /* Next the `from' keyword.  */	      arg = lr_token (ldfile, charmap, repertoire);	      if (arg->tok != tok_from)		{		  free ((char *) symbol);		  goto err_label;		}	      ldfile->return_widestr = 1;	      /* Finally the string with the replacement.  */	      arg = lr_token (ldfile, charmap, repertoire);	      ldfile->return_widestr = 0;	      if (arg->tok != tok_string)		goto err_label;	      if (!ignore_content)		{		  if (symbol == NULL)		    lr_error (ldfile, _("\%s: unknown character in collating element name"),			      "LC_COLLATE");		  if (arg->val.str.startmb == NULL)		    lr_error (ldfile, _("\%s: unknown character in collating element definition"),			      "LC_COLLATE");		  if (arg->val.str.startwc == NULL)		    lr_error (ldfile, _("\%s: unknown wide character in collating element definition"),			      "LC_COLLATE");		  else if (arg->val.str.lenwc < 2)		    lr_error (ldfile, _("\%s: substitution string in collating element definition must have at least two characters"),			      "LC_COLLATE");		  if (symbol != NULL)		    {		      /* The name is already defined.  */		      if (check_duplicate (ldfile, collate, charmap,					   repertoire, symbol, symbol_len))			goto col_elem_free;		      if (insert_entry (&collate->elem_table,					symbol, symbol_len,					new_element (collate,						     arg->val.str.startmb,						     arg->val.str.startwc))			  < 0)			lr_error (ldfile, _("\error while adding collating element"));		    }		  else		    goto col_elem_free;		}	      else		{		col_elem_free:		  if (symbol != NULL)		    free ((char *) symbol);		  if (arg->val.str.startmb != NULL)		    free (arg->val.str.startmb);		  if (arg->val.str.startwc != NULL)		    free (arg->val.str.startwc);		}	      lr_ignore_rest (ldfile, 1);	    }	  break;	case tok_collating_symbol:	  if (state != 0)	    goto err_label;	  arg = lr_token (ldfile, charmap, repertoire);	  if (arg->tok != tok_bsymbol)	    goto err_label;	  else	    {	      const char *symbol = arg->val.str.startmb;	      size_t symbol_len = arg->val.str.lenmb;	      if (!ignore_content)		{		  if (symbol == NULL)		    lr_error (ldfile, _("\%s: unknown character in collating symbol name"),			      "LC_COLLATE");		  else		    {		      /* The name is already defined.  */		      if (check_duplicate (ldfile, collate, charmap,					   repertoire, symbol, symbol_len))			goto col_sym_free;		      if (insert_entry (&collate->sym_table,					symbol, symbol_len,					new_symbol (collate)) < 0)			lr_error (ldfile, _("\error while adding collating symbol"));		    }		}	      else		{		col_sym_free:		  if (symbol != NULL)		    free ((char *) symbol);		}	      lr_ignore_rest (ldfile, 1);	    }	  break;	case tok_symbol_equivalence:	  if (state != 0)	    goto err_label;	  arg = lr_token (ldfile, charmap, repertoire);	  if (arg->tok != tok_bsymbol)	    goto err_label;	  else	    {	      const char *newname = arg->val.str.startmb;	      size_t newname_len = arg->val.str.lenmb;	      const char *symname;	      size_t symname_len;	      struct symbol_t *symval;	      arg = lr_token (ldfile, charmap, repertoire);	      if (arg->tok != tok_bsymbol)		{		  if (newname != NULL)		    free ((char *) newname);		  goto err_label;		}	      symname = arg->val.str.startmb;	      symname_len = arg->val.str.lenmb;	      if (!ignore_content)		{		  if (newname == NULL)		    {		      lr_error (ldfile, _("\%s: unknown character in equivalent definition name"),				"LC_COLLATE");		      goto sym_equiv_free;		    }		  if (symname == NULL)		    {		      lr_error (ldfile, _("\%s: unknown character in equivalent definition value"),				"LC_COLLATE");		      goto sym_equiv_free;		    }		  /* The name is already defined.  */		  if (check_duplicate (ldfile, collate, charmap,				       repertoire, symname, symname_len))		    goto col_sym_free;		  /* See whether the symbol name is already defined.  */		  if (find_entry (&collate->sym_table, symname, symname_len,				  (void **) &symval) != 0)		    {		      lr_error (ldfile, _("\%s: unknown symbol `%s' in equivalent definition"),				"LC_COLLATE", symname);		      goto col_sym_free;		    }		  if (insert_entry (&collate->sym_table,				    newname, newname_len, symval) < 0)		    {		      lr_error (ldfile, _("\error while adding equivalent collating symbol"));		      goto sym_equiv_free;		    }		  free ((char *) symname);		}	      else		{		sym_equiv_free:		  if (newname != NULL)		    free ((char *) newname);		  if (symname != NULL)		    free ((char *) symname);		}	      lr_ignore_rest (ldfile, 1);	    }	  break;	case tok_order_start:	  if (state != 0 && state != 1)	    goto err_label;	  state = 1;	  /* The 14652 draft does not specify whether all `order_start' lines	     must contain the same number of sort-rules, but 14651 does.  So	     we require this here as well.  */	  arg = lr_token (ldfile, charmap, repertoire);	  if (arg->tok == tok_bsymbol)	    {	      /* This better should be a section name.  */	      struct section_list *sp = collate->sections;	      while (sp != NULL		     && strcmp (sp->name, arg->val.str.startmb) != 0)		sp = sp->next;	      if (sp == NULL)		{		  lr_error (ldfile, _("\%s: unknown section name `%s'"),			    "LC_COLLATE", arg->val.str.startmb);		  /* We use the error section.  */		  collate->current_section = &collate->error_section;		}	      else		{		  /* Remember this section.  */		  collate->current_section = sp;		  /* One should not be allowed to open the same                     section twice.  */		  if (sp->first != NULL)		    lr_error (ldfile, _("\%s: multiple order definitions for section `%s'"),			      "LC_COLLATE", sp->name);		  /* Next should come the end of the line or a semicolon.  */		  arg = lr_token (ldfile, charmap, repertoire);		  if (arg->tok == tok_eol)		    {		      uint32_t cnt;		      /* This means we have exactly one rule: `forward'.  */		      if (collate->nrules > 1)			lr_error (ldfile, _("\%s: invalid number of sorting rules"),				  "LC_COLLATE");		      else			collate->nrules = 1;		      sp->rules = obstack_alloc (&collate->mempool,						 (sizeof (enum coll_sort_rule)						  * collate->nrules));		      for (cnt = 0; cnt < collate->nrules; ++cnt)			sp->rules[cnt] = sort_forward;		      /* Next line.  */		      break;		    }		  /* Get the next token.  */		  arg = lr_token (ldfile, charmap, repertoire);		}	    }	  else	    {	      /* There is no section symbol.  Therefore we use the unnamed		 section.  */	      collate->current_section = &collate->unnamed_section;	      if (collate->unnamed_section.first != NULL)		lr_error (ldfile, _("\%s: multiple order definitions for unnamed section"),			  "LC_COLLATE");	    }	  /* Now read the direction names.  */	  read_directions (ldfile, arg, charmap, repertoire, collate);	  break;	case tok_order_end:	  if (state != 1)	    goto err_label;	  state = 2;	  lr_ignore_rest (ldfile, 1);	  break;	case tok_reorder_after:	  if (state != 2 && state != 3)	    goto err_label;	  state = 3;	  /* XXX get symbol */	  break;	case tok_reorder_end:	  if (state != 3)	    goto err_label;	  state = 4;	  lr_ignore_rest (ldfile, 1);	  break;	case tok_bsymbol:	  if (state != 1 && state != 3)	    goto err_label;	  if (state == 3)	    {	      /* It is possible that we already have this collation sequence.		 In this case we move the entry.  */	      struct element_t *seqp;	      if (find_entry (&collate->seq_table, arg->val.str.startmb,			      arg->val.str.lenmb, (void **) &seqp) == 0)		{		  /* Remove the entry from the old position.  */		  if (seqp->last == NULL)		    collate->start = seqp->next;		  else		    seqp->last->next = seqp->next;		  if (seqp->next != NULL)		    seqp->next->last = seqp->last;		  /* We also have to check whether this entry is the                     first or last of a section.  */		  if (seqp->section->first == seqp)		    {		      if (seqp->section->first == seqp->section->last)			/* This setion has no content anymore.  */			seqp->section->first = seqp->section->last = NULL;		      else			seqp->section->first = seqp->next;		    }		  else if (seqp->section->last == seqp)		    seqp->section->last = seqp->last;		  seqp->last = seqp->next = NULL;		}	    }	  /* Now insert in the new place.  */	  insert_value (ldfile, arg, charmap, repertoire, collate);	  break;	case tok_undefined:	  if (state != 1)	    goto err_label;	  /* XXX handle UNDEFINED weight */	  break;	case tok_ellipsis3:	  if (state != 1 && state != 3)	    goto err_label;	  was_ellipsis = 1;	  /* XXX Read the remainder of the line and remember what are	     the weights.  */	  break;	case tok_end:	  /* Next we assume `LC_COLLATE'.  */	  if (state == 0)	    /* We must either see a copy statement or have ordering values.  */	    lr_error (ldfile, _("%s: empty category description not allowed"),		      "LC_COLLATE");	  else if (state == 1)	    lr_error (ldfile, _("%s: missing `order_end' keyword"),		      "LC_COLLATE");	  else if (state == 3)	    error (0, 0, _("%s: missing `reorder-end' keyword"),		   "LC_COLLATE");	  arg = lr_token (ldfile, charmap, NULL);	  if (arg->tok == tok_eof)	    break;	  if (arg->tok == tok_eol)	    lr_error (ldfile, _("%s: incomplete `END' line"), "LC_COLLATE");	  else if (arg->tok != tok_lc_collate)	    lr_error (ldfile, _("\%1$s: definition does not end with `END %1$s'"), "LC_COLLATE");	  lr_ignore_rest (ldfile, arg->tok == tok_lc_collate);	  return;	default:	err_label:	  SYNTAX_ERROR (_("%s: syntax error"), "LC_COLLATE");	}      /* 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_COLLATE");}