#if defined(__BORLANDC__)
#pragma hdrstop
#endif

#include <algorithm>
#include "wmatch.h"

#if defined(__BORLANDC__)
#pragma package(smart_init)
#endif

/* ポインタの差すマルチバイト文字のバイト数を返す
   マクロINC(p)の定義を行う */

#if defined(__BORLANDC__) || defined(_MSC_VER) || defined(__MINGW32__)
/* S JIS */
#define K1H(x) ((0x81 <= ((x) & 0xff)) && (((x) & 0xff) <= 0x9f))
#define K2H(x) ((0xe0 <= ((x) & 0xff)) && (((x) & 0xff) <= 0xef))
#define KH(x)  (K1H(x) || K2H(x))
#define KL(x)  ((0x40 <= ((x) & 0xff) <= 0xfc) && (((x) & 0xff) != 0x7f))
#define KP(p)  (KH((p)[0]) && KL((p)[1]))
#define INC(p) ((*(p)) ? (KP(p) ? 2 : 1) : 0)
#else
/* U JIS */
#define K1H(x) ((0xa1 <= ((x) & 0xff)) && (((x) & 0xff) <= 0xcf))
#define K2H(x) ((0xd0 <= ((x) & 0xff)) && (((x) & 0xff) <= 0xfe))
#define KH(x)  (K1H(x) || K2H(x))
#define KL(x)  ((0xa1 <= ((x) & 0xff)) && (((x) & 0xff) <= 0xfe))
#define KP(p)  (KH((p)[0]) && KL((p)[1]))
#define HK(x)  ((0xa1 <= ((x) & 0xff)) && (((x) & 0xff) <= 0xdf))
#define HP(x)  ((((p)[0] & 0xff) == 0x8e) && HK((p)[1]))
#define INC(p) ((*(p)) ? ((KP(p) || HP(p)) ? 2 : 1) : 0)
#endif

static unsigned long wcs(const char *&p);
static bool chclass(const char *p, unsigned long ch);
static bool chclass(const char *&p, const char *&s);

static unsigned long wcs(const char *&p) {
  unsigned long w = 0UL;
  int n = INC(p);
  for (int i = 0; i < n; i++) {
    w <<= 8UL;
    w |= (p[i] & 0xffUL);
  } 
  p += n;
  return w;
}

static bool chclass(const char *p, unsigned long ch) {
  do {
    unsigned long cs = wcs(p);
    if ((p[0] == '-') && (p[1] != ']')) {
      p++;
      unsigned long ce = wcs(p);
      if ((cs <= ch) && (ch <= ce)) return true;
    } else if (cs == ch) return true;
  } while (*p != ']'); // 先頭は閉じカッコではない
  return false;
}

static bool chclass(const char *&p, const char *&s) {
  unsigned long ch = wcs(s);
  const char *e = p;
  if (*e == '^') e++;
  do {
    // [ペア]になっていない時はリテラル
    if (!*e) return ch == '[';
    e += INC(e);
  } while (*e != ']'); // 先頭は閉じカッコではない
  bool v;
  if (*p == '^') { // 否定
    p++;
    v = !chclass(p, ch);
  } else {
    v = chclass(p, ch);
  }
  p = e + 1;
  return v;
}

bool wmatch(const char *p, const char *s) {
  for (;;) {
    switch (*p) {
    case '[':
      if (*s == '\0') return false;
      p++;
      if (!chclass(p, s)) return false;
      break;
    case '\0':
      if (*s == '\0') return true;
      else return false;
    case '*':
      while (*p == '*') p++;
      if (*p == '\0') return true; // 末尾の*
      for (;;) {
        if (wmatch(p, s)) return true;
        if (*s == '\0') return false;
        else s += INC(s);
      }
    case '?':
      if (*s == '\0') return false;
      p++;
      s += INC(s);
      break;
    case '\\': // 下へ抜けてリテラルとして扱う
      if (p[1]) { // 行末の￥は￥のリテラルとする
        p++; 
      }
    default:
      int n = INC(p);
      for (int i = 0; i < n; i++) {
        if (p[i] != s[i]) return false;
      }
      p += n;
      s += n;
    }
  }
}

#if 0 /* テストプログラム:lsのようなもの */
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <dirent.h>
#include <errno.h>

int main(int argc, char *argv[]) {
  switch (argc) {
  case 1:
    fprintf(stderr, "usage:%s patterns\n", argv[0]);
    exit(1);
    break;
  defualt:
    break;
  }
  DIR *dp;
  struct dirent *ep;
  if ((dp = opendir(".")) == NULL) {
  }
  while (ep = readdir(dp)) {
    for (int i = 1; i < argc; i++) {
      if (wmatch(argv[i], ep->d_name)) {
        printf("%s\n", ep->d_name);
      } 
    }
  }
  if (errno) {
    fprintf(stderr, "%s\n", strerror(errno));
    exit(-1);
  }
  exit(0);
  return 0;
}
#endif
