/** Editor ED - Modul UT: Utensilien **/

#include "top.h"
#include <windows.h>
#include <tchar.h>
#include <stdarg.h>

#define SWAPLONG(l) (((l) >> 16) | ((l) & 0x00FF00) | (((l) & 0x0000FF) << 16))

/** Function: Erweiterte MessageBox-Funktion **/
int ut_messageBoxExt(HWND hWnd, const TCHAR *msg, const TCHAR *title, unsigned type, ...)
  {
  va_list varg;
  TCHAR s[256];
  va_start(varg, type); // Muss auf letztes Fixarg zeigen
  wvsprintf(s, msg, varg);
  va_end(varg); // LCC-Warn. ignorieren
  s[sizeof s / sizeof(TCHAR) - 1] = TEXT('\0');
  return MessageBox(hWnd, s, title, type);
  }

/** Function: Kopiere Text aus EDIT-Control in Puffer **/
TCHAR *ut_getEditText(HWND hWinEdit, int *len)
  {
  int bufLen;
  TCHAR *buf;
  if (len)
    *len = 0;
  if ((bufLen=GetWindowTextLength(hWinEdit)) == 0)
    return NULL;
  if ((buf=(TCHAR*)GlobalAlloc(GMEM_FIXED, (bufLen+1)*sizeof(TCHAR))) == NULL)
    return NULL; // Leider muss erst _gesamter_ Text kopiert werden, um Markierung zu erhalten
  GetWindowText(hWinEdit, buf, bufLen+1); // Selbst wenn Text aus Datei mit SetWindowTextA() auf
  if (len) // ANSI fixiert eingelesen wurde, befuellt GetWindowText() unter UNICODE (GetWindowTextW)
    *len = bufLen; // Puffer mit Unicode-Text - daher funktionieren Suchroutinen!
  return buf;
  }

/** Function: Kopiere markierten Text aus EDIT-Control in Puffer **/
TCHAR *ut_getEditSel(HWND hWinEdit, int *len)
  {
  int sos, eos, selLen;
  TCHAR *buf, *sel;
  if (len)
    *len = 0;
  SendMessage(hWinEdit, EM_GETSEL, (WPARAM)&sos, (LPARAM)&eos);
  if ((selLen=eos-sos) == 0)
    return NULL;
  if ((buf=ut_getEditText(hWinEdit, NULL)) == NULL)
    return NULL;
  if ((sel=(TCHAR*)GlobalAlloc(GMEM_FIXED, (selLen+1)*sizeof(TCHAR))) == NULL) {
    GlobalFree(buf); return NULL; }
  lstrcpyn(sel, buf+sos, selLen+1); // Unterschied zu strncpy: lstrcpyn kopiert nur n Zeichen,
  GlobalFree(buf); // wenn n+1 angegeben, um Null mitanzuhaengen!
  if (len)
    *len = selLen;
  return sel;
  }

/** Function: Wandele Zahl in Zeichenkette **/
TCHAR *ut_uLong2Str(unsigned long l, unsigned int radix)
  {
  static TCHAR s[13]; // Muss 13 sein, da printf Zahlen nicht trunkieren kann (Strings schon)!
  s[0] = 0;
  if (radix == 16)
    wsprintf(s, TEXT("%06lX"), l); // _ultot(l,s,16) erlaubt leider keine Formatbreite
  else if (radix == 10)
    wsprintf(s, TEXT("%ld"), l);
  return s;
  }

#ifdef BUILD_UC

/** Function: Wandele BGR-Zahl in RGB-Zeichenkette **/
TCHAR *ut_revRGBStr(unsigned long l)
  {
  return ut_uLong2Str(SWAPLONG(l),16); // BGR -> RGB
  }

/** Function: Wandele RGB-Zeichenkette in BGR-Zahl **/
unsigned long ut_revRGBVal(TCHAR *s)
  {
  unsigned long l = _tcstoul(s, NULL, 16); // Es gibt kein lstrtoul() in Windows
  return SWAPLONG(l); // RGB -> BGR
  }

#endif

/** Function: Ermittele Kommandozeilenargumente **/
BOOL ut_getArg(TCHAR s[], TCHAR arg[])
  {
  static TCHAR *psave;
  TCHAR stop, *p;

  /* Initialisiere */
  if (!arg) {
    if (!s)
      return FALSE;
    psave = s;
    return FALSE;
    }
  if (!psave) // Von nun an MUSS psave ein gueltiger Zeiger sein!
    return FALSE;
  /* Fahre an letzter Suchposition fort */
  *arg = TEXT('\0');
  p = psave;
  /* Ueberspringe fuehrende Leerzeichen */
  while (*p == TEXT(' '))
    ++p;
  if (!*p) {
    psave = NULL; return FALSE; }
  /* Ermittele Endezeichen */
  if (*p == TEXT('"')) {
    stop = TEXT('"'); ++p; }
  else
    stop = TEXT(' ');
  /* Merke Wortbeginn */
  psave = p;
  /* Laufe bis Endezeichen */
  do ++p; while (*p && *p != stop);
  /* Kopiere Zeichenkette */
  lstrcpyn(arg, psave, (int)(p-psave+1)); // Anders als strncpy kopiert lstrcpyn nur n Zeichen,
  if (!*p) // wenn n+1 angegeben, um 0 mitanzuhaengen!
    psave = p;
  else
    psave = p + 1;
  return TRUE;
  }

/** Function: Ergibt TRUE, wenn path als Ordner existiert **/
BOOL ut_dirExists(const TCHAR path[])
  {
  DWORD h;
  if (!path || path[0] == '\0')
    return FALSE;
  h = GetFileAttributes(path);
  if (h == 0xFFFFFFFF)
    return FALSE;
  return (BOOL) (h & FILE_ATTRIBUTE_DIRECTORY);
  }

/** Function: Ergibt TRUE, wenn path als Datei existiert **/
BOOL ut_fileExists(const TCHAR path[])
  {
  DWORD h;
  if (!path || path[0] == '\0')
    return FALSE;
  h = GetFileAttributes(path);
  if (h == 0xFFFFFFFF)
    return FALSE;
  return (BOOL) !(h & FILE_ATTRIBUTE_DIRECTORY);
  /* Oder:
  WIN32_FIND_DATA data;
  HANDLE handle = FindFirstFile(dirName,&data);
  if (handle != INVALID_HANDLE_VALUE) {
    FindClose(handle);
    return true;
    }
  return false;
  */
  }

#ifdef BUILD_FR

/** Function: Suche Zeichenkette in Zeichenkette ohne Beachtung von Gross- und Kleinschreibung **/
static TCHAR *_ut_strstri(const TCHAR *str, const TCHAR *pat)
  {
  // Rev. History:
  // 02/03/94 Fred Cole: Original
  // 07/04/95 Bob Stout: ANSI-fy
  // 16/07/97 Greg Thayer: Optimized
  // 09/01/03 Bob Stout: Bug fix (lines 40-41) per Fred Bulback
  // 12/09/08 As Dala: Modified

  // CharLower() wandelt sowohl Zeichenketten als auch Zeichen um; da aber Funktion als
  // LPTSTR CharLower(LPTSTR lpsz) deklariert ist, muessen wir Funktionsergebnis fuer Zeichen in
  // TCHAR* umwandeln, damit Kompiler Ruhe gibt. Wenn wir nur CharLower-Ergebnisse vergleichen,
  // kann allerdings Umwandlung des Funktionsergebnisses entfallen. Ausserdem muessen wir
  // Suchzeichen in WORD umwandeln, damit keine neg. Vorzeichenerw. passiert ('ü' -> int -4).
  // Ignoriere LCC-Warnungen: CharLower gibt 32bit zurück, falls Parameter ein Zeichen war.
  TCHAR *s0, *s, p0, *p;

  /* Init */
  s0 = (TCHAR *) str;
  p0 = (TCHAR) CharLower((TCHAR*)(WORD)(*pat)); // Ignoriere Warn.
  while (*s0) {

    /* pat[0] in str enthalten? */
    while ((TCHAR) CharLower((TCHAR*)(WORD)*s0) != p0) // Ignoriere Warn.
      if (!*++s0)
        return NULL;

    s = s0;
    p = (TCHAR *) pat;

    /* Ja. pat[1..n] in str enthalten? */
    do {
      ++s;
      ++p;
      if (!*p) // Falls  Ende des Suchmusters erreicht, ist Fund bestaetigt
        return (TCHAR *) s0;
      } while (CharLower((TCHAR*)(WORD)*s) == CharLower((TCHAR*)(WORD)*p));

    s0++;
    }
  return NULL;
  }

/** Function: Suche Zeichenkette in Zeichenkette **/
TCHAR *ut_strstr(const TCHAR *str, const TCHAR *pat, BOOL matchCase, BOOL wholeWord)
  {
  TCHAR *h = (TCHAR*)str;
  UINT patlen = lstrlen(pat);
  if (str == NULL || pat == NULL)
    return NULL;
  while ((h = matchCase ? _tcsstr(h,pat) : _ut_strstri(h,pat)) != NULL) {
    if (!wholeWord || ((h==str || !IsCharAlpha(*(h-1))) && !IsCharAlpha(*(h+patlen))))
      break;
    ++h;
    }
  return h;
  }


#endif