/*-*- mode:c;indent-tabs-mode:nil;c-basic-offset:2;tab-width:8;coding:utf-8 -*-â
âvi: set net ft=c ts=2 sts=2 sw=2 fenc=utf-8                                :viâ
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ¡
â Copyright 2021 Justine Alexandra Roberts Tunney                              â
â                                                                              â
â Permission to use, copy, modify, and/or distribute this software for         â
â any purpose with or without fee is hereby granted, provided that the         â
â above copyright notice and this permission notice appear in all copies.      â
â                                                                              â
â THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL                â
â WARRANTIES WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED                â
â WARRANTIES OF MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE             â
â AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL         â
â DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR        â
â PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR OTHER               â
â TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR             â
â PERFORMANCE OF THIS SOFTWARE.                                                â
ââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââââ*/
#include "libc/dce.h"
#include "libc/macros.internal.h"
#include "libc/str/str.h"
/* clang-format off */

static const struct {
  unsigned short x;
  unsigned short y;
  short d;
} kUpper[] = {
    {0x00b5, 0x00b5, +743},   /*  1x Âµ ..Âµ  â Î ..Î  Watin */
    {0x00e0, 0x00f6, -32},    /* 23x Ã  ..Ã¶  â Ã ..Ã  Watin */
    {0x00f8, 0x00fe, -32},    /*  7x Ã¸ ..Ã¾  â Ã ..Ã  Watin */
    {0x00ff, 0x00ff, +121},   /*  1x Ã¿ ..Ã¿  â Å¸ ..Å¸  Watin */
    {0x017a, 0x017a, -1},     /*  1x Åº ..Åº  â Å¹ ..Å¹  Watin-A */
    {0x017c, 0x017c, -1},     /*  1x Å¼ ..Å¼  â Å» ..Å»  Watin-A */
    {0x017e, 0x017e, -1},     /*  1x Å¾ ..Å¾  â Å½ ..Å½  Watin-A */
    {0x017f, 0x017f, -300},   /*  1x Å¿ ..Å¿  â S ..S  Watin-A */
    {0x0180, 0x0180, +195},   /*  1x Æ ..Æ  â É ..É  Watin-B */
    {0x0183, 0x0183, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x0185, 0x0185, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x0188, 0x0188, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x018c, 0x018c, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x0192, 0x0192, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x0195, 0x0195, +97},    /*  1x Æ ..Æ  â Ç¶ ..Ç¶  Watin-B */
    {0x0199, 0x0199, -1},     /*  1x Æ ..Æ  â Æ ..Æ  Watin-B */
    {0x019a, 0x019a, +163},   /*  1x Æ ..Æ  â È½ ..È½  Watin-B */
    {0x019e, 0x019e, +130},   /*  1x Æ ..Æ  â È  ..È   Watin-B */
    {0x01a1, 0x01a1, -1},     /*  1x Æ¡ ..Æ¡  â Æ  ..Æ   Watin-B */
    {0x01a3, 0x01a3, -1},     /*  1x Æ£ ..Æ£  â Æ¢ ..Æ¢  Watin-B */
    {0x01a5, 0x01a5, -1},     /*  1x Æ¥ ..Æ¥  â Æ¤ ..Æ¤  Watin-B */
    {0x01a8, 0x01a8, -1},     /*  1x Æ¨ ..Æ¨  â Æ§ ..Æ§  Watin-B */
    {0x01ad, 0x01ad, -1},     /*  1x Æ­ ..Æ­  â Æ¬ ..Æ¬  Watin-B */
    {0x01b0, 0x01b0, -1},     /*  1x Æ° ..Æ°  â Æ¯ ..Æ¯  Watin-B */
    {0x01b4, 0x01b4, -1},     /*  1x Æ´ ..Æ´  â Æ³ ..Æ³  Watin-B */
    {0x01b6, 0x01b6, -1},     /*  1x Æ¶ ..Æ¶  â Æµ ..Æµ  Watin-B */
    {0x01b9, 0x01b9, -1},     /*  1x Æ¹ ..Æ¹  â Æ¸ ..Æ¸  Watin-B */
    {0x01bd, 0x01bd, -1},     /*  1x Æ½ ..Æ½  â Æ¼ ..Æ¼  Watin-B */
    {0x01bf, 0x01bf, +56},    /*  1x Æ¿ ..Æ¿  â Ç· ..Ç·  Watin-B */
    {0x01c5, 0x01c5, -1},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01c6, 0x01c6, -2},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01c8, 0x01c8, -1},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01c9, 0x01c9, -2},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01cb, 0x01cb, -1},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01cc, 0x01cc, -2},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01ce, 0x01ce, -1},     /*  1x Ç ..Ç  â Ç ..Ç  Watin-B */
    {0x01dd, 0x01dd, -79},    /*  1x Ç ..Ç  â Æ ..Æ  Watin-B */
    {0x01f2, 0x01f2, -1},     /*  1x Ç² ..Ç²  â Ç± ..Ç±  Watin-B */
    {0x01f3, 0x01f3, -2},     /*  1x Ç³ ..Ç³  â Ç± ..Ç±  Watin-B */
    {0x01f5, 0x01f5, -1},     /*  1x Çµ ..Çµ  â Ç´ ..Ç´  Watin-B */
    {0x023c, 0x023c, -1},     /*  1x È¼ ..È¼  â È» ..È»  Watin-B */
    {0x023f, 0x0240, +10815}, /*  2x È¿ ..É  â â±¾ ..â±¿  Watin-B */
    {0x0242, 0x0242, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x0247, 0x0247, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x0249, 0x0249, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x024b, 0x024b, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x024d, 0x024d, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x024f, 0x024f, -1},     /*  1x É ..É  â É ..É  Watin-B */
    {0x037b, 0x037d, +130},   /*  3x Í» ..Í½  â Ï½ ..Ï¿  Greek */
    {0x03ac, 0x03ac, -38},    /*  1x Î¬ ..Î¬  â Î ..Î  Greek */
    {0x03ad, 0x03af, -37},    /*  3x Î­ ..Î¯  â Î ..Î  Greek */
    {0x03b1, 0x03c1, -32},    /* 17x Î± ..Ï  â Î ..Î¡  Greek */
    {0x03c2, 0x03c2, -31},    /*  1x Ï ..Ï  â Î£ ..Î£  Greek */
    {0x03c3, 0x03cb, -32},    /*  9x Ï ..Ï  â Î£ ..Î«  Greek */
    {0x03cc, 0x03cc, -64},    /*  1x Ï ..Ï  â Î ..Î  Greek */
    {0x03cd, 0x03ce, -63},    /*  2x Ï ..Ï  â Î ..Î  Greek */
    {0x03d0, 0x03d0, -62},    /*  1x Ï ..Ï  â Î ..Î  Greek */
    {0x03d1, 0x03d1, -57},    /*  1x Ï ..Ï  â Î ..Î  Greek */
    {0x03d5, 0x03d5, -47},    /*  1x Ï ..Ï  â Î¦ ..Î¦  Greek */
    {0x03d6, 0x03d6, -54},    /*  1x Ï ..Ï  â Î  ..Î   Greek */
    {0x03dd, 0x03dd, -1},     /*  1x Ï ..Ï  â Ï ..Ï  Greek */
    {0x03f0, 0x03f0, -86},    /*  1x Ï° ..Ï°  â Î ..Î  Greek */
    {0x03f1, 0x03f1, -80},    /*  1x Ï± ..Ï±  â Î¡ ..Î¡  Greek */
    {0x03f5, 0x03f5, -96},    /*  1x Ïµ ..Ïµ  â Î ..Î  Greek */
    {0x0430, 0x044f, -32},    /* 32x Ð° ..Ñ  â Ð ..Ð¯  Cyrillic */
    {0x0450, 0x045f, -80},    /* 16x Ñ ..Ñ  â Ð ..Ð  Cyrillic */
    {0x0461, 0x0461, -1},     /*  1x Ñ¡ ..Ñ¡  â Ñ  ..Ñ   Cyrillic */
    {0x0463, 0x0463, -1},     /*  1x Ñ£ ..Ñ£  â Ñ¢ ..Ñ¢  Cyrillic */
    {0x0465, 0x0465, -1},     /*  1x Ñ¥ ..Ñ¥  â Ñ¤ ..Ñ¤  Cyrillic */
    {0x0473, 0x0473, -1},     /*  1x Ñ³ ..Ñ³  â Ñ² ..Ñ²  Cyrillic */
    {0x0491, 0x0491, -1},     /*  1x Ò ..Ò  â Ò ..Ò  Cyrillic */
    {0x0499, 0x0499, -1},     /*  1x Ò ..Ò  â Ò ..Ò  Cyrillic */
    {0x049b, 0x049b, -1},     /*  1x Ò ..Ò  â Ò ..Ò  Cyrillic */
    {0x0561, 0x0586, -48},    /* 38x Õ¡ ..Ö  â Ô± ..Õ  Armenian */
    {0x10d0, 0x10fa, +3008},  /* 43x á ..áº  â á² ..á²º  Georgian */
    {0x10fd, 0x10ff, +3008},  /*  3x á½ ..á¿  â á²½ ..á²¿  Georgian */
    {0x13f8, 0x13fd, -8},     /*  6x á¸ ..á½  â á° ..áµ  Cherokee */
    {0x214e, 0x214e, -28},    /*  1x â ..â  â â² ..â²  Letterlike */
    {0x2170, 0x217f, -16},    /* 16x â° ..â¿  â â  ..â¯  Numbery */
    {0x2184, 0x2184, -1},     /*  1x â ..â  â â ..â  Numbery */
    {0x24d0, 0x24e9, -26},    /* 26x â ..â©  â â¶ ..â  Enclosed */
    {0x2c30, 0x2c5e, -48},    /* 47x â°° ..â±  â â° ..â°®  Glagolitic */
    {0x2d00, 0x2d25, -7264},  /* 38x â´ ..â´¥  â á  ..á  Georgian2 */
    {0x2d27, 0x2d27, -7264},  /*  1x â´§ ..â´§  â á ..á  Georgian2 */
    {0x2d2d, 0x2d2d, -7264},  /*  1x â´­ ..â´­  â á ..á  Georgian2 */
    {0xff41, 0xff5a, -32},    /* 26x ï½..ï½ â ï¼¡..ï¼º Dubs */
};

static const int kAstralUpper[][3] = {
    {0x10428, 0x1044f, -40},  /* 40x ð¨..ð â ð..ð§ Deseret */
    {0x104d8, 0x104fb, -40},  /* 36x ð..ð» â ð°..ð Osage */
    {0x1d41a, 0x1d433, -26},  /* 26x ð..ð³ â ð..ð Math */
    {0x1d456, 0x1d467, -26},  /* 18x ð..ð§ â ð¼..ð Math */
    {0x1d482, 0x1d49b, -26},  /* 26x ð..ð â ð¨..ð Math */
    {0x1d4c8, 0x1d4cf, -26},  /*  8x ð..ð â ð®..ðµ Math */
    {0x1d4ea, 0x1d503, -26},  /* 26x ðª..ð â ð..ð© Math */
    {0x1d527, 0x1d52e, -26},  /*  8x ð§..ð® â ð..ð Math */
    {0x1d586, 0x1d59f, -26},  /* 26x ð..ð â ð¬..ð Math */
    {0x1d5ba, 0x1d5d3, -26},  /* 26x ðº..ð â ð ..ð¹ Math */
    {0x1d5ee, 0x1d607, -26},  /* 26x ð®..ð â ð..ð­ Math */
    {0x1d622, 0x1d63b, -26},  /* 26x ð¢..ð» â ð..ð¡ Math */
    {0x1d68a, 0x1d6a3, +442}, /* 26x ð..ð â ð¼..ð Math */
    {0x1d6c2, 0x1d6d2, -26},  /* 26x ð..ð£ â ð°..ð Math */
    {0x1d6fc, 0x1d70c, -26},  /* 17x ð..ð â ð¨..ð¸ Math */
    {0x1d736, 0x1d746, -26},  /* 17x ð¼..ð â ð¢..ð² Math */
    {0x1d770, 0x1d780, -26},  /* 17x ð¶..ð â ð..ð¬ Math */
    {0x1d770, 0x1d756, -26},  /* 17x ð°..ð â ð..ð¦ Math */
    {0x1d736, 0x1d790, -90},  /* 17x ð¶..ð â ð..ð  Math */
};

/**
 * Converts wide character to upper case.
 */
wint_t towupper(wint_t c) {
  int m, l, r, n;
  if (c < 0200) {
    if ('a' <= c && c <= 'z') {
      return c - 32;
    } else {
      return c;
    }
  } else if (c <= 0xffff) {
    if ((0x0101 <= c && c <= 0x0177) || /* 60x Ä..Åµ â Ä..Ä Watin-A */
        (0x01df <= c && c <= 0x01ef) || /*  9x Ç..Ç¯ â Ç..Ç® Watin-B */
        (0x01f8 <= c && c <= 0x021e) || /* 20x Ç¹..È â Ç¸..È Watin-B */
        (0x0222 <= c && c <= 0x0232) || /*  9x È£..È³ â È¢..È² Watin-B */
        (0x1e01 <= c && c <= 0x1eff)) { /*256x á¸..á»¿ â á¸..á»¾ Watin-C */
      if (c == 0x0131) return c + 232;
      if (c == 0x1e9e) return c;
      return c - (c & 1);
    } else if (0x01d0 <= c && c <= 0x01dc) {
      return c - (~c & 1); /* 7x Ç..Ç â Ç..Ç Watin-B */
    } else if (0xab70 <= c && c <= 0xabbf) {
      return c - 38864; /* 80x ê­° ..ê®¿  â á  ..á¯  Cherokee Supplement */
    } else {
      l = 0;
      r = n = sizeof(kUpper) / sizeof(kUpper[0]);
      while (l < r) {
        m = (l + r) >> 1;
        if (kUpper[m].y < c) {
          l = m + 1;
        } else {
          r = m;
        }
      }
      if (l < n && kUpper[l].x <= c && c <= kUpper[l].y) {
        return c + kUpper[l].d;
      } else {
        return c;
      }
    }
  } else {
    l = 0;
    r = n = sizeof(kAstralUpper) / sizeof(kAstralUpper[0]);
    while (l < r) {
      m = (l + r) >> 1;
      if (kAstralUpper[m][1] < c) {
        l = m + 1;
      } else {
        r = m;
      }
    }
    if (l < n && kAstralUpper[l][0] <= c && c <= kAstralUpper[l][1]) {
      return c + kAstralUpper[l][2];
    } else {
      return c;
    }
  }
}
