/* _mbtowc.c (emx+gcc) -- Copyright (c) 1994-1996 by Eberhard Mattes */

#include <stdlib.h>
#include <sys/nls.h>
#include <emx/locale.h>

int _mbtowc (wchar_t *pwc, const char *s, size_t n, int *pshift)
{
  unsigned char c;

  /* ANSI X3.159-1989, 4.10.7.2: "If s is not a null pointer, the
     mbtowc function either returns 0 (if s points to the null
     character)" */

  c = *s;
  if (c == 0)
    return 0;
  if (n == 0)
    return -1;
  switch (_cur_mbyte.mode)
    {
    case _MB_8BITS:
      if (pwc != NULL)
        *pwc = c;
      return 1;
  
    case _MB_DBCS:
      if (_nls_is_dbcs_lead (c))
        {
          if (n >= 2 && s[1] != 0)
            {
              if (pwc != NULL)
                *pwc = (c << 8) | (unsigned char)s[1];
              return 2;
            }
        }
      else
        {
          if (pwc != NULL)
            *pwc = c;
          return 1;
        }
      break;
      
    case _MB_UTF_2:         /* UTF-2 */
      if (c <= 0x7f)
        {
          if (pwc != NULL)
            *pwc = c;
          return 1;
        }
      else
        {
          int i, n;
          unsigned long x, m;

          if ((c & 0xe0) == 0xc0)
            {
              n = 1; x = c & 0x1f; m = 0x80;
            }
          else if ((c & 0xf0) == 0xe0)
            {
              n = 2; x = c & 0x0f; m = 0x800;
            }
          else if ((c & 0xf8) == 0xf0)
            {
              n = 3; x = c & 0x07; m = 0x10000;
            }
          else if ((c & 0xfc) == 0xf8)
            {
              n = 4; x = c & 0x03; m = 0x200000;
            }
          else if ((c & 0xfe) == 0xfc)
            {
              n = 5; x = c & 0x01; m = 0x4000000;
            }
          else
            return -1;
          ++s;
          for (i = 0; i < n; ++i)
            {
              if ((*s & 0xc0) != 0x80)
                return -1;
              x = (x << 6) | (*s & 0x3f);
              ++s;
            }
          if (x < m)
            return -1;
          if (pwc != NULL)
            *pwc = (wchar_t)x;
          return n + 1;
        }
      break;
    }
  return -1;
}
