/* Copyright (C) 1991, 1992, 1993 Free Software Foundation, Inc.
This file is part of the GNU C Library.

The GNU C Library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public License as
published by the Free Software Foundation; either version 2 of the
License, or (at your option) any later version.

The GNU C Library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
Library General Public License for more details.

You should have received a copy of the GNU Library General Public
License along with the GNU C Library; see the file COPYING.LIB.  If
not, write to the Free Software Foundation, Inc., 675 Mass Ave,
Cambridge, MA 02139, USA.  */

#include <ansidecl.h>
#include <localeinfo.h>
#include <errno.h>
#include <locale.h>
#include <string.h>
#include <stdlib.h>

#if defined(__linux__) && defined(USE_ISO_8859_1)
#include <ctype.h>

extern CONST unsigned short int __ctype_b_C[];
extern CONST unsigned char __ctype_tolower_C[];
extern CONST unsigned char __ctype_toupper_C[];
extern CONST struct ctype_info __ctype_C;

extern CONST unsigned short int __ctype_b_ISO_8859_1[];
extern CONST unsigned char __ctype_tolower_ISO_8859_1[];
extern CONST unsigned char __ctype_toupper_ISO_8859_1[];
extern CONST struct ctype_info __ctype_ISO_8859_1;

#endif


/* Switch to the locale called NAME in CATEGORY.
   Return a string describing the locale.  This string can
   be used as the NAME argument in a later call.
   If NAME is NULL, don't switch locales, but return the current one.
   If NAME is "", switch to a locale based on the environment variables,
   as per POSIX.  Return NULL on error.  */
char *
DEFUN(setlocale, (category, name), int category AND CONST char *name)
{
#if defined(__linux__) && defined(USE_ISO_8859_1)
  /* Don't ask me why I did this. H.J. */

  /* Fixed up setlocale() by Mitch (m.dsouza@mrc-apu.cam.ac.uk) */

  static struct message_struct { int category; CONST char *name;} ms[]= {
	{ LC_COLLATE,	"LC_COLLATE" },
	{ LC_CTYPE,	"LC_CTYPE" },
	{ LC_MONETARY,	"LC_MONETARY" },
	{ LC_NUMERIC,	"LC_NUMERIC" },
	{ LC_TIME,	"LC_TIME" },
	{ LC_RESPONSE,	"LC_RESPONSE" },
	{ LC_MESSAGES,	"LC_MESSAGES" },
/*
 * New categories go in between here.
 */
	{ LC_ALL,	"LC_ALL" }
  };

  char *ptr=NULL;
  int i;

  /* The default locale is C. */
  static CONST char * current_locale = "C";

  /* If not a valid category */
  if (category & ~LC_ALL) return (char *) NULL;

  /* Return the current locale. */
  if (name == NULL)
    return (char *) current_locale;

  for (i=0; i < sizeof(ms)/sizeof(struct message_struct)-1; i++)
  {
    if (category & ms[i].category)
    {
      /* If "" is given as the locale then we check environment vars */
      if ( *name == (char) NULL)
      {
	if ((ptr=getenv(ms[i].name)) == NULL)
	{
	  if (category == LC_ALL)
	  {
	    continue;
	  }
	  else
	  {
	    if ((name=getenv("LANG")) == NULL)
	    {
	      if ((name=getenv("LC_default"))==NULL)
		name="C";
	    }
	  }
	}
      else
      {
	name = ptr;
      }
    }

      /* For POSIX or if the locale is the same as the current we
	 do nothing. */
      if (!strcmp(name, "POSIX") || !strcmp(name, current_locale))
	continue;

      if (strcmp(name, "C") && strcmp(name, "ISO-8859-1"))
      {
	/* Not a vaild locale so return immediately */
	errno = EINVAL;
	return NULL;
      }

      current_locale = name;

      switch (category & ms[i].category) {

      case LC_COLLATE:
	/* Not yet implemented */
	break;

      case LC_CTYPE:

	/* Change locale */
	/* For C, we use the C char set. */
	if (!strcmp(name, "C"))
	{
	  __ctype_b = __ctype_b_C + 1;
	  __ctype_tolower = __ctype_tolower_C + 1;
	  __ctype_toupper = __ctype_toupper_C + 1;
	  _ctype_info = &__ctype_C;
	}
	else
	{
	  /* For ISO-8859-1, we use the ISO-8859-1 char set. */
	  if (!strcmp(name, "ISO-8859-1"))
	  {
	    __ctype_b = __ctype_b_ISO_8859_1 + 1;
	    __ctype_tolower = __ctype_tolower_ISO_8859_1 + 1;
	    __ctype_toupper = __ctype_toupper_ISO_8859_1 + 1;
	    _ctype_info = &__ctype_ISO_8859_1;
	  }
	}
	break;

      case LC_MONETARY:
	/* Not yet implemented */
  	break;

      case LC_NUMERIC:
	/* Not yet implemented */
  	break;

      case LC_TIME:
	/* Not yet implemented */
  	break;

      case LC_RESPONSE:
	/* Not yet implemented */
  	break;

      case LC_MESSAGES:
	/* Nothing needs to be done */
  	break;
      }
    }
  }

  /* If we were invoked as setlocale(LC_ALL,"") and we haven't returned NULL
     for any invalid categories by now then we can return the current locale */
  if (category == LC_ALL)
	return (char *) current_locale;

  /* If we haven't returned NULL by now, then we are fine */
  return (char *) name;

#else

  /* Braindead implementation until I finish the fancy one.  */

  if (name == NULL || name[0] == '\0')
    return (char *) "C";

  if (!strcmp(name, "C") || !strcmp(name, "POSIX"))
    return (char *) name;

  errno = EINVAL;
  return NULL;
#endif
}
