/*
 * This software is distributed under the GNU General Public License
 * either version 2, or (at your option) any later version.
 */

#include "postgres.h"

#include <locale.h>

#include "utils/builtins.h"

static 
unsigned char * xfrm(unsigned char *data, int size, const unsigned char *locale, int localesize);

unsigned char * c_varcharxfrm(unsigned char *s, const unsigned char *locale);


static unsigned char *
xfrm(unsigned char *data, int size, const unsigned char *locale, int localesize)
{
  size_t length = size*3+4;
  char *transformed;
  size_t transformed_length;
  char *oldlocale, *newlocale;
     
  /* First try a buffer perhaps big enough.  */
  transformed = palloc (length);
     
  oldlocale = setlocale(LC_COLLATE, NULL);
  if (!oldlocale) {
    elog(ERROR, "setlocale(LC_COLLATE,NULL) failed to return a locale");
    return NULL;
  }
  
  newlocale = setlocale(LC_COLLATE, locale);
  if (!newlocale) {
    elog(ERROR, "setlocale(LC_COLLATE,%s) failed to return a locale", locale);
    return NULL;
  }

  transformed_length = strxfrm (transformed, data, length);

  /* If the buffer was not large enough, resize it and try again.  */
  if (transformed_length >= length) {
    elog(INFO, "Calling strxfrm again because result didn't fit (%d>%d)", transformed_length, length);
    length = transformed_length + 1;
    transformed = palloc(length);
    strxfrm (transformed, data, length);
  }
     
  newlocale = setlocale(LC_COLLATE, oldlocale);

  Assert(newlocale && !strcmp(newlocale,oldlocale));
  if (!newlocale || strcmp(newlocale,oldlocale)) {
    elog(ERROR, "Failed to reset locale (trying to reset locale to %s from %s instead got %s)", oldlocale, locale, newlocale);
  }
  
  return transformed;
}


unsigned char *
c_varcharxfrm(unsigned char *s, const unsigned char *l)
{
  int lens = 0, lenl = 0, lenr = 0;
  unsigned char *str, *locale, *retval, *retval2;

  if (s) {
    lens = *(int32 *) s - 4;
    str = palloc(lens+1);
    memcpy(str, s+4, lens);
    str[lens]='\0';
  }

  if (l) {
    lenl = *(int32 *) l - 4;
    locale = palloc(lenl+1);
    memcpy(locale, l+4, lenl);
    locale[lenl]='\0';
  }

  retval = xfrm(str, lens, locale, lenl);
  
  lenr = strlen(retval);
  retval2 = palloc(lenr+5);
  memcpy(retval2+4, retval, lenr+1);
  *(int32 *)retval2 = lenr;
  
  return retval2;
}





/*
 * Local Variables:
 *	tab-width: 4
 *	c-indent-level: 4
 *	c-basic-offset: 4
 * End:
 */
