From 04daecdd21e86e7556a9462380096530228cd6ca Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?John=20Ankarstr=C3=B6m?= Date: Wed, 3 Aug 2022 21:57:27 +0200 Subject: Split common.h to util.h, wcharptr.h and win.h. --- c/common.cpp | 166 -------------------------------------------------- c/common.h | 146 -------------------------------------------- c/datalistview.cpp | 1 - c/debug.cpp | 3 +- c/episodelistview.cpp | 3 +- c/layout.cpp | 2 +- c/layout.h | 2 +- c/listview.cpp | 2 +- c/main.cpp | 2 +- c/pl.h | 2 +- c/util.h | 19 ++++++ c/wcharptr.cpp | 64 +++++++++++++++++++ c/wcharptr.h | 33 ++++++++++ c/win.cpp | 108 ++++++++++++++++++++++++++++++++ c/win.h | 105 +++++++++++++++++++++++++++++++ 15 files changed, 338 insertions(+), 320 deletions(-) delete mode 100644 c/common.cpp delete mode 100644 c/common.h create mode 100644 c/util.h create mode 100644 c/wcharptr.cpp create mode 100644 c/wcharptr.h create mode 100644 c/win.cpp create mode 100644 c/win.h diff --git a/c/common.cpp b/c/common.cpp deleted file mode 100644 index 0a54f69..0000000 --- a/c/common.cpp +++ /dev/null @@ -1,166 +0,0 @@ -#include -#include - -#include "common.h" - -wchar_ptr::wchar_ptr() noexcept {} - -wchar_ptr::wchar_ptr(wchar_t* const s) noexcept : m_p(s) {} - -wchar_ptr& wchar_ptr::operator=(wchar_t* const s) noexcept -{ - if (m_p != s) { - delete m_p; - m_p = s; - } - return *this; -} - -wchar_ptr::wchar_ptr(wchar_ptr&& other) noexcept : m_p(std::exchange(other.m_p, nullptr)) {} - -wchar_ptr& wchar_ptr::operator=(wchar_ptr&& other) noexcept -{ - std::swap(m_p, other.m_p); - return *this; -} - -wchar_ptr::operator wchar_t*() noexcept -{ - return m_p; -} - -wchar_t* wchar_ptr::release() noexcept -{ - wchar_t* p2 = m_p; - m_p = nullptr; - return p2; -} - -wchar_ptr::~wchar_ptr() noexcept -{ - delete m_p; -} - -wchar_ptr wchar_ptr::from_narrow(const char* const src, const int cp) -{ - int cbMultiByte = strlen(src)+1; - int cchWideChar = MultiByteToWideChar(cp, 0, src, cbMultiByte, NULL, 0); - wchar_t* dst = new wchar_t[cchWideChar]; - if (!MultiByteToWideChar(cp, 0, src, cbMultiByte, dst, cchWideChar)) { - delete dst; - throw Win32Error(); - } - return dst; -} - -wchar_ptr wchar_ptr::copy(const wchar_t* const src) -{ - const int cb = wcslen(src)+1; - wchar_t* dst = new wchar_t[cb]; - memcpy(dst, src, cb*sizeof(wchar_t)); - return dst; -} - -Win32Error::Win32Error() : code(GetLastError()) {} -Win32Error::Win32Error(const DWORD code) : code(code) {} - -Win32Error::~Win32Error() -{ - if (m_szMsg) - HeapFree(GetProcessHeap(), 0, m_szMsg); - if (m_wszMsg) - HeapFree(GetProcessHeap(), 0, m_wszMsg); -} - -const char* Win32Error::what() const noexcept -{ - if (!m_szMsg) - FormatMessageA( - FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - code, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - (char*)&m_szMsg, - 0, NULL); - return m_szMsg; -} - -const wchar_t* Win32Error::What() const noexcept -{ - if (!m_wszMsg) - FormatMessage( - FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, - NULL, - code, - MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), - (wchar_t*)&m_wszMsg, - 0, NULL); - return m_wszMsg; -} - -std::optional Library::Maybe(const wchar_t* const lib) -{ - HMODULE hModule = LoadLibrary(lib); - if (!hModule) return {}; - return Library(hModule); -} - -Library::Library(const HMODULE hModule) : m_hModule(hModule) {} - -Library::Library(const wchar_t* const lib) -{ - m_hModule = LoadLibrary(lib); - if (!m_hModule) - throw Win32Error(); -} - -Library::~Library() -{ - FreeLibrary(m_hModule); -} - -int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const unsigned uType) -{ - extern HWND g_hWnd; - - auto proc = [](const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept - -> LRESULT CALLBACK - { - if (!g_hWnd || nCode < 0 || nCode != HCBT_ACTIVATE) - return CallNextHookEx(0, nCode, wParam, lParam); - - HWND hWnd = (HWND)wParam; - long lStyle = GetWindowLong(hWnd, GWL_STYLE); - if (!(lStyle & WS_POPUP)) return 0; - - RECT rcMain, rcMsg; - GetWindowRect(g_hWnd, &rcMain); - GetWindowRect(hWnd, &rcMsg); - SetWindowPos(hWnd, NULL, - rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2, - rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2, - -1, -1, - SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); - - return 0; - }; - - HHOOK hHook = require(SetWindowsHookEx(WH_CBT, proc, (HINSTANCE)NULL, GetCurrentThreadId())); - int r = MessageBox(g_hWnd, wszText, wszCaption, uType); - require(UnhookWindowsHookEx(hHook)); - return r; -} - -int GetRelativeCursorPos(HWND hWnd, POINT* pt) -{ - RECT rc; - if (!GetClientRect(hWnd, &rc)) return 0; - SetLastError(ERROR_SUCCESS); - if (!MapWindowPoints(hWnd, NULL, (POINT*)&rc, 2)) return 0; - - POINT ptMouse; - if (!GetCursorPos(&ptMouse)) return 0; - pt->x = ptMouse.x-rc.left; - pt->y = ptMouse.y-rc.top; - return 1; -} diff --git a/c/common.h b/c/common.h deleted file mode 100644 index 70c2c32..0000000 --- a/c/common.h +++ /dev/null @@ -1,146 +0,0 @@ -#ifndef COMMON_H -#define COMMON_H - -#include -#include -#include - -int EBMessageBox(const wchar_t* wszText, const wchar_t* wszCaption, unsigned uType); -int GetRelativeCursorPos(HWND hWnd, POINT* pt); - -/* wchar_ptr: Simple wrapper for wide C strings. */ -struct wchar_ptr -{ - /* Named copy constructors (expensive). */ - static wchar_ptr from_narrow(const char* buf, int cp = CP_UTF8); - static wchar_ptr copy(const wchar_t* s); - - /* Non-explicit copies are disabled. */ - wchar_ptr(wchar_ptr& other) = delete; - wchar_ptr& operator=(wchar_ptr& other) = delete; - - wchar_ptr() noexcept; - ~wchar_ptr(); - operator wchar_t*() noexcept; - - wchar_ptr(wchar_t* s) noexcept; - wchar_ptr& operator=(wchar_t* s) noexcept; - - wchar_ptr(wchar_ptr&& other) noexcept; - wchar_ptr& operator=(wchar_ptr&& other) noexcept; - - /* Return pointer, releasing ownership. */ - wchar_t *release() noexcept; -private: - wchar_t* m_p = nullptr; -}; - -/* Win32Error: Exception for Windows API errors. */ -struct Win32Error : public std::exception -{ - Win32Error(); - Win32Error(DWORD code); - ~Win32Error(); - const char* what() const noexcept override; - const wchar_t* What() const noexcept; - DWORD code; -private: - char* m_szMsg = NULL; - wchar_t* m_wszMsg = NULL; -}; - -/* Library: Wrapper for loading and freeing dynamically linked libraries. */ -struct Library -{ - static std::optional Maybe(const wchar_t* lib); - Library(const wchar_t* lib); - ~Library(); - template T* GetProcAddress(const char* szProc); -private: - Library(HMODULE hModule); - HMODULE m_hModule; -}; - -template -T* Library::GetProcAddress(const char* const szProc) -{ - return (T*)(void*)::GetProcAddress(m_hModule, szProc); -} - -template -inline int Swprintf(wchar_t (&buf)[N], const wchar_t* const fmt, T... xs) -{ - return _snwprintf_s(buf, N, _TRUNCATE, fmt, xs...); -} - -/* Variable template for caching values from GetSystemMetrics. */ -template -auto Metric = GetSystemMetrics(I); - -/* Check result of Windows API call, throwing error on NULL. */ -template -inline T require(const T x) -{ - if (!x) throw Win32Error(); - return x; -} - -/* Check result of Windows API call, showing a warning on NULL. */ -template -inline T prefer(const T x) -{ - if (!x) { - EBMessageBox(Win32Error().What(), L"System Error", MB_ICONWARNING); - return (T)NULL; - } - return x; -} - -/* Return integer scaled for current DPI. */ -inline int Dpi(const int i) -{ - extern int g_dpi; - return MulDiv(i, g_dpi, 96); -} - -inline int Cmp(const int a, const int b) -{ - if (a == b) return 0; - if (a > b) return 1; - return -1; -} - -/* Get window rectangle relative to parent. */ -inline BOOL GetRelativeRect(const HWND hWnd, RECT* const rr) -{ - if (!GetClientRect(hWnd, rr)) return 0; - return MapWindowPoints(hWnd, GetParent(hWnd), (POINT*)rr, 2); -} - -inline BOOL SetWindowRect(const HWND hWnd, - const long left, const long top, const long right, const long bottom) -{ - return MoveWindow(hWnd, - left, top, - right-left, bottom-top, - TRUE); -} - -inline BOOL SetWindowRect(const HWND hWnd, const RECT r) -{ - return SetWindowRect(hWnd, r.left, r.top, r.right, r.bottom); -} - -inline BOOL EBIsThemeActive() -{ - extern BOOL (*IsThemeActive)(); - return IsThemeActive? IsThemeActive(): 0; -} - -inline BOOL EBSetWindowTheme(HWND hWnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList) -{ - extern BOOL (*SetWindowTheme)(HWND, LPCWSTR, LPCWSTR); - return SetWindowTheme? SetWindowTheme(hWnd, pszSubAppName, pszSubIdList): 0; -} - -#endif diff --git a/c/datalistview.cpp b/c/datalistview.cpp index e6cc6ca..e44592b 100644 --- a/c/datalistview.cpp +++ b/c/datalistview.cpp @@ -5,7 +5,6 @@ #include #include "resource.h" -#include "common.h" #include "datalistview.h" #include "episodelistview.h" #include "listview.h" diff --git a/c/debug.cpp b/c/debug.cpp index 07006a9..934533b 100644 --- a/c/debug.cpp +++ b/c/debug.cpp @@ -1,8 +1,9 @@ #include +#include #include -#include "common.h" #include "debug.h" +#include "win.h" struct Avg { int id; diff --git a/c/episodelistview.cpp b/c/episodelistview.cpp index 313f82f..b3a581d 100644 --- a/c/episodelistview.cpp +++ b/c/episodelistview.cpp @@ -4,11 +4,12 @@ #include #include "resource.h" -#include "common.h" #include "datalistview.h" #include "episodelistview.h" #include "listview.h" #include "pl.h" +#include "util.h" +#include "win.h" EpisodeListView::EpisodeListView(const HWND hWndParent) : ListView(hWndParent, (HMENU)IDC_EPISODELISTVIEW, 0) diff --git a/c/layout.cpp b/c/layout.cpp index 94978bb..cbfb831 100644 --- a/c/layout.cpp +++ b/c/layout.cpp @@ -1,9 +1,9 @@ #include -#include "common.h" #include "episodelistview.h" #include "datalistview.h" #include "layout.h" +#include "win.h" extern HWND g_hWnd; extern HWND g_hWndStatus; diff --git a/c/layout.h b/c/layout.h index 752e660..578f065 100644 --- a/c/layout.h +++ b/c/layout.h @@ -3,9 +3,9 @@ #include -#include "common.h" #include "datalistview.h" #include "pl.h" +#include "win.h" void UpdateLayout(int w = 0, int h = 0); diff --git a/c/listview.cpp b/c/listview.cpp index 531e9dd..107d34b 100644 --- a/c/listview.cpp +++ b/c/listview.cpp @@ -1,9 +1,9 @@ #include #include -#include "common.h" #include "listview.h" #include "layout.h" +#include "win.h" extern HFONT g_hfNormal; static LRESULT CALLBACK WndProc(HWND, UINT, WPARAM, LPARAM); diff --git a/c/main.cpp b/c/main.cpp index 87b15be..c237e31 100644 --- a/c/main.cpp +++ b/c/main.cpp @@ -6,11 +6,11 @@ #include "debug.h" #include "resource.h" -#include "common.h" #include "datalistview.h" #include "episodelistview.h" #include "layout.h" #include "pl.h" +#include "util.h" /* Looked-up constants. */ int g_dpi = 96; diff --git a/c/pl.h b/c/pl.h index 28e13b0..670c926 100644 --- a/c/pl.h +++ b/c/pl.h @@ -5,7 +5,7 @@ #include #include -#include "common.h" +#include "wcharptr.h" wchar_ptr PlString(const term_t t, const int flags = CVT_WRITE); diff --git a/c/util.h b/c/util.h new file mode 100644 index 0000000..babe0c5 --- /dev/null +++ b/c/util.h @@ -0,0 +1,19 @@ +#ifndef UTIL_H +#define UTIL_H + +#include + +template +inline int Swprintf(wchar_t (&buf)[N], const wchar_t* const fmt, T... xs) +{ + return _snwprintf_s(buf, N, _TRUNCATE, fmt, xs...); +} + +inline int Cmp(const int a, const int b) +{ + if (a == b) return 0; + if (a > b) return 1; + return -1; +} + +#endif diff --git a/c/wcharptr.cpp b/c/wcharptr.cpp new file mode 100644 index 0000000..e406ed1 --- /dev/null +++ b/c/wcharptr.cpp @@ -0,0 +1,64 @@ +#include +#include + +#include "wcharptr.h" +#include "win.h" + +wchar_ptr::wchar_ptr() noexcept {} + +wchar_ptr::wchar_ptr(wchar_t* const s) noexcept : m_p(s) {} + +wchar_ptr& wchar_ptr::operator=(wchar_t* const s) noexcept +{ + if (m_p != s) { + delete m_p; + m_p = s; + } + return *this; +} + +wchar_ptr::wchar_ptr(wchar_ptr&& other) noexcept + : m_p(std::exchange(other.m_p, nullptr)) {} + +wchar_ptr& wchar_ptr::operator=(wchar_ptr&& other) noexcept +{ + std::swap(m_p, other.m_p); + return *this; +} + +wchar_ptr::operator wchar_t*() noexcept +{ + return m_p; +} + +wchar_t* wchar_ptr::release() noexcept +{ + wchar_t* p2 = m_p; + m_p = nullptr; + return p2; +} + +wchar_ptr::~wchar_ptr() noexcept +{ + delete m_p; +} + +wchar_ptr wchar_ptr::from_narrow(const char* const src, const int cp) +{ + int cbMultiByte = strlen(src)+1; + int cchWideChar = MultiByteToWideChar(cp, 0, src, cbMultiByte, NULL, 0); + wchar_t* dst = new wchar_t[cchWideChar]; + if (!MultiByteToWideChar(cp, 0, src, cbMultiByte, dst, cchWideChar)) { + delete dst; + throw Win32Error(); + } + return dst; +} + +wchar_ptr wchar_ptr::copy(const wchar_t* const src) +{ + const int cb = wcslen(src)+1; + wchar_t* dst = new wchar_t[cb]; + memcpy(dst, src, cb*sizeof(wchar_t)); + return dst; +} diff --git a/c/wcharptr.h b/c/wcharptr.h new file mode 100644 index 0000000..1f579b5 --- /dev/null +++ b/c/wcharptr.h @@ -0,0 +1,33 @@ +#ifndef WCHARPTR_H +#define WCHARPTR_H + +#include + +/* wchar_ptr: Simple wrapper for wide C strings. */ +struct wchar_ptr +{ + /* Named copy constructors (expensive). */ + static wchar_ptr from_narrow(const char* buf, int cp = CP_UTF8); + static wchar_ptr copy(const wchar_t* s); + + /* Non-explicit copies are disabled. */ + wchar_ptr(wchar_ptr& other) = delete; + wchar_ptr& operator=(wchar_ptr& other) = delete; + + wchar_ptr() noexcept; + ~wchar_ptr(); + operator wchar_t*() noexcept; + + wchar_ptr(wchar_t* s) noexcept; + wchar_ptr& operator=(wchar_t* s) noexcept; + + wchar_ptr(wchar_ptr&& other) noexcept; + wchar_ptr& operator=(wchar_ptr&& other) noexcept; + + /* Return pointer, releasing ownership. */ + wchar_t *release() noexcept; +private: + wchar_t* m_p = nullptr; +}; + +#endif diff --git a/c/win.cpp b/c/win.cpp new file mode 100644 index 0000000..435e739 --- /dev/null +++ b/c/win.cpp @@ -0,0 +1,108 @@ +#include +#include + +#include "win.h" + +Win32Error::Win32Error() : code(GetLastError()) {} +Win32Error::Win32Error(const DWORD code) : code(code) {} + +Win32Error::~Win32Error() +{ + if (m_szMsg) + HeapFree(GetProcessHeap(), 0, m_szMsg); + if (m_wszMsg) + HeapFree(GetProcessHeap(), 0, m_wszMsg); +} + +const char* Win32Error::what() const noexcept +{ + if (!m_szMsg) + FormatMessageA( + FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + code, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (char*)&m_szMsg, + 0, NULL); + return m_szMsg; +} + +const wchar_t* Win32Error::What() const noexcept +{ + if (!m_wszMsg) + FormatMessage( + FORMAT_MESSAGE_ALLOCATE_BUFFER|FORMAT_MESSAGE_FROM_SYSTEM|FORMAT_MESSAGE_IGNORE_INSERTS, + NULL, + code, + MAKELANGID(LANG_ENGLISH, SUBLANG_ENGLISH_US), + (wchar_t*)&m_wszMsg, + 0, NULL); + return m_wszMsg; +} + +std::optional Library::Maybe(const wchar_t* const lib) +{ + HMODULE hModule = LoadLibrary(lib); + if (!hModule) return {}; + return Library(hModule); +} + +Library::Library(const HMODULE hModule) : m_hModule(hModule) {} + +Library::Library(const wchar_t* const lib) +{ + m_hModule = LoadLibrary(lib); + if (!m_hModule) + throw Win32Error(); +} + +Library::~Library() +{ + FreeLibrary(m_hModule); +} + +int EBMessageBox(const wchar_t* const wszText, const wchar_t* const wszCaption, const unsigned uType) +{ + extern HWND g_hWnd; + + auto proc = [](const int nCode, const WPARAM wParam, const LPARAM lParam) noexcept + -> LRESULT CALLBACK + { + if (!g_hWnd || nCode < 0 || nCode != HCBT_ACTIVATE) + return CallNextHookEx(0, nCode, wParam, lParam); + + HWND hWnd = (HWND)wParam; + long lStyle = GetWindowLong(hWnd, GWL_STYLE); + if (!(lStyle & WS_POPUP)) return 0; + + RECT rcMain, rcMsg; + GetWindowRect(g_hWnd, &rcMain); + GetWindowRect(hWnd, &rcMsg); + SetWindowPos(hWnd, NULL, + rcMain.left+(rcMain.right-rcMain.left)/2-(rcMsg.right-rcMsg.left)/2, + rcMain.top+(rcMain.bottom-rcMain.top)/2-(rcMsg.bottom-rcMsg.top)/2, + -1, -1, + SWP_NOZORDER|SWP_NOSIZE|SWP_NOACTIVATE); + + return 0; + }; + + HHOOK hHook = require(SetWindowsHookEx(WH_CBT, proc, (HINSTANCE)NULL, GetCurrentThreadId())); + int r = MessageBox(g_hWnd, wszText, wszCaption, uType); + require(UnhookWindowsHookEx(hHook)); + return r; +} + +int GetRelativeCursorPos(HWND hWnd, POINT* pt) +{ + RECT rc; + if (!GetClientRect(hWnd, &rc)) return 0; + SetLastError(ERROR_SUCCESS); + if (!MapWindowPoints(hWnd, NULL, (POINT*)&rc, 2)) return 0; + + POINT ptMouse; + if (!GetCursorPos(&ptMouse)) return 0; + pt->x = ptMouse.x-rc.left; + pt->y = ptMouse.y-rc.top; + return 1; +} diff --git a/c/win.h b/c/win.h new file mode 100644 index 0000000..038f8ea --- /dev/null +++ b/c/win.h @@ -0,0 +1,105 @@ +#ifndef WIN_H +#define WIN_H + +#include +#include + +int EBMessageBox(const wchar_t* wszText, const wchar_t* wszCaption, unsigned uType); +int GetRelativeCursorPos(HWND hWnd, POINT* pt); + +/* Win32Error: Exception for Windows API errors. */ +struct Win32Error : public std::exception +{ + Win32Error(); + Win32Error(DWORD code); + ~Win32Error(); + const char* what() const noexcept override; + const wchar_t* What() const noexcept; + DWORD code; +private: + char* m_szMsg = NULL; + wchar_t* m_wszMsg = NULL; +}; + +/* Library: Wrapper for loading and freeing dynamically linked libraries. */ +struct Library +{ + static std::optional Maybe(const wchar_t* lib); + Library(const wchar_t* lib); + ~Library(); + template T* GetProcAddress(const char* szProc); +private: + Library(HMODULE hModule); + HMODULE m_hModule; +}; + +template +T* Library::GetProcAddress(const char* const szProc) +{ + return (T*)(void*)::GetProcAddress(m_hModule, szProc); +} + +/* Variable template for caching values from GetSystemMetrics. */ +template +auto Metric = GetSystemMetrics(I); + +/* Check result of Windows API call, throwing error on NULL. */ +template +inline T require(const T x) +{ + if (!x) throw Win32Error(); + return x; +} + +/* Check result of Windows API call, showing a warning on NULL. */ +template +inline T prefer(const T x) +{ + if (!x) { + EBMessageBox(Win32Error().What(), L"System Error", MB_ICONWARNING); + return (T)NULL; + } + return x; +} + +/* Return integer scaled for current DPI. */ +inline int Dpi(const int i) +{ + extern int g_dpi; + return MulDiv(i, g_dpi, 96); +} + +/* Get window rectangle relative to parent. */ +inline BOOL GetRelativeRect(const HWND hWnd, RECT* const rr) +{ + if (!GetClientRect(hWnd, rr)) return 0; + return MapWindowPoints(hWnd, GetParent(hWnd), (POINT*)rr, 2); +} + +inline BOOL SetWindowRect(const HWND hWnd, + const long left, const long top, const long right, const long bottom) +{ + return MoveWindow(hWnd, + left, top, + right-left, bottom-top, + TRUE); +} + +inline BOOL SetWindowRect(const HWND hWnd, const RECT r) +{ + return SetWindowRect(hWnd, r.left, r.top, r.right, r.bottom); +} + +inline BOOL EBIsThemeActive() +{ + extern BOOL (*IsThemeActive)(); + return IsThemeActive? IsThemeActive(): 0; +} + +inline BOOL EBSetWindowTheme(HWND hWnd, LPCWSTR pszSubAppName, LPCWSTR pszSubIdList) +{ + extern BOOL (*SetWindowTheme)(HWND, LPCWSTR, LPCWSTR); + return SetWindowTheme? SetWindowTheme(hWnd, pszSubAppName, pszSubIdList): 0; +} + +#endif -- cgit v1.2.3