text: /* A conio implementation for Mingw/Dev-C++.
   *
   * Written by:
   * Hongli Lai <hongli@telekabel.nl>
   * tkorrovi <tkorrovi@altavista.net> on 2002/02/26.
   * Andrew Westcott <ajwestco@users.sourceforge.net>
   * Michal Molhanec <michal@molhanec.net>
   *
   * Offered for use in the public domain without any warranty.
   *
   */
  
  #include <stdio.h>
  #include <stdlib.h>
  //#include <unistd.h>
  #include <windows.h>
  #include <string.h>
  #include "conio2.h"
  
  #ifdef __cplusplus
  extern "C" {
  #endif
  
  static int __BACKGROUND = BLACK;
  static int __FOREGROUND = LIGHTGRAY;
  static struct text_info __text_info = {
      1, 1,
      LIGHTGRAY + (BLACK << 4),
      LIGHTGRAY + (BLACK << 4),
      80, 25
  };
  static int __CONIO_TOP = 0;
  static int __CONIO_LEFT = 0;
  
  static void
  __fill_text_info (void)
  {
      CONSOLE_SCREEN_BUFFER_INFO info;
  
      GetConsoleScreenBufferInfo(GetStdHandle(STD_OUTPUT_HANDLE), &info);
      __CONIO_LEFT = info.srWindow.Left;
      __CONIO_TOP = info.srWindow.Top;
      __text_info.curx = info.dwCursorPosition.X - __CONIO_LEFT + 1;
      __text_info.cury = info.dwCursorPosition.Y - __CONIO_TOP  + 1;
      __text_info.attribute = info.wAttributes;
      __text_info.screenwidth  = info.srWindow.Right - info.srWindow.Left + 1;
      __text_info.screenheight = info.srWindow.Bottom - info.srWindow.Top + 1;
  }
  
  void
  gettextinfo (struct text_info * info)
  {
      __fill_text_info();
      *info = __text_info;
  }
  
  void
  inittextinfo (void)
  {
      CONSOLE_SCREEN_BUFFER_INFO info;
  
      GetConsoleScreenBufferInfo (GetStdHandle(STD_OUTPUT_HANDLE), &info);
      __text_info.normattr = info.wAttributes;
  }
  
  void
  clrscr (void)
  {
      DWORD written;
      int i;
  
      __fill_text_info();
      for (i = __CONIO_TOP; i < __CONIO_TOP + __text_info.screenheight; i++) {
        FillConsoleOutputAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
          __FOREGROUND + (__BACKGROUND << 4), __text_info.screenwidth,
          (COORD) {__CONIO_LEFT, i},
          &written);
        FillConsoleOutputCharacter (GetStdHandle(STD_OUTPUT_HANDLE), ' ',
          __text_info.screenwidth,
          (COORD) {__CONIO_LEFT, i},
          &written);
      }
      gotoxy (1, 1);
  }
  
  
  void
  clreol (void)
  {
      COORD coord;
      DWORD written;
  
      __fill_text_info();
      coord.X = __CONIO_LEFT + __text_info.curx - 1;
      coord.Y = __CONIO_TOP  + __text_info.cury - 1;
  
      FillConsoleOutputAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
        __FOREGROUND + (__BACKGROUND << 4),
        __text_info.screenwidth - __text_info.curx + 1, coord, &written);
      FillConsoleOutputCharacter (GetStdHandle (STD_OUTPUT_HANDLE),
        ' ', __text_info.screenwidth - __text_info.curx + 1, coord, &written);
      gotoxy (__text_info.curx, __text_info.cury);
  }
  
  
  void
  delline (void)
  {
      COORD coord;
      SMALL_RECT rect;
      CHAR_INFO fillchar;
  
      __fill_text_info();
      coord.X = __CONIO_LEFT;
      coord.Y = __CONIO_TOP + __text_info.cury - 1;
      rect.Left = __CONIO_LEFT;
      rect.Top = __CONIO_TOP + __text_info.cury;
      rect.Right = __CONIO_LEFT + __text_info.screenwidth - 1;
      rect.Bottom = __CONIO_TOP + __text_info.screenheight - 1;
      fillchar.Attributes = __FOREGROUND + (__BACKGROUND << 4);
  #ifdef UNICODE
      fillchar.Char.UnicodeChar = L' ';
      ScrollConsoleScreenBufferW (GetStdHandle (STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
  #else
      fillchar.Char.AsciiChar = ' ';
      ScrollConsoleScreenBufferA (GetStdHandle (STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
  #endif
  
  
      gotoxy (__text_info.curx, __text_info.cury);
  }
  
  void
  insline (void)
  {
      COORD coord;
      SMALL_RECT rect;
      CHAR_INFO fillchar;
  
      __fill_text_info();
      coord.X = __CONIO_LEFT;
      coord.Y = __CONIO_TOP + __text_info.cury;
      rect.Left = __CONIO_LEFT;
      rect.Top = __CONIO_TOP + __text_info.cury - 1;
      rect.Right = __CONIO_LEFT + __text_info.screenwidth - 1;
      rect.Bottom = __CONIO_TOP + __text_info.screenheight - 2;
      fillchar.Attributes = __FOREGROUND + (__BACKGROUND << 4);
  #ifdef UNICODE
      fillchar.Char.UnicodeChar = L' ';
      ScrollConsoleScreenBufferW (GetStdHandle (STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
  #else
      fillchar.Char.AsciiChar = ' ';
      ScrollConsoleScreenBufferA (GetStdHandle (STD_OUTPUT_HANDLE),
        &rect, NULL, coord, &fillchar);
  #endif
  
      gotoxy (__text_info.curx, __text_info.cury);
  }
  
  void
  movetext (int left, int top, int right, int bottom, int destleft, int desttop)
  {
      struct char_info * buffer;
  
      buffer = malloc ((right - left + 1) * (bottom - top + 1) * sizeof(struct char_info));
      gettext (left, top, right, bottom, buffer);
      puttext (destleft, desttop, destleft + right - left, desttop + bottom - top, buffer);
      free(buffer);
  }
  
  void
  _conio_gettext (int left, int top, int right, int bottom,
    struct char_info * buf)
  {
      int i;
      SMALL_RECT r;
      CHAR_INFO* buffer;
      COORD size;
  
      __fill_text_info();
      r = (SMALL_RECT) {__CONIO_LEFT + left - 1, __CONIO_TOP + top - 1,
        __CONIO_LEFT + right - 1, __CONIO_TOP + bottom - 1};
      size.X = right - left + 1;
      size.Y = bottom - top + 1;
      buffer = malloc (size.X * size.Y * sizeof(CHAR_INFO));
  
      ReadConsoleOutput (GetStdHandle (STD_OUTPUT_HANDLE),
        (PCHAR_INFO) buffer, size, (COORD) {0, 0}, &r);
  
      for (i = 0; i < size.X * size.Y; i++)
      {
  #ifdef UNICODE
          buf[i].letter = buffer[i].Char.UnicodeChar;
  #else
          buf[i].letter = buffer[i].Char.AsciiChar;
  #endif
          buf[i].attr = buffer[i].Attributes;
      }
      free (buffer);
  }
  
  void
  puttext (int left, int top, int right, int bottom, struct char_info * buf)
  {
      int i;
      SMALL_RECT r;
      CHAR_INFO* buffer;
      COORD size;
  
      __fill_text_info();
      r = (SMALL_RECT) {__CONIO_LEFT + left - 1, __CONIO_TOP + top - 1,
        __CONIO_LEFT + right - 1, __CONIO_TOP + bottom - 1};
      size.X = right - left + 1;
      size.Y = bottom - top + 1;
      buffer = malloc (size.X * size.Y * sizeof(CHAR_INFO));
  
      for (i = 0; i < size.X * size.Y; i++)
      {
  #ifdef UNICODE
          buffer[i].Char.UnicodeChar = buf[i].letter;
  #else
          buffer[i].Char.AsciiChar = buf[i].letter;
  #endif
          buffer[i].Attributes = buf[i].attr;
      }
  
      WriteConsoleOutput (GetStdHandle (STD_OUTPUT_HANDLE),
        buffer, size, (COORD) {0, 0}, &r);
      free (buffer);
  }
  
  void
  gotoxy(int x, int y)
  {
    COORD c;
  
    c.X = __CONIO_LEFT + x - 1;
    c.Y = __CONIO_TOP  + y - 1;
    SetConsoleCursorPosition (GetStdHandle(STD_OUTPUT_HANDLE), c);
  }
  
  void
  cputsxy (int x, int y, char * str)
  {
      gotoxy (x, y);
      cputs (str);
  }
  
  void
  putchxy (int x, int y, char ch)
  {
      gotoxy (x, y);
      putch (ch);
  }
  
  void
  _setcursortype (int type)
  {
      CONSOLE_CURSOR_INFO Info;
  
      if (type == 0) {
          Info.bVisible = FALSE;
      } else {
        Info.dwSize = type;
        Info.bVisible = TRUE;
      }
      SetConsoleCursorInfo (GetStdHandle (STD_OUTPUT_HANDLE),
        &Info);
  }
  
  
  void
  textattr (int _attr)
  {
      __FOREGROUND = _attr & 0xF;
      __BACKGROUND = _attr >> 4;
      SetConsoleTextAttribute (GetStdHandle(STD_OUTPUT_HANDLE), _attr);
  }
  
  void
  normvideo (void)
  {
      textattr (__text_info.normattr);
  }
  
  void
  textbackground (int color)
  {
      __BACKGROUND = color;
      SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
        __FOREGROUND + (color << 4));
  }
  
  
  void
  textcolor (int color)
  {
      __FOREGROUND = color;
      SetConsoleTextAttribute (GetStdHandle (STD_OUTPUT_HANDLE),
        color + (__BACKGROUND << 4));
  }
  
  
  int
  wherex (void)
  {
      __fill_text_info();
      return __text_info.curx;
  }
  
  
  int
  wherey (void)
  {
      __fill_text_info();
      return __text_info.cury;
  }
  
  char *
  getpass (const char * prompt, char * str)
  {
      int maxlength = str[0];
      int length = 0;
      int ch = 0;
      int x, y;
  
      cputs(prompt);
      __fill_text_info();
      x = __text_info.curx;
      y = __text_info.cury;
  
      while (ch != '\r') {
          ch = getch();
          switch (ch) {
              case '\r' : /* enter */
                  break;
              case '\b' : /* backspace */
                  if (length > 0) putchxy (x + --length, y, ' ');
                  gotoxy (x + length, y);
                  break;
              default:
                  if (length < maxlength) {
                      putchxy (x + length, y, '*');
                      str[2 + length++] = ch;
                  }
          }
      }
  
      str[1] = length;
      str[2 + length] = '\0';
      return &str[2];
  }
  
  void
  highvideo (void)
  {
      if (__FOREGROUND < DARKGRAY) textcolor(__FOREGROUND + 8);
  }
  
  void
  lowvideo (void)
  {
      if (__FOREGROUND > LIGHTGRAY) textcolor(__FOREGROUND - 8);
  }
  
  void
  delay (int ms)
  {
      Sleep(ms);
  }
  
  void
  switchbackground (int color)
  {
      struct char_info* buffer;
      int i;
  
      buffer = malloc(__text_info.screenwidth * __text_info.screenheight *
        sizeof(struct char_info));
      _conio_gettext(1, 1, __text_info.screenwidth, __text_info.screenheight,
        buffer);
      for (i = 0; i < __text_info.screenwidth * __text_info.screenheight; i++) {
          unsigned short attr = buffer[i].attr & 0xF;
          buffer[i].attr = (color << 4) | attr;
      }
      puttext(1, 1, __text_info.screenwidth, __text_info.screenheight, buffer);
      free(buffer);
  }
  
  void
  flashbackground (int color, int ms)
  {
      struct char_info* buffer;
  
      buffer = malloc(__text_info.screenwidth * __text_info.screenheight *
        sizeof(struct char_info));
      _conio_gettext(1, 1, __text_info.screenwidth, __text_info.screenheight,
        buffer);
      switchbackground(color);
      delay(ms);
      puttext(1, 1, __text_info.screenwidth, __text_info.screenheight, buffer);
      free(buffer);
  }
  
  void
  clearkeybuf (void)
  {
      while (kbhit()) {
          getch();
      }
  }
  
  #ifdef __cplusplus
  }
  #endif
  