aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorJohn Ankarström <john@ankarstrom.se>2022-07-23 18:59:37 +0200
committerJohn Ankarström <john@ankarstrom.se>2022-07-23 18:59:37 +0200
commitc6cd2f1f164baac1414f2cf658566de146b10552 (patch)
treecec573bbddacd175f37d8d45e48e8cea80727420
parent2958c57db73b5af03af36598c9dffc9123a0a003 (diff)
downloadEpisodeBrowser-c6cd2f1f164baac1414f2cf658566de146b10552.tar.gz
Fix display of Unicode text.
Turns out that SWI-Prolog's wide string functions, which I started using in 03fe361, do not convert between narrow Prolog atoms and wide C strings, as I mistakenly thought. Instead, they work with wide Prolog atoms. In hindsight, it is not surprising.
-rw-r--r--README9
-rw-r--r--c/common.cpp18
-rw-r--r--c/common.h1
-rw-r--r--c/datalistview.cpp10
-rw-r--r--c/episodelistview.cpp9
-rw-r--r--c/pl.h25
6 files changed, 52 insertions, 20 deletions
diff --git a/README b/README
index ebe22ef..c8b3f5c 100644
--- a/README
+++ b/README
@@ -69,12 +69,13 @@ Following is a summary of some coding conventions used in the project.
- w = WORD, WPARAM
- dw = DWORD
- lvi = LVITEM
- - sz = unmangaged, zero-terminated string (char *)
- - wsz = ... wide string (wchar_t *)
- - tsz = ... tstring (TCHAR *)
- - str = ... managed string (std::string)
+ - sz = unmanaged, zero-terminated narrow string (char*)
+ - wsz = ... wide string (wchar_t*)
+ - tsz = ... tstring (TCHAR*)
+ - str = managed narrow string (std::string)
- wstr = ... (std::wstring)
- tstr = ... (std::basic_string<TCHAR>)
+ - bstr = ... (std::basic_string<T> of any type T)
The list above is non-exhaustive. Variables whose type is unknown (in
templates) do not need prefixes. Some very common self-explanatory
diff --git a/c/common.cpp b/c/common.cpp
index 4ce95a0..155c099 100644
--- a/c/common.cpp
+++ b/c/common.cpp
@@ -57,6 +57,24 @@ Library::~Library()
FreeLibrary(m_hModule);
}
+/* Convert narrow unmanaged string to narrow/wide basic string. */
+template <>
+std::basic_string<char> BstrFromSz(const char* sz, int)
+{
+ return std::string(sz);
+}
+
+template <>
+std::basic_string<wchar_t> BstrFromSz(const char* sz, int iCp)
+{
+ int cbMultiByte = strlen(sz)+1;
+ int cchWideChar = MultiByteToWideChar(iCp, 0, sz, cbMultiByte, NULL, 0);
+ std::wstring wstr(cchWideChar, 0);
+ if (!MultiByteToWideChar(iCp, 0, sz, cbMultiByte, wstr.data(), cchWideChar))
+ throw Win32Error(GetLastError());
+ return wstr;
+}
+
/* Move message box to center of main window. */
static LRESULT CALLBACK CBTProc(const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept
{
diff --git a/c/common.h b/c/common.h
index 5fe6d62..fb21e6f 100644
--- a/c/common.h
+++ b/c/common.h
@@ -11,6 +11,7 @@
#define WA "A"
#endif
+template <typename T> std::basic_string<T> BstrFromSz(const char* sz, int iCp = CP_UTF8);
int EBMessageBox(const TCHAR* tszText, const TCHAR* tszCaption, unsigned uType);
struct Win32Error : public std::exception
diff --git a/c/datalistview.cpp b/c/datalistview.cpp
index b728fa8..1ceeb3b 100644
--- a/c/datalistview.cpp
+++ b/c/datalistview.cpp
@@ -57,21 +57,21 @@ void DataListView::ShowEpisode(const int iEpisode)
PL_predicate("episode_datum", 3, "episode_data"), t);
for (int i = 0; PL_next_solution(q); i++) {
- TCHAR* tszKey;
- TCHAR* tszValue;
+ std::basic_string<TCHAR> tstrKey;
+ std::basic_string<TCHAR> tstrValue;
- if (!(PlGet(t+1, &tszKey) && PlGet(t+2, &tszValue)))
+ if (!(PlGet(t+1, &tstrKey) && PlGet(t+2, &tstrValue)))
continue;
lviKey.mask = LVIF_TEXT;
lviKey.iItem = i;
lviKey.iSubItem = 0;
- lviKey.pszText = tszKey;
+ lviKey.pszText = tstrKey.data();
ListView_InsertItem(hWnd, &lviKey);
lviValue.iItem = i;
lviValue.iSubItem = 1;
- lviValue.pszText = tszValue;
+ lviValue.pszText = tstrValue.data();
ListView_SetItem(hWnd, &lviValue);
}
diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp
index cdb3dc7..bc01ce9 100644
--- a/c/episodelistview.cpp
+++ b/c/episodelistview.cpp
@@ -414,17 +414,16 @@ void EpisodeListView::Update()
/* Update episode name and rating. */
void EpisodeListView::UpdateItem(const LVITEM* const pLvi)
{
- Mark m;
- TCHAR* tszName;
+ std::basic_string<TCHAR> tstrName;
int iRating;
static TCHAR tszRating[3];
- if (!Pl("episode_data","episode_title",pLvi->lParam,&tszName)) {
+ if (!Pl("episode_data","episode_title",pLvi->lParam,&tstrName)) {
if (!Pl("episode_data","update_episode_data")) goto r;
- if (!Pl("episode_data","episode_title",pLvi->lParam,&tszName))
+ if (!Pl("episode_data","episode_title",pLvi->lParam,&tstrName))
goto r;
}
- ListView_SetItemText(hWnd, pLvi->iItem, ELVSITITLE, tszName);
+ ListView_SetItemText(hWnd, pLvi->iItem, ELVSITITLE, tstrName.data());
r: if (!Pl("episode_data","episode_rating",pLvi->lParam,&iRating)) {
ListView_SetItemText(hWnd, pLvi->iItem, ELVSIRATING, (TCHAR*)TEXT(""));
diff --git a/c/pl.h b/c/pl.h
index 8325c86..44b8a5e 100644
--- a/c/pl.h
+++ b/c/pl.h
@@ -1,9 +1,12 @@
#ifndef PL_H
#define PL_H
+#include <string>
#include <windows.h>
#include <SWI-Prolog.h>
+#include "common.h"
+
int PL_get_tchars(term_t t, TCHAR** pTsz, int iFlags);
struct Frame
@@ -43,14 +46,13 @@ inline int PlPut(term_t t, long long x) { return PL_put_int64(t, x); }
inline int PlPut(term_t t, atom_t x) { return PL_put_atom(t, x); }
inline int PlPut(term_t t, char* x) { return PL_put_atom_chars(t, x); }
inline int PlPut(term_t t, const char* x) { return PL_put_atom_chars(t, x); }
-inline int PlPut(term_t t, wchar_t* x) { return PL_unify_wchars(t, PL_ATOM, -1, x); }
-inline int PlPut(term_t t, const wchar_t* x) { return PL_unify_wchars(t, PL_ATOM, -1, x); }
inline int PlPut(term_t, int*) { return -1; }
inline int PlPut(term_t, long*) { return -1; }
inline int PlPut(term_t, long long*) { return -1; }
inline int PlPut(term_t, atom_t*) { return -1; }
inline int PlPut(term_t, char**) { return -1; }
-inline int PlPut(term_t, wchar_t**) { return -1; }
+inline int PlPut(term_t, std::string*) { return -1; }
+inline int PlPut(term_t, std::wstring*) { return -1; }
inline int PlGet(term_t, int) { return -1; }
inline int PlGet(term_t, long) { return -1; }
@@ -58,14 +60,25 @@ inline int PlGet(term_t, long long) { return -1; }
inline int PlGet(term_t, atom_t) { return -1; }
inline int PlGet(term_t, char*) { return -1; }
inline int PlGet(term_t, const char*) { return -1; }
-inline int PlGet(term_t, wchar_t*) { return -1; }
-inline int PlGet(term_t, const wchar_t*) { return -1; }
inline int PlGet(term_t t, int* x) { return PL_get_integer(t, x); }
inline int PlGet(term_t t, long* x) { return PL_get_long(t, x); }
inline int PlGet(term_t t, long long* x) { return PL_get_int64(t, x); }
inline int PlGet(term_t t, atom_t* x) { return PL_get_atom(t, x); }
inline int PlGet(term_t t, char** x) { return PL_get_atom_chars(t, x); }
-inline int PlGet(term_t t, wchar_t** x) { size_t len; return PL_get_wchars(t, &len, x, CVT_ATOM); }
+inline int PlGet(term_t t, std::string* x) {
+ Mark m;
+ char* sz;
+ if (!PlGet(t, &sz)) return 0;
+ *x = sz;
+ return 1;
+}
+inline int PlGet(term_t t, std::wstring* x) {
+ Mark m;
+ char* sz;
+ if (!PlGet(t, &sz)) return 0;
+ *x = BstrFromSz<wchar_t>(sz);
+ return 1; /* or catch potential exception from BstrFromSz? */
+}
/* Put in or get from a term reference an arbitrary number of values,
* returning false if any value could not be put/got. */