Blame locale/programs/repertoire.c

Packit 6c4009
/* Copyright (C) 1998-2018 Free Software Foundation, Inc.
Packit 6c4009
   This file is part of the GNU C Library.
Packit 6c4009
   Contributed by Ulrich Drepper <drepper@cygnus.com>, 1998.
Packit 6c4009
Packit 6c4009
   This program is free software; you can redistribute it and/or modify
Packit 6c4009
   it under the terms of the GNU General Public License as published
Packit 6c4009
   by the Free Software Foundation; version 2 of the License, or
Packit 6c4009
   (at your option) any later version.
Packit 6c4009
Packit 6c4009
   This program is distributed in the hope that it will be useful,
Packit 6c4009
   but WITHOUT ANY WARRANTY; without even the implied warranty of
Packit 6c4009
   MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
Packit 6c4009
   GNU General Public License for more details.
Packit 6c4009
Packit 6c4009
   You should have received a copy of the GNU General Public License
Packit 6c4009
   along with this program; if not, see <http://www.gnu.org/licenses/>.  */
Packit 6c4009
Packit 6c4009
#ifdef HAVE_CONFIG_H
Packit 6c4009
# include <config.h>
Packit 6c4009
#endif
Packit 6c4009
Packit 6c4009
#include <errno.h>
Packit 6c4009
#include <limits.h>
Packit 6c4009
#include <obstack.h>
Packit 6c4009
#include <search.h>
Packit 6c4009
#include <stdlib.h>
Packit 6c4009
#include <string.h>
Packit 6c4009
#include <unistd.h>
Packit 6c4009
#include <stdint.h>
Packit 6c4009
Packit 6c4009
#include "localedef.h"
Packit 6c4009
#include "linereader.h"
Packit 6c4009
#include "charmap.h"
Packit 6c4009
#include "repertoire.h"
Packit 6c4009
#include "simple-hash.h"
Packit 6c4009
Packit 6c4009
Packit 6c4009
/* Simple keyword hashing for the repertoiremap.  */
Packit 6c4009
static const struct keyword_t *repertoiremap_hash (const char *str,
Packit 6c4009
						   unsigned int len);
Packit 6c4009
static void repertoire_new_char (struct linereader *lr, hash_table *ht,
Packit 6c4009
				 hash_table *rt, struct obstack *ob,
Packit 6c4009
				 uint32_t value, const char *from,
Packit 6c4009
				 const char *to, int decimal_ellipsis);
Packit 6c4009
static int repertoire_compare (const void *p1, const void *p2);
Packit 6c4009
Packit 6c4009
/* Already known repertoire maps.  */
Packit 6c4009
static void *known;
Packit 6c4009
Packit 6c4009
/* List of repertoire maps which are not available and which have been
Packit 6c4009
   reported to not be.  */
Packit 6c4009
static void *unavailable;
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct repertoire_t *
Packit 6c4009
repertoire_read (const char *filename)
Packit 6c4009
{
Packit 6c4009
  struct linereader *repfile;
Packit 6c4009
  struct repertoire_t *result;
Packit 6c4009
  struct repertoire_t **resultp;
Packit 6c4009
  struct repertoire_t search;
Packit 6c4009
  int state;
Packit 6c4009
  char *from_name = NULL;
Packit 6c4009
  char *to_name = NULL;
Packit 6c4009
  enum token_t ellipsis = tok_none;
Packit 6c4009
Packit 6c4009
  search.name = filename;
Packit 6c4009
  resultp = tfind (&search, &known, &repertoire_compare);
Packit 6c4009
  if (resultp != NULL)
Packit 6c4009
    return *resultp;
Packit 6c4009
Packit 6c4009
  /* Determine path.  */
Packit 6c4009
  repfile = lr_open (filename, repertoiremap_hash);
Packit 6c4009
  if (repfile == NULL)
Packit 6c4009
    {
Packit 6c4009
      if (strchr (filename, '/') == NULL)
Packit 6c4009
	{
Packit 6c4009
	  char *i18npath = getenv ("I18NPATH");
Packit 6c4009
	  if (i18npath != NULL && *i18npath != '\0')
Packit 6c4009
	    {
Packit 6c4009
	      const size_t pathlen = strlen (i18npath);
Packit 6c4009
	      char i18npathbuf[pathlen + 1];
Packit 6c4009
	      char path[strlen (filename) + 1 + pathlen
Packit 6c4009
		        + sizeof ("/repertoiremaps/") - 1];
Packit 6c4009
	      char *next;
Packit 6c4009
	      i18npath = memcpy (i18npathbuf, i18npath, pathlen + 1);
Packit 6c4009
Packit 6c4009
	      while (repfile == NULL
Packit 6c4009
		     && (next = strsep (&i18npath, ":")) != NULL)
Packit 6c4009
		{
Packit 6c4009
		  stpcpy (stpcpy (stpcpy (path, next), "/repertoiremaps/"),
Packit 6c4009
			  filename);
Packit 6c4009
Packit 6c4009
		  repfile = lr_open (path, repertoiremap_hash);
Packit 6c4009
Packit 6c4009
		  if (repfile == NULL)
Packit 6c4009
		    {
Packit 6c4009
		      stpcpy (stpcpy (stpcpy (path, next), "/"), filename);
Packit 6c4009
Packit 6c4009
		      repfile = lr_open (path, repertoiremap_hash);
Packit 6c4009
		    }
Packit 6c4009
		}
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (repfile == NULL)
Packit 6c4009
	    {
Packit 6c4009
	      /* Look in the systems charmap directory.  */
Packit 6c4009
	      char *buf = xmalloc (strlen (filename) + 1
Packit 6c4009
				   + sizeof (REPERTOIREMAP_PATH));
Packit 6c4009
Packit 6c4009
	      stpcpy (stpcpy (stpcpy (buf, REPERTOIREMAP_PATH), "/"),
Packit 6c4009
		      filename);
Packit 6c4009
	      repfile = lr_open (buf, repertoiremap_hash);
Packit 6c4009
Packit 6c4009
	      free (buf);
Packit 6c4009
	    }
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      if (repfile == NULL)
Packit 6c4009
	return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We don't want symbolic names in string to be translated.  */
Packit 6c4009
  repfile->translate_strings = 0;
Packit 6c4009
Packit 6c4009
  /* Allocate room for result.  */
Packit 6c4009
  result = (struct repertoire_t *) xmalloc (sizeof (struct repertoire_t));
Packit 6c4009
  memset (result, '\0', sizeof (struct repertoire_t));
Packit 6c4009
Packit 6c4009
  result->name = xstrdup (filename);
Packit 6c4009
Packit 6c4009
#define obstack_chunk_alloc malloc
Packit 6c4009
#define obstack_chunk_free free
Packit 6c4009
  obstack_init (&result->mem_pool);
Packit 6c4009
Packit 6c4009
  if (init_hash (&result->char_table, 256)
Packit 6c4009
      || init_hash (&result->reverse_table, 256)
Packit 6c4009
      || init_hash (&result->seq_table, 256))
Packit 6c4009
    {
Packit 6c4009
      free (result);
Packit 6c4009
      return NULL;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We use a state machine to describe the charmap description file
Packit 6c4009
     format.  */
Packit 6c4009
  state = 1;
Packit 6c4009
  while (1)
Packit 6c4009
    {
Packit 6c4009
      /* What's on?  */
Packit 6c4009
      struct token *now = lr_token (repfile, NULL, NULL, NULL, verbose);
Packit 6c4009
      enum token_t nowtok = now->tok;
Packit 6c4009
      struct token *arg;
Packit 6c4009
Packit 6c4009
      if (nowtok == tok_eof)
Packit 6c4009
	break;
Packit 6c4009
Packit 6c4009
      switch (state)
Packit 6c4009
	{
Packit 6c4009
	case 1:
Packit 6c4009
	  /* We haven't yet read any character definition.  This is where
Packit 6c4009
	     we accept escape_char and comment_char definitions.  */
Packit 6c4009
	  if (nowtok == tok_eol)
Packit 6c4009
	    /* Ignore empty lines.  */
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (nowtok == tok_escape_char || nowtok == tok_comment_char)
Packit 6c4009
	    {
Packit 6c4009
	      /* We know that we need an argument.  */
Packit 6c4009
	      arg = lr_token (repfile, NULL, NULL, NULL, verbose);
Packit 6c4009
Packit 6c4009
	      if (arg->tok != tok_ident)
Packit 6c4009
		{
Packit 6c4009
		  lr_error (repfile, _("syntax error in prolog: %s"),
Packit 6c4009
			    _("bad argument"));
Packit 6c4009
Packit 6c4009
		  lr_ignore_rest (repfile, 0);
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (arg->val.str.lenmb != 1)
Packit 6c4009
		{
Packit 6c4009
		  lr_error (repfile, _("\
Packit 6c4009
argument to <%s> must be a single character"),
Packit 6c4009
			    nowtok == tok_escape_char ? "escape_char"
Packit 6c4009
						      : "comment_char");
Packit 6c4009
Packit 6c4009
		  lr_ignore_rest (repfile, 0);
Packit 6c4009
		  continue;
Packit 6c4009
		}
Packit 6c4009
Packit 6c4009
	      if (nowtok == tok_escape_char)
Packit 6c4009
		repfile->escape_char = *arg->val.str.startmb;
Packit 6c4009
	      else
Packit 6c4009
		repfile->comment_char = *arg->val.str.startmb;
Packit 6c4009
Packit 6c4009
	      lr_ignore_rest (repfile, 1);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (nowtok == tok_charids)
Packit 6c4009
	    {
Packit 6c4009
	      lr_ignore_rest (repfile, 1);
Packit 6c4009
Packit 6c4009
	      state = 2;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Otherwise we start reading the character definitions.  */
Packit 6c4009
	  state = 2;
Packit 6c4009
	  /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
	case 2:
Packit 6c4009
	  /* We are now are in the body.  Each line
Packit 6c4009
	     must have the format "%s %s %s\n" or "%s...%s %s %s\n".  */
Packit 6c4009
	  if (nowtok == tok_eol)
Packit 6c4009
	    /* Ignore empty lines.  */
Packit 6c4009
	    continue;
Packit 6c4009
Packit 6c4009
	  if (nowtok == tok_end)
Packit 6c4009
	    {
Packit 6c4009
	      state = 90;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  if (nowtok != tok_bsymbol)
Packit 6c4009
	    {
Packit 6c4009
	      lr_error (repfile,
Packit 6c4009
			_("syntax error in repertoire map definition: %s"),
Packit 6c4009
			_("no symbolic name given"));
Packit 6c4009
Packit 6c4009
	      lr_ignore_rest (repfile, 0);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* If the previous line was not completely correct free the
Packit 6c4009
	     used memory.  */
Packit 6c4009
	  if (from_name != NULL)
Packit 6c4009
	    obstack_free (&result->mem_pool, from_name);
Packit 6c4009
Packit 6c4009
	  from_name = (char *) obstack_copy0 (&result->mem_pool,
Packit 6c4009
					      now->val.str.startmb,
Packit 6c4009
					      now->val.str.lenmb);
Packit 6c4009
	  to_name = NULL;
Packit 6c4009
Packit 6c4009
	  state = 3;
Packit 6c4009
	  continue;
Packit 6c4009
Packit 6c4009
	case 3:
Packit 6c4009
	  /* We have two possibilities: We can see an ellipsis or an
Packit 6c4009
	     encoding value.  */
Packit 6c4009
	  if (nowtok == tok_ellipsis3 || nowtok == tok_ellipsis4
Packit 6c4009
	      || nowtok == tok_ellipsis2)
Packit 6c4009
	    {
Packit 6c4009
	      ellipsis = nowtok;
Packit 6c4009
	      state = 4;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
	  /* FALLTHROUGH */
Packit 6c4009
Packit 6c4009
	case 5:
Packit 6c4009
	  /* We expect a value of the form <Uxxxx> or <Uxxxxxxxx> where
Packit 6c4009
	     the xxx mean a hexadecimal value.  */
Packit 6c4009
	  state = 2;
Packit 6c4009
Packit 6c4009
	  errno = 0;
Packit 6c4009
	  if (nowtok != tok_ucs4)
Packit 6c4009
	    {
Packit 6c4009
	      lr_error (repfile,
Packit 6c4009
			_("syntax error in repertoire map definition: %s"),
Packit 6c4009
			_("no <Uxxxx> or <Uxxxxxxxx> value given"));
Packit 6c4009
Packit 6c4009
	      lr_ignore_rest (repfile, 0);
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* We've found a new valid definition.  */
Packit 6c4009
	  repertoire_new_char (repfile, &result->char_table,
Packit 6c4009
			       &result->reverse_table, &result->mem_pool,
Packit 6c4009
			       now->val.ucs4, from_name, to_name,
Packit 6c4009
			       ellipsis != tok_ellipsis2);
Packit 6c4009
Packit 6c4009
	  /* Ignore the rest of the line.  */
Packit 6c4009
	  lr_ignore_rest (repfile, 0);
Packit 6c4009
Packit 6c4009
	  from_name = NULL;
Packit 6c4009
	  to_name = NULL;
Packit 6c4009
Packit 6c4009
	  continue;
Packit 6c4009
Packit 6c4009
	case 4:
Packit 6c4009
	  if (nowtok != tok_bsymbol)
Packit 6c4009
	    {
Packit 6c4009
	      lr_error (repfile,
Packit 6c4009
			_("syntax error in repertoire map definition: %s"),
Packit 6c4009
			_("no symbolic name given for end of range"));
Packit 6c4009
Packit 6c4009
	      lr_ignore_rest (repfile, 0);
Packit 6c4009
	      state = 2;
Packit 6c4009
	      continue;
Packit 6c4009
	    }
Packit 6c4009
Packit 6c4009
	  /* Copy the to-name in a safe place.  */
Packit 6c4009
	  to_name = (char *) obstack_copy0 (&result->mem_pool,
Packit 6c4009
					    repfile->token.val.str.startmb,
Packit 6c4009
					    repfile->token.val.str.lenmb);
Packit 6c4009
Packit 6c4009
	  state = 5;
Packit 6c4009
	  continue;
Packit 6c4009
Packit 6c4009
	case 90:
Packit 6c4009
	  if (nowtok != tok_charids)
Packit 6c4009
	    lr_error (repfile, _("\
Packit 6c4009
%1$s: definition does not end with `END %1$s'"), "CHARIDS");
Packit 6c4009
Packit 6c4009
	  lr_ignore_rest (repfile, nowtok == tok_charids);
Packit 6c4009
	  break;
Packit 6c4009
	}
Packit 6c4009
Packit 6c4009
      break;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (state != 2 && state != 90 && !be_quiet)
Packit 6c4009
    record_error (0, 0, _("%s: premature end of file"),
Packit 6c4009
		  repfile->fname);
Packit 6c4009
Packit 6c4009
  lr_close (repfile);
Packit 6c4009
Packit 6c4009
  if (tsearch (result, &known, &repertoire_compare) == NULL)
Packit 6c4009
    /* Something went wrong.  */
Packit 6c4009
    record_error (0, errno, _("cannot save new repertoire map"));
Packit 6c4009
Packit 6c4009
  return result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
void
Packit 6c4009
repertoire_complain (const char *name)
Packit 6c4009
{
Packit 6c4009
  if (tfind (name, &unavailable, (__compar_fn_t) strcmp) == NULL)
Packit 6c4009
    {
Packit 6c4009
      record_error (0, errno, _("\
Packit 6c4009
repertoire map file `%s' not found"), name);
Packit 6c4009
Packit 6c4009
      /* Remember that we reported this map.  */
Packit 6c4009
      tsearch (name, &unavailable, (__compar_fn_t) strcmp);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static int
Packit 6c4009
repertoire_compare (const void *p1, const void *p2)
Packit 6c4009
{
Packit 6c4009
  struct repertoire_t *r1 = (struct repertoire_t *) p1;
Packit 6c4009
  struct repertoire_t *r2 = (struct repertoire_t *) p2;
Packit 6c4009
Packit 6c4009
  return strcmp (r1->name, r2->name);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static const struct keyword_t *
Packit 6c4009
repertoiremap_hash (const char *str, unsigned int len)
Packit 6c4009
{
Packit 6c4009
  static const struct keyword_t wordlist[] =
Packit 6c4009
  {
Packit 6c4009
    {"escape_char",      tok_escape_char,     0},
Packit 6c4009
    {"comment_char",     tok_comment_char,    0},
Packit 6c4009
    {"CHARIDS",          tok_charids,         0},
Packit 6c4009
    {"END",              tok_end,             0},
Packit 6c4009
  };
Packit 6c4009
Packit 6c4009
  if (len == 11 && memcmp (wordlist[0].name, str, 11) == 0)
Packit 6c4009
    return &wordlist[0];
Packit 6c4009
  if (len == 12 && memcmp (wordlist[1].name, str, 12) == 0)
Packit 6c4009
    return &wordlist[1];
Packit 6c4009
  if (len == 7 && memcmp (wordlist[2].name, str, 7) == 0)
Packit 6c4009
    return &wordlist[2];
Packit 6c4009
  if (len == 3 && memcmp (wordlist[3].name, str, 3) == 0)
Packit 6c4009
    return &wordlist[3];
Packit 6c4009
Packit 6c4009
  return NULL;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
static void
Packit 6c4009
repertoire_new_char (struct linereader *lr, hash_table *ht, hash_table *rt,
Packit 6c4009
		     struct obstack *ob, uint32_t value, const char *from,
Packit 6c4009
		     const char *to, int decimal_ellipsis)
Packit 6c4009
{
Packit 6c4009
  char *from_end;
Packit 6c4009
  char *to_end;
Packit 6c4009
  const char *cp;
Packit 6c4009
  char *buf = NULL;
Packit 6c4009
  int prefix_len, len1, len2;
Packit 6c4009
  unsigned long int from_nr, to_nr, cnt;
Packit 6c4009
Packit 6c4009
  if (to == NULL)
Packit 6c4009
    {
Packit 6c4009
      insert_entry (ht, from, strlen (from),
Packit 6c4009
		    (void *) (unsigned long int) value);
Packit 6c4009
      /* Please note that it isn't a bug if a symbol is defined more
Packit 6c4009
	 than once.  All later definitions are simply discarded.  */
Packit 6c4009
Packit 6c4009
      insert_entry (rt, obstack_copy (ob, &value, sizeof (value)),
Packit 6c4009
		    sizeof (value), (void *) from);
Packit 6c4009
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  /* We have a range: the names must have names with equal prefixes
Packit 6c4009
     and an equal number of digits, where the second number is greater
Packit 6c4009
     or equal than the first.  */
Packit 6c4009
  len1 = strlen (from);
Packit 6c4009
  len2 = strlen (to);
Packit 6c4009
Packit 6c4009
  if (len1 != len2)
Packit 6c4009
    {
Packit 6c4009
    invalid_range:
Packit 6c4009
      lr_error (lr, _("invalid names for character range"));
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  cp = &from[len1 - 1];
Packit 6c4009
  if (decimal_ellipsis)
Packit 6c4009
    while (isdigit (*cp) && cp >= from)
Packit 6c4009
      --cp;
Packit 6c4009
  else
Packit 6c4009
    while (isxdigit (*cp) && cp >= from)
Packit 6c4009
      {
Packit 6c4009
	if (!isdigit (*cp) && !isupper (*cp))
Packit 6c4009
	  lr_error (lr, _("\
Packit 6c4009
hexadecimal range format should use only capital characters"));
Packit 6c4009
	--cp;
Packit 6c4009
      }
Packit 6c4009
Packit 6c4009
  prefix_len = (cp - from) + 1;
Packit 6c4009
Packit 6c4009
  if (cp == &from[len1 - 1] || strncmp (from, to, prefix_len) != 0)
Packit 6c4009
    goto invalid_range;
Packit 6c4009
Packit 6c4009
  errno = 0;
Packit 6c4009
  from_nr = strtoul (&from[prefix_len], &from_end, decimal_ellipsis ? 10 : 16);
Packit 6c4009
  if (*from_end != '\0' || (from_nr == ULONG_MAX && errno == ERANGE)
Packit 6c4009
      || ((to_nr = strtoul (&to[prefix_len], &to_end,
Packit 6c4009
			    decimal_ellipsis ? 10 : 16)) == ULONG_MAX
Packit 6c4009
          && errno == ERANGE)
Packit 6c4009
      || *to_end != '\0')
Packit 6c4009
    {
Packit 6c4009
      lr_error (lr, _("<%s> and <%s> are invalid names for range"),
Packit 6c4009
		from, to);
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  if (from_nr > to_nr)
Packit 6c4009
    {
Packit 6c4009
      lr_error (lr, _("upper limit in range is smaller than lower limit"));
Packit 6c4009
      return;
Packit 6c4009
    }
Packit 6c4009
Packit 6c4009
  for (cnt = from_nr; cnt <= to_nr; ++cnt)
Packit 6c4009
    {
Packit 6c4009
      uint32_t this_value = value + (cnt - from_nr);
Packit 6c4009
Packit 6c4009
      obstack_printf (ob, decimal_ellipsis ? "%.*s%0*ld" : "%.*s%0*lX",
Packit 6c4009
		      prefix_len, from, len1 - prefix_len, cnt);
Packit 6c4009
      obstack_1grow (ob, '\0');
Packit 6c4009
Packit 6c4009
      insert_entry (ht, buf, len1,
Packit 6c4009
		    (void *) (unsigned long int) this_value);
Packit 6c4009
      /* Please note we don't examine the return value since it is no error
Packit 6c4009
	 if we have two definitions for a symbol.  */
Packit 6c4009
Packit 6c4009
      insert_entry (rt, obstack_copy (ob, &this_value, sizeof (this_value)),
Packit 6c4009
		    sizeof (this_value), (void *) from);
Packit 6c4009
    }
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
uint32_t
Packit 6c4009
repertoire_find_value (const struct repertoire_t *rep, const char *name,
Packit 6c4009
		       size_t len)
Packit 6c4009
{
Packit 6c4009
  void *result;
Packit 6c4009
Packit 6c4009
  if (rep == NULL)
Packit 6c4009
    return ILLEGAL_CHAR_VALUE;
Packit 6c4009
Packit 6c4009
  if (find_entry ((hash_table *) &rep->char_table, name, len, &result) < 0)
Packit 6c4009
    return ILLEGAL_CHAR_VALUE;
Packit 6c4009
Packit 6c4009
  return (uint32_t) ((unsigned long int) result);
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
const char *
Packit 6c4009
repertoire_find_symbol (const struct repertoire_t *rep, uint32_t ucs)
Packit 6c4009
{
Packit 6c4009
  void *result;
Packit 6c4009
Packit 6c4009
  if (rep == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  if (find_entry ((hash_table *) &rep->reverse_table, &ucs, sizeof (ucs),
Packit 6c4009
		  &result) < 0)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  return (const char *) result;
Packit 6c4009
}
Packit 6c4009
Packit 6c4009
Packit 6c4009
struct charseq *
Packit 6c4009
repertoire_find_seq (const struct repertoire_t *rep, uint32_t ucs)
Packit 6c4009
{
Packit 6c4009
  void *result;
Packit 6c4009
Packit 6c4009
  if (rep == NULL)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  if (find_entry ((hash_table *) &rep->seq_table, &ucs, sizeof (ucs),
Packit 6c4009
		  &result) < 0)
Packit 6c4009
    return NULL;
Packit 6c4009
Packit 6c4009
  return (struct charseq *) result;
Packit 6c4009
}