From ea435d78766dbf324ecdee62d98f17fd077b9bd3 Mon Sep 17 00:00:00 2001 From: Aleksey Bragin Date: Sun, 18 Jan 2009 10:22:07 +0000 Subject: [PATCH] - SVN maintenance. svn path=/trunk/; revision=38880 --- reactos/base/applications/winhlp32/callback.c | 360 +- reactos/base/applications/winhlp32/hlpfile.c | 5324 ++++++++--------- reactos/base/applications/winhlp32/hlpfile.h | 382 +- reactos/base/applications/winhlp32/lex.yy.c | 3726 ++++++------ reactos/base/applications/winhlp32/macro.c | 1920 +++--- reactos/base/applications/winhlp32/macro.h | 124 +- .../base/applications/winhlp32/macro.lex.l | 632 +- reactos/base/applications/winhlp32/string.c | 68 +- reactos/base/applications/winhlp32/winhelp.c | 3440 +++++------ reactos/base/applications/winhlp32/winhelp.h | 334 +- .../base/applications/winhlp32/winhelp_res.h | 118 +- 11 files changed, 8214 insertions(+), 8214 deletions(-) diff --git a/reactos/base/applications/winhlp32/callback.c b/reactos/base/applications/winhlp32/callback.c index 4d56b0c46fc..0b3e62e014d 100644 --- a/reactos/base/applications/winhlp32/callback.c +++ b/reactos/base/applications/winhlp32/callback.c @@ -1,180 +1,180 @@ -/* - * Help Viewer - DLL callback into WineHelp - * - * Copyright 2004 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define WIN32_LEAN_AND_MEAN - -#include - -#include "windows.h" -#include "winhelp.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -static WORD CALLBACK WHD_GetFSError(void) -{ - WINE_FIXME("()\n"); - return 0; -} - -static HANDLE CALLBACK WHD_Open(LPSTR name, BYTE flags) -{ - unsigned mode = 0; - - WINE_FIXME("(%s %x)\n", wine_dbgstr_a(name), flags); - switch (flags) - { - case 0: mode = GENERIC_READ | GENERIC_WRITE; break; - case 2: mode = GENERIC_READ; break; - default: WINE_FIXME("Undocumented flags %x\n", flags); - } - return CreateFile(name, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, - OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); -} - -static WORD CALLBACK WHD_Close(HANDLE fs) -{ - WINE_FIXME("(%p)\n", fs); - CloseHandle(fs); - return 0; -} - -static HANDLE CALLBACK WHD_OpenBag(HANDLE fs, LPSTR name, BYTE flags) -{ - WINE_FIXME("(%p %s %x)\n", fs, name, flags); - return NULL; -} - -static HANDLE CALLBACK WHD_CloseBag(HANDLE bag) -{ - WINE_FIXME("()\n"); - return NULL; -} - -static LONG CALLBACK WHD_ReadBag(HANDLE bag, BYTE* ptr, LONG len) -{ - WINE_FIXME("()\n"); - return 0; -} - -static LONG CALLBACK WHD_TellBag(HANDLE bag) -{ - WINE_FIXME("()\n"); - return 0; -} - -static LONG CALLBACK WHD_SeekBag(HANDLE bag, LONG offset, WORD whence) -{ - WINE_FIXME("()\n"); - return 0; -} - -static BOOL CALLBACK WHD_IsEofBag(HANDLE bag) -{ - WINE_FIXME("()\n"); - return FALSE; -} - -static LONG CALLBACK WHD_SizeBag(HANDLE bag) -{ - WINE_FIXME("()\n"); - return 0; -} - -static BOOL CALLBACK WHD_Access(HANDLE fs, LPSTR name, BYTE flags) -{ - WINE_FIXME("()\n"); - return FALSE; -} - -static WORD CALLBACK WHD_LLInfoFromBag(HANDLE bag, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3) -{ - WINE_FIXME("()\n"); - return 0; -} - -static WORD CALLBACK WHD_LLInfoFromFile(HANDLE fs, LPSTR name, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3) -{ - WINE_FIXME("()\n"); - return 0; -} - -static void CALLBACK WHD_Error(int err) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK WHD_ErrorString(LPSTR err) -{ - WINE_FIXME("()\n"); -} - -static ULONG_PTR CALLBACK WHD_GetInfo(WORD what, HWND hnd) -{ - ULONG_PTR ret = 0; - - WINE_TRACE("(%x %p)\n", what, hnd); - switch (what) - { - case 0: break; - case 1: /* instance */ ret = (ULONG_PTR)Globals.hInstance; break; - case 3: /* current window */ ret = (ULONG_PTR)Globals.active_win->hMainWnd; break; - case 2: /* main window */ - case 4: /* handle to opened file */ - case 5: /* foreground color */ - case 6: /* background color */ - case 7: /* topic number */ - case 8: /* current opened file name */ - WINE_FIXME("NIY %u\n", what); - break; - default: - WINE_FIXME("Undocumented %u\n", what); - break; - } - return ret; -} - -static LONG CALLBACK WHD_API(LPSTR x, WORD xx, DWORD xxx) -{ - WINE_FIXME("()\n"); - return 0; -} - -FARPROC Callbacks[] = -{ - (FARPROC)WHD_GetFSError, - (FARPROC)WHD_Open, - (FARPROC)WHD_Close, - (FARPROC)WHD_OpenBag, - (FARPROC)WHD_CloseBag, - (FARPROC)WHD_ReadBag, - (FARPROC)WHD_TellBag, - (FARPROC)WHD_SeekBag, - (FARPROC)WHD_IsEofBag, - (FARPROC)WHD_SizeBag, - (FARPROC)WHD_Access, - (FARPROC)WHD_LLInfoFromBag, - (FARPROC)WHD_LLInfoFromFile, - (FARPROC)WHD_Error, - (FARPROC)WHD_ErrorString, - (FARPROC)WHD_GetInfo, - (FARPROC)WHD_API -}; +/* + * Help Viewer - DLL callback into WineHelp + * + * Copyright 2004 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "windows.h" +#include "winhelp.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +static WORD CALLBACK WHD_GetFSError(void) +{ + WINE_FIXME("()\n"); + return 0; +} + +static HANDLE CALLBACK WHD_Open(LPSTR name, BYTE flags) +{ + unsigned mode = 0; + + WINE_FIXME("(%s %x)\n", wine_dbgstr_a(name), flags); + switch (flags) + { + case 0: mode = GENERIC_READ | GENERIC_WRITE; break; + case 2: mode = GENERIC_READ; break; + default: WINE_FIXME("Undocumented flags %x\n", flags); + } + return CreateFile(name, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL, + OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL); +} + +static WORD CALLBACK WHD_Close(HANDLE fs) +{ + WINE_FIXME("(%p)\n", fs); + CloseHandle(fs); + return 0; +} + +static HANDLE CALLBACK WHD_OpenBag(HANDLE fs, LPSTR name, BYTE flags) +{ + WINE_FIXME("(%p %s %x)\n", fs, name, flags); + return NULL; +} + +static HANDLE CALLBACK WHD_CloseBag(HANDLE bag) +{ + WINE_FIXME("()\n"); + return NULL; +} + +static LONG CALLBACK WHD_ReadBag(HANDLE bag, BYTE* ptr, LONG len) +{ + WINE_FIXME("()\n"); + return 0; +} + +static LONG CALLBACK WHD_TellBag(HANDLE bag) +{ + WINE_FIXME("()\n"); + return 0; +} + +static LONG CALLBACK WHD_SeekBag(HANDLE bag, LONG offset, WORD whence) +{ + WINE_FIXME("()\n"); + return 0; +} + +static BOOL CALLBACK WHD_IsEofBag(HANDLE bag) +{ + WINE_FIXME("()\n"); + return FALSE; +} + +static LONG CALLBACK WHD_SizeBag(HANDLE bag) +{ + WINE_FIXME("()\n"); + return 0; +} + +static BOOL CALLBACK WHD_Access(HANDLE fs, LPSTR name, BYTE flags) +{ + WINE_FIXME("()\n"); + return FALSE; +} + +static WORD CALLBACK WHD_LLInfoFromBag(HANDLE bag, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3) +{ + WINE_FIXME("()\n"); + return 0; +} + +static WORD CALLBACK WHD_LLInfoFromFile(HANDLE fs, LPSTR name, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3) +{ + WINE_FIXME("()\n"); + return 0; +} + +static void CALLBACK WHD_Error(int err) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK WHD_ErrorString(LPSTR err) +{ + WINE_FIXME("()\n"); +} + +static ULONG_PTR CALLBACK WHD_GetInfo(WORD what, HWND hnd) +{ + ULONG_PTR ret = 0; + + WINE_TRACE("(%x %p)\n", what, hnd); + switch (what) + { + case 0: break; + case 1: /* instance */ ret = (ULONG_PTR)Globals.hInstance; break; + case 3: /* current window */ ret = (ULONG_PTR)Globals.active_win->hMainWnd; break; + case 2: /* main window */ + case 4: /* handle to opened file */ + case 5: /* foreground color */ + case 6: /* background color */ + case 7: /* topic number */ + case 8: /* current opened file name */ + WINE_FIXME("NIY %u\n", what); + break; + default: + WINE_FIXME("Undocumented %u\n", what); + break; + } + return ret; +} + +static LONG CALLBACK WHD_API(LPSTR x, WORD xx, DWORD xxx) +{ + WINE_FIXME("()\n"); + return 0; +} + +FARPROC Callbacks[] = +{ + (FARPROC)WHD_GetFSError, + (FARPROC)WHD_Open, + (FARPROC)WHD_Close, + (FARPROC)WHD_OpenBag, + (FARPROC)WHD_CloseBag, + (FARPROC)WHD_ReadBag, + (FARPROC)WHD_TellBag, + (FARPROC)WHD_SeekBag, + (FARPROC)WHD_IsEofBag, + (FARPROC)WHD_SizeBag, + (FARPROC)WHD_Access, + (FARPROC)WHD_LLInfoFromBag, + (FARPROC)WHD_LLInfoFromFile, + (FARPROC)WHD_Error, + (FARPROC)WHD_ErrorString, + (FARPROC)WHD_GetInfo, + (FARPROC)WHD_API +}; diff --git a/reactos/base/applications/winhlp32/hlpfile.c b/reactos/base/applications/winhlp32/hlpfile.c index 483be5a1c27..d9bdc7ec0c3 100644 --- a/reactos/base/applications/winhlp32/hlpfile.c +++ b/reactos/base/applications/winhlp32/hlpfile.c @@ -1,2662 +1,2662 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * 2002, 2008 Eric Pouech - * 2007 Kirill K. Smirnov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "winhelp.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i) -{ - return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1]; -} - -static inline short GET_SHORT(const BYTE* buffer, unsigned i) -{ - return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1]; -} - -static inline unsigned GET_UINT(const BYTE* buffer, unsigned i) -{ - return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2); -} - -static HLPFILE *first_hlpfile = 0; - - -/************************************************************************** - * HLPFILE_BPTreeSearch - * - * Searches for an element in B+ tree - * - * PARAMS - * buf [I] pointer to the embedded file structured as a B+ tree - * key [I] pointer to data to find - * comp [I] compare function - * - * RETURNS - * Pointer to block identified by key, or NULL if failure. - * - */ -static void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key, - HLPFILE_BPTreeCompare comp) -{ - unsigned magic; - unsigned page_size; - unsigned cur_page; - unsigned level; - BYTE *pages, *ptr, *newptr; - int i, entries; - int ret; - - magic = GET_USHORT(buf, 9); - if (magic != 0x293B) - { - WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); - return NULL; - } - page_size = GET_USHORT(buf, 9+4); - cur_page = GET_USHORT(buf, 9+26); - level = GET_USHORT(buf, 9+32); - pages = buf + 9 + 38; - while (--level > 0) - { - ptr = pages + cur_page*page_size; - entries = GET_SHORT(ptr, 2); - ptr += 6; - for (i = 0; i < entries; i++) - { - if (comp(ptr, key, 0, (void **)&newptr) > 0) break; - ptr = newptr; - } - cur_page = GET_USHORT(ptr-2, 0); - } - ptr = pages + cur_page*page_size; - entries = GET_SHORT(ptr, 2); - ptr += 8; - for (i = 0; i < entries; i++) - { - ret = comp(ptr, key, 1, (void **)&newptr); - if (ret == 0) return ptr; - if (ret > 0) return NULL; - ptr = newptr; - } - return NULL; -} - -/************************************************************************** - * HLPFILE_BPTreeEnum - * - * Enumerates elements in B+ tree. - * - * PARAMS - * buf [I] pointer to the embedded file structured as a B+ tree - * cb [I] compare function - * cookie [IO] cookie for cb function - */ -void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie) -{ - unsigned magic; - unsigned page_size; - unsigned cur_page; - unsigned level; - BYTE *pages, *ptr, *newptr; - int i, entries; - - magic = GET_USHORT(buf, 9); - if (magic != 0x293B) - { - WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); - return; - } - page_size = GET_USHORT(buf, 9+4); - cur_page = GET_USHORT(buf, 9+26); - level = GET_USHORT(buf, 9+32); - pages = buf + 9 + 38; - while (--level > 0) - { - ptr = pages + cur_page*page_size; - cur_page = GET_USHORT(ptr, 4); - } - while (cur_page != 0xFFFF) - { - ptr = pages + cur_page*page_size; - entries = GET_SHORT(ptr, 2); - ptr += 8; - for (i = 0; i < entries; i++) - { - cb(ptr, (void **)&newptr, cookie); - ptr = newptr; - } - cur_page = GET_USHORT(pages+cur_page*page_size, 6); - } -} - - -/*********************************************************************** - * - * HLPFILE_UncompressedLZ77_Size - */ -static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end) -{ - int i, newsize = 0; - - while (ptr < end) - { - int mask = *ptr++; - for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) - { - if (mask & 1) - { - int code = GET_USHORT(ptr, 0); - int len = 3 + (code >> 12); - newsize += len; - ptr += 2; - } - else newsize++, ptr++; - } - } - - return newsize; -} - -/*********************************************************************** - * - * HLPFILE_UncompressLZ77 - */ -static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr) -{ - int i; - - while (ptr < end) - { - int mask = *ptr++; - for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) - { - if (mask & 1) - { - int code = GET_USHORT(ptr, 0); - int len = 3 + (code >> 12); - int offset = code & 0xfff; - /* - * We must copy byte-by-byte here. We cannot use memcpy nor - * memmove here. Just example: - * a[]={1,2,3,4,5,6,7,8,9,10} - * newptr=a+2; - * offset=1; - * We expect: - * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12} - */ - for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1); - ptr += 2; - } - else *newptr++ = *ptr++; - } - } - - return newptr; -} - -/*********************************************************************** - * - * HLPFILE_Uncompress2 - */ - -static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend) -{ - BYTE *phptr, *phend; - UINT code; - UINT index; - - while (ptr < end && newptr < newend) - { - if (!*ptr || *ptr >= 0x10) - *newptr++ = *ptr++; - else - { - code = 0x100 * ptr[0] + ptr[1]; - index = (code - 0x100) / 2; - - phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index]; - phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1]; - - if (newptr + (phend - phptr) > newend) - { - WINE_FIXME("buffer overflow %p > %p for %lu bytes\n", - newptr, newend, (SIZE_T)(phend - phptr)); - return; - } - memcpy(newptr, phptr, phend - phptr); - newptr += phend - phptr; - if (code & 1) *newptr++ = ' '; - - ptr += 2; - } - } - if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend); -} - -/****************************************************************** - * HLPFILE_Uncompress3 - * - * - */ -static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end, - const BYTE* src, const BYTE* src_end) -{ - unsigned int idx, len; - - for (; src < src_end; src++) - { - if ((*src & 1) == 0) - { - idx = *src / 2; - if (idx > hlpfile->num_phrases) - { - WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); - len = 0; - } - else - { - len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; - if (dst + len <= dst_end) - memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); - } - } - else if ((*src & 0x03) == 0x01) - { - idx = (*src + 1) * 64; - idx += *++src; - if (idx > hlpfile->num_phrases) - { - WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); - len = 0; - } - else - { - len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; - if (dst + len <= dst_end) - memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); - } - } - else if ((*src & 0x07) == 0x03) - { - len = (*src / 8) + 1; - if (dst + len <= dst_end) - memcpy(dst, src + 1, len); - src += len; - } - else - { - len = (*src / 16) + 1; - if (dst + len <= dst_end) - memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len); - } - dst += len; - } - - if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end); - return TRUE; -} - -/****************************************************************** - * HLPFILE_UncompressRLE - * - * - */ -static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz) -{ - BYTE ch; - BYTE* sdst = dst + dstsz; - - while (src < end) - { - ch = *src++; - if (ch & 0x80) - { - ch &= 0x7F; - if (dst + ch <= sdst) - memcpy(dst, src, ch); - src += ch; - } - else - { - if (dst + ch <= sdst) - memset(dst, (char)*src, ch); - src++; - } - dst += ch; - } - if (dst != sdst) - WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n", - (SIZE_T)(dst - (sdst - dstsz)), dstsz); -} - - -/****************************************************************** - * HLPFILE_PageByOffset - * - * - */ -HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative) -{ - HLPFILE_PAGE* page; - HLPFILE_PAGE* found; - - if (!hlpfile) return 0; - - WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, offset); - - if (offset == 0xFFFFFFFF) return NULL; - page = NULL; - - for (found = NULL, page = hlpfile->first_page; page; page = page->next) - { - if (page->offset <= offset && (!found || found->offset < page->offset)) - { - *relative = offset - page->offset; - found = page; - } - } - if (!found) - WINE_ERR("Page of offset %u not found in file %s\n", - offset, hlpfile->lpszPath); - return found; -} - -/*********************************************************************** - * - * HLPFILE_Contents - */ -static HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative) -{ - HLPFILE_PAGE* page = NULL; - - if (!hlpfile) return NULL; - - page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative); - if (!page) - { - page = hlpfile->first_page; - *relative = 0; - } - return page; -} - -/************************************************************************** - * comp_PageByHash - * - * HLPFILE_BPTreeCompare function for '|CONTEXT' B+ tree file - * - */ -static int comp_PageByHash(void *p, const void *key, - int leaf, void** next) -{ - LONG lKey = (LONG_PTR)key; - LONG lTest = (INT)GET_UINT(p, 0); - - *next = (char *)p+(leaf?8:6); - WINE_TRACE("Comparing '%d' with '%d'\n", lKey, lTest); - if (lTest < lKey) return -1; - if (lTest > lKey) return 1; - return 0; -} - -/*********************************************************************** - * - * HLPFILE_PageByHash - */ -HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative) -{ - BYTE *ptr; - - if (!hlpfile) return NULL; - if (!lHash) return HLPFILE_Contents(hlpfile, relative); - - WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lHash); - - /* For win 3.0 files hash values are really page numbers */ - if (hlpfile->version <= 16) - { - if (lHash >= hlpfile->wTOMapLen) return NULL; - return HLPFILE_PageByOffset(hlpfile, hlpfile->TOMap[lHash], relative); - } - - ptr = HLPFILE_BPTreeSearch(hlpfile->Context, LongToPtr(lHash), comp_PageByHash); - if (!ptr) - { - WINE_ERR("Page of hash %x not found in file %s\n", lHash, hlpfile->lpszPath); - return NULL; - } - - return HLPFILE_PageByOffset(hlpfile, GET_UINT(ptr, 4), relative); -} - -/*********************************************************************** - * - * HLPFILE_PageByMap - */ -HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative) -{ - unsigned int i; - - if (!hlpfile) return 0; - - WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lMap); - - for (i = 0; i < hlpfile->wMapLen; i++) - { - if (hlpfile->Map[i].lMap == lMap) - return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset, relative); - } - - WINE_ERR("Page of Map %x not found in file %s\n", lMap, hlpfile->lpszPath); - return NULL; -} - -/************************************************************************** - * comp_FindSubFile - * - * HLPFILE_BPTreeCompare function for HLPFILE directory. - * - */ -static int comp_FindSubFile(void *p, const void *key, - int leaf, void** next) -{ - *next = (char *)p+strlen(p)+(leaf?5:3); - WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (char *)key); - return strcmp(p, key); -} - -/*********************************************************************** - * - * HLPFILE_FindSubFile - */ -static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend) -{ - BYTE *ptr; - - WINE_TRACE("looking for file '%s'\n", name); - ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4), - name, comp_FindSubFile); - if (!ptr) return FALSE; - *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1); - if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size) - { - WINE_ERR("internal file %s does not fit\n", name); - return FALSE; - } - *subend = *subbuf + GET_UINT(*subbuf, 0); - if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size) - { - WINE_ERR("internal file %s does not fit\n", name); - return FALSE; - } - if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9) - { - WINE_ERR("invalid size provided for internal file %s\n", name); - return FALSE; - } - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_Hash - */ -LONG HLPFILE_Hash(LPCSTR lpszContext) -{ - LONG lHash = 0; - CHAR c; - - while ((c = *lpszContext++)) - { - CHAR x = 0; - if (c >= 'A' && c <= 'Z') x = c - 'A' + 17; - if (c >= 'a' && c <= 'z') x = c - 'a' + 17; - if (c >= '1' && c <= '9') x = c - '0'; - if (c == '0') x = 10; - if (c == '.') x = 12; - if (c == '_') x = 13; - if (x) lHash = lHash * 43 + x; - } - return lHash; -} - -static LONG fetch_long(const BYTE** ptr) -{ - LONG ret; - - if (*(*ptr) & 1) - { - ret = (*(const ULONG*)(*ptr) - 0x80000000) / 2; - (*ptr) += 4; - } - else - { - ret = (*(const USHORT*)(*ptr) - 0x8000) / 2; - (*ptr) += 2; - } - - return ret; -} - -static ULONG fetch_ulong(const BYTE** ptr) -{ - ULONG ret; - - if (*(*ptr) & 1) - { - ret = *(const ULONG*)(*ptr) / 2; - (*ptr) += 4; - } - else - { - ret = *(const USHORT*)(*ptr) / 2; - (*ptr) += 2; - } - return ret; -} - -static short fetch_short(const BYTE** ptr) -{ - short ret; - - if (*(*ptr) & 1) - { - ret = (*(const unsigned short*)(*ptr) - 0x8000) / 2; - (*ptr) += 2; - } - else - { - ret = (*(const unsigned char*)(*ptr) - 0x80) / 2; - (*ptr)++; - } - return ret; -} - -static unsigned short fetch_ushort(const BYTE** ptr) -{ - unsigned short ret; - - if (*(*ptr) & 1) - { - ret = *(const unsigned short*)(*ptr) / 2; - (*ptr) += 2; - } - else - { - ret = *(const unsigned char*)(*ptr) / 2; - (*ptr)++; - } - return ret; -} - -/****************************************************************** - * HLPFILE_DecompressGfx - * - * Decompress the data part of a bitmap or a metafile - */ -static const BYTE* HLPFILE_DecompressGfx(const BYTE* src, unsigned csz, unsigned sz, BYTE packing, - BYTE** alloc) -{ - const BYTE* dst; - BYTE* tmp; - unsigned sz77; - - WINE_TRACE("Unpacking (%d) from %u bytes to %u bytes\n", packing, csz, sz); - - switch (packing) - { - case 0: /* uncompressed */ - if (sz != csz) - WINE_WARN("Bogus gfx sizes (uncompressed): %u / %u\n", sz, csz); - dst = src; - *alloc = NULL; - break; - case 1: /* RunLen */ - dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); - if (!dst) return NULL; - HLPFILE_UncompressRLE(src, src + csz, *alloc, sz); - break; - case 2: /* LZ77 */ - sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); - dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz77); - if (!dst) return NULL; - HLPFILE_UncompressLZ77(src, src + csz, *alloc); - if (sz77 != sz) - WINE_WARN("Bogus gfx sizes (LZ77): %u / %u\n", sz77, sz); - break; - case 3: /* LZ77 then RLE */ - sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); - tmp = HeapAlloc(GetProcessHeap(), 0, sz77); - if (!tmp) return FALSE; - HLPFILE_UncompressLZ77(src, src + csz, tmp); - dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); - if (!dst) - { - HeapFree(GetProcessHeap(), 0, tmp); - return FALSE; - } - HLPFILE_UncompressRLE(tmp, tmp + sz77, *alloc, sz); - HeapFree(GetProcessHeap(), 0, tmp); - break; - default: - WINE_FIXME("Unsupported packing %u\n", packing); - return NULL; - } - return dst; -} - -static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz) -{ - if (rd->ptr + sz >= rd->data + rd->allocated) - { - char* new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2); - if (!new) return FALSE; - rd->ptr = new + (rd->ptr - rd->data); - rd->data = new; - } - memcpy(rd->ptr, str, sz); - rd->ptr += sz; - - return TRUE; -} - -static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str) -{ - if (*str == '\\' || *str == '{') rd->in_text = FALSE; - else if (*str == '}') rd->in_text = TRUE; - return HLPFILE_RtfAddRawString(rd, str, strlen(str)); -} - -static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str) -{ - const char* p; - const char* last; - const char* replace; - unsigned rlen; - - if (!rd->in_text) - { - if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; - rd->in_text = TRUE; - } - for (last = p = str; *p; p++) - { - if (*p < 0) /* escape non ASCII chars */ - { - static char xx[8]; - rlen = sprintf(xx, "\\'%x", *(const BYTE*)p); - replace = xx; - } - else switch (*p) - { - case '{': rlen = 2; replace = "\\{"; break; - case '}': rlen = 2; replace = "\\}"; break; - case '\\': rlen = 2; replace = "\\\\"; break; - default: continue; - } - if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) || - !HLPFILE_RtfAddRawString(rd, replace, rlen)) return FALSE; - last = p + 1; - } - return HLPFILE_RtfAddRawString(rd, last, p - last); -} - -/****************************************************************** - * RtfAddHexBytes - * - */ -static BOOL HLPFILE_RtfAddHexBytes(struct RtfData* rd, const void* _ptr, unsigned sz) -{ - char tmp[512]; - unsigned i, step; - const BYTE* ptr = _ptr; - static const char* _2hex = "0123456789abcdef"; - - if (!rd->in_text) - { - if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; - rd->in_text = TRUE; - } - for (; sz; sz -= step) - { - step = min(256, sz); - for (i = 0; i < step; i++) - { - tmp[2 * i + 0] = _2hex[*ptr >> 4]; - tmp[2 * i + 1] = _2hex[*ptr++ & 0xF]; - } - if (!HLPFILE_RtfAddRawString(rd, tmp, 2 * step)) return FALSE; - } - return TRUE; -} - -/****************************************************************** - * HLPFILE_RtfAddTransparentBitmap - * - * We'll transform a transparent bitmap into an metafile that - * we then transform into RTF - */ -static BOOL HLPFILE_RtfAddTransparentBitmap(struct RtfData* rd, const BITMAPINFO* bi, - const void* pict, unsigned nc) -{ - HDC hdc, hdcMask, hdcMem, hdcEMF; - HBITMAP hbm, hbmMask, hbmOldMask, hbmOldMem; - HENHMETAFILE hEMF; - BOOL ret = FALSE; - void* data; - UINT sz; - - hbm = CreateDIBitmap(hdc = GetDC(0), &bi->bmiHeader, - CBM_INIT, pict, bi, DIB_RGB_COLORS); - - hdcMem = CreateCompatibleDC(hdc); - hbmOldMem = SelectObject(hdcMem, hbm); - - /* create the mask bitmap from the main bitmap */ - hdcMask = CreateCompatibleDC(hdc); - hbmMask = CreateBitmap(bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, 1, 1, NULL); - hbmOldMask = SelectObject(hdcMask, hbmMask); - SetBkColor(hdcMem, - RGB(bi->bmiColors[nc - 1].rgbRed, - bi->bmiColors[nc - 1].rgbGreen, - bi->bmiColors[nc - 1].rgbBlue)); - BitBlt(hdcMask, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY); - - /* sets to RGB(0,0,0) the transparent bits in main bitmap */ - SetBkColor(hdcMem, RGB(0,0,0)); - SetTextColor(hdcMem, RGB(255,255,255)); - BitBlt(hdcMem, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMask, 0, 0, SRCAND); - - SelectObject(hdcMask, hbmOldMask); - DeleteDC(hdcMask); - - SelectObject(hdcMem, hbmOldMem); - DeleteDC(hdcMem); - - /* we create the bitmap on the fly */ - hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL); - hdcMem = CreateCompatibleDC(hdcEMF); - - /* sets to RGB(0,0,0) the transparent bits in final bitmap */ - hbmOldMem = SelectObject(hdcMem, hbmMask); - SetBkColor(hdcEMF, RGB(255, 255, 255)); - SetTextColor(hdcEMF, RGB(0, 0, 0)); - BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCAND); - - /* and copy the remaining bits of main bitmap */ - SelectObject(hdcMem, hbm); - BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCPAINT); - SelectObject(hdcMem, hbmOldMem); - DeleteDC(hdcMem); - - /* do the cleanup */ - ReleaseDC(0, hdc); - DeleteObject(hbmMask); - DeleteObject(hbm); - - hEMF = CloseEnhMetaFile(hdcEMF); - - /* generate rtf stream */ - sz = GetEnhMetaFileBits(hEMF, 0, NULL); - if (sz && (data = HeapAlloc(GetProcessHeap(), 0, sz))) - { - if (sz == GetEnhMetaFileBits(hEMF, sz, data)) - { - ret = HLPFILE_RtfAddControl(rd, "{\\pict\\emfblip") && - HLPFILE_RtfAddHexBytes(rd, data, sz) && - HLPFILE_RtfAddControl(rd, "}"); - } - HeapFree(GetProcessHeap(), 0, data); - } - DeleteEnhMetaFile(hEMF); - - return ret; -} - -/****************************************************************** - * HLPFILE_RtfAddBitmap - * - */ -static BOOL HLPFILE_RtfAddBitmap(struct RtfData* rd, const BYTE* beg, BYTE type, BYTE pack) -{ - const BYTE* ptr; - const BYTE* pict_beg; - BYTE* alloc = NULL; - BITMAPINFO* bi; - ULONG off, csz; - unsigned nc = 0; - BOOL clrImportant = FALSE; - BOOL ret = FALSE; - char tmp[256]; - - bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi)); - if (!bi) return FALSE; - - ptr = beg + 2; /* for type and pack */ - - bi->bmiHeader.biSize = sizeof(bi->bmiHeader); - bi->bmiHeader.biXPelsPerMeter = fetch_ulong(&ptr); - bi->bmiHeader.biYPelsPerMeter = fetch_ulong(&ptr); - bi->bmiHeader.biPlanes = fetch_ushort(&ptr); - bi->bmiHeader.biBitCount = fetch_ushort(&ptr); - bi->bmiHeader.biWidth = fetch_ulong(&ptr); - bi->bmiHeader.biHeight = fetch_ulong(&ptr); - bi->bmiHeader.biClrUsed = fetch_ulong(&ptr); - clrImportant = fetch_ulong(&ptr); - bi->bmiHeader.biClrImportant = (clrImportant > 1) ? clrImportant : 0; - bi->bmiHeader.biCompression = BI_RGB; - if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount); - if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes); - bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight; - WINE_TRACE("planes=%d bc=%d size=(%d,%d)\n", - bi->bmiHeader.biPlanes, bi->bmiHeader.biBitCount, - bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); - - csz = fetch_ulong(&ptr); - fetch_ulong(&ptr); /* hotspot size */ - - off = GET_UINT(ptr, 0); ptr += 4; - /* GET_UINT(ptr, 0); hotspot offset */ ptr += 4; - - /* now read palette info */ - if (type == 0x06) - { - unsigned i; - - nc = bi->bmiHeader.biClrUsed; - /* not quite right, especially for bitfields type of compression */ - if (!nc && bi->bmiHeader.biBitCount <= 8) - nc = 1 << bi->bmiHeader.biBitCount; - - bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD)); - if (!bi) return FALSE; - for (i = 0; i < nc; i++) - { - bi->bmiColors[i].rgbBlue = ptr[0]; - bi->bmiColors[i].rgbGreen = ptr[1]; - bi->bmiColors[i].rgbRed = ptr[2]; - bi->bmiColors[i].rgbReserved = 0; - ptr += 4; - } - } - pict_beg = HLPFILE_DecompressGfx(beg + off, csz, bi->bmiHeader.biSizeImage, pack, &alloc); - - if (clrImportant == 1 && nc > 0) - { - ret = HLPFILE_RtfAddTransparentBitmap(rd, bi, pict_beg, nc); - goto done; - } - if (!HLPFILE_RtfAddControl(rd, "{\\pict")) goto done; - if (type == 0x06) - { - sprintf(tmp, "\\dibitmap0\\picw%d\\pich%d", - bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - if (!HLPFILE_RtfAddHexBytes(rd, bi, sizeof(*bi) + nc * sizeof(RGBQUAD))) goto done; - } - else - { - sprintf(tmp, "\\wbitmap0\\wbmbitspixel%d\\wbmplanes%d\\picw%d\\pich%d", - bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes, - bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (!HLPFILE_RtfAddHexBytes(rd, pict_beg, bi->bmiHeader.biSizeImage)) goto done; - if (!HLPFILE_RtfAddControl(rd, "}")) goto done; - - ret = TRUE; -done: - HeapFree(GetProcessHeap(), 0, bi); - HeapFree(GetProcessHeap(), 0, alloc); - - return ret; -} - -/****************************************************************** - * HLPFILE_RtfAddMetaFile - * - */ -static BOOL HLPFILE_RtfAddMetaFile(struct RtfData* rd, const BYTE* beg, BYTE pack) -{ - ULONG size, csize, off, hsoff; - const BYTE* ptr; - const BYTE* bits; - BYTE* alloc = NULL; - char tmp[256]; - unsigned mm; - BOOL ret; - - WINE_TRACE("Loading metafile\n"); - - ptr = beg + 2; /* for type and pack */ - - mm = fetch_ushort(&ptr); /* mapping mode */ - sprintf(tmp, "{\\pict\\wmetafile%d\\picw%d\\pich%d", - mm, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2)); - if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; - ptr += 4; - - size = fetch_ulong(&ptr); /* decompressed size */ - csize = fetch_ulong(&ptr); /* compressed size */ - fetch_ulong(&ptr); /* hotspot size */ - off = GET_UINT(ptr, 0); - hsoff = GET_UINT(ptr, 4); - ptr += 8; - - WINE_TRACE("sz=%u csz=%u offs=%u/%u,%u\n", - size, csize, off, (ULONG)(ptr - beg), hsoff); - - bits = HLPFILE_DecompressGfx(beg + off, csize, size, pack, &alloc); - if (!bits) return FALSE; - - ret = HLPFILE_RtfAddHexBytes(rd, bits, size) && - HLPFILE_RtfAddControl(rd, "}"); - - HeapFree(GetProcessHeap(), 0, alloc); - - return ret; -} - -/****************************************************************** - * HLPFILE_RtfAddGfxByAddr - * - */ -static BOOL HLPFILE_RtfAddGfxByAddr(struct RtfData* rd, HLPFILE *hlpfile, - const BYTE* ref, ULONG size) -{ - unsigned i, numpict; - - numpict = GET_USHORT(ref, 2); - WINE_TRACE("Got picture magic=%04x #=%d\n", GET_USHORT(ref, 0), numpict); - - for (i = 0; i < numpict; i++) - { - const BYTE* beg; - const BYTE* ptr; - BYTE type, pack; - - WINE_TRACE("Offset[%d] = %x\n", i, GET_UINT(ref, (1 + i) * 4)); - beg = ptr = ref + GET_UINT(ref, (1 + i) * 4); - - type = *ptr++; - pack = *ptr++; - - switch (type) - { - case 5: /* device dependent bmp */ - case 6: /* device independent bmp */ - HLPFILE_RtfAddBitmap(rd, beg, type, pack); - break; - case 8: - HLPFILE_RtfAddMetaFile(rd, beg, pack); - break; - default: WINE_FIXME("Unknown type %u\n", type); return FALSE; - } - - /* FIXME: hotspots */ - - /* FIXME: implement support for multiple picture format */ - if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n"); - break; - } - return TRUE; -} - -/****************************************************************** - * HLPFILE_RtfAddGfxByIndex - * - * - */ -static BOOL HLPFILE_RtfAddGfxByIndex(struct RtfData* rd, HLPFILE *hlpfile, - unsigned index) -{ - char tmp[16]; - BYTE *ref, *end; - - WINE_TRACE("Loading picture #%d\n", index); - - sprintf(tmp, "|bm%u", index); - - if (!HLPFILE_FindSubFile(hlpfile, tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;} - - ref += 9; - return HLPFILE_RtfAddGfxByAddr(rd, hlpfile, ref, end - ref); -} - -/****************************************************************** - * HLPFILE_AllocLink - * - * - */ -static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie, - const char* str, unsigned len, LONG hash, - unsigned clrChange, unsigned wnd) -{ - HLPFILE_LINK* link; - char* link_str; - - /* FIXME: should build a string table for the attributes.link.lpszPath - * they are reallocated for each link - */ - if (len == -1) len = strlen(str); - link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + len + 1); - if (!link) return NULL; - - link->cookie = cookie; - link->string = link_str = (char*)(link + 1); - memcpy(link_str, str, len); - link_str[len] = '\0'; - link->hash = hash; - link->bClrChange = clrChange ? 1 : 0; - link->window = wnd; - link->next = rd->first_link; - rd->first_link = link; - link->cpMin = rd->char_pos; - link->cpMax = 0; - rd->force_color = clrChange; - if (rd->current_link) WINE_FIXME("Pending link\n"); - rd->current_link = link; - - WINE_TRACE("Link[%d] to %s@%08x:%d\n", - link->cookie, link->string, link->hash, link->window); - return link; -} - -static unsigned HLPFILE_HalfPointsToTwips(unsigned pts) -{ - static unsigned logPxY; - if (!logPxY) - { - HDC hdc = GetDC(NULL); - logPxY = GetDeviceCaps(hdc, LOGPIXELSY); - ReleaseDC(NULL, hdc); - } - return MulDiv(pts, 72 * 10, logPxY); -} - -/*********************************************************************** - * - * HLPFILE_BrowseParagraph - */ -static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, - BYTE *buf, BYTE* end, unsigned* parlen) -{ - UINT textsize; - const BYTE *format, *format_end; - char *text, *text_base, *text_end; - LONG size, blocksize, datalen; - unsigned short bits; - unsigned nc, ncol = 1; - short table_width; - BOOL in_table = FALSE; - char tmp[256]; - BOOL ret = FALSE; - - if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; - - *parlen = 0; - blocksize = GET_UINT(buf, 0); - size = GET_UINT(buf, 0x4); - datalen = GET_UINT(buf, 0x10); - text = text_base = HeapAlloc(GetProcessHeap(), 0, size); - if (!text) return FALSE; - if (size > blocksize - datalen) - { - /* need to decompress */ - if (page->file->hasPhrases) - HLPFILE_Uncompress2(page->file, buf + datalen, end, (BYTE*)text, (BYTE*)text + size); - else if (page->file->hasPhrases40) - HLPFILE_Uncompress3(page->file, text, text + size, buf + datalen, end); - else - { - WINE_FIXME("Text size is too long, splitting\n"); - size = blocksize - datalen; - memcpy(text, buf + datalen, size); - } - } - else - memcpy(text, buf + datalen, size); - - text_end = text + size; - - format = buf + 0x15; - format_end = buf + GET_UINT(buf, 0x10); - - if (buf[0x14] == 0x20 || buf[0x14] == 0x23) - { - fetch_long(&format); - *parlen = fetch_ushort(&format); - } - - if (buf[0x14] == 0x23) - { - char type; - - in_table = TRUE; - ncol = *format++; - - if (!HLPFILE_RtfAddControl(rd, "\\trowd")) goto done; - type = *format++; - if (type == 0 || type == 2) - { - table_width = GET_SHORT(format, 0); - format += 2; - } - else - table_width = 32767; - WINE_TRACE("New table: cols=%d type=%x width=%d\n", - ncol, type, table_width); - if (ncol > 1) - { - int pos; - sprintf(tmp, "\\trgaph%d\\trleft%d", - HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6), table_width, 32767)), - HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - pos = HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6) / 2, table_width, 32767)); - for (nc = 0; nc < ncol; nc++) - { - WINE_TRACE("column(%d/%d) gap=%d width=%d\n", - nc, ncol, GET_SHORT(format, nc*4), - GET_SHORT(format, nc*4+2)); - pos += GET_SHORT(format, nc * 4) + GET_SHORT(format, nc * 4 + 2); - sprintf(tmp, "\\cellx%d", - HLPFILE_HalfPointsToTwips(MulDiv(pos, table_width, 32767))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - } - else - { - WINE_TRACE("column(0/%d) gap=%d width=%d\n", - ncol, GET_SHORT(format, 0), GET_SHORT(format, 2)); - sprintf(tmp, "\\trleft%d\\cellx%d ", - HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767)), - HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0) + GET_SHORT(format, 2), - table_width, 32767))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - format += ncol * 4; - } - - for (nc = 0; nc < ncol; /**/) - { - WINE_TRACE("looking for format at offset %lu in column %d\n", (SIZE_T)(format - (buf + 0x15)), nc); - if (!HLPFILE_RtfAddControl(rd, "\\pard")) goto done; - if (in_table) - { - nc = GET_SHORT(format, 0); - if (nc == -1) break; - format += 5; - if (!HLPFILE_RtfAddControl(rd, "\\intbl")) goto done; - } - else nc++; - if (buf[0x14] == 0x01) - format += 6; - else - format += 4; - bits = GET_USHORT(format, 0); format += 2; - if (bits & 0x0001) fetch_long(&format); - if (bits & 0x0002) - { - sprintf(tmp, "\\sb%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0004) - { - sprintf(tmp, "\\sa%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0008) - { - sprintf(tmp, "\\sl%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0010) - { - sprintf(tmp, "\\li%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0020) - { - sprintf(tmp, "\\ri%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0040) - { - sprintf(tmp, "\\fi%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - if (bits & 0x0100) - { - BYTE brdr = *format++; - short w; - - if (brdr & 0x01 && !HLPFILE_RtfAddControl(rd, "\\box")) goto done; - if (brdr & 0x02 && !HLPFILE_RtfAddControl(rd, "\\brdrt")) goto done; - if (brdr & 0x04 && !HLPFILE_RtfAddControl(rd, "\\brdrl")) goto done; - if (brdr & 0x08 && !HLPFILE_RtfAddControl(rd, "\\brdrb")) goto done; - if (brdr & 0x10 && !HLPFILE_RtfAddControl(rd, "\\brdrr")) goto done; - if (brdr & 0x20 && !HLPFILE_RtfAddControl(rd, "\\brdrth")) goto done; - if (!(brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrs")) goto done; - if (brdr & 0x40 && !HLPFILE_RtfAddControl(rd, "\\brdrdb")) goto done; - /* 0x80: unknown */ - - w = GET_SHORT(format, 0); format += 2; - if (w) - { - sprintf(tmp, "\\brdrw%d", HLPFILE_HalfPointsToTwips(w)); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - } - if (bits & 0x0200) - { - int i, ntab = fetch_short(&format); - unsigned tab, ts; - const char* kind; - - for (i = 0; i < ntab; i++) - { - tab = fetch_ushort(&format); - ts = (tab & 0x4000) ? fetch_ushort(&format) : 0 /* left */; - switch (ts) - { - default: WINE_FIXME("Unknown tab style %x\n", ts); - /* fall through */ - case 0: kind = ""; break; - case 1: kind = "\\tqr"; break; - case 2: kind = "\\tqc"; break; - } - /* FIXME: do kind */ - sprintf(tmp, "%s\\tx%d", - kind, HLPFILE_HalfPointsToTwips(tab & 0x3FFF)); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - } - switch (bits & 0xc00) - { - default: WINE_FIXME("Unsupported alignment 0xC00\n"); break; - case 0: if (!HLPFILE_RtfAddControl(rd, "\\ql")) goto done; break; - case 0x400: if (!HLPFILE_RtfAddControl(rd, "\\qr")) goto done; break; - case 0x800: if (!HLPFILE_RtfAddControl(rd, "\\qc")) goto done; break; - } - - /* 0x1000 doesn't need space */ - if ((bits & 0x1000) && !HLPFILE_RtfAddControl(rd, "\\keep")) goto done; - if ((bits & 0xE080) != 0) - WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits); - - while (text < text_end && format < format_end) - { - WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", wine_dbgstr_a(text), text, text_end, format, format_end); - textsize = strlen(text); - if (textsize) - { - if (rd->force_color) - { - if ((rd->current_link->cookie == hlp_link_popup) ? - !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") : - !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done; - } - if (!HLPFILE_RtfAddText(rd, text)) goto done; - if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done; - rd->char_pos += textsize; - } - /* else: null text, keep on storing attributes */ - text += textsize + 1; - - if (*format == 0xff) - { - format++; - break; - } - - WINE_TRACE("format=%02x\n", *format); - switch (*format) - { - case 0x20: - WINE_FIXME("NIY20\n"); - format += 5; - break; - - case 0x21: - WINE_FIXME("NIY21\n"); - format += 3; - break; - - case 0x80: - { - unsigned font = GET_USHORT(format, 1); - unsigned fs; - - WINE_TRACE("Changing font to %d\n", font); - format += 3; - /* Font size in hlpfile is given in the same units as - rtf control word \fs uses (half-points). */ - switch (rd->font_scale) - { - case 0: fs = page->file->fonts[font].LogFont.lfHeight - 4; break; - default: - case 1: fs = page->file->fonts[font].LogFont.lfHeight; break; - case 2: fs = page->file->fonts[font].LogFont.lfHeight + 4; break; - } - /* FIXME: missing at least colors, also bold attribute looses information */ - - sprintf(tmp, "\\f%d\\cf%d\\fs%d%s%s%s%s", - font, font + 2, fs, - page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0", - page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0", - page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0", - page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0"); - if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; - } - break; - - case 0x81: - if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done; - format += 1; - rd->char_pos++; - break; - - case 0x82: - if (in_table) - { - if (format[1] != 0xFF) - { - if (!HLPFILE_RtfAddControl(rd, "\\par\\intbl")) goto done; - } - else - { - if (!HLPFILE_RtfAddControl(rd, "\\cell\\pard\\intbl")) goto done; - } - } - else if (!HLPFILE_RtfAddControl(rd, "\\par")) goto done; - format += 1; - rd->char_pos++; - break; - - case 0x83: - if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done; - format += 1; - rd->char_pos++; - break; - -#if 0 - case 0x84: - format += 3; - break; -#endif - - case 0x86: - case 0x87: - case 0x88: - { - BYTE type = format[1]; - LONG size; - - /* FIXME: we don't use 'BYTE pos = (*format - 0x86);' for the image position */ - format += 2; - size = fetch_long(&format); - - switch (type) - { - case 0x22: - fetch_ushort(&format); /* hot spot */ - /* fall thru */ - case 0x03: - switch (GET_SHORT(format, 0)) - { - case 0: - HLPFILE_RtfAddGfxByIndex(rd, page->file, GET_SHORT(format, 2)); - rd->char_pos++; - break; - case 1: - WINE_FIXME("does it work ??? %x<%u>#%u\n", - GET_SHORT(format, 0), - size, GET_SHORT(format, 2)); - HLPFILE_RtfAddGfxByAddr(rd, page->file, format + 2, size - 4); - rd->char_pos++; - break; - default: - WINE_FIXME("??? %u\n", GET_SHORT(format, 0)); - break; - } - break; - case 0x05: - WINE_FIXME("Got an embedded element %s\n", format + 6); - break; - default: - WINE_FIXME("Got a type %d picture\n", type); - break; - } - format += size; - } - break; - - case 0x89: - format += 1; - if (!rd->current_link) - WINE_FIXME("No existing link\n"); - rd->current_link->cpMax = rd->char_pos; - rd->current_link = NULL; - rd->force_color = FALSE; - break; - - case 0x8B: - if (!HLPFILE_RtfAddControl(rd, "\\~")) goto done; - format += 1; - rd->char_pos++; - break; - - case 0x8C: - if (!HLPFILE_RtfAddControl(rd, "\\_")) goto done; - /* FIXME: it could be that hypen is also in input stream !! */ - format += 1; - rd->char_pos++; - break; - -#if 0 - case 0xA9: - format += 2; - break; -#endif - - case 0xC8: - case 0xCC: - WINE_TRACE("macro => %s\n", format + 3); - HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3, - GET_USHORT(format, 1), 0, !(*format & 4), -1); - format += 3 + GET_USHORT(format, 1); - break; - - case 0xE0: - case 0xE1: - WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1)); - HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, - page->file->lpszPath, -1, GET_UINT(format, 1), 1, -1); - - - format += 5; - break; - - case 0xE2: - case 0xE3: - case 0xE6: - case 0xE7: - HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, - page->file->lpszPath, -1, GET_UINT(format, 1), - !(*format & 4), -1); - format += 5; - break; - - case 0xEA: - case 0xEB: - case 0xEE: - case 0xEF: - { - char* ptr = (char*) format + 8; - BYTE type = format[3]; - int wnd = -1; - - switch (type) - { - case 1: - wnd = *ptr; - /* fall through */ - case 0: - ptr = page->file->lpszPath; - break; - case 6: - for (wnd = page->file->numWindows - 1; wnd >= 0; wnd--) - { - if (!strcmp(ptr, page->file->windows[wnd].name)) break; - } - if (wnd == -1) - WINE_WARN("Couldn't find window info for %s\n", ptr); - ptr += strlen(ptr) + 1; - /* fall through */ - case 4: - break; - default: - WINE_WARN("Unknown link type %d\n", type); - break; - } - HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, - ptr, -1, GET_UINT(format, 4), !(*format & 4), wnd); - } - format += 3 + GET_USHORT(format, 1); - break; - - default: - WINE_WARN("format %02x\n", *format); - format++; - } - } - } - if (in_table) - { - if (!HLPFILE_RtfAddControl(rd, "\\row\\par\\pard\\plain")) goto done; - rd->char_pos += 2; - } - ret = TRUE; -done: - - HeapFree(GetProcessHeap(), 0, text_base); - return ret; -} - -/****************************************************************** - * HLPFILE_BrowsePage - * - */ -BOOL HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd, - unsigned font_scale, unsigned relative) -{ - HLPFILE *hlpfile = page->file; - BYTE *buf, *end; - DWORD ref = page->reference; - unsigned index, old_index = -1, offset, count = 0, offs = 0; - unsigned cpg, parlen; - char tmp[1024]; - const char* ck = NULL; - - rd->in_text = TRUE; - rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768); - rd->char_pos = 0; - rd->first_link = rd->current_link = NULL; - rd->force_color = FALSE; - rd->font_scale = font_scale; - rd->relative = relative; - rd->char_pos_rel = 0; - - switch (hlpfile->charset) - { - case DEFAULT_CHARSET: - case ANSI_CHARSET: cpg = 1252; break; - case SHIFTJIS_CHARSET: cpg = 932; break; - case HANGEUL_CHARSET: cpg = 949; break; - case GB2312_CHARSET: cpg = 936; break; - case CHINESEBIG5_CHARSET: cpg = 950; break; - case GREEK_CHARSET: cpg = 1253; break; - case TURKISH_CHARSET: cpg = 1254; break; - case HEBREW_CHARSET: cpg = 1255; break; - case ARABIC_CHARSET: cpg = 1256; break; - case BALTIC_CHARSET: cpg = 1257; break; - case VIETNAMESE_CHARSET: cpg = 1258; break; - case RUSSIAN_CHARSET: cpg = 1251; break; - case EE_CHARSET: cpg = 1250; break; - case THAI_CHARSET: cpg = 874; break; - case JOHAB_CHARSET: cpg = 1361; break; - case MAC_CHARSET: ck = "mac"; break; - default: - WINE_FIXME("Unsupported charset %u\n", hlpfile->charset); - cpg = 1252; - } - if (ck) - { - sprintf(tmp, "{\\rtf1\\%s\\deff0", ck); - if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; - } - else - { - sprintf(tmp, "{\\rtf1\\ansi\\ansicpg%d\\deff0", cpg); - if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; - } - - /* generate font table */ - if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE; - for (index = 0; index < hlpfile->numFonts; index++) - { - const char* family; - switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0) - { - case FF_MODERN: family = "modern"; break; - case FF_ROMAN: family = "roman"; break; - case FF_SWISS: family = "swiss"; break; - case FF_SCRIPT: family = "script"; break; - case FF_DECORATIVE: family = "decor"; break; - default: family = "nil"; break; - } - sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset%d %s;}", - index, family, - hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F, - hlpfile->fonts[index].LogFont.lfCharSet, - hlpfile->fonts[index].LogFont.lfFaceName); - if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; - } - if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; - /* generate color table */ - if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE; - for (index = 0; index < hlpfile->numFonts; index++) - { - const char* family; - switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0) - { - case FF_MODERN: family = "modern"; break; - case FF_ROMAN: family = "roman"; break; - case FF_SWISS: family = "swiss"; break; - case FF_SCRIPT: family = "script"; break; - case FF_DECORATIVE: family = "decor"; break; - default: family = "nil"; break; - } - sprintf(tmp, "\\red%d\\green%d\\blue%d;", - GetRValue(hlpfile->fonts[index].color), - GetGValue(hlpfile->fonts[index].color), - GetBValue(hlpfile->fonts[index].color)); - if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; - } - if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; - - do - { - if (hlpfile->version <= 16) - { - index = (ref - 0x0C) / hlpfile->dsize; - offset = (ref - 0x0C) % hlpfile->dsize; - } - else - { - index = (ref - 0x0C) >> 14; - offset = (ref - 0x0C) & 0x3FFF; - } - - if (hlpfile->version <= 16 && index != old_index && old_index != -1) - { - /* we jumped to the next block, adjust pointers */ - ref -= 12; - offset -= 12; - } - - if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} - buf = hlpfile->topic_map[index] + offset; - if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} - end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); - if (index != old_index) {offs = 0; old_index = index;} - - switch (buf[0x14]) - { - case 0x02: - if (count++) goto done; - break; - case 0x01: - case 0x20: - case 0x23: - if (!HLPFILE_BrowseParagraph(page, rd, buf, end, &parlen)) return FALSE; - if (relative > index * 0x8000 + offs) - rd->char_pos_rel = rd->char_pos; - offs += parlen; - break; - default: - WINE_ERR("buf[0x14] = %x\n", buf[0x14]); - } - if (hlpfile->version <= 16) - { - ref += GET_UINT(buf, 0xc); - if (GET_UINT(buf, 0xc) == 0) - break; - } - else - ref = GET_UINT(buf, 0xc); - } while (ref != 0xffffffff); -done: - page->first_link = rd->first_link; - return HLPFILE_RtfAddControl(rd, "}"); -} - -/****************************************************************** - * HLPFILE_ReadFont - * - * - */ -static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile) -{ - BYTE *ref, *end; - unsigned i, len, idx; - unsigned face_num, dscr_num, face_offset, dscr_offset; - BYTE flag, family; - - if (!HLPFILE_FindSubFile(hlpfile, "|FONT", &ref, &end)) - { - WINE_WARN("no subfile FONT\n"); - hlpfile->numFonts = 0; - hlpfile->fonts = NULL; - return FALSE; - } - - ref += 9; - - face_num = GET_USHORT(ref, 0); - dscr_num = GET_USHORT(ref, 2); - face_offset = GET_USHORT(ref, 4); - dscr_offset = GET_USHORT(ref, 6); - - WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n", - face_num, face_offset, dscr_num, dscr_offset); - - hlpfile->numFonts = dscr_num; - hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num); - - len = (dscr_offset - face_offset) / face_num; -/* EPP for (i = face_offset; i < dscr_offset; i += len) */ -/* EPP WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */ - for (i = 0; i < dscr_num; i++) - { - flag = ref[dscr_offset + i * 11 + 0]; - family = ref[dscr_offset + i * 11 + 2]; - - hlpfile->fonts[i].LogFont.lfHeight = ref[dscr_offset + i * 11 + 1]; - hlpfile->fonts[i].LogFont.lfWidth = 0; - hlpfile->fonts[i].LogFont.lfEscapement = 0; - hlpfile->fonts[i].LogFont.lfOrientation = 0; - hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400; - hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) ? TRUE : FALSE; - hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) ? TRUE : FALSE; - hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) ? TRUE : FALSE; - hlpfile->fonts[i].LogFont.lfCharSet = hlpfile->charset; - hlpfile->fonts[i].LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS; - hlpfile->fonts[i].LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; - hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY; - hlpfile->fonts[i].LogFont.lfPitchAndFamily = DEFAULT_PITCH; - - switch (family) - { - case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN; break; - case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN; break; - case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS; break; - case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT; break; - case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break; - default: WINE_FIXME("Unknown family %u\n", family); - } - idx = GET_USHORT(ref, dscr_offset + i * 11 + 3); - - if (idx < face_num) - { - memcpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1)); - hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1)] = '\0'; - } - else - { - WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num); - strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv"); - } - hlpfile->fonts[i].hFont = 0; - hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5], - ref[dscr_offset + i * 11 + 6], - ref[dscr_offset + i * 11 + 7]); -#define X(b,s) ((flag & (1 << b)) ? "-"s: "") - WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08x\n", - i, flag, - X(0, "bold"), - X(1, "italic"), - X(2, "underline"), - X(3, "strikeOut"), - X(4, "dblUnderline"), - X(5, "smallCaps"), - ref[dscr_offset + i * 11 + 1], - family, - hlpfile->fonts[i].LogFont.lfFaceName, idx, - GET_UINT(ref, dscr_offset + i * 11 + 5) & 0x00FFFFFF); - } - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_ReadFileToBuffer - */ -static BOOL HLPFILE_ReadFileToBuffer(HLPFILE* hlpfile, HFILE hFile) -{ - BYTE header[16], dummy[1]; - - if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;}; - - /* sanity checks */ - if (GET_UINT(header, 0) != 0x00035F3F) - {WINE_WARN("wrong header\n"); return FALSE;}; - - hlpfile->file_buffer_size = GET_UINT(header, 12); - hlpfile->file_buffer = HeapAlloc(GetProcessHeap(), 0, hlpfile->file_buffer_size + 1); - if (!hlpfile->file_buffer) return FALSE; - - memcpy(hlpfile->file_buffer, header, 16); - if (_hread(hFile, hlpfile->file_buffer + 16, hlpfile->file_buffer_size - 16) !=hlpfile->file_buffer_size - 16) - {WINE_WARN("filesize1\n"); return FALSE;}; - - if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n"); - - hlpfile->file_buffer[hlpfile->file_buffer_size] = '\0'; /* FIXME: was '0', sounds backwards to me */ - - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_SystemCommands - */ -static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile) -{ - BYTE *buf, *ptr, *end; - HLPFILE_MACRO *macro, **m; - LPSTR p; - unsigned short magic, minor, major, flags; - - hlpfile->lpszTitle = NULL; - - if (!HLPFILE_FindSubFile(hlpfile, "|SYSTEM", &buf, &end)) return FALSE; - - magic = GET_USHORT(buf + 9, 0); - minor = GET_USHORT(buf + 9, 2); - major = GET_USHORT(buf + 9, 4); - /* gen date on 4 bytes */ - flags = GET_USHORT(buf + 9, 10); - WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n", - magic, major, minor, flags); - if (magic != 0x036C || major != 1) - {WINE_WARN("Wrong system header\n"); return FALSE;} - if (minor <= 16) - { - hlpfile->tbsize = 0x800; - hlpfile->compressed = 0; - } - else if (flags == 0) - { - hlpfile->tbsize = 0x1000; - hlpfile->compressed = 0; - } - else if (flags == 4) - { - hlpfile->tbsize = 0x1000; - hlpfile->compressed = 1; - } - else - { - hlpfile->tbsize = 0x800; - hlpfile->compressed = 1; - } - - if (hlpfile->compressed) - hlpfile->dsize = 0x4000; - else - hlpfile->dsize = hlpfile->tbsize - 0x0C; - - hlpfile->version = minor; - hlpfile->flags = flags; - hlpfile->charset = DEFAULT_CHARSET; - - if (hlpfile->version <= 16) - { - char *str = (char*)buf + 0x15; - - hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); - if (!hlpfile->lpszTitle) return FALSE; - lstrcpy(hlpfile->lpszTitle, str); - WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); - /* Nothing more to parse */ - return TRUE; - } - for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4) - { - char *str = (char*) ptr + 4; - switch (GET_USHORT(ptr, 0)) - { - case 1: - if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;} - hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); - if (!hlpfile->lpszTitle) return FALSE; - lstrcpy(hlpfile->lpszTitle, str); - WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); - break; - - case 2: - if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;} - hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); - if (!hlpfile->lpszCopyright) return FALSE; - lstrcpy(hlpfile->lpszCopyright, str); - WINE_TRACE("Copyright: %s\n", hlpfile->lpszCopyright); - break; - - case 3: - if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;} - hlpfile->contents_start = GET_UINT(ptr, 4); - WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start); - break; - - case 4: - macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + lstrlen(str) + 1); - if (!macro) break; - p = (char*)macro + sizeof(HLPFILE_MACRO); - lstrcpy(p, str); - macro->lpszMacro = p; - macro->next = 0; - for (m = &hlpfile->first_macro; *m; m = &(*m)->next); - *m = macro; - break; - - case 5: - if (GET_USHORT(ptr, 4 + 4) != 1) - WINE_FIXME("More than one icon, picking up first\n"); - /* 0x16 is sizeof(CURSORICONDIR), see user32/user_private.h */ - hlpfile->hIcon = CreateIconFromResourceEx(ptr + 4 + 0x16, - GET_USHORT(ptr, 2) - 0x16, TRUE, - 0x30000, 0, 0, 0); - break; - - case 6: - if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;} - - if (hlpfile->windows) - hlpfile->windows = HeapReAlloc(GetProcessHeap(), 0, hlpfile->windows, - sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); - else - hlpfile->windows = HeapAlloc(GetProcessHeap(), 0, - sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); - - if (hlpfile->windows) - { - unsigned flags = GET_USHORT(ptr, 4); - HLPFILE_WINDOWINFO* wi = &hlpfile->windows[hlpfile->numWindows - 1]; - - if (flags & 0x0001) strcpy(wi->type, &str[2]); - else wi->type[0] = '\0'; - if (flags & 0x0002) strcpy(wi->name, &str[12]); - else wi->name[0] = '\0'; - if (flags & 0x0004) strcpy(wi->caption, &str[21]); - else lstrcpynA(wi->caption, hlpfile->lpszTitle, sizeof(wi->caption)); - wi->origin.x = (flags & 0x0008) ? GET_USHORT(ptr, 76) : CW_USEDEFAULT; - wi->origin.y = (flags & 0x0010) ? GET_USHORT(ptr, 78) : CW_USEDEFAULT; - wi->size.cx = (flags & 0x0020) ? GET_USHORT(ptr, 80) : CW_USEDEFAULT; - wi->size.cy = (flags & 0x0040) ? GET_USHORT(ptr, 82) : CW_USEDEFAULT; - wi->style = (flags & 0x0080) ? GET_USHORT(ptr, 84) : SW_SHOW; - wi->win_style = WS_OVERLAPPEDWINDOW; - wi->sr_color = (flags & 0x0100) ? GET_UINT(ptr, 86) : 0xFFFFFF; - wi->nsr_color = (flags & 0x0200) ? GET_UINT(ptr, 90) : 0xFFFFFF; - WINE_TRACE("System-Window: flags=%c%c%c%c%c%c%c%c type=%s name=%s caption=%s (%d,%d)x(%d,%d)\n", - flags & 0x0001 ? 'T' : 't', - flags & 0x0002 ? 'N' : 'n', - flags & 0x0004 ? 'C' : 'c', - flags & 0x0008 ? 'X' : 'x', - flags & 0x0010 ? 'Y' : 'y', - flags & 0x0020 ? 'W' : 'w', - flags & 0x0040 ? 'H' : 'h', - flags & 0x0080 ? 'S' : 's', - wi->type, wi->name, wi->caption, wi->origin.x, wi->origin.y, - wi->size.cx, wi->size.cy); - } - break; - case 8: - WINE_WARN("Citation: '%s'\n", ptr + 4); - break; - case 11: - hlpfile->charset = ptr[4]; - WINE_TRACE("Charset: %d\n", hlpfile->charset); - break; - default: - WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0)); - } - } - if (!hlpfile->lpszTitle) - hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1); - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_GetContext - */ -static BOOL HLPFILE_GetContext(HLPFILE *hlpfile) -{ - BYTE *cbuf, *cend; - unsigned clen; - - if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT", &cbuf, &cend)) - {WINE_WARN("context0\n"); return FALSE;} - - clen = cend - cbuf; - hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen); - if (!hlpfile->Context) return FALSE; - memcpy(hlpfile->Context, cbuf, clen); - - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_GetKeywords - */ -static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile) -{ - BYTE *cbuf, *cend; - unsigned clen; - - if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE; - clen = cend - cbuf; - hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen); - if (!hlpfile->kwbtree) return FALSE; - memcpy(hlpfile->kwbtree, cbuf, clen); - - if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend)) - { - WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n"); - HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree); - return FALSE; - } - clen = cend - cbuf; - hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen); - if (!hlpfile->kwdata) - { - HeapFree(GetProcessHeap(), 0, hlpfile->kwdata); - return FALSE; - } - memcpy(hlpfile->kwdata, cbuf, clen); - - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_GetMap - */ -static BOOL HLPFILE_GetMap(HLPFILE *hlpfile) -{ - BYTE *cbuf, *cend; - unsigned entries, i; - - if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP", &cbuf, &cend)) - {WINE_WARN("no map section\n"); return FALSE;} - - entries = GET_USHORT(cbuf, 9); - hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP)); - if (!hlpfile->Map) return FALSE; - hlpfile->wMapLen = entries; - for (i = 0; i < entries; i++) - { - hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8); - hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4); - } - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_GetTOMap - */ -static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile) -{ - BYTE *cbuf, *cend; - unsigned clen; - - if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP", &cbuf, &cend)) - {WINE_WARN("no tomap section\n"); return FALSE;} - - clen = cend - cbuf - 9; - hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen); - if (!hlpfile->TOMap) return FALSE; - memcpy(hlpfile->TOMap, cbuf+9, clen); - hlpfile->wTOMapLen = clen/4; - return TRUE; -} - -/*********************************************************************** - * - * DeleteMacro - */ -static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro) -{ - HLPFILE_MACRO* next; - - while (macro) - { - next = macro->next; - HeapFree(GetProcessHeap(), 0, macro); - macro = next; - } -} - -/*********************************************************************** - * - * DeletePage - */ -static void HLPFILE_DeletePage(HLPFILE_PAGE* page) -{ - HLPFILE_PAGE* next; - - while (page) - { - next = page->next; - HLPFILE_DeleteMacro(page->first_macro); - HeapFree(GetProcessHeap(), 0, page); - page = next; - } -} - -/*********************************************************************** - * - * HLPFILE_FreeHlpFile - */ -void HLPFILE_FreeHlpFile(HLPFILE* hlpfile) -{ - unsigned i; - - if (!hlpfile || --hlpfile->wRefCount > 0) return; - - if (hlpfile->next) hlpfile->next->prev = hlpfile->prev; - if (hlpfile->prev) hlpfile->prev->next = hlpfile->next; - else first_hlpfile = hlpfile->next; - - if (hlpfile->numFonts) - { - for (i = 0; i < hlpfile->numFonts; i++) - { - DeleteObject(hlpfile->fonts[i].hFont); - } - HeapFree(GetProcessHeap(), 0, hlpfile->fonts); - } - - if (hlpfile->numBmps) - { - for (i = 0; i < hlpfile->numBmps; i++) - { - DeleteObject(hlpfile->bmps[i]); - } - HeapFree(GetProcessHeap(), 0, hlpfile->bmps); - } - - HLPFILE_DeletePage(hlpfile->first_page); - HLPFILE_DeleteMacro(hlpfile->first_macro); - - DestroyIcon(hlpfile->hIcon); - if (hlpfile->numWindows) HeapFree(GetProcessHeap(), 0, hlpfile->windows); - HeapFree(GetProcessHeap(), 0, hlpfile->Context); - HeapFree(GetProcessHeap(), 0, hlpfile->Map); - HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle); - HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright); - HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer); - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); - HeapFree(GetProcessHeap(), 0, hlpfile->topic_map); - HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file); - HeapFree(GetProcessHeap(), 0, hlpfile); -} - -/*********************************************************************** - * - * HLPFILE_UncompressLZ77_Phrases - */ -static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE* hlpfile) -{ - UINT i, num, dec_size, head_size; - BYTE *buf, *end; - - if (!HLPFILE_FindSubFile(hlpfile, "|Phrases", &buf, &end)) return FALSE; - - if (hlpfile->version <= 16) - head_size = 13; - else - head_size = 17; - - num = hlpfile->num_phrases = GET_USHORT(buf, 9); - if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;}; - - if (hlpfile->version <= 16) - dec_size = end - buf - 15 - 2 * num; - else - dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end); - - hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); - hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); - if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) - { - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); - return FALSE; - } - - for (i = 0; i <= num; i++) - hlpfile->phrases_offsets[i] = GET_USHORT(buf, head_size + 2 * i) - 2 * num - 2; - - if (hlpfile->version <= 16) - memcpy(hlpfile->phrases_buffer, buf + 15 + 2*num, dec_size); - else - HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, (BYTE*)hlpfile->phrases_buffer); - - hlpfile->hasPhrases = TRUE; - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_Uncompress_Phrases40 - */ -static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile) -{ - UINT num; - INT dec_size, cpr_size; - BYTE *buf_idx, *end_idx; - BYTE *buf_phs, *end_phs; - LONG* ptr, mask = 0; - unsigned int i; - unsigned short bc, n; - - if (!HLPFILE_FindSubFile(hlpfile, "|PhrIndex", &buf_idx, &end_idx) || - !HLPFILE_FindSubFile(hlpfile, "|PhrImage", &buf_phs, &end_phs)) return FALSE; - - ptr = (LONG*)(buf_idx + 9 + 28); - bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F; - num = hlpfile->num_phrases = GET_USHORT(buf_idx, 9 + 4); - - WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n" - "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n", - GET_UINT(buf_idx, 9 + 0), - GET_UINT(buf_idx, 9 + 4), - GET_UINT(buf_idx, 9 + 8), - GET_UINT(buf_idx, 9 + 12), - GET_UINT(buf_idx, 9 + 16), - GET_UINT(buf_idx, 9 + 20), - GET_USHORT(buf_idx, 9 + 24), - GET_USHORT(buf_idx, 9 + 26)); - - dec_size = GET_UINT(buf_idx, 9 + 12); - cpr_size = GET_UINT(buf_idx, 9 + 16); - - if (dec_size != cpr_size && - dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)) - { - WINE_WARN("size mismatch %u %u\n", - dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); - dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); - } - - hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); - hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); - if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) - { - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); - HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); - return FALSE; - } - -#define getbit() (ptr += (mask < 0), mask = mask*2 + (mask<=0), (*ptr & mask) != 0) - - hlpfile->phrases_offsets[0] = 0; - for (i = 0; i < num; i++) - { - for (n = 1; getbit(); n += 1 << bc); - if (getbit()) n++; - if (bc > 1 && getbit()) n += 2; - if (bc > 2 && getbit()) n += 4; - if (bc > 3 && getbit()) n += 8; - if (bc > 4 && getbit()) n += 16; - hlpfile->phrases_offsets[i + 1] = hlpfile->phrases_offsets[i] + n; - } -#undef getbit - - if (dec_size == cpr_size) - memcpy(hlpfile->phrases_buffer, buf_phs + 9, dec_size); - else - HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, (BYTE*)hlpfile->phrases_buffer); - - hlpfile->hasPhrases40 = TRUE; - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_Uncompress_Topic - */ -static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile) -{ - BYTE *buf, *ptr, *end, *newptr; - unsigned int i, newsize = 0; - unsigned int topic_size; - - if (!HLPFILE_FindSubFile(hlpfile, "|TOPIC", &buf, &end)) - {WINE_WARN("topic0\n"); return FALSE;} - - buf += 9; /* Skip file header */ - topic_size = end - buf; - if (hlpfile->compressed) - { - hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; - - for (i = 0; i < hlpfile->topic_maplen; i++) - { - ptr = buf + i * hlpfile->tbsize; - - /* I don't know why, it's necessary for printman.hlp */ - if (ptr + 0x44 > end) ptr = end - 0x44; - - newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + hlpfile->tbsize)); - } - - hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, - hlpfile->topic_maplen * sizeof(hlpfile->topic_map[0]) + newsize); - if (!hlpfile->topic_map) return FALSE; - newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); - hlpfile->topic_end = newptr + newsize; - - for (i = 0; i < hlpfile->topic_maplen; i++) - { - ptr = buf + i * hlpfile->tbsize; - if (ptr + 0x44 > end) ptr = end - 0x44; - - hlpfile->topic_map[i] = newptr; - newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + hlpfile->tbsize), newptr); - } - } - else - { - /* basically, we need to copy the TopicBlockSize byte pages - * (removing the first 0x0C) in one single area in memory - */ - hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; - hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, - hlpfile->topic_maplen * (sizeof(hlpfile->topic_map[0]) + hlpfile->dsize)); - if (!hlpfile->topic_map) return FALSE; - newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); - hlpfile->topic_end = newptr + topic_size; - - for (i = 0; i < hlpfile->topic_maplen; i++) - { - hlpfile->topic_map[i] = newptr + i * hlpfile->dsize; - memcpy(hlpfile->topic_map[i], buf + i * hlpfile->tbsize + 0x0C, hlpfile->dsize); - } - } - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_AddPage - */ -static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset) -{ - HLPFILE_PAGE* page; - const BYTE* title; - UINT titlesize, blocksize, datalen; - char* ptr; - HLPFILE_MACRO*macro; - - blocksize = GET_UINT(buf, 0); - datalen = GET_UINT(buf, 0x10); - title = buf + datalen; - if (title > end) {WINE_WARN("page2\n"); return FALSE;}; - - titlesize = GET_UINT(buf, 4); - page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1); - if (!page) return FALSE; - page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE); - - if (titlesize > blocksize - datalen) - { - /* need to decompress */ - if (hlpfile->hasPhrases) - HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize); - else if (hlpfile->hasPhrases40) - HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end); - else - { - WINE_FIXME("Text size is too long, splitting\n"); - titlesize = blocksize - datalen; - memcpy(page->lpszTitle, title, titlesize); - } - } - else - memcpy(page->lpszTitle, title, titlesize); - - page->lpszTitle[titlesize] = '\0'; - - if (hlpfile->first_page) - { - hlpfile->last_page->next = page; - page->prev = hlpfile->last_page; - hlpfile->last_page = page; - } - else - { - hlpfile->first_page = page; - hlpfile->last_page = page; - page->prev = NULL; - } - - page->file = hlpfile; - page->next = NULL; - page->first_macro = NULL; - page->first_link = NULL; - page->wNumber = GET_UINT(buf, 0x21); - page->offset = offset; - page->reference = ref; - - page->browse_bwd = GET_UINT(buf, 0x19); - page->browse_fwd = GET_UINT(buf, 0x1D); - - if (hlpfile->version <= 16) - { - if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF) - page->browse_bwd = 0xFFFFFFFF; - else - page->browse_bwd = hlpfile->TOMap[page->browse_bwd]; - - if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF) - page->browse_fwd = 0xFFFFFFFF; - else - page->browse_fwd = hlpfile->TOMap[page->browse_fwd]; - } - - WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n", - page->wNumber, page->lpszTitle, - page->browse_bwd, page->offset, page->browse_fwd); - - /* now load macros */ - ptr = page->lpszTitle + strlen(page->lpszTitle) + 1; - while (ptr < page->lpszTitle + titlesize) - { - unsigned len = strlen(ptr); - char* macro_str; - - WINE_TRACE("macro: %s\n", ptr); - macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1); - macro->lpszMacro = macro_str = (char*)(macro + 1); - memcpy(macro_str, ptr, len + 1); - /* FIXME: shall we really link macro in reverse order ?? - * may produce strange results when played at page opening - */ - macro->next = page->first_macro; - page->first_macro = macro; - ptr += len + 1; - } - - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_SkipParagraph - */ -static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len) -{ - const BYTE *tmp; - - if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;}; - if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; - - tmp = buf + 0x15; - if (buf[0x14] == 0x20 || buf[0x14] == 0x23) - { - fetch_long(&tmp); - *len = fetch_ushort(&tmp); - } - else *len = end-buf-15; - - return TRUE; -} - -/*********************************************************************** - * - * HLPFILE_DoReadHlpFile - */ -static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath) -{ - BOOL ret; - HFILE hFile; - OFSTRUCT ofs; - BYTE* buf; - DWORD ref = 0x0C; - unsigned index, old_index, offset, len, offs, topicoffset; - - hFile = OpenFile(lpszPath, &ofs, OF_READ); - if (hFile == HFILE_ERROR) return FALSE; - - ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile); - _lclose(hFile); - if (!ret) return FALSE; - - if (!HLPFILE_SystemCommands(hlpfile)) return FALSE; - - if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE; - - /* load phrases support */ - if (!HLPFILE_UncompressLZ77_Phrases(hlpfile)) - HLPFILE_Uncompress_Phrases40(hlpfile); - - if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE; - if (!HLPFILE_ReadFont(hlpfile)) return FALSE; - - buf = hlpfile->topic_map[0]; - old_index = -1; - offs = 0; - do - { - BYTE* end; - - if (hlpfile->version <= 16) - { - index = (ref - 0x0C) / hlpfile->dsize; - offset = (ref - 0x0C) % hlpfile->dsize; - } - else - { - index = (ref - 0x0C) >> 14; - offset = (ref - 0x0C) & 0x3FFF; - } - - if (hlpfile->version <= 16 && index != old_index && old_index != -1) - { - /* we jumped to the next block, adjust pointers */ - ref -= 12; - offset -= 12; - } - - WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset); - - if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} - buf = hlpfile->topic_map[index] + offset; - if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} - end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); - if (index != old_index) {offs = 0; old_index = index;} - - switch (buf[0x14]) - { - case 0x02: - if (hlpfile->version <= 16) - topicoffset = ref + index * 12; - else - topicoffset = index * 0x8000 + offs; - if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE; - break; - - case 0x01: - case 0x20: - case 0x23: - if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE; - offs += len; - break; - - default: - WINE_ERR("buf[0x14] = %x\n", buf[0x14]); - } - - if (hlpfile->version <= 16) - { - ref += GET_UINT(buf, 0xc); - if (GET_UINT(buf, 0xc) == 0) - break; - } - else - ref = GET_UINT(buf, 0xc); - } while (ref != 0xffffffff); - - HLPFILE_GetKeywords(hlpfile); - HLPFILE_GetMap(hlpfile); - if (hlpfile->version <= 16) return TRUE; - return HLPFILE_GetContext(hlpfile); -} - -/*********************************************************************** - * - * HLPFILE_ReadHlpFile - */ -HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath) -{ - HLPFILE* hlpfile; - - for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next) - { - if (!strcmp(lpszPath, hlpfile->lpszPath)) - { - hlpfile->wRefCount++; - return hlpfile; - } - } - - hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(HLPFILE) + lstrlen(lpszPath) + 1); - if (!hlpfile) return 0; - - hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE); - hlpfile->contents_start = 0xFFFFFFFF; - hlpfile->next = first_hlpfile; - hlpfile->wRefCount = 1; - - strcpy(hlpfile->lpszPath, lpszPath); - - first_hlpfile = hlpfile; - if (hlpfile->next) hlpfile->next->prev = hlpfile; - - if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath)) - { - HLPFILE_FreeHlpFile(hlpfile); - hlpfile = 0; - } - - return hlpfile; -} +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * 2002, 2008 Eric Pouech + * 2007 Kirill K. Smirnov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "winhelp.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i) +{ + return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1]; +} + +static inline short GET_SHORT(const BYTE* buffer, unsigned i) +{ + return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1]; +} + +static inline unsigned GET_UINT(const BYTE* buffer, unsigned i) +{ + return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2); +} + +static HLPFILE *first_hlpfile = 0; + + +/************************************************************************** + * HLPFILE_BPTreeSearch + * + * Searches for an element in B+ tree + * + * PARAMS + * buf [I] pointer to the embedded file structured as a B+ tree + * key [I] pointer to data to find + * comp [I] compare function + * + * RETURNS + * Pointer to block identified by key, or NULL if failure. + * + */ +static void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key, + HLPFILE_BPTreeCompare comp) +{ + unsigned magic; + unsigned page_size; + unsigned cur_page; + unsigned level; + BYTE *pages, *ptr, *newptr; + int i, entries; + int ret; + + magic = GET_USHORT(buf, 9); + if (magic != 0x293B) + { + WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); + return NULL; + } + page_size = GET_USHORT(buf, 9+4); + cur_page = GET_USHORT(buf, 9+26); + level = GET_USHORT(buf, 9+32); + pages = buf + 9 + 38; + while (--level > 0) + { + ptr = pages + cur_page*page_size; + entries = GET_SHORT(ptr, 2); + ptr += 6; + for (i = 0; i < entries; i++) + { + if (comp(ptr, key, 0, (void **)&newptr) > 0) break; + ptr = newptr; + } + cur_page = GET_USHORT(ptr-2, 0); + } + ptr = pages + cur_page*page_size; + entries = GET_SHORT(ptr, 2); + ptr += 8; + for (i = 0; i < entries; i++) + { + ret = comp(ptr, key, 1, (void **)&newptr); + if (ret == 0) return ptr; + if (ret > 0) return NULL; + ptr = newptr; + } + return NULL; +} + +/************************************************************************** + * HLPFILE_BPTreeEnum + * + * Enumerates elements in B+ tree. + * + * PARAMS + * buf [I] pointer to the embedded file structured as a B+ tree + * cb [I] compare function + * cookie [IO] cookie for cb function + */ +void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie) +{ + unsigned magic; + unsigned page_size; + unsigned cur_page; + unsigned level; + BYTE *pages, *ptr, *newptr; + int i, entries; + + magic = GET_USHORT(buf, 9); + if (magic != 0x293B) + { + WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic); + return; + } + page_size = GET_USHORT(buf, 9+4); + cur_page = GET_USHORT(buf, 9+26); + level = GET_USHORT(buf, 9+32); + pages = buf + 9 + 38; + while (--level > 0) + { + ptr = pages + cur_page*page_size; + cur_page = GET_USHORT(ptr, 4); + } + while (cur_page != 0xFFFF) + { + ptr = pages + cur_page*page_size; + entries = GET_SHORT(ptr, 2); + ptr += 8; + for (i = 0; i < entries; i++) + { + cb(ptr, (void **)&newptr, cookie); + ptr = newptr; + } + cur_page = GET_USHORT(pages+cur_page*page_size, 6); + } +} + + +/*********************************************************************** + * + * HLPFILE_UncompressedLZ77_Size + */ +static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end) +{ + int i, newsize = 0; + + while (ptr < end) + { + int mask = *ptr++; + for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) + { + if (mask & 1) + { + int code = GET_USHORT(ptr, 0); + int len = 3 + (code >> 12); + newsize += len; + ptr += 2; + } + else newsize++, ptr++; + } + } + + return newsize; +} + +/*********************************************************************** + * + * HLPFILE_UncompressLZ77 + */ +static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr) +{ + int i; + + while (ptr < end) + { + int mask = *ptr++; + for (i = 0; i < 8 && ptr < end; i++, mask >>= 1) + { + if (mask & 1) + { + int code = GET_USHORT(ptr, 0); + int len = 3 + (code >> 12); + int offset = code & 0xfff; + /* + * We must copy byte-by-byte here. We cannot use memcpy nor + * memmove here. Just example: + * a[]={1,2,3,4,5,6,7,8,9,10} + * newptr=a+2; + * offset=1; + * We expect: + * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12} + */ + for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1); + ptr += 2; + } + else *newptr++ = *ptr++; + } + } + + return newptr; +} + +/*********************************************************************** + * + * HLPFILE_Uncompress2 + */ + +static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend) +{ + BYTE *phptr, *phend; + UINT code; + UINT index; + + while (ptr < end && newptr < newend) + { + if (!*ptr || *ptr >= 0x10) + *newptr++ = *ptr++; + else + { + code = 0x100 * ptr[0] + ptr[1]; + index = (code - 0x100) / 2; + + phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index]; + phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1]; + + if (newptr + (phend - phptr) > newend) + { + WINE_FIXME("buffer overflow %p > %p for %lu bytes\n", + newptr, newend, (SIZE_T)(phend - phptr)); + return; + } + memcpy(newptr, phptr, phend - phptr); + newptr += phend - phptr; + if (code & 1) *newptr++ = ' '; + + ptr += 2; + } + } + if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend); +} + +/****************************************************************** + * HLPFILE_Uncompress3 + * + * + */ +static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end, + const BYTE* src, const BYTE* src_end) +{ + unsigned int idx, len; + + for (; src < src_end; src++) + { + if ((*src & 1) == 0) + { + idx = *src / 2; + if (idx > hlpfile->num_phrases) + { + WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); + len = 0; + } + else + { + len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; + if (dst + len <= dst_end) + memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); + } + } + else if ((*src & 0x03) == 0x01) + { + idx = (*src + 1) * 64; + idx += *++src; + if (idx > hlpfile->num_phrases) + { + WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases); + len = 0; + } + else + { + len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx]; + if (dst + len <= dst_end) + memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len); + } + } + else if ((*src & 0x07) == 0x03) + { + len = (*src / 8) + 1; + if (dst + len <= dst_end) + memcpy(dst, src + 1, len); + src += len; + } + else + { + len = (*src / 16) + 1; + if (dst + len <= dst_end) + memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len); + } + dst += len; + } + + if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end); + return TRUE; +} + +/****************************************************************** + * HLPFILE_UncompressRLE + * + * + */ +static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz) +{ + BYTE ch; + BYTE* sdst = dst + dstsz; + + while (src < end) + { + ch = *src++; + if (ch & 0x80) + { + ch &= 0x7F; + if (dst + ch <= sdst) + memcpy(dst, src, ch); + src += ch; + } + else + { + if (dst + ch <= sdst) + memset(dst, (char)*src, ch); + src++; + } + dst += ch; + } + if (dst != sdst) + WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n", + (SIZE_T)(dst - (sdst - dstsz)), dstsz); +} + + +/****************************************************************** + * HLPFILE_PageByOffset + * + * + */ +HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative) +{ + HLPFILE_PAGE* page; + HLPFILE_PAGE* found; + + if (!hlpfile) return 0; + + WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, offset); + + if (offset == 0xFFFFFFFF) return NULL; + page = NULL; + + for (found = NULL, page = hlpfile->first_page; page; page = page->next) + { + if (page->offset <= offset && (!found || found->offset < page->offset)) + { + *relative = offset - page->offset; + found = page; + } + } + if (!found) + WINE_ERR("Page of offset %u not found in file %s\n", + offset, hlpfile->lpszPath); + return found; +} + +/*********************************************************************** + * + * HLPFILE_Contents + */ +static HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative) +{ + HLPFILE_PAGE* page = NULL; + + if (!hlpfile) return NULL; + + page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative); + if (!page) + { + page = hlpfile->first_page; + *relative = 0; + } + return page; +} + +/************************************************************************** + * comp_PageByHash + * + * HLPFILE_BPTreeCompare function for '|CONTEXT' B+ tree file + * + */ +static int comp_PageByHash(void *p, const void *key, + int leaf, void** next) +{ + LONG lKey = (LONG_PTR)key; + LONG lTest = (INT)GET_UINT(p, 0); + + *next = (char *)p+(leaf?8:6); + WINE_TRACE("Comparing '%d' with '%d'\n", lKey, lTest); + if (lTest < lKey) return -1; + if (lTest > lKey) return 1; + return 0; +} + +/*********************************************************************** + * + * HLPFILE_PageByHash + */ +HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative) +{ + BYTE *ptr; + + if (!hlpfile) return NULL; + if (!lHash) return HLPFILE_Contents(hlpfile, relative); + + WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lHash); + + /* For win 3.0 files hash values are really page numbers */ + if (hlpfile->version <= 16) + { + if (lHash >= hlpfile->wTOMapLen) return NULL; + return HLPFILE_PageByOffset(hlpfile, hlpfile->TOMap[lHash], relative); + } + + ptr = HLPFILE_BPTreeSearch(hlpfile->Context, LongToPtr(lHash), comp_PageByHash); + if (!ptr) + { + WINE_ERR("Page of hash %x not found in file %s\n", lHash, hlpfile->lpszPath); + return NULL; + } + + return HLPFILE_PageByOffset(hlpfile, GET_UINT(ptr, 4), relative); +} + +/*********************************************************************** + * + * HLPFILE_PageByMap + */ +HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative) +{ + unsigned int i; + + if (!hlpfile) return 0; + + WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lMap); + + for (i = 0; i < hlpfile->wMapLen; i++) + { + if (hlpfile->Map[i].lMap == lMap) + return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset, relative); + } + + WINE_ERR("Page of Map %x not found in file %s\n", lMap, hlpfile->lpszPath); + return NULL; +} + +/************************************************************************** + * comp_FindSubFile + * + * HLPFILE_BPTreeCompare function for HLPFILE directory. + * + */ +static int comp_FindSubFile(void *p, const void *key, + int leaf, void** next) +{ + *next = (char *)p+strlen(p)+(leaf?5:3); + WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (char *)key); + return strcmp(p, key); +} + +/*********************************************************************** + * + * HLPFILE_FindSubFile + */ +static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend) +{ + BYTE *ptr; + + WINE_TRACE("looking for file '%s'\n", name); + ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4), + name, comp_FindSubFile); + if (!ptr) return FALSE; + *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1); + if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size) + { + WINE_ERR("internal file %s does not fit\n", name); + return FALSE; + } + *subend = *subbuf + GET_UINT(*subbuf, 0); + if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size) + { + WINE_ERR("internal file %s does not fit\n", name); + return FALSE; + } + if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9) + { + WINE_ERR("invalid size provided for internal file %s\n", name); + return FALSE; + } + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_Hash + */ +LONG HLPFILE_Hash(LPCSTR lpszContext) +{ + LONG lHash = 0; + CHAR c; + + while ((c = *lpszContext++)) + { + CHAR x = 0; + if (c >= 'A' && c <= 'Z') x = c - 'A' + 17; + if (c >= 'a' && c <= 'z') x = c - 'a' + 17; + if (c >= '1' && c <= '9') x = c - '0'; + if (c == '0') x = 10; + if (c == '.') x = 12; + if (c == '_') x = 13; + if (x) lHash = lHash * 43 + x; + } + return lHash; +} + +static LONG fetch_long(const BYTE** ptr) +{ + LONG ret; + + if (*(*ptr) & 1) + { + ret = (*(const ULONG*)(*ptr) - 0x80000000) / 2; + (*ptr) += 4; + } + else + { + ret = (*(const USHORT*)(*ptr) - 0x8000) / 2; + (*ptr) += 2; + } + + return ret; +} + +static ULONG fetch_ulong(const BYTE** ptr) +{ + ULONG ret; + + if (*(*ptr) & 1) + { + ret = *(const ULONG*)(*ptr) / 2; + (*ptr) += 4; + } + else + { + ret = *(const USHORT*)(*ptr) / 2; + (*ptr) += 2; + } + return ret; +} + +static short fetch_short(const BYTE** ptr) +{ + short ret; + + if (*(*ptr) & 1) + { + ret = (*(const unsigned short*)(*ptr) - 0x8000) / 2; + (*ptr) += 2; + } + else + { + ret = (*(const unsigned char*)(*ptr) - 0x80) / 2; + (*ptr)++; + } + return ret; +} + +static unsigned short fetch_ushort(const BYTE** ptr) +{ + unsigned short ret; + + if (*(*ptr) & 1) + { + ret = *(const unsigned short*)(*ptr) / 2; + (*ptr) += 2; + } + else + { + ret = *(const unsigned char*)(*ptr) / 2; + (*ptr)++; + } + return ret; +} + +/****************************************************************** + * HLPFILE_DecompressGfx + * + * Decompress the data part of a bitmap or a metafile + */ +static const BYTE* HLPFILE_DecompressGfx(const BYTE* src, unsigned csz, unsigned sz, BYTE packing, + BYTE** alloc) +{ + const BYTE* dst; + BYTE* tmp; + unsigned sz77; + + WINE_TRACE("Unpacking (%d) from %u bytes to %u bytes\n", packing, csz, sz); + + switch (packing) + { + case 0: /* uncompressed */ + if (sz != csz) + WINE_WARN("Bogus gfx sizes (uncompressed): %u / %u\n", sz, csz); + dst = src; + *alloc = NULL; + break; + case 1: /* RunLen */ + dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); + if (!dst) return NULL; + HLPFILE_UncompressRLE(src, src + csz, *alloc, sz); + break; + case 2: /* LZ77 */ + sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); + dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz77); + if (!dst) return NULL; + HLPFILE_UncompressLZ77(src, src + csz, *alloc); + if (sz77 != sz) + WINE_WARN("Bogus gfx sizes (LZ77): %u / %u\n", sz77, sz); + break; + case 3: /* LZ77 then RLE */ + sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz); + tmp = HeapAlloc(GetProcessHeap(), 0, sz77); + if (!tmp) return FALSE; + HLPFILE_UncompressLZ77(src, src + csz, tmp); + dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz); + if (!dst) + { + HeapFree(GetProcessHeap(), 0, tmp); + return FALSE; + } + HLPFILE_UncompressRLE(tmp, tmp + sz77, *alloc, sz); + HeapFree(GetProcessHeap(), 0, tmp); + break; + default: + WINE_FIXME("Unsupported packing %u\n", packing); + return NULL; + } + return dst; +} + +static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz) +{ + if (rd->ptr + sz >= rd->data + rd->allocated) + { + char* new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2); + if (!new) return FALSE; + rd->ptr = new + (rd->ptr - rd->data); + rd->data = new; + } + memcpy(rd->ptr, str, sz); + rd->ptr += sz; + + return TRUE; +} + +static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str) +{ + if (*str == '\\' || *str == '{') rd->in_text = FALSE; + else if (*str == '}') rd->in_text = TRUE; + return HLPFILE_RtfAddRawString(rd, str, strlen(str)); +} + +static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str) +{ + const char* p; + const char* last; + const char* replace; + unsigned rlen; + + if (!rd->in_text) + { + if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; + rd->in_text = TRUE; + } + for (last = p = str; *p; p++) + { + if (*p < 0) /* escape non ASCII chars */ + { + static char xx[8]; + rlen = sprintf(xx, "\\'%x", *(const BYTE*)p); + replace = xx; + } + else switch (*p) + { + case '{': rlen = 2; replace = "\\{"; break; + case '}': rlen = 2; replace = "\\}"; break; + case '\\': rlen = 2; replace = "\\\\"; break; + default: continue; + } + if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) || + !HLPFILE_RtfAddRawString(rd, replace, rlen)) return FALSE; + last = p + 1; + } + return HLPFILE_RtfAddRawString(rd, last, p - last); +} + +/****************************************************************** + * RtfAddHexBytes + * + */ +static BOOL HLPFILE_RtfAddHexBytes(struct RtfData* rd, const void* _ptr, unsigned sz) +{ + char tmp[512]; + unsigned i, step; + const BYTE* ptr = _ptr; + static const char* _2hex = "0123456789abcdef"; + + if (!rd->in_text) + { + if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE; + rd->in_text = TRUE; + } + for (; sz; sz -= step) + { + step = min(256, sz); + for (i = 0; i < step; i++) + { + tmp[2 * i + 0] = _2hex[*ptr >> 4]; + tmp[2 * i + 1] = _2hex[*ptr++ & 0xF]; + } + if (!HLPFILE_RtfAddRawString(rd, tmp, 2 * step)) return FALSE; + } + return TRUE; +} + +/****************************************************************** + * HLPFILE_RtfAddTransparentBitmap + * + * We'll transform a transparent bitmap into an metafile that + * we then transform into RTF + */ +static BOOL HLPFILE_RtfAddTransparentBitmap(struct RtfData* rd, const BITMAPINFO* bi, + const void* pict, unsigned nc) +{ + HDC hdc, hdcMask, hdcMem, hdcEMF; + HBITMAP hbm, hbmMask, hbmOldMask, hbmOldMem; + HENHMETAFILE hEMF; + BOOL ret = FALSE; + void* data; + UINT sz; + + hbm = CreateDIBitmap(hdc = GetDC(0), &bi->bmiHeader, + CBM_INIT, pict, bi, DIB_RGB_COLORS); + + hdcMem = CreateCompatibleDC(hdc); + hbmOldMem = SelectObject(hdcMem, hbm); + + /* create the mask bitmap from the main bitmap */ + hdcMask = CreateCompatibleDC(hdc); + hbmMask = CreateBitmap(bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, 1, 1, NULL); + hbmOldMask = SelectObject(hdcMask, hbmMask); + SetBkColor(hdcMem, + RGB(bi->bmiColors[nc - 1].rgbRed, + bi->bmiColors[nc - 1].rgbGreen, + bi->bmiColors[nc - 1].rgbBlue)); + BitBlt(hdcMask, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY); + + /* sets to RGB(0,0,0) the transparent bits in main bitmap */ + SetBkColor(hdcMem, RGB(0,0,0)); + SetTextColor(hdcMem, RGB(255,255,255)); + BitBlt(hdcMem, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMask, 0, 0, SRCAND); + + SelectObject(hdcMask, hbmOldMask); + DeleteDC(hdcMask); + + SelectObject(hdcMem, hbmOldMem); + DeleteDC(hdcMem); + + /* we create the bitmap on the fly */ + hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL); + hdcMem = CreateCompatibleDC(hdcEMF); + + /* sets to RGB(0,0,0) the transparent bits in final bitmap */ + hbmOldMem = SelectObject(hdcMem, hbmMask); + SetBkColor(hdcEMF, RGB(255, 255, 255)); + SetTextColor(hdcEMF, RGB(0, 0, 0)); + BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCAND); + + /* and copy the remaining bits of main bitmap */ + SelectObject(hdcMem, hbm); + BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCPAINT); + SelectObject(hdcMem, hbmOldMem); + DeleteDC(hdcMem); + + /* do the cleanup */ + ReleaseDC(0, hdc); + DeleteObject(hbmMask); + DeleteObject(hbm); + + hEMF = CloseEnhMetaFile(hdcEMF); + + /* generate rtf stream */ + sz = GetEnhMetaFileBits(hEMF, 0, NULL); + if (sz && (data = HeapAlloc(GetProcessHeap(), 0, sz))) + { + if (sz == GetEnhMetaFileBits(hEMF, sz, data)) + { + ret = HLPFILE_RtfAddControl(rd, "{\\pict\\emfblip") && + HLPFILE_RtfAddHexBytes(rd, data, sz) && + HLPFILE_RtfAddControl(rd, "}"); + } + HeapFree(GetProcessHeap(), 0, data); + } + DeleteEnhMetaFile(hEMF); + + return ret; +} + +/****************************************************************** + * HLPFILE_RtfAddBitmap + * + */ +static BOOL HLPFILE_RtfAddBitmap(struct RtfData* rd, const BYTE* beg, BYTE type, BYTE pack) +{ + const BYTE* ptr; + const BYTE* pict_beg; + BYTE* alloc = NULL; + BITMAPINFO* bi; + ULONG off, csz; + unsigned nc = 0; + BOOL clrImportant = FALSE; + BOOL ret = FALSE; + char tmp[256]; + + bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi)); + if (!bi) return FALSE; + + ptr = beg + 2; /* for type and pack */ + + bi->bmiHeader.biSize = sizeof(bi->bmiHeader); + bi->bmiHeader.biXPelsPerMeter = fetch_ulong(&ptr); + bi->bmiHeader.biYPelsPerMeter = fetch_ulong(&ptr); + bi->bmiHeader.biPlanes = fetch_ushort(&ptr); + bi->bmiHeader.biBitCount = fetch_ushort(&ptr); + bi->bmiHeader.biWidth = fetch_ulong(&ptr); + bi->bmiHeader.biHeight = fetch_ulong(&ptr); + bi->bmiHeader.biClrUsed = fetch_ulong(&ptr); + clrImportant = fetch_ulong(&ptr); + bi->bmiHeader.biClrImportant = (clrImportant > 1) ? clrImportant : 0; + bi->bmiHeader.biCompression = BI_RGB; + if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount); + if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes); + bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight; + WINE_TRACE("planes=%d bc=%d size=(%d,%d)\n", + bi->bmiHeader.biPlanes, bi->bmiHeader.biBitCount, + bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); + + csz = fetch_ulong(&ptr); + fetch_ulong(&ptr); /* hotspot size */ + + off = GET_UINT(ptr, 0); ptr += 4; + /* GET_UINT(ptr, 0); hotspot offset */ ptr += 4; + + /* now read palette info */ + if (type == 0x06) + { + unsigned i; + + nc = bi->bmiHeader.biClrUsed; + /* not quite right, especially for bitfields type of compression */ + if (!nc && bi->bmiHeader.biBitCount <= 8) + nc = 1 << bi->bmiHeader.biBitCount; + + bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD)); + if (!bi) return FALSE; + for (i = 0; i < nc; i++) + { + bi->bmiColors[i].rgbBlue = ptr[0]; + bi->bmiColors[i].rgbGreen = ptr[1]; + bi->bmiColors[i].rgbRed = ptr[2]; + bi->bmiColors[i].rgbReserved = 0; + ptr += 4; + } + } + pict_beg = HLPFILE_DecompressGfx(beg + off, csz, bi->bmiHeader.biSizeImage, pack, &alloc); + + if (clrImportant == 1 && nc > 0) + { + ret = HLPFILE_RtfAddTransparentBitmap(rd, bi, pict_beg, nc); + goto done; + } + if (!HLPFILE_RtfAddControl(rd, "{\\pict")) goto done; + if (type == 0x06) + { + sprintf(tmp, "\\dibitmap0\\picw%d\\pich%d", + bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + if (!HLPFILE_RtfAddHexBytes(rd, bi, sizeof(*bi) + nc * sizeof(RGBQUAD))) goto done; + } + else + { + sprintf(tmp, "\\wbitmap0\\wbmbitspixel%d\\wbmplanes%d\\picw%d\\pich%d", + bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes, + bi->bmiHeader.biWidth, bi->bmiHeader.biHeight); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (!HLPFILE_RtfAddHexBytes(rd, pict_beg, bi->bmiHeader.biSizeImage)) goto done; + if (!HLPFILE_RtfAddControl(rd, "}")) goto done; + + ret = TRUE; +done: + HeapFree(GetProcessHeap(), 0, bi); + HeapFree(GetProcessHeap(), 0, alloc); + + return ret; +} + +/****************************************************************** + * HLPFILE_RtfAddMetaFile + * + */ +static BOOL HLPFILE_RtfAddMetaFile(struct RtfData* rd, const BYTE* beg, BYTE pack) +{ + ULONG size, csize, off, hsoff; + const BYTE* ptr; + const BYTE* bits; + BYTE* alloc = NULL; + char tmp[256]; + unsigned mm; + BOOL ret; + + WINE_TRACE("Loading metafile\n"); + + ptr = beg + 2; /* for type and pack */ + + mm = fetch_ushort(&ptr); /* mapping mode */ + sprintf(tmp, "{\\pict\\wmetafile%d\\picw%d\\pich%d", + mm, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2)); + if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; + ptr += 4; + + size = fetch_ulong(&ptr); /* decompressed size */ + csize = fetch_ulong(&ptr); /* compressed size */ + fetch_ulong(&ptr); /* hotspot size */ + off = GET_UINT(ptr, 0); + hsoff = GET_UINT(ptr, 4); + ptr += 8; + + WINE_TRACE("sz=%u csz=%u offs=%u/%u,%u\n", + size, csize, off, (ULONG)(ptr - beg), hsoff); + + bits = HLPFILE_DecompressGfx(beg + off, csize, size, pack, &alloc); + if (!bits) return FALSE; + + ret = HLPFILE_RtfAddHexBytes(rd, bits, size) && + HLPFILE_RtfAddControl(rd, "}"); + + HeapFree(GetProcessHeap(), 0, alloc); + + return ret; +} + +/****************************************************************** + * HLPFILE_RtfAddGfxByAddr + * + */ +static BOOL HLPFILE_RtfAddGfxByAddr(struct RtfData* rd, HLPFILE *hlpfile, + const BYTE* ref, ULONG size) +{ + unsigned i, numpict; + + numpict = GET_USHORT(ref, 2); + WINE_TRACE("Got picture magic=%04x #=%d\n", GET_USHORT(ref, 0), numpict); + + for (i = 0; i < numpict; i++) + { + const BYTE* beg; + const BYTE* ptr; + BYTE type, pack; + + WINE_TRACE("Offset[%d] = %x\n", i, GET_UINT(ref, (1 + i) * 4)); + beg = ptr = ref + GET_UINT(ref, (1 + i) * 4); + + type = *ptr++; + pack = *ptr++; + + switch (type) + { + case 5: /* device dependent bmp */ + case 6: /* device independent bmp */ + HLPFILE_RtfAddBitmap(rd, beg, type, pack); + break; + case 8: + HLPFILE_RtfAddMetaFile(rd, beg, pack); + break; + default: WINE_FIXME("Unknown type %u\n", type); return FALSE; + } + + /* FIXME: hotspots */ + + /* FIXME: implement support for multiple picture format */ + if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n"); + break; + } + return TRUE; +} + +/****************************************************************** + * HLPFILE_RtfAddGfxByIndex + * + * + */ +static BOOL HLPFILE_RtfAddGfxByIndex(struct RtfData* rd, HLPFILE *hlpfile, + unsigned index) +{ + char tmp[16]; + BYTE *ref, *end; + + WINE_TRACE("Loading picture #%d\n", index); + + sprintf(tmp, "|bm%u", index); + + if (!HLPFILE_FindSubFile(hlpfile, tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;} + + ref += 9; + return HLPFILE_RtfAddGfxByAddr(rd, hlpfile, ref, end - ref); +} + +/****************************************************************** + * HLPFILE_AllocLink + * + * + */ +static HLPFILE_LINK* HLPFILE_AllocLink(struct RtfData* rd, int cookie, + const char* str, unsigned len, LONG hash, + unsigned clrChange, unsigned wnd) +{ + HLPFILE_LINK* link; + char* link_str; + + /* FIXME: should build a string table for the attributes.link.lpszPath + * they are reallocated for each link + */ + if (len == -1) len = strlen(str); + link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + len + 1); + if (!link) return NULL; + + link->cookie = cookie; + link->string = link_str = (char*)(link + 1); + memcpy(link_str, str, len); + link_str[len] = '\0'; + link->hash = hash; + link->bClrChange = clrChange ? 1 : 0; + link->window = wnd; + link->next = rd->first_link; + rd->first_link = link; + link->cpMin = rd->char_pos; + link->cpMax = 0; + rd->force_color = clrChange; + if (rd->current_link) WINE_FIXME("Pending link\n"); + rd->current_link = link; + + WINE_TRACE("Link[%d] to %s@%08x:%d\n", + link->cookie, link->string, link->hash, link->window); + return link; +} + +static unsigned HLPFILE_HalfPointsToTwips(unsigned pts) +{ + static unsigned logPxY; + if (!logPxY) + { + HDC hdc = GetDC(NULL); + logPxY = GetDeviceCaps(hdc, LOGPIXELSY); + ReleaseDC(NULL, hdc); + } + return MulDiv(pts, 72 * 10, logPxY); +} + +/*********************************************************************** + * + * HLPFILE_BrowseParagraph + */ +static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd, + BYTE *buf, BYTE* end, unsigned* parlen) +{ + UINT textsize; + const BYTE *format, *format_end; + char *text, *text_base, *text_end; + LONG size, blocksize, datalen; + unsigned short bits; + unsigned nc, ncol = 1; + short table_width; + BOOL in_table = FALSE; + char tmp[256]; + BOOL ret = FALSE; + + if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; + + *parlen = 0; + blocksize = GET_UINT(buf, 0); + size = GET_UINT(buf, 0x4); + datalen = GET_UINT(buf, 0x10); + text = text_base = HeapAlloc(GetProcessHeap(), 0, size); + if (!text) return FALSE; + if (size > blocksize - datalen) + { + /* need to decompress */ + if (page->file->hasPhrases) + HLPFILE_Uncompress2(page->file, buf + datalen, end, (BYTE*)text, (BYTE*)text + size); + else if (page->file->hasPhrases40) + HLPFILE_Uncompress3(page->file, text, text + size, buf + datalen, end); + else + { + WINE_FIXME("Text size is too long, splitting\n"); + size = blocksize - datalen; + memcpy(text, buf + datalen, size); + } + } + else + memcpy(text, buf + datalen, size); + + text_end = text + size; + + format = buf + 0x15; + format_end = buf + GET_UINT(buf, 0x10); + + if (buf[0x14] == 0x20 || buf[0x14] == 0x23) + { + fetch_long(&format); + *parlen = fetch_ushort(&format); + } + + if (buf[0x14] == 0x23) + { + char type; + + in_table = TRUE; + ncol = *format++; + + if (!HLPFILE_RtfAddControl(rd, "\\trowd")) goto done; + type = *format++; + if (type == 0 || type == 2) + { + table_width = GET_SHORT(format, 0); + format += 2; + } + else + table_width = 32767; + WINE_TRACE("New table: cols=%d type=%x width=%d\n", + ncol, type, table_width); + if (ncol > 1) + { + int pos; + sprintf(tmp, "\\trgaph%d\\trleft%d", + HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6), table_width, 32767)), + HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + pos = HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6) / 2, table_width, 32767)); + for (nc = 0; nc < ncol; nc++) + { + WINE_TRACE("column(%d/%d) gap=%d width=%d\n", + nc, ncol, GET_SHORT(format, nc*4), + GET_SHORT(format, nc*4+2)); + pos += GET_SHORT(format, nc * 4) + GET_SHORT(format, nc * 4 + 2); + sprintf(tmp, "\\cellx%d", + HLPFILE_HalfPointsToTwips(MulDiv(pos, table_width, 32767))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + } + else + { + WINE_TRACE("column(0/%d) gap=%d width=%d\n", + ncol, GET_SHORT(format, 0), GET_SHORT(format, 2)); + sprintf(tmp, "\\trleft%d\\cellx%d ", + HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767)), + HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0) + GET_SHORT(format, 2), + table_width, 32767))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + format += ncol * 4; + } + + for (nc = 0; nc < ncol; /**/) + { + WINE_TRACE("looking for format at offset %lu in column %d\n", (SIZE_T)(format - (buf + 0x15)), nc); + if (!HLPFILE_RtfAddControl(rd, "\\pard")) goto done; + if (in_table) + { + nc = GET_SHORT(format, 0); + if (nc == -1) break; + format += 5; + if (!HLPFILE_RtfAddControl(rd, "\\intbl")) goto done; + } + else nc++; + if (buf[0x14] == 0x01) + format += 6; + else + format += 4; + bits = GET_USHORT(format, 0); format += 2; + if (bits & 0x0001) fetch_long(&format); + if (bits & 0x0002) + { + sprintf(tmp, "\\sb%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0004) + { + sprintf(tmp, "\\sa%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0008) + { + sprintf(tmp, "\\sl%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0010) + { + sprintf(tmp, "\\li%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0020) + { + sprintf(tmp, "\\ri%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0040) + { + sprintf(tmp, "\\fi%d", HLPFILE_HalfPointsToTwips(fetch_short(&format))); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + if (bits & 0x0100) + { + BYTE brdr = *format++; + short w; + + if (brdr & 0x01 && !HLPFILE_RtfAddControl(rd, "\\box")) goto done; + if (brdr & 0x02 && !HLPFILE_RtfAddControl(rd, "\\brdrt")) goto done; + if (brdr & 0x04 && !HLPFILE_RtfAddControl(rd, "\\brdrl")) goto done; + if (brdr & 0x08 && !HLPFILE_RtfAddControl(rd, "\\brdrb")) goto done; + if (brdr & 0x10 && !HLPFILE_RtfAddControl(rd, "\\brdrr")) goto done; + if (brdr & 0x20 && !HLPFILE_RtfAddControl(rd, "\\brdrth")) goto done; + if (!(brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrs")) goto done; + if (brdr & 0x40 && !HLPFILE_RtfAddControl(rd, "\\brdrdb")) goto done; + /* 0x80: unknown */ + + w = GET_SHORT(format, 0); format += 2; + if (w) + { + sprintf(tmp, "\\brdrw%d", HLPFILE_HalfPointsToTwips(w)); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + } + if (bits & 0x0200) + { + int i, ntab = fetch_short(&format); + unsigned tab, ts; + const char* kind; + + for (i = 0; i < ntab; i++) + { + tab = fetch_ushort(&format); + ts = (tab & 0x4000) ? fetch_ushort(&format) : 0 /* left */; + switch (ts) + { + default: WINE_FIXME("Unknown tab style %x\n", ts); + /* fall through */ + case 0: kind = ""; break; + case 1: kind = "\\tqr"; break; + case 2: kind = "\\tqc"; break; + } + /* FIXME: do kind */ + sprintf(tmp, "%s\\tx%d", + kind, HLPFILE_HalfPointsToTwips(tab & 0x3FFF)); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + } + switch (bits & 0xc00) + { + default: WINE_FIXME("Unsupported alignment 0xC00\n"); break; + case 0: if (!HLPFILE_RtfAddControl(rd, "\\ql")) goto done; break; + case 0x400: if (!HLPFILE_RtfAddControl(rd, "\\qr")) goto done; break; + case 0x800: if (!HLPFILE_RtfAddControl(rd, "\\qc")) goto done; break; + } + + /* 0x1000 doesn't need space */ + if ((bits & 0x1000) && !HLPFILE_RtfAddControl(rd, "\\keep")) goto done; + if ((bits & 0xE080) != 0) + WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits); + + while (text < text_end && format < format_end) + { + WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", wine_dbgstr_a(text), text, text_end, format, format_end); + textsize = strlen(text); + if (textsize) + { + if (rd->force_color) + { + if ((rd->current_link->cookie == hlp_link_popup) ? + !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") : + !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done; + } + if (!HLPFILE_RtfAddText(rd, text)) goto done; + if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done; + rd->char_pos += textsize; + } + /* else: null text, keep on storing attributes */ + text += textsize + 1; + + if (*format == 0xff) + { + format++; + break; + } + + WINE_TRACE("format=%02x\n", *format); + switch (*format) + { + case 0x20: + WINE_FIXME("NIY20\n"); + format += 5; + break; + + case 0x21: + WINE_FIXME("NIY21\n"); + format += 3; + break; + + case 0x80: + { + unsigned font = GET_USHORT(format, 1); + unsigned fs; + + WINE_TRACE("Changing font to %d\n", font); + format += 3; + /* Font size in hlpfile is given in the same units as + rtf control word \fs uses (half-points). */ + switch (rd->font_scale) + { + case 0: fs = page->file->fonts[font].LogFont.lfHeight - 4; break; + default: + case 1: fs = page->file->fonts[font].LogFont.lfHeight; break; + case 2: fs = page->file->fonts[font].LogFont.lfHeight + 4; break; + } + /* FIXME: missing at least colors, also bold attribute looses information */ + + sprintf(tmp, "\\f%d\\cf%d\\fs%d%s%s%s%s", + font, font + 2, fs, + page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0", + page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0", + page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0", + page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0"); + if (!HLPFILE_RtfAddControl(rd, tmp)) goto done; + } + break; + + case 0x81: + if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done; + format += 1; + rd->char_pos++; + break; + + case 0x82: + if (in_table) + { + if (format[1] != 0xFF) + { + if (!HLPFILE_RtfAddControl(rd, "\\par\\intbl")) goto done; + } + else + { + if (!HLPFILE_RtfAddControl(rd, "\\cell\\pard\\intbl")) goto done; + } + } + else if (!HLPFILE_RtfAddControl(rd, "\\par")) goto done; + format += 1; + rd->char_pos++; + break; + + case 0x83: + if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done; + format += 1; + rd->char_pos++; + break; + +#if 0 + case 0x84: + format += 3; + break; +#endif + + case 0x86: + case 0x87: + case 0x88: + { + BYTE type = format[1]; + LONG size; + + /* FIXME: we don't use 'BYTE pos = (*format - 0x86);' for the image position */ + format += 2; + size = fetch_long(&format); + + switch (type) + { + case 0x22: + fetch_ushort(&format); /* hot spot */ + /* fall thru */ + case 0x03: + switch (GET_SHORT(format, 0)) + { + case 0: + HLPFILE_RtfAddGfxByIndex(rd, page->file, GET_SHORT(format, 2)); + rd->char_pos++; + break; + case 1: + WINE_FIXME("does it work ??? %x<%u>#%u\n", + GET_SHORT(format, 0), + size, GET_SHORT(format, 2)); + HLPFILE_RtfAddGfxByAddr(rd, page->file, format + 2, size - 4); + rd->char_pos++; + break; + default: + WINE_FIXME("??? %u\n", GET_SHORT(format, 0)); + break; + } + break; + case 0x05: + WINE_FIXME("Got an embedded element %s\n", format + 6); + break; + default: + WINE_FIXME("Got a type %d picture\n", type); + break; + } + format += size; + } + break; + + case 0x89: + format += 1; + if (!rd->current_link) + WINE_FIXME("No existing link\n"); + rd->current_link->cpMax = rd->char_pos; + rd->current_link = NULL; + rd->force_color = FALSE; + break; + + case 0x8B: + if (!HLPFILE_RtfAddControl(rd, "\\~")) goto done; + format += 1; + rd->char_pos++; + break; + + case 0x8C: + if (!HLPFILE_RtfAddControl(rd, "\\_")) goto done; + /* FIXME: it could be that hypen is also in input stream !! */ + format += 1; + rd->char_pos++; + break; + +#if 0 + case 0xA9: + format += 2; + break; +#endif + + case 0xC8: + case 0xCC: + WINE_TRACE("macro => %s\n", format + 3); + HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3, + GET_USHORT(format, 1), 0, !(*format & 4), -1); + format += 3 + GET_USHORT(format, 1); + break; + + case 0xE0: + case 0xE1: + WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1)); + HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, + page->file->lpszPath, -1, GET_UINT(format, 1), 1, -1); + + + format += 5; + break; + + case 0xE2: + case 0xE3: + case 0xE6: + case 0xE7: + HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, + page->file->lpszPath, -1, GET_UINT(format, 1), + !(*format & 4), -1); + format += 5; + break; + + case 0xEA: + case 0xEB: + case 0xEE: + case 0xEF: + { + char* ptr = (char*) format + 8; + BYTE type = format[3]; + int wnd = -1; + + switch (type) + { + case 1: + wnd = *ptr; + /* fall through */ + case 0: + ptr = page->file->lpszPath; + break; + case 6: + for (wnd = page->file->numWindows - 1; wnd >= 0; wnd--) + { + if (!strcmp(ptr, page->file->windows[wnd].name)) break; + } + if (wnd == -1) + WINE_WARN("Couldn't find window info for %s\n", ptr); + ptr += strlen(ptr) + 1; + /* fall through */ + case 4: + break; + default: + WINE_WARN("Unknown link type %d\n", type); + break; + } + HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup, + ptr, -1, GET_UINT(format, 4), !(*format & 4), wnd); + } + format += 3 + GET_USHORT(format, 1); + break; + + default: + WINE_WARN("format %02x\n", *format); + format++; + } + } + } + if (in_table) + { + if (!HLPFILE_RtfAddControl(rd, "\\row\\par\\pard\\plain")) goto done; + rd->char_pos += 2; + } + ret = TRUE; +done: + + HeapFree(GetProcessHeap(), 0, text_base); + return ret; +} + +/****************************************************************** + * HLPFILE_BrowsePage + * + */ +BOOL HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd, + unsigned font_scale, unsigned relative) +{ + HLPFILE *hlpfile = page->file; + BYTE *buf, *end; + DWORD ref = page->reference; + unsigned index, old_index = -1, offset, count = 0, offs = 0; + unsigned cpg, parlen; + char tmp[1024]; + const char* ck = NULL; + + rd->in_text = TRUE; + rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768); + rd->char_pos = 0; + rd->first_link = rd->current_link = NULL; + rd->force_color = FALSE; + rd->font_scale = font_scale; + rd->relative = relative; + rd->char_pos_rel = 0; + + switch (hlpfile->charset) + { + case DEFAULT_CHARSET: + case ANSI_CHARSET: cpg = 1252; break; + case SHIFTJIS_CHARSET: cpg = 932; break; + case HANGEUL_CHARSET: cpg = 949; break; + case GB2312_CHARSET: cpg = 936; break; + case CHINESEBIG5_CHARSET: cpg = 950; break; + case GREEK_CHARSET: cpg = 1253; break; + case TURKISH_CHARSET: cpg = 1254; break; + case HEBREW_CHARSET: cpg = 1255; break; + case ARABIC_CHARSET: cpg = 1256; break; + case BALTIC_CHARSET: cpg = 1257; break; + case VIETNAMESE_CHARSET: cpg = 1258; break; + case RUSSIAN_CHARSET: cpg = 1251; break; + case EE_CHARSET: cpg = 1250; break; + case THAI_CHARSET: cpg = 874; break; + case JOHAB_CHARSET: cpg = 1361; break; + case MAC_CHARSET: ck = "mac"; break; + default: + WINE_FIXME("Unsupported charset %u\n", hlpfile->charset); + cpg = 1252; + } + if (ck) + { + sprintf(tmp, "{\\rtf1\\%s\\deff0", ck); + if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; + } + else + { + sprintf(tmp, "{\\rtf1\\ansi\\ansicpg%d\\deff0", cpg); + if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; + } + + /* generate font table */ + if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE; + for (index = 0; index < hlpfile->numFonts; index++) + { + const char* family; + switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0) + { + case FF_MODERN: family = "modern"; break; + case FF_ROMAN: family = "roman"; break; + case FF_SWISS: family = "swiss"; break; + case FF_SCRIPT: family = "script"; break; + case FF_DECORATIVE: family = "decor"; break; + default: family = "nil"; break; + } + sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset%d %s;}", + index, family, + hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F, + hlpfile->fonts[index].LogFont.lfCharSet, + hlpfile->fonts[index].LogFont.lfFaceName); + if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; + } + if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; + /* generate color table */ + if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE; + for (index = 0; index < hlpfile->numFonts; index++) + { + const char* family; + switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0) + { + case FF_MODERN: family = "modern"; break; + case FF_ROMAN: family = "roman"; break; + case FF_SWISS: family = "swiss"; break; + case FF_SCRIPT: family = "script"; break; + case FF_DECORATIVE: family = "decor"; break; + default: family = "nil"; break; + } + sprintf(tmp, "\\red%d\\green%d\\blue%d;", + GetRValue(hlpfile->fonts[index].color), + GetGValue(hlpfile->fonts[index].color), + GetBValue(hlpfile->fonts[index].color)); + if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE; + } + if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE; + + do + { + if (hlpfile->version <= 16) + { + index = (ref - 0x0C) / hlpfile->dsize; + offset = (ref - 0x0C) % hlpfile->dsize; + } + else + { + index = (ref - 0x0C) >> 14; + offset = (ref - 0x0C) & 0x3FFF; + } + + if (hlpfile->version <= 16 && index != old_index && old_index != -1) + { + /* we jumped to the next block, adjust pointers */ + ref -= 12; + offset -= 12; + } + + if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} + buf = hlpfile->topic_map[index] + offset; + if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} + end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); + if (index != old_index) {offs = 0; old_index = index;} + + switch (buf[0x14]) + { + case 0x02: + if (count++) goto done; + break; + case 0x01: + case 0x20: + case 0x23: + if (!HLPFILE_BrowseParagraph(page, rd, buf, end, &parlen)) return FALSE; + if (relative > index * 0x8000 + offs) + rd->char_pos_rel = rd->char_pos; + offs += parlen; + break; + default: + WINE_ERR("buf[0x14] = %x\n", buf[0x14]); + } + if (hlpfile->version <= 16) + { + ref += GET_UINT(buf, 0xc); + if (GET_UINT(buf, 0xc) == 0) + break; + } + else + ref = GET_UINT(buf, 0xc); + } while (ref != 0xffffffff); +done: + page->first_link = rd->first_link; + return HLPFILE_RtfAddControl(rd, "}"); +} + +/****************************************************************** + * HLPFILE_ReadFont + * + * + */ +static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile) +{ + BYTE *ref, *end; + unsigned i, len, idx; + unsigned face_num, dscr_num, face_offset, dscr_offset; + BYTE flag, family; + + if (!HLPFILE_FindSubFile(hlpfile, "|FONT", &ref, &end)) + { + WINE_WARN("no subfile FONT\n"); + hlpfile->numFonts = 0; + hlpfile->fonts = NULL; + return FALSE; + } + + ref += 9; + + face_num = GET_USHORT(ref, 0); + dscr_num = GET_USHORT(ref, 2); + face_offset = GET_USHORT(ref, 4); + dscr_offset = GET_USHORT(ref, 6); + + WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n", + face_num, face_offset, dscr_num, dscr_offset); + + hlpfile->numFonts = dscr_num; + hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num); + + len = (dscr_offset - face_offset) / face_num; +/* EPP for (i = face_offset; i < dscr_offset; i += len) */ +/* EPP WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */ + for (i = 0; i < dscr_num; i++) + { + flag = ref[dscr_offset + i * 11 + 0]; + family = ref[dscr_offset + i * 11 + 2]; + + hlpfile->fonts[i].LogFont.lfHeight = ref[dscr_offset + i * 11 + 1]; + hlpfile->fonts[i].LogFont.lfWidth = 0; + hlpfile->fonts[i].LogFont.lfEscapement = 0; + hlpfile->fonts[i].LogFont.lfOrientation = 0; + hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400; + hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) ? TRUE : FALSE; + hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) ? TRUE : FALSE; + hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) ? TRUE : FALSE; + hlpfile->fonts[i].LogFont.lfCharSet = hlpfile->charset; + hlpfile->fonts[i].LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS; + hlpfile->fonts[i].LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS; + hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY; + hlpfile->fonts[i].LogFont.lfPitchAndFamily = DEFAULT_PITCH; + + switch (family) + { + case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN; break; + case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN; break; + case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS; break; + case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT; break; + case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break; + default: WINE_FIXME("Unknown family %u\n", family); + } + idx = GET_USHORT(ref, dscr_offset + i * 11 + 3); + + if (idx < face_num) + { + memcpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1)); + hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1)] = '\0'; + } + else + { + WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num); + strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv"); + } + hlpfile->fonts[i].hFont = 0; + hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5], + ref[dscr_offset + i * 11 + 6], + ref[dscr_offset + i * 11 + 7]); +#define X(b,s) ((flag & (1 << b)) ? "-"s: "") + WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08x\n", + i, flag, + X(0, "bold"), + X(1, "italic"), + X(2, "underline"), + X(3, "strikeOut"), + X(4, "dblUnderline"), + X(5, "smallCaps"), + ref[dscr_offset + i * 11 + 1], + family, + hlpfile->fonts[i].LogFont.lfFaceName, idx, + GET_UINT(ref, dscr_offset + i * 11 + 5) & 0x00FFFFFF); + } + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_ReadFileToBuffer + */ +static BOOL HLPFILE_ReadFileToBuffer(HLPFILE* hlpfile, HFILE hFile) +{ + BYTE header[16], dummy[1]; + + if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;}; + + /* sanity checks */ + if (GET_UINT(header, 0) != 0x00035F3F) + {WINE_WARN("wrong header\n"); return FALSE;}; + + hlpfile->file_buffer_size = GET_UINT(header, 12); + hlpfile->file_buffer = HeapAlloc(GetProcessHeap(), 0, hlpfile->file_buffer_size + 1); + if (!hlpfile->file_buffer) return FALSE; + + memcpy(hlpfile->file_buffer, header, 16); + if (_hread(hFile, hlpfile->file_buffer + 16, hlpfile->file_buffer_size - 16) !=hlpfile->file_buffer_size - 16) + {WINE_WARN("filesize1\n"); return FALSE;}; + + if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n"); + + hlpfile->file_buffer[hlpfile->file_buffer_size] = '\0'; /* FIXME: was '0', sounds backwards to me */ + + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_SystemCommands + */ +static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile) +{ + BYTE *buf, *ptr, *end; + HLPFILE_MACRO *macro, **m; + LPSTR p; + unsigned short magic, minor, major, flags; + + hlpfile->lpszTitle = NULL; + + if (!HLPFILE_FindSubFile(hlpfile, "|SYSTEM", &buf, &end)) return FALSE; + + magic = GET_USHORT(buf + 9, 0); + minor = GET_USHORT(buf + 9, 2); + major = GET_USHORT(buf + 9, 4); + /* gen date on 4 bytes */ + flags = GET_USHORT(buf + 9, 10); + WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n", + magic, major, minor, flags); + if (magic != 0x036C || major != 1) + {WINE_WARN("Wrong system header\n"); return FALSE;} + if (minor <= 16) + { + hlpfile->tbsize = 0x800; + hlpfile->compressed = 0; + } + else if (flags == 0) + { + hlpfile->tbsize = 0x1000; + hlpfile->compressed = 0; + } + else if (flags == 4) + { + hlpfile->tbsize = 0x1000; + hlpfile->compressed = 1; + } + else + { + hlpfile->tbsize = 0x800; + hlpfile->compressed = 1; + } + + if (hlpfile->compressed) + hlpfile->dsize = 0x4000; + else + hlpfile->dsize = hlpfile->tbsize - 0x0C; + + hlpfile->version = minor; + hlpfile->flags = flags; + hlpfile->charset = DEFAULT_CHARSET; + + if (hlpfile->version <= 16) + { + char *str = (char*)buf + 0x15; + + hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); + if (!hlpfile->lpszTitle) return FALSE; + lstrcpy(hlpfile->lpszTitle, str); + WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); + /* Nothing more to parse */ + return TRUE; + } + for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4) + { + char *str = (char*) ptr + 4; + switch (GET_USHORT(ptr, 0)) + { + case 1: + if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;} + hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); + if (!hlpfile->lpszTitle) return FALSE; + lstrcpy(hlpfile->lpszTitle, str); + WINE_TRACE("Title: %s\n", hlpfile->lpszTitle); + break; + + case 2: + if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;} + hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); + if (!hlpfile->lpszCopyright) return FALSE; + lstrcpy(hlpfile->lpszCopyright, str); + WINE_TRACE("Copyright: %s\n", hlpfile->lpszCopyright); + break; + + case 3: + if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;} + hlpfile->contents_start = GET_UINT(ptr, 4); + WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start); + break; + + case 4: + macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + lstrlen(str) + 1); + if (!macro) break; + p = (char*)macro + sizeof(HLPFILE_MACRO); + lstrcpy(p, str); + macro->lpszMacro = p; + macro->next = 0; + for (m = &hlpfile->first_macro; *m; m = &(*m)->next); + *m = macro; + break; + + case 5: + if (GET_USHORT(ptr, 4 + 4) != 1) + WINE_FIXME("More than one icon, picking up first\n"); + /* 0x16 is sizeof(CURSORICONDIR), see user32/user_private.h */ + hlpfile->hIcon = CreateIconFromResourceEx(ptr + 4 + 0x16, + GET_USHORT(ptr, 2) - 0x16, TRUE, + 0x30000, 0, 0, 0); + break; + + case 6: + if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;} + + if (hlpfile->windows) + hlpfile->windows = HeapReAlloc(GetProcessHeap(), 0, hlpfile->windows, + sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); + else + hlpfile->windows = HeapAlloc(GetProcessHeap(), 0, + sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows); + + if (hlpfile->windows) + { + unsigned flags = GET_USHORT(ptr, 4); + HLPFILE_WINDOWINFO* wi = &hlpfile->windows[hlpfile->numWindows - 1]; + + if (flags & 0x0001) strcpy(wi->type, &str[2]); + else wi->type[0] = '\0'; + if (flags & 0x0002) strcpy(wi->name, &str[12]); + else wi->name[0] = '\0'; + if (flags & 0x0004) strcpy(wi->caption, &str[21]); + else lstrcpynA(wi->caption, hlpfile->lpszTitle, sizeof(wi->caption)); + wi->origin.x = (flags & 0x0008) ? GET_USHORT(ptr, 76) : CW_USEDEFAULT; + wi->origin.y = (flags & 0x0010) ? GET_USHORT(ptr, 78) : CW_USEDEFAULT; + wi->size.cx = (flags & 0x0020) ? GET_USHORT(ptr, 80) : CW_USEDEFAULT; + wi->size.cy = (flags & 0x0040) ? GET_USHORT(ptr, 82) : CW_USEDEFAULT; + wi->style = (flags & 0x0080) ? GET_USHORT(ptr, 84) : SW_SHOW; + wi->win_style = WS_OVERLAPPEDWINDOW; + wi->sr_color = (flags & 0x0100) ? GET_UINT(ptr, 86) : 0xFFFFFF; + wi->nsr_color = (flags & 0x0200) ? GET_UINT(ptr, 90) : 0xFFFFFF; + WINE_TRACE("System-Window: flags=%c%c%c%c%c%c%c%c type=%s name=%s caption=%s (%d,%d)x(%d,%d)\n", + flags & 0x0001 ? 'T' : 't', + flags & 0x0002 ? 'N' : 'n', + flags & 0x0004 ? 'C' : 'c', + flags & 0x0008 ? 'X' : 'x', + flags & 0x0010 ? 'Y' : 'y', + flags & 0x0020 ? 'W' : 'w', + flags & 0x0040 ? 'H' : 'h', + flags & 0x0080 ? 'S' : 's', + wi->type, wi->name, wi->caption, wi->origin.x, wi->origin.y, + wi->size.cx, wi->size.cy); + } + break; + case 8: + WINE_WARN("Citation: '%s'\n", ptr + 4); + break; + case 11: + hlpfile->charset = ptr[4]; + WINE_TRACE("Charset: %d\n", hlpfile->charset); + break; + default: + WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0)); + } + } + if (!hlpfile->lpszTitle) + hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1); + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_GetContext + */ +static BOOL HLPFILE_GetContext(HLPFILE *hlpfile) +{ + BYTE *cbuf, *cend; + unsigned clen; + + if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT", &cbuf, &cend)) + {WINE_WARN("context0\n"); return FALSE;} + + clen = cend - cbuf; + hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen); + if (!hlpfile->Context) return FALSE; + memcpy(hlpfile->Context, cbuf, clen); + + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_GetKeywords + */ +static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile) +{ + BYTE *cbuf, *cend; + unsigned clen; + + if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE; + clen = cend - cbuf; + hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen); + if (!hlpfile->kwbtree) return FALSE; + memcpy(hlpfile->kwbtree, cbuf, clen); + + if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend)) + { + WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n"); + HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree); + return FALSE; + } + clen = cend - cbuf; + hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen); + if (!hlpfile->kwdata) + { + HeapFree(GetProcessHeap(), 0, hlpfile->kwdata); + return FALSE; + } + memcpy(hlpfile->kwdata, cbuf, clen); + + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_GetMap + */ +static BOOL HLPFILE_GetMap(HLPFILE *hlpfile) +{ + BYTE *cbuf, *cend; + unsigned entries, i; + + if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP", &cbuf, &cend)) + {WINE_WARN("no map section\n"); return FALSE;} + + entries = GET_USHORT(cbuf, 9); + hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP)); + if (!hlpfile->Map) return FALSE; + hlpfile->wMapLen = entries; + for (i = 0; i < entries; i++) + { + hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8); + hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4); + } + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_GetTOMap + */ +static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile) +{ + BYTE *cbuf, *cend; + unsigned clen; + + if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP", &cbuf, &cend)) + {WINE_WARN("no tomap section\n"); return FALSE;} + + clen = cend - cbuf - 9; + hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen); + if (!hlpfile->TOMap) return FALSE; + memcpy(hlpfile->TOMap, cbuf+9, clen); + hlpfile->wTOMapLen = clen/4; + return TRUE; +} + +/*********************************************************************** + * + * DeleteMacro + */ +static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro) +{ + HLPFILE_MACRO* next; + + while (macro) + { + next = macro->next; + HeapFree(GetProcessHeap(), 0, macro); + macro = next; + } +} + +/*********************************************************************** + * + * DeletePage + */ +static void HLPFILE_DeletePage(HLPFILE_PAGE* page) +{ + HLPFILE_PAGE* next; + + while (page) + { + next = page->next; + HLPFILE_DeleteMacro(page->first_macro); + HeapFree(GetProcessHeap(), 0, page); + page = next; + } +} + +/*********************************************************************** + * + * HLPFILE_FreeHlpFile + */ +void HLPFILE_FreeHlpFile(HLPFILE* hlpfile) +{ + unsigned i; + + if (!hlpfile || --hlpfile->wRefCount > 0) return; + + if (hlpfile->next) hlpfile->next->prev = hlpfile->prev; + if (hlpfile->prev) hlpfile->prev->next = hlpfile->next; + else first_hlpfile = hlpfile->next; + + if (hlpfile->numFonts) + { + for (i = 0; i < hlpfile->numFonts; i++) + { + DeleteObject(hlpfile->fonts[i].hFont); + } + HeapFree(GetProcessHeap(), 0, hlpfile->fonts); + } + + if (hlpfile->numBmps) + { + for (i = 0; i < hlpfile->numBmps; i++) + { + DeleteObject(hlpfile->bmps[i]); + } + HeapFree(GetProcessHeap(), 0, hlpfile->bmps); + } + + HLPFILE_DeletePage(hlpfile->first_page); + HLPFILE_DeleteMacro(hlpfile->first_macro); + + DestroyIcon(hlpfile->hIcon); + if (hlpfile->numWindows) HeapFree(GetProcessHeap(), 0, hlpfile->windows); + HeapFree(GetProcessHeap(), 0, hlpfile->Context); + HeapFree(GetProcessHeap(), 0, hlpfile->Map); + HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle); + HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright); + HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer); + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); + HeapFree(GetProcessHeap(), 0, hlpfile->topic_map); + HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file); + HeapFree(GetProcessHeap(), 0, hlpfile); +} + +/*********************************************************************** + * + * HLPFILE_UncompressLZ77_Phrases + */ +static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE* hlpfile) +{ + UINT i, num, dec_size, head_size; + BYTE *buf, *end; + + if (!HLPFILE_FindSubFile(hlpfile, "|Phrases", &buf, &end)) return FALSE; + + if (hlpfile->version <= 16) + head_size = 13; + else + head_size = 17; + + num = hlpfile->num_phrases = GET_USHORT(buf, 9); + if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;}; + + if (hlpfile->version <= 16) + dec_size = end - buf - 15 - 2 * num; + else + dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end); + + hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); + hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); + if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) + { + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); + return FALSE; + } + + for (i = 0; i <= num; i++) + hlpfile->phrases_offsets[i] = GET_USHORT(buf, head_size + 2 * i) - 2 * num - 2; + + if (hlpfile->version <= 16) + memcpy(hlpfile->phrases_buffer, buf + 15 + 2*num, dec_size); + else + HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, (BYTE*)hlpfile->phrases_buffer); + + hlpfile->hasPhrases = TRUE; + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_Uncompress_Phrases40 + */ +static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile) +{ + UINT num; + INT dec_size, cpr_size; + BYTE *buf_idx, *end_idx; + BYTE *buf_phs, *end_phs; + LONG* ptr, mask = 0; + unsigned int i; + unsigned short bc, n; + + if (!HLPFILE_FindSubFile(hlpfile, "|PhrIndex", &buf_idx, &end_idx) || + !HLPFILE_FindSubFile(hlpfile, "|PhrImage", &buf_phs, &end_phs)) return FALSE; + + ptr = (LONG*)(buf_idx + 9 + 28); + bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F; + num = hlpfile->num_phrases = GET_USHORT(buf_idx, 9 + 4); + + WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n" + "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n", + GET_UINT(buf_idx, 9 + 0), + GET_UINT(buf_idx, 9 + 4), + GET_UINT(buf_idx, 9 + 8), + GET_UINT(buf_idx, 9 + 12), + GET_UINT(buf_idx, 9 + 16), + GET_UINT(buf_idx, 9 + 20), + GET_USHORT(buf_idx, 9 + 24), + GET_USHORT(buf_idx, 9 + 26)); + + dec_size = GET_UINT(buf_idx, 9 + 12); + cpr_size = GET_UINT(buf_idx, 9 + 16); + + if (dec_size != cpr_size && + dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)) + { + WINE_WARN("size mismatch %u %u\n", + dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); + dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs)); + } + + hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1)); + hlpfile->phrases_buffer = HeapAlloc(GetProcessHeap(), 0, dec_size); + if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer) + { + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets); + HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer); + return FALSE; + } + +#define getbit() (ptr += (mask < 0), mask = mask*2 + (mask<=0), (*ptr & mask) != 0) + + hlpfile->phrases_offsets[0] = 0; + for (i = 0; i < num; i++) + { + for (n = 1; getbit(); n += 1 << bc); + if (getbit()) n++; + if (bc > 1 && getbit()) n += 2; + if (bc > 2 && getbit()) n += 4; + if (bc > 3 && getbit()) n += 8; + if (bc > 4 && getbit()) n += 16; + hlpfile->phrases_offsets[i + 1] = hlpfile->phrases_offsets[i] + n; + } +#undef getbit + + if (dec_size == cpr_size) + memcpy(hlpfile->phrases_buffer, buf_phs + 9, dec_size); + else + HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, (BYTE*)hlpfile->phrases_buffer); + + hlpfile->hasPhrases40 = TRUE; + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_Uncompress_Topic + */ +static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile) +{ + BYTE *buf, *ptr, *end, *newptr; + unsigned int i, newsize = 0; + unsigned int topic_size; + + if (!HLPFILE_FindSubFile(hlpfile, "|TOPIC", &buf, &end)) + {WINE_WARN("topic0\n"); return FALSE;} + + buf += 9; /* Skip file header */ + topic_size = end - buf; + if (hlpfile->compressed) + { + hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; + + for (i = 0; i < hlpfile->topic_maplen; i++) + { + ptr = buf + i * hlpfile->tbsize; + + /* I don't know why, it's necessary for printman.hlp */ + if (ptr + 0x44 > end) ptr = end - 0x44; + + newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + hlpfile->tbsize)); + } + + hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, + hlpfile->topic_maplen * sizeof(hlpfile->topic_map[0]) + newsize); + if (!hlpfile->topic_map) return FALSE; + newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); + hlpfile->topic_end = newptr + newsize; + + for (i = 0; i < hlpfile->topic_maplen; i++) + { + ptr = buf + i * hlpfile->tbsize; + if (ptr + 0x44 > end) ptr = end - 0x44; + + hlpfile->topic_map[i] = newptr; + newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + hlpfile->tbsize), newptr); + } + } + else + { + /* basically, we need to copy the TopicBlockSize byte pages + * (removing the first 0x0C) in one single area in memory + */ + hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1; + hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0, + hlpfile->topic_maplen * (sizeof(hlpfile->topic_map[0]) + hlpfile->dsize)); + if (!hlpfile->topic_map) return FALSE; + newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen); + hlpfile->topic_end = newptr + topic_size; + + for (i = 0; i < hlpfile->topic_maplen; i++) + { + hlpfile->topic_map[i] = newptr + i * hlpfile->dsize; + memcpy(hlpfile->topic_map[i], buf + i * hlpfile->tbsize + 0x0C, hlpfile->dsize); + } + } + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_AddPage + */ +static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset) +{ + HLPFILE_PAGE* page; + const BYTE* title; + UINT titlesize, blocksize, datalen; + char* ptr; + HLPFILE_MACRO*macro; + + blocksize = GET_UINT(buf, 0); + datalen = GET_UINT(buf, 0x10); + title = buf + datalen; + if (title > end) {WINE_WARN("page2\n"); return FALSE;}; + + titlesize = GET_UINT(buf, 4); + page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1); + if (!page) return FALSE; + page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE); + + if (titlesize > blocksize - datalen) + { + /* need to decompress */ + if (hlpfile->hasPhrases) + HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize); + else if (hlpfile->hasPhrases40) + HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end); + else + { + WINE_FIXME("Text size is too long, splitting\n"); + titlesize = blocksize - datalen; + memcpy(page->lpszTitle, title, titlesize); + } + } + else + memcpy(page->lpszTitle, title, titlesize); + + page->lpszTitle[titlesize] = '\0'; + + if (hlpfile->first_page) + { + hlpfile->last_page->next = page; + page->prev = hlpfile->last_page; + hlpfile->last_page = page; + } + else + { + hlpfile->first_page = page; + hlpfile->last_page = page; + page->prev = NULL; + } + + page->file = hlpfile; + page->next = NULL; + page->first_macro = NULL; + page->first_link = NULL; + page->wNumber = GET_UINT(buf, 0x21); + page->offset = offset; + page->reference = ref; + + page->browse_bwd = GET_UINT(buf, 0x19); + page->browse_fwd = GET_UINT(buf, 0x1D); + + if (hlpfile->version <= 16) + { + if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF) + page->browse_bwd = 0xFFFFFFFF; + else + page->browse_bwd = hlpfile->TOMap[page->browse_bwd]; + + if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF) + page->browse_fwd = 0xFFFFFFFF; + else + page->browse_fwd = hlpfile->TOMap[page->browse_fwd]; + } + + WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n", + page->wNumber, page->lpszTitle, + page->browse_bwd, page->offset, page->browse_fwd); + + /* now load macros */ + ptr = page->lpszTitle + strlen(page->lpszTitle) + 1; + while (ptr < page->lpszTitle + titlesize) + { + unsigned len = strlen(ptr); + char* macro_str; + + WINE_TRACE("macro: %s\n", ptr); + macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1); + macro->lpszMacro = macro_str = (char*)(macro + 1); + memcpy(macro_str, ptr, len + 1); + /* FIXME: shall we really link macro in reverse order ?? + * may produce strange results when played at page opening + */ + macro->next = page->first_macro; + page->first_macro = macro; + ptr += len + 1; + } + + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_SkipParagraph + */ +static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len) +{ + const BYTE *tmp; + + if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;}; + if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;}; + + tmp = buf + 0x15; + if (buf[0x14] == 0x20 || buf[0x14] == 0x23) + { + fetch_long(&tmp); + *len = fetch_ushort(&tmp); + } + else *len = end-buf-15; + + return TRUE; +} + +/*********************************************************************** + * + * HLPFILE_DoReadHlpFile + */ +static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath) +{ + BOOL ret; + HFILE hFile; + OFSTRUCT ofs; + BYTE* buf; + DWORD ref = 0x0C; + unsigned index, old_index, offset, len, offs, topicoffset; + + hFile = OpenFile(lpszPath, &ofs, OF_READ); + if (hFile == HFILE_ERROR) return FALSE; + + ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile); + _lclose(hFile); + if (!ret) return FALSE; + + if (!HLPFILE_SystemCommands(hlpfile)) return FALSE; + + if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE; + + /* load phrases support */ + if (!HLPFILE_UncompressLZ77_Phrases(hlpfile)) + HLPFILE_Uncompress_Phrases40(hlpfile); + + if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE; + if (!HLPFILE_ReadFont(hlpfile)) return FALSE; + + buf = hlpfile->topic_map[0]; + old_index = -1; + offs = 0; + do + { + BYTE* end; + + if (hlpfile->version <= 16) + { + index = (ref - 0x0C) / hlpfile->dsize; + offset = (ref - 0x0C) % hlpfile->dsize; + } + else + { + index = (ref - 0x0C) >> 14; + offset = (ref - 0x0C) & 0x3FFF; + } + + if (hlpfile->version <= 16 && index != old_index && old_index != -1) + { + /* we jumped to the next block, adjust pointers */ + ref -= 12; + offset -= 12; + } + + WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset); + + if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;} + buf = hlpfile->topic_map[index] + offset; + if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;} + end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end); + if (index != old_index) {offs = 0; old_index = index;} + + switch (buf[0x14]) + { + case 0x02: + if (hlpfile->version <= 16) + topicoffset = ref + index * 12; + else + topicoffset = index * 0x8000 + offs; + if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE; + break; + + case 0x01: + case 0x20: + case 0x23: + if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE; + offs += len; + break; + + default: + WINE_ERR("buf[0x14] = %x\n", buf[0x14]); + } + + if (hlpfile->version <= 16) + { + ref += GET_UINT(buf, 0xc); + if (GET_UINT(buf, 0xc) == 0) + break; + } + else + ref = GET_UINT(buf, 0xc); + } while (ref != 0xffffffff); + + HLPFILE_GetKeywords(hlpfile); + HLPFILE_GetMap(hlpfile); + if (hlpfile->version <= 16) return TRUE; + return HLPFILE_GetContext(hlpfile); +} + +/*********************************************************************** + * + * HLPFILE_ReadHlpFile + */ +HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath) +{ + HLPFILE* hlpfile; + + for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next) + { + if (!strcmp(lpszPath, hlpfile->lpszPath)) + { + hlpfile->wRefCount++; + return hlpfile; + } + } + + hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(HLPFILE) + lstrlen(lpszPath) + 1); + if (!hlpfile) return 0; + + hlpfile->lpszPath = (char*)hlpfile + sizeof(HLPFILE); + hlpfile->contents_start = 0xFFFFFFFF; + hlpfile->next = first_hlpfile; + hlpfile->wRefCount = 1; + + strcpy(hlpfile->lpszPath, lpszPath); + + first_hlpfile = hlpfile; + if (hlpfile->next) hlpfile->next->prev = hlpfile; + + if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath)) + { + HLPFILE_FreeHlpFile(hlpfile); + hlpfile = 0; + } + + return hlpfile; +} diff --git a/reactos/base/applications/winhlp32/hlpfile.h b/reactos/base/applications/winhlp32/hlpfile.h index 590c0bcae47..0e3f35e8966 100644 --- a/reactos/base/applications/winhlp32/hlpfile.h +++ b/reactos/base/applications/winhlp32/hlpfile.h @@ -1,191 +1,191 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * 2002, 2008 Eric Pouech - * 2007 Kirill K. Smirnov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -struct tagHelpFile; - -typedef struct -{ - char type[10]; - char name[9]; - char caption[51]; - POINT origin; - SIZE size; - int style; - DWORD win_style; - COLORREF sr_color; /* color for scrollable region */ - COLORREF nsr_color; /* color for non scrollable region */ -} HLPFILE_WINDOWINFO; - -typedef struct tagHlpFileLink -{ - enum {hlp_link_link, hlp_link_popup, hlp_link_macro} cookie; - LPCSTR string; /* name of the file to for the link (NULL if same file) */ - LONG hash; /* topic index */ - unsigned bClrChange : 1; /* true if the link is green & underlined */ - unsigned window; /* window number for displaying the link (-1 is current) */ - DWORD cpMin; - DWORD cpMax; - struct tagHlpFileLink* next; -} HLPFILE_LINK; - -typedef struct tagHlpFileMacro -{ - LPCSTR lpszMacro; - struct tagHlpFileMacro* next; -} HLPFILE_MACRO; - -typedef struct tagHlpFilePage -{ - LPSTR lpszTitle; - HLPFILE_MACRO* first_macro; - - HLPFILE_LINK* first_link; - - unsigned wNumber; - unsigned offset; - DWORD reference; - struct tagHlpFilePage* next; - struct tagHlpFilePage* prev; - - DWORD browse_bwd; - DWORD browse_fwd; - - struct tagHlpFileFile* file; -} HLPFILE_PAGE; - -typedef struct -{ - LONG lMap; - unsigned long offset; -} HLPFILE_MAP; - -typedef struct -{ - LOGFONT LogFont; - HFONT hFont; - COLORREF color; -} HLPFILE_FONT; - -typedef struct tagHlpFileFile -{ - BYTE* file_buffer; - UINT file_buffer_size; - LPSTR lpszPath; - LPSTR lpszTitle; - LPSTR lpszCopyright; - HLPFILE_PAGE* first_page; - HLPFILE_PAGE* last_page; - HLPFILE_MACRO* first_macro; - BYTE* Context; - BYTE* kwbtree; - BYTE* kwdata; - unsigned wMapLen; - HLPFILE_MAP* Map; - unsigned wTOMapLen; - unsigned* TOMap; - unsigned long contents_start; - - struct tagHlpFileFile* prev; - struct tagHlpFileFile* next; - - unsigned wRefCount; - - unsigned short version; - unsigned short flags; - unsigned short charset; - unsigned short tbsize; /* topic block size */ - unsigned short dsize; /* decompress size */ - unsigned short compressed; - unsigned hasPhrases; /* file has |Phrases */ - unsigned hasPhrases40; /* file has |PhrIndex/|PhrImage */ - UINT num_phrases; - unsigned* phrases_offsets; - char* phrases_buffer; - - BYTE** topic_map; - BYTE* topic_end; - UINT topic_maplen; - - unsigned numBmps; - HBITMAP* bmps; - - unsigned numFonts; - HLPFILE_FONT* fonts; - - unsigned numWindows; - HLPFILE_WINDOWINFO* windows; - HICON hIcon; - - BOOL has_popup_color; - COLORREF popup_color; - - LPSTR help_on_file; -} HLPFILE; - -/* - * Compare function type for HLPFILE_BPTreeSearch function. - * - * PARAMS - * p [I] pointer to testing block (key + data) - * key [I] pointer to key value to look for - * leaf [I] whether this function called for index of leaf page - * next [O] pointer to pointer to next block - */ -typedef int (*HLPFILE_BPTreeCompare)(void *p, const void *key, - int leaf, void **next); - -/* - * Callback function type for HLPFILE_BPTreeEnum function. - * - * PARAMS - * p [I] pointer to data block - * next [O] pointer to pointer to next block - * cookie [IO] cookie data - */ -typedef void (*HLPFILE_BPTreeCallback)(void *p, void **next, void *cookie); - -HLPFILE* HLPFILE_ReadHlpFile(LPCSTR lpszPath); -HLPFILE_PAGE* HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative); -HLPFILE_PAGE* HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative); -HLPFILE_PAGE* HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative); -LONG HLPFILE_Hash(LPCSTR lpszContext); -void HLPFILE_FreeHlpFile(HLPFILE*); - -void HLPFILE_BPTreeEnum(BYTE*, HLPFILE_BPTreeCallback cb, void *cookie); - -struct RtfData { - BOOL in_text; - char* data; /* RTF stream start */ - char* ptr; /* current position in stream */ - unsigned allocated; /* overall allocated size */ - unsigned char_pos; /* current char position (in richedit) */ - char* where; /* pointer to feed back richedit */ - unsigned font_scale; /* how to scale fonts */ - HLPFILE_LINK*first_link; - HLPFILE_LINK*current_link; - BOOL force_color; - unsigned relative; /* offset within page to lookup for */ - unsigned char_pos_rel; /* char_pos correspondinf to relative */ -}; - -BOOL HLPFILE_BrowsePage(HLPFILE_PAGE*, struct RtfData* rd, - unsigned font_scale, unsigned relative); +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * 2002, 2008 Eric Pouech + * 2007 Kirill K. Smirnov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +struct tagHelpFile; + +typedef struct +{ + char type[10]; + char name[9]; + char caption[51]; + POINT origin; + SIZE size; + int style; + DWORD win_style; + COLORREF sr_color; /* color for scrollable region */ + COLORREF nsr_color; /* color for non scrollable region */ +} HLPFILE_WINDOWINFO; + +typedef struct tagHlpFileLink +{ + enum {hlp_link_link, hlp_link_popup, hlp_link_macro} cookie; + LPCSTR string; /* name of the file to for the link (NULL if same file) */ + LONG hash; /* topic index */ + unsigned bClrChange : 1; /* true if the link is green & underlined */ + unsigned window; /* window number for displaying the link (-1 is current) */ + DWORD cpMin; + DWORD cpMax; + struct tagHlpFileLink* next; +} HLPFILE_LINK; + +typedef struct tagHlpFileMacro +{ + LPCSTR lpszMacro; + struct tagHlpFileMacro* next; +} HLPFILE_MACRO; + +typedef struct tagHlpFilePage +{ + LPSTR lpszTitle; + HLPFILE_MACRO* first_macro; + + HLPFILE_LINK* first_link; + + unsigned wNumber; + unsigned offset; + DWORD reference; + struct tagHlpFilePage* next; + struct tagHlpFilePage* prev; + + DWORD browse_bwd; + DWORD browse_fwd; + + struct tagHlpFileFile* file; +} HLPFILE_PAGE; + +typedef struct +{ + LONG lMap; + unsigned long offset; +} HLPFILE_MAP; + +typedef struct +{ + LOGFONT LogFont; + HFONT hFont; + COLORREF color; +} HLPFILE_FONT; + +typedef struct tagHlpFileFile +{ + BYTE* file_buffer; + UINT file_buffer_size; + LPSTR lpszPath; + LPSTR lpszTitle; + LPSTR lpszCopyright; + HLPFILE_PAGE* first_page; + HLPFILE_PAGE* last_page; + HLPFILE_MACRO* first_macro; + BYTE* Context; + BYTE* kwbtree; + BYTE* kwdata; + unsigned wMapLen; + HLPFILE_MAP* Map; + unsigned wTOMapLen; + unsigned* TOMap; + unsigned long contents_start; + + struct tagHlpFileFile* prev; + struct tagHlpFileFile* next; + + unsigned wRefCount; + + unsigned short version; + unsigned short flags; + unsigned short charset; + unsigned short tbsize; /* topic block size */ + unsigned short dsize; /* decompress size */ + unsigned short compressed; + unsigned hasPhrases; /* file has |Phrases */ + unsigned hasPhrases40; /* file has |PhrIndex/|PhrImage */ + UINT num_phrases; + unsigned* phrases_offsets; + char* phrases_buffer; + + BYTE** topic_map; + BYTE* topic_end; + UINT topic_maplen; + + unsigned numBmps; + HBITMAP* bmps; + + unsigned numFonts; + HLPFILE_FONT* fonts; + + unsigned numWindows; + HLPFILE_WINDOWINFO* windows; + HICON hIcon; + + BOOL has_popup_color; + COLORREF popup_color; + + LPSTR help_on_file; +} HLPFILE; + +/* + * Compare function type for HLPFILE_BPTreeSearch function. + * + * PARAMS + * p [I] pointer to testing block (key + data) + * key [I] pointer to key value to look for + * leaf [I] whether this function called for index of leaf page + * next [O] pointer to pointer to next block + */ +typedef int (*HLPFILE_BPTreeCompare)(void *p, const void *key, + int leaf, void **next); + +/* + * Callback function type for HLPFILE_BPTreeEnum function. + * + * PARAMS + * p [I] pointer to data block + * next [O] pointer to pointer to next block + * cookie [IO] cookie data + */ +typedef void (*HLPFILE_BPTreeCallback)(void *p, void **next, void *cookie); + +HLPFILE* HLPFILE_ReadHlpFile(LPCSTR lpszPath); +HLPFILE_PAGE* HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative); +HLPFILE_PAGE* HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative); +HLPFILE_PAGE* HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative); +LONG HLPFILE_Hash(LPCSTR lpszContext); +void HLPFILE_FreeHlpFile(HLPFILE*); + +void HLPFILE_BPTreeEnum(BYTE*, HLPFILE_BPTreeCallback cb, void *cookie); + +struct RtfData { + BOOL in_text; + char* data; /* RTF stream start */ + char* ptr; /* current position in stream */ + unsigned allocated; /* overall allocated size */ + unsigned char_pos; /* current char position (in richedit) */ + char* where; /* pointer to feed back richedit */ + unsigned font_scale; /* how to scale fonts */ + HLPFILE_LINK*first_link; + HLPFILE_LINK*current_link; + BOOL force_color; + unsigned relative; /* offset within page to lookup for */ + unsigned char_pos_rel; /* char_pos correspondinf to relative */ +}; + +BOOL HLPFILE_BrowsePage(HLPFILE_PAGE*, struct RtfData* rd, + unsigned font_scale, unsigned relative); diff --git a/reactos/base/applications/winhlp32/lex.yy.c b/reactos/base/applications/winhlp32/lex.yy.c index c91bc9e2b9d..b1d60a8d97b 100644 --- a/reactos/base/applications/winhlp32/lex.yy.c +++ b/reactos/base/applications/winhlp32/lex.yy.c @@ -1,1863 +1,1863 @@ -/* A lexical scanner generated by flex */ - -/* Scanner skeleton version: - * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ - */ - -#define FLEX_SCANNER -#define YY_FLEX_MAJOR_VERSION 2 -#define YY_FLEX_MINOR_VERSION 5 - -#include - - -/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ -#ifdef c_plusplus -#ifndef __cplusplus -#define __cplusplus -#endif -#endif - - -#ifdef __cplusplus - -#include -#include - -/* Use prototypes in function declarations. */ -#define YY_USE_PROTOS - -/* The "const" storage-class-modifier is valid. */ -#define YY_USE_CONST - -#else /* ! __cplusplus */ - -#if __STDC__ - -#define YY_USE_PROTOS -#define YY_USE_CONST - -#endif /* __STDC__ */ -#endif /* ! __cplusplus */ - -#ifdef __TURBOC__ - #pragma warn -rch - #pragma warn -use -#include -#include -#define YY_USE_CONST -#define YY_USE_PROTOS -#endif - -#ifdef YY_USE_CONST -#define yyconst const -#else -#define yyconst -#endif - - -#ifdef YY_USE_PROTOS -#define YY_PROTO(proto) proto -#else -#define YY_PROTO(proto) () -#endif - -/* Returned upon end-of-file. */ -#define YY_NULL 0 - -/* Promotes a possibly negative, possibly signed char to an unsigned - * integer for use as an array index. If the signed char is negative, - * we want to instead treat it as an 8-bit unsigned char, hence the - * double cast. - */ -#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) - -/* Enter a start condition. This macro really ought to take a parameter, - * but we do it the disgusting crufty way forced on us by the ()-less - * definition of BEGIN. - */ -#define BEGIN yy_start = 1 + 2 * - -/* Translate the current start state into a value that can be later handed - * to BEGIN to return to the state. The YYSTATE alias is for lex - * compatibility. - */ -#define YY_START ((yy_start - 1) / 2) -#define YYSTATE YY_START - -/* Action number for EOF rule of a given start state. */ -#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) - -/* Special action meaning "start processing a new file". */ -#define YY_NEW_FILE yyrestart( yyin ) - -#define YY_END_OF_BUFFER_CHAR 0 - -/* Size of default input buffer. */ -#define YY_BUF_SIZE 16384 - -typedef struct yy_buffer_state *YY_BUFFER_STATE; - -extern int yyleng; -extern FILE *yyin, *yyout; - -#define EOB_ACT_CONTINUE_SCAN 0 -#define EOB_ACT_END_OF_FILE 1 -#define EOB_ACT_LAST_MATCH 2 - -/* The funky do-while in the following #define is used to turn the definition - * int a single C statement (which needs a semi-colon terminator). This - * avoids problems with code like: - * - * if ( condition_holds ) - * yyless( 5 ); - * else - * do_something_else(); - * - * Prior to using the do-while the compiler would get upset at the - * "else" because it interpreted the "if" statement as being all - * done when it reached the ';' after the yyless() call. - */ - -/* Return all but the first 'n' matched characters back to the input stream. */ - -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - *yy_cp = yy_hold_char; \ - YY_RESTORE_YY_MORE_OFFSET \ - yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ - YY_DO_BEFORE_ACTION; /* set up yytext again */ \ - } \ - while ( 0 ) - -#define unput(c) yyunput( c, yytext_ptr ) - -/* The following is because we cannot portably get our hands on size_t - * (without autoconf's help, which isn't available because we want - * flex-generated scanners to compile on their own). - */ -typedef unsigned int yy_size_t; - - -struct yy_buffer_state - { - FILE *yy_input_file; - - char *yy_ch_buf; /* input buffer */ - char *yy_buf_pos; /* current position in input buffer */ - - /* Size of input buffer in bytes, not including room for EOB - * characters. - */ - yy_size_t yy_buf_size; - - /* Number of characters read into yy_ch_buf, not including EOB - * characters. - */ - int yy_n_chars; - - /* Whether we "own" the buffer - i.e., we know we created it, - * and can realloc() it to grow it, and should free() it to - * delete it. - */ - int yy_is_our_buffer; - - /* Whether this is an "interactive" input source; if so, and - * if we're using stdio for input, then we want to use getc() - * instead of fread(), to make sure we stop fetching input after - * each newline. - */ - int yy_is_interactive; - - /* Whether we're considered to be at the beginning of a line. - * If so, '^' rules will be active on the next match, otherwise - * not. - */ - int yy_at_bol; - - /* Whether to try to fill the input buffer when we reach the - * end of it. - */ - int yy_fill_buffer; - - int yy_buffer_status; -#define YY_BUFFER_NEW 0 -#define YY_BUFFER_NORMAL 1 - /* When an EOF's been seen but there's still some text to process - * then we mark the buffer as YY_EOF_PENDING, to indicate that we - * shouldn't try reading from the input source any more. We might - * still have a bunch of tokens to match, though, because of - * possible backing-up. - * - * When we actually see the EOF, we change the status to "new" - * (via yyrestart()), so that the user can continue scanning by - * just pointing yyin at a new input file. - */ -#define YY_BUFFER_EOF_PENDING 2 - }; - -static YY_BUFFER_STATE yy_current_buffer = 0; - -/* We provide macros for accessing buffer states in case in the - * future we want to put the buffer states in a more general - * "scanner state". - */ -#define YY_CURRENT_BUFFER yy_current_buffer - - -/* yy_hold_char holds the character lost when yytext is formed. */ -static char yy_hold_char; - -static int yy_n_chars; /* number of characters read into yy_ch_buf */ - - -int yyleng; - -/* Points to current character in buffer. */ -static char *yy_c_buf_p = (char *) 0; -static int yy_init = 1; /* whether we need to initialize */ -static int yy_start = 0; /* start state number */ - -/* Flag which is used to allow yywrap()'s to do buffer switches - * instead of setting up a fresh yyin. A bit of a hack ... - */ -static int yy_did_buffer_switch_on_eof; - -void yyrestart YY_PROTO(( FILE *input_file )); - -void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); -void yy_load_buffer_state YY_PROTO(( void )); -YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); -void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); -void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); -void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); -#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) - -YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); -YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); -YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); - -static void *yy_flex_alloc YY_PROTO(( yy_size_t )); -static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); -static void yy_flex_free YY_PROTO(( void * )); - -#define yy_new_buffer yy_create_buffer - -#define yy_set_interactive(is_interactive) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_is_interactive = is_interactive; \ - } - -#define yy_set_bol(at_bol) \ - { \ - if ( ! yy_current_buffer ) \ - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ - yy_current_buffer->yy_at_bol = at_bol; \ - } - -#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) - -typedef unsigned char YY_CHAR; -FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; -typedef int yy_state_type; -extern char *yytext; -#define yytext_ptr yytext - -static yy_state_type yy_get_previous_state YY_PROTO(( void )); -static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); -static int yy_get_next_buffer YY_PROTO(( void )); -static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); - -/* Done after the current pattern has been matched and before the - * corresponding action - sets up yytext. - */ -#define YY_DO_BEFORE_ACTION \ - yytext_ptr = yy_bp; \ - yyleng = (int) (yy_cp - yy_bp); \ - yy_hold_char = *yy_cp; \ - *yy_cp = '\0'; \ - yy_c_buf_p = yy_cp; - -#define YY_NUM_RULES 14 -#define YY_END_OF_BUFFER 15 -static yyconst short int yy_accept[28] = - { 0, - 0, 0, 0, 0, 15, 13, 14, 12, 5, 6, - 13, 1, 1, 3, 4, 10, 8, 9, 10, 7, - 1, 1, 0, 3, 11, 2, 0 - } ; - -static yyconst int yy_ec[256] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 3, 1, 4, 1, 1, 1, 1, 5, 1, - 1, 1, 6, 1, 6, 1, 1, 7, 8, 8, - 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, - 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, - 1, 11, 1, 1, 12, 13, 14, 14, 14, 14, - - 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, - 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, - 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 1 - } ; - -static yyconst int yy_meta[15] = - { 0, - 1, 2, 1, 1, 1, 1, 3, 3, 4, 5, - 1, 4, 1, 6 - } ; - -static yyconst short int yy_base[33] = - { 0, - 0, 0, 13, 25, 25, 62, 62, 62, 62, 62, - 12, 13, 14, 0, 62, 62, 62, 62, 0, 62, - 6, 24, 0, 0, 62, 0, 62, 38, 42, 45, - 51, 55 - } ; - -static yyconst short int yy_def[33] = - { 0, - 27, 1, 28, 28, 27, 27, 27, 27, 27, 27, - 27, 29, 27, 30, 27, 27, 27, 27, 31, 27, - 29, 27, 32, 30, 27, 32, 0, 27, 27, 27, - 27, 27 - } ; - -static yyconst short int yy_nxt[77] = - { 0, - 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, - 6, 6, 15, 14, 7, 23, 17, 18, 21, 22, - 22, 22, 23, 19, 27, 20, 7, 27, 17, 18, - 22, 22, 27, 27, 27, 19, 27, 20, 16, 16, - 16, 16, 16, 16, 22, 27, 22, 24, 24, 24, - 24, 25, 27, 25, 25, 25, 25, 26, 27, 27, - 26, 5, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27 - } ; - -static yyconst short int yy_chk[77] = - { 0, - 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, - 1, 1, 1, 1, 3, 21, 3, 3, 11, 11, - 13, 13, 12, 3, 5, 3, 4, 0, 4, 4, - 22, 22, 0, 0, 0, 4, 0, 4, 28, 28, - 28, 28, 28, 28, 29, 0, 29, 30, 30, 30, - 30, 31, 0, 31, 31, 31, 31, 32, 0, 0, - 32, 27, 27, 27, 27, 27, 27, 27, 27, 27, - 27, 27, 27, 27, 27, 27 - } ; - -static yy_state_type yy_last_accepting_state; -static char *yy_last_accepting_cpos; - -/* The intent behind this definition is that it'll catch - * any uses of REJECT which flex missed. - */ -#define REJECT reject_used_but_not_detected -#define yymore() yymore_used_but_not_detected -#define YY_MORE_ADJ 0 -#define YY_RESTORE_YY_MORE_OFFSET -char *yytext; -#line 1 "macro.lex.l" -#define INITIAL 0 -#line 2 "macro.lex.l" -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * Copyright 2002,2008 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -#define YY_NO_INPUT 1 -#define YY_NO_UNPUT 1 -#define quote 1 - -#line 26 "macro.lex.l" -#include "config.h" -#include - -#ifndef HAVE_UNISTD_H -#define YY_NO_UNISTD_H -#endif - -#include "macro.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -struct lex_data { - LPCSTR macroptr; - LPSTR strptr; - int quote_stack[32]; - unsigned quote_stk_idx; - LPSTR cache_string[32]; - int cache_used; -}; -static struct lex_data* lex_data = NULL; - -struct lexret yylval; - -#define YY_INPUT(buf,result,max_size)\ - if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++; - -#line 440 "lex.yy.c" - -/* Macros after this point can all be overridden by user definitions in - * section 1. - */ - -#ifndef YY_SKIP_YYWRAP -#ifdef __cplusplus -extern "C" int yywrap YY_PROTO(( void )); -#else -extern int yywrap YY_PROTO(( void )); -#endif -#endif - -#ifndef YY_NO_UNPUT -static void yyunput YY_PROTO(( int c, char *buf_ptr )); -#endif - -#ifndef yytext_ptr -static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); -#endif - -#ifdef YY_NEED_STRLEN -static int yy_flex_strlen YY_PROTO(( yyconst char * )); -#endif - -#ifndef YY_NO_INPUT -#ifdef __cplusplus -static int yyinput YY_PROTO(( void )); -#else -static int input YY_PROTO(( void )); -#endif -#endif - -#if YY_STACK_USED -static int yy_start_stack_ptr = 0; -static int yy_start_stack_depth = 0; -static int *yy_start_stack = 0; -#ifndef YY_NO_PUSH_STATE -static void yy_push_state YY_PROTO(( int new_state )); -#endif -#ifndef YY_NO_POP_STATE -static void yy_pop_state YY_PROTO(( void )); -#endif -#ifndef YY_NO_TOP_STATE -static int yy_top_state YY_PROTO(( void )); -#endif - -#else -#define YY_NO_PUSH_STATE 1 -#define YY_NO_POP_STATE 1 -#define YY_NO_TOP_STATE 1 -#endif - -#ifdef YY_MALLOC_DECL -YY_MALLOC_DECL -#else -#if __STDC__ -#ifndef __cplusplus -#include -#endif -#else -/* Just try to get by without declaring the routines. This will fail - * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) - * or sizeof(void*) != sizeof(int). - */ -#endif -#endif - -/* Amount of stuff to slurp up with each read. */ -#ifndef YY_READ_BUF_SIZE -#define YY_READ_BUF_SIZE 8192 -#endif - -/* Copy whatever the last rule matched to the standard output. */ - -#ifndef ECHO -/* This used to be an fputs(), but since the string might contain NUL's, - * we now use fwrite(). - */ -#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) -#endif - -/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, - * is returned in "result". - */ -#ifndef YY_INPUT -#define YY_INPUT(buf,result,max_size) \ - if ( yy_current_buffer->yy_is_interactive ) \ - { \ - int c = '*', n; \ - for ( n = 0; n < max_size && \ - (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ - buf[n] = (char) c; \ - if ( c == '\n' ) \ - buf[n++] = (char) c; \ - if ( c == EOF && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); \ - result = n; \ - } \ - else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ - && ferror( yyin ) ) \ - YY_FATAL_ERROR( "input in flex scanner failed" ); -#endif - -/* No semi-colon after return; correct usage is to write "yyterminate();" - - * we don't want an extra ';' after the "return" because that will cause - * some compilers to complain about unreachable statements. - */ -#ifndef yyterminate -#define yyterminate() return YY_NULL -#endif - -/* Number of entries by which start-condition stack grows. */ -#ifndef YY_START_STACK_INCR -#define YY_START_STACK_INCR 25 -#endif - -/* Report a fatal error. */ -#ifndef YY_FATAL_ERROR -#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) -#endif - -/* Default declaration of generated scanner - a define so the user can - * easily add parameters. - */ -#ifndef YY_DECL -#define YY_DECL int yylex YY_PROTO(( void )) -#endif - -/* Code executed at the beginning of each rule, after yytext and yyleng - * have been set up. - */ -#ifndef YY_USER_ACTION -#define YY_USER_ACTION -#endif - -/* Code executed at the end of each rule. */ -#ifndef YY_BREAK -#define YY_BREAK break; -#endif - -#define YY_RULE_SETUP \ - YY_USER_ACTION - -YY_DECL - { - register yy_state_type yy_current_state; - register char *yy_cp, *yy_bp; - register int yy_act; - -#line 55 "macro.lex.l" - - -#line 594 "lex.yy.c" - - if ( yy_init ) - { - yy_init = 0; - -#ifdef YY_USER_INIT - YY_USER_INIT; -#endif - - if ( ! yy_start ) - yy_start = 1; /* first start state */ - - if ( ! yyin ) - yyin = stdin; - - if ( ! yyout ) - yyout = stdout; - - if ( ! yy_current_buffer ) - yy_current_buffer = - yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_load_buffer_state(); - } - - while ( 1 ) /* loops until end-of-file is reached */ - { - yy_cp = yy_c_buf_p; - - /* Support of yytext. */ - *yy_cp = yy_hold_char; - - /* yy_bp points to the position in yy_ch_buf of the start of - * the current run. - */ - yy_bp = yy_cp; - - yy_current_state = yy_start; -yy_match: - do - { - register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 28 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - ++yy_cp; - } - while ( yy_base[yy_current_state] != 62 ); - -yy_find_action: - yy_act = yy_accept[yy_current_state]; - if ( yy_act == 0 ) - { /* have to back up */ - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - yy_act = yy_accept[yy_current_state]; - } - - YY_DO_BEFORE_ACTION; - - -do_action: /* This label is used only to access EOF actions. */ - - - switch ( yy_act ) - { /* beginning of action switch */ - case 0: /* must back up */ - /* undo the effects of YY_DO_BEFORE_ACTION */ - *yy_cp = yy_hold_char; - yy_cp = yy_last_accepting_cpos; - yy_current_state = yy_last_accepting_state; - goto yy_find_action; - -case 1: -YY_RULE_SETUP -#line 57 "macro.lex.l" -yylval.integer = strtol(yytext, NULL, 10); return INTEGER; - YY_BREAK -case 2: -YY_RULE_SETUP -#line 58 "macro.lex.l" -yylval.integer = strtol(yytext, NULL, 16); return INTEGER; - YY_BREAK -case 3: -YY_RULE_SETUP -#line 60 "macro.lex.l" -return MACRO_Lookup(yytext, &yylval); - YY_BREAK -case 4: -#line 63 "macro.lex.l" -case 5: -#line 64 "macro.lex.l" -case 6: -#line 65 "macro.lex.l" -case 7: -#line 66 "macro.lex.l" -case 8: -#line 67 "macro.lex.l" -case 9: -YY_RULE_SETUP -#line 67 "macro.lex.l" -{ - if (lex_data->quote_stk_idx == 0 || - (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') || - (yytext[0] == '`')) - { - /* opening a new one */ - if (lex_data->quote_stk_idx == 0) - { - assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0])); - lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1); - yylval.string = lex_data->strptr; - lex_data->cache_used++; - BEGIN(quote); - } - else *lex_data->strptr++ = yytext[0]; - lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0]; - assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0])); - } - else - { - if (yytext[0] == '`') assert(0); - /* close the current quote */ - if (--lex_data->quote_stk_idx == 0) - { - BEGIN INITIAL; - *lex_data->strptr++ = '\0'; - return STRING; - } - else *lex_data->strptr++ = yytext[0]; - } -} - YY_BREAK -case 10: -YY_RULE_SETUP -#line 99 "macro.lex.l" -*lex_data->strptr++ = yytext[0]; - YY_BREAK -case 11: -YY_RULE_SETUP -#line 100 "macro.lex.l" -*lex_data->strptr++ = yytext[1]; - YY_BREAK -case YY_STATE_EOF(quote): -#line 101 "macro.lex.l" -return 0; - YY_BREAK -case 12: -YY_RULE_SETUP -#line 103 "macro.lex.l" - - YY_BREAK -case 13: -YY_RULE_SETUP -#line 104 "macro.lex.l" -return yytext[0]; - YY_BREAK -case 14: -YY_RULE_SETUP -#line 105 "macro.lex.l" -ECHO; - YY_BREAK -#line 766 "lex.yy.c" -case YY_STATE_EOF(INITIAL): - yyterminate(); - - case YY_END_OF_BUFFER: - { - /* Amount of text matched not including the EOB char. */ - int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; - - /* Undo the effects of YY_DO_BEFORE_ACTION. */ - *yy_cp = yy_hold_char; - YY_RESTORE_YY_MORE_OFFSET - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) - { - /* We're scanning a new file or input source. It's - * possible that this happened because the user - * just pointed yyin at a new source and called - * yylex(). If so, then we have to assure - * consistency between yy_current_buffer and our - * globals. Here is the right place to do so, because - * this is the first action (other than possibly a - * back-up) that will match for the new input source. - */ - yy_n_chars = yy_current_buffer->yy_n_chars; - yy_current_buffer->yy_input_file = yyin; - yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; - } - - /* Note that here we test for yy_c_buf_p "<=" to the position - * of the first EOB in the buffer, since yy_c_buf_p will - * already have been incremented past the NUL character - * (since all states make transitions on EOB to the - * end-of-buffer state). Contrast this with the test - * in input(). - */ - if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - { /* This was really a NUL. */ - yy_state_type yy_next_state; - - yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - /* Okay, we're now positioned to make the NUL - * transition. We couldn't have - * yy_get_previous_state() go ahead and do it - * for us because it doesn't know how to deal - * with the possibility of jamming (and we don't - * want to build jamming into it because then it - * will run more slowly). - */ - - yy_next_state = yy_try_NUL_trans( yy_current_state ); - - yy_bp = yytext_ptr + YY_MORE_ADJ; - - if ( yy_next_state ) - { - /* Consume the NUL. */ - yy_cp = ++yy_c_buf_p; - yy_current_state = yy_next_state; - goto yy_match; - } - - else - { - yy_cp = yy_c_buf_p; - goto yy_find_action; - } - } - - else switch ( yy_get_next_buffer() ) - { - case EOB_ACT_END_OF_FILE: - { - yy_did_buffer_switch_on_eof = 0; - - if ( yywrap() ) - { - /* Note: because we've taken care in - * yy_get_next_buffer() to have set up - * yytext, we can now set up - * yy_c_buf_p so that if some total - * hoser (like flex itself) wants to - * call the scanner after we return the - * YY_NULL, it'll still work - another - * YY_NULL will get returned. - */ - yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; - - yy_act = YY_STATE_EOF(YY_START); - goto do_action; - } - - else - { - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; - } - break; - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = - yytext_ptr + yy_amount_of_matched_text; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_match; - - case EOB_ACT_LAST_MATCH: - yy_c_buf_p = - &yy_current_buffer->yy_ch_buf[yy_n_chars]; - - yy_current_state = yy_get_previous_state(); - - yy_cp = yy_c_buf_p; - yy_bp = yytext_ptr + YY_MORE_ADJ; - goto yy_find_action; - } - break; - } - - default: - YY_FATAL_ERROR( - "fatal flex scanner internal error--no action found" ); - } /* end of action switch */ - } /* end of scanning one token */ - } /* end of yylex */ - - -/* yy_get_next_buffer - try to read in a new buffer - * - * Returns a code representing an action: - * EOB_ACT_LAST_MATCH - - * EOB_ACT_CONTINUE_SCAN - continue scanning from current position - * EOB_ACT_END_OF_FILE - end of file - */ - -static int yy_get_next_buffer() - { - register char *dest = yy_current_buffer->yy_ch_buf; - register char *source = yytext_ptr; - register int number_to_move, i; - int ret_val; - - if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) - YY_FATAL_ERROR( - "fatal flex scanner internal error--end of buffer missed" ); - - if ( yy_current_buffer->yy_fill_buffer == 0 ) - { /* Don't try to fill the buffer, so this is an EOF. */ - if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) - { - /* We matched a single character, the EOB, so - * treat this as a final EOF. - */ - return EOB_ACT_END_OF_FILE; - } - - else - { - /* We matched some text prior to the EOB, first - * process it. - */ - return EOB_ACT_LAST_MATCH; - } - } - - /* Try to read more data. */ - - /* First move last chars to start of buffer. */ - number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; - - for ( i = 0; i < number_to_move; ++i ) - *(dest++) = *(source++); - - if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) - /* don't do the read, it's not guaranteed to return an EOF, - * just force an EOF - */ - yy_current_buffer->yy_n_chars = yy_n_chars = 0; - - else - { - int num_to_read = - yy_current_buffer->yy_buf_size - number_to_move - 1; - - while ( num_to_read <= 0 ) - { /* Not enough room in the buffer - grow it. */ -#ifdef YY_USES_REJECT - YY_FATAL_ERROR( -"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); -#else - - /* just a shorter name for the current buffer */ - YY_BUFFER_STATE b = yy_current_buffer; - - int yy_c_buf_p_offset = - (int) (yy_c_buf_p - b->yy_ch_buf); - - if ( b->yy_is_our_buffer ) - { - int new_size = b->yy_buf_size * 2; - - if ( new_size <= 0 ) - b->yy_buf_size += b->yy_buf_size / 8; - else - b->yy_buf_size *= 2; - - b->yy_ch_buf = (char *) - /* Include room in for 2 EOB chars. */ - yy_flex_realloc( (void *) b->yy_ch_buf, - b->yy_buf_size + 2 ); - } - else - /* Can't grow it, we don't own it. */ - b->yy_ch_buf = 0; - - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( - "fatal error - scanner input buffer overflow" ); - - yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; - - num_to_read = yy_current_buffer->yy_buf_size - - number_to_move - 1; -#endif - } - - if ( num_to_read > YY_READ_BUF_SIZE ) - num_to_read = YY_READ_BUF_SIZE; - - /* Read in more data. */ - YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), - yy_n_chars, num_to_read ); - - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - if ( yy_n_chars == 0 ) - { - if ( number_to_move == YY_MORE_ADJ ) - { - ret_val = EOB_ACT_END_OF_FILE; - yyrestart( yyin ); - } - - else - { - ret_val = EOB_ACT_LAST_MATCH; - yy_current_buffer->yy_buffer_status = - YY_BUFFER_EOF_PENDING; - } - } - - else - ret_val = EOB_ACT_CONTINUE_SCAN; - - yy_n_chars += number_to_move; - yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; - yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; - - yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; - - return ret_val; - } - - -/* yy_get_previous_state - get the state just before the EOB char was reached */ - -static yy_state_type yy_get_previous_state() - { - register yy_state_type yy_current_state; - register char *yy_cp; - - yy_current_state = yy_start; - - for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) - { - register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 28 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - } - - return yy_current_state; - } - - -/* yy_try_NUL_trans - try to make a transition on the NUL character - * - * synopsis - * next_state = yy_try_NUL_trans( current_state ); - */ - -#ifdef YY_USE_PROTOS -static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) -#else -static yy_state_type yy_try_NUL_trans( yy_current_state ) -yy_state_type yy_current_state; -#endif - { - register int yy_is_jam; - register char *yy_cp = yy_c_buf_p; - - register YY_CHAR yy_c = 1; - if ( yy_accept[yy_current_state] ) - { - yy_last_accepting_state = yy_current_state; - yy_last_accepting_cpos = yy_cp; - } - while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) - { - yy_current_state = (int) yy_def[yy_current_state]; - if ( yy_current_state >= 28 ) - yy_c = yy_meta[(unsigned int) yy_c]; - } - yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; - yy_is_jam = (yy_current_state == 27); - - return yy_is_jam ? 0 : yy_current_state; - } - - -#ifndef YY_NO_UNPUT -#ifdef YY_USE_PROTOS -static void yyunput( int c, register char *yy_bp ) -#else -static void yyunput( c, yy_bp ) -int c; -register char *yy_bp; -#endif - { - register char *yy_cp = yy_c_buf_p; - - /* undo effects of setting up yytext */ - *yy_cp = yy_hold_char; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - { /* need to shift things up to make room */ - /* +2 for EOB chars. */ - register int number_to_move = yy_n_chars + 2; - register char *dest = &yy_current_buffer->yy_ch_buf[ - yy_current_buffer->yy_buf_size + 2]; - register char *source = - &yy_current_buffer->yy_ch_buf[number_to_move]; - - while ( source > yy_current_buffer->yy_ch_buf ) - *--dest = *--source; - - yy_cp += (int) (dest - source); - yy_bp += (int) (dest - source); - yy_current_buffer->yy_n_chars = - yy_n_chars = yy_current_buffer->yy_buf_size; - - if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) - YY_FATAL_ERROR( "flex scanner push-back overflow" ); - } - - *--yy_cp = (char) c; - - - yytext_ptr = yy_bp; - yy_hold_char = *yy_cp; - yy_c_buf_p = yy_cp; - } -#endif /* ifndef YY_NO_UNPUT */ - - -#ifdef __cplusplus -static int yyinput() -#else -static int input() -#endif - { - int c; - - *yy_c_buf_p = yy_hold_char; - - if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) - { - /* yy_c_buf_p now points to the character we want to return. - * If this occurs *before* the EOB characters, then it's a - * valid NUL; if not, then we've hit the end of the buffer. - */ - if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) - /* This was really a NUL. */ - *yy_c_buf_p = '\0'; - - else - { /* need more input */ - int offset = yy_c_buf_p - yytext_ptr; - ++yy_c_buf_p; - - switch ( yy_get_next_buffer() ) - { - case EOB_ACT_LAST_MATCH: - /* This happens because yy_g_n_b() - * sees that we've accumulated a - * token and flags that we need to - * try matching the token before - * proceeding. But for input(), - * there's no matching to consider. - * So convert the EOB_ACT_LAST_MATCH - * to EOB_ACT_END_OF_FILE. - */ - - /* Reset buffer status. */ - yyrestart( yyin ); - - /* fall through */ - - case EOB_ACT_END_OF_FILE: - { - if ( yywrap() ) - return EOF; - - if ( ! yy_did_buffer_switch_on_eof ) - YY_NEW_FILE; -#ifdef __cplusplus - return yyinput(); -#else - return input(); -#endif - } - - case EOB_ACT_CONTINUE_SCAN: - yy_c_buf_p = yytext_ptr + offset; - break; - } - } - } - - c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ - *yy_c_buf_p = '\0'; /* preserve yytext */ - yy_hold_char = *++yy_c_buf_p; - - - return c; - } - - -#ifdef YY_USE_PROTOS -void yyrestart( FILE *input_file ) -#else -void yyrestart( input_file ) -FILE *input_file; -#endif - { - if ( ! yy_current_buffer ) - yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); - - yy_init_buffer( yy_current_buffer, input_file ); - yy_load_buffer_state(); - } - - -#ifdef YY_USE_PROTOS -void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) -#else -void yy_switch_to_buffer( new_buffer ) -YY_BUFFER_STATE new_buffer; -#endif - { - if ( yy_current_buffer == new_buffer ) - return; - - if ( yy_current_buffer ) - { - /* Flush out information for old buffer. */ - *yy_c_buf_p = yy_hold_char; - yy_current_buffer->yy_buf_pos = yy_c_buf_p; - yy_current_buffer->yy_n_chars = yy_n_chars; - } - - yy_current_buffer = new_buffer; - yy_load_buffer_state(); - - /* We don't actually know whether we did this switch during - * EOF (yywrap()) processing, but the only time this flag - * is looked at is after yywrap() is called, so it's safe - * to go ahead and always set it. - */ - yy_did_buffer_switch_on_eof = 1; - } - - -#ifdef YY_USE_PROTOS -void yy_load_buffer_state( void ) -#else -void yy_load_buffer_state() -#endif - { - yy_n_chars = yy_current_buffer->yy_n_chars; - yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; - yyin = yy_current_buffer->yy_input_file; - yy_hold_char = *yy_c_buf_p; - } - - -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) -#else -YY_BUFFER_STATE yy_create_buffer( file, size ) -FILE *file; -int size; -#endif - { - YY_BUFFER_STATE b; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_buf_size = size; - - /* yy_ch_buf has to be 2 characters longer than the size given because - * we need to put in 2 end-of-buffer characters. - */ - b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); - if ( ! b->yy_ch_buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); - - b->yy_is_our_buffer = 1; - - yy_init_buffer( b, file ); - - return b; - } - - -#ifdef YY_USE_PROTOS -void yy_delete_buffer( YY_BUFFER_STATE b ) -#else -void yy_delete_buffer( b ) -YY_BUFFER_STATE b; -#endif - { - if ( ! b ) - return; - - if ( b == yy_current_buffer ) - yy_current_buffer = (YY_BUFFER_STATE) 0; - - if ( b->yy_is_our_buffer ) - yy_flex_free( (void *) b->yy_ch_buf ); - - yy_flex_free( (void *) b ); - } - - -#ifndef YY_ALWAYS_INTERACTIVE -#ifndef YY_NEVER_INTERACTIVE -extern int isatty YY_PROTO(( int )); -#endif -#endif - -#ifdef YY_USE_PROTOS -void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) -#else -void yy_init_buffer( b, file ) -YY_BUFFER_STATE b; -FILE *file; -#endif - - - { - yy_flush_buffer( b ); - - b->yy_input_file = file; - b->yy_fill_buffer = 1; - -#if YY_ALWAYS_INTERACTIVE - b->yy_is_interactive = 1; -#else -#if YY_NEVER_INTERACTIVE - b->yy_is_interactive = 0; -#else - b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; -#endif -#endif - } - - -#ifdef YY_USE_PROTOS -void yy_flush_buffer( YY_BUFFER_STATE b ) -#else -void yy_flush_buffer( b ) -YY_BUFFER_STATE b; -#endif - - { - if ( ! b ) - return; - - b->yy_n_chars = 0; - - /* We always need two end-of-buffer characters. The first causes - * a transition to the end-of-buffer state. The second causes - * a jam in that state. - */ - b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; - b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; - - b->yy_buf_pos = &b->yy_ch_buf[0]; - - b->yy_at_bol = 1; - b->yy_buffer_status = YY_BUFFER_NEW; - - if ( b == yy_current_buffer ) - yy_load_buffer_state(); - } - - -#ifndef YY_NO_SCAN_BUFFER -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) -#else -YY_BUFFER_STATE yy_scan_buffer( base, size ) -char *base; -yy_size_t size; -#endif - { - YY_BUFFER_STATE b; - - if ( size < 2 || - base[size-2] != YY_END_OF_BUFFER_CHAR || - base[size-1] != YY_END_OF_BUFFER_CHAR ) - /* They forgot to leave room for the EOB's. */ - return 0; - - b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); - if ( ! b ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); - - b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ - b->yy_buf_pos = b->yy_ch_buf = base; - b->yy_is_our_buffer = 0; - b->yy_input_file = 0; - b->yy_n_chars = b->yy_buf_size; - b->yy_is_interactive = 0; - b->yy_at_bol = 1; - b->yy_fill_buffer = 0; - b->yy_buffer_status = YY_BUFFER_NEW; - - yy_switch_to_buffer( b ); - - return b; - } -#endif - - -#ifndef YY_NO_SCAN_STRING -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) -#else -YY_BUFFER_STATE yy_scan_string( yy_str ) -yyconst char *yy_str; -#endif - { - int len; - for ( len = 0; yy_str[len]; ++len ) - ; - - return yy_scan_bytes( yy_str, len ); - } -#endif - - -#ifndef YY_NO_SCAN_BYTES -#ifdef YY_USE_PROTOS -YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) -#else -YY_BUFFER_STATE yy_scan_bytes( bytes, len ) -yyconst char *bytes; -int len; -#endif - { - YY_BUFFER_STATE b; - char *buf; - yy_size_t n; - int i; - - /* Get memory for full buffer, including space for trailing EOB's. */ - n = len + 2; - buf = (char *) yy_flex_alloc( n ); - if ( ! buf ) - YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); - - for ( i = 0; i < len; ++i ) - buf[i] = bytes[i]; - - buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; - - b = yy_scan_buffer( buf, n ); - if ( ! b ) - YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); - - /* It's okay to grow etc. this buffer, and we should throw it - * away when we're done. - */ - b->yy_is_our_buffer = 1; - - return b; - } -#endif - - -#ifndef YY_NO_PUSH_STATE -#ifdef YY_USE_PROTOS -static void yy_push_state( int new_state ) -#else -static void yy_push_state( new_state ) -int new_state; -#endif - { - if ( yy_start_stack_ptr >= yy_start_stack_depth ) - { - yy_size_t new_size; - - yy_start_stack_depth += YY_START_STACK_INCR; - new_size = yy_start_stack_depth * sizeof( int ); - - if ( ! yy_start_stack ) - yy_start_stack = (int *) yy_flex_alloc( new_size ); - - else - yy_start_stack = (int *) yy_flex_realloc( - (void *) yy_start_stack, new_size ); - - if ( ! yy_start_stack ) - YY_FATAL_ERROR( - "out of memory expanding start-condition stack" ); - } - - yy_start_stack[yy_start_stack_ptr++] = YY_START; - - BEGIN(new_state); - } -#endif - - -#ifndef YY_NO_POP_STATE -static void yy_pop_state() - { - if ( --yy_start_stack_ptr < 0 ) - YY_FATAL_ERROR( "start-condition stack underflow" ); - - BEGIN(yy_start_stack[yy_start_stack_ptr]); - } -#endif - - -#ifndef YY_NO_TOP_STATE -static int yy_top_state() - { - return yy_start_stack[yy_start_stack_ptr - 1]; - } -#endif - -#ifndef YY_EXIT_FAILURE -#define YY_EXIT_FAILURE 2 -#endif - -#ifdef YY_USE_PROTOS -static void yy_fatal_error( yyconst char msg[] ) -#else -static void yy_fatal_error( msg ) -char msg[]; -#endif - { - (void) fprintf( stderr, "%s\n", msg ); - exit( YY_EXIT_FAILURE ); - } - - - -/* Redefine yyless() so it works in section 3 code. */ - -#undef yyless -#define yyless(n) \ - do \ - { \ - /* Undo effects of setting up yytext. */ \ - yytext[yyleng] = yy_hold_char; \ - yy_c_buf_p = yytext + n; \ - yy_hold_char = *yy_c_buf_p; \ - *yy_c_buf_p = '\0'; \ - yyleng = n; \ - } \ - while ( 0 ) - - -/* Internal utility routines. */ - -#ifndef yytext_ptr -#ifdef YY_USE_PROTOS -static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) -#else -static void yy_flex_strncpy( s1, s2, n ) -char *s1; -yyconst char *s2; -int n; -#endif - { - register int i; - for ( i = 0; i < n; ++i ) - s1[i] = s2[i]; - } -#endif - -#ifdef YY_NEED_STRLEN -#ifdef YY_USE_PROTOS -static int yy_flex_strlen( yyconst char *s ) -#else -static int yy_flex_strlen( s ) -yyconst char *s; -#endif - { - register int n; - for ( n = 0; s[n]; ++n ) - ; - - return n; - } -#endif - - -#ifdef YY_USE_PROTOS -static void *yy_flex_alloc( yy_size_t size ) -#else -static void *yy_flex_alloc( size ) -yy_size_t size; -#endif - { - return (void *) malloc( size ); - } - -#ifdef YY_USE_PROTOS -static void *yy_flex_realloc( void *ptr, yy_size_t size ) -#else -static void *yy_flex_realloc( ptr, size ) -void *ptr; -yy_size_t size; -#endif - { - /* The cast to (char *) in the following accommodates both - * implementations that use char* generic pointers, and those - * that use void* generic pointers. It works with the latter - * because both ANSI C and C++ allow castless assignment from - * any pointer type to void*, and deal with argument conversions - * as though doing an assignment. - */ - return (void *) realloc( (char *) ptr, size ); - } - -#ifdef YY_USE_PROTOS -static void yy_flex_free( void *ptr ) -#else -static void yy_flex_free( ptr ) -void *ptr; -#endif - { - free( ptr ); - } - -#if YY_MAIN -int main() - { - yylex(); - return 0; - } -#endif -#line 105 "macro.lex.l" - - -#if 0 -/* all code for testing macros */ -#include "winhelp.h" -static CHAR szTestMacro[256]; - -static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_COMMAND && wParam == IDOK) - { - GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro)); - EndDialog(hDlg, IDOK); - return TRUE; - } - return FALSE; -} - -void macro_test(void) -{ - WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance); - DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg); - FreeProcInstance(lpfnDlg); - macro = szTestMacro; -} -#endif - -/* small helper function for debug messages */ -static const char* ts(int t) -{ - static char c[2] = {0,0}; - - switch (t) - { - case EMPTY: return "EMPTY"; - case VOID_FUNCTION: return "VOID_FUNCTION"; - case BOOL_FUNCTION: return "BOOL_FUNCTION"; - case INTEGER: return "INTEGER"; - case STRING: return "STRING"; - case IDENTIFIER: return "IDENTIFIER"; - default: c[0] = (char)t; return c; - } -} - -static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret); - -/****************************************************************** - * MACRO_CheckArgs - * - * checks number of arguments against prototype, and stores arguments on - * stack pa for later call - * returns -1 on error, otherwise the number of pushed parameters - */ -static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args) -{ - int t; - unsigned int len = 0, idx = 0; - - WINE_TRACE("Checking %s\n", args); - - if (yylex() != '(') {WINE_WARN("missing (\n");return -1;} - - if (*args) - { - len = strlen(args); - for (;;) - { - t = yylex(); - WINE_TRACE("Got %s <=> %c\n", ts(t), *args); - - switch (*args) - { - case 'S': - if (t != STRING) - {WINE_WARN("missing S\n");return -1;} - pa[idx] = (void*)yylval.string; - break; - case 'U': - case 'I': - if (t != INTEGER) - {WINE_WARN("missing U\n");return -1;} - pa[idx] = LongToPtr(yylval.integer); - break; - case 'B': - if (t != BOOL_FUNCTION) - {WINE_WARN("missing B\n");return -1;} - if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0) - return -1; - break; - default: - WINE_WARN("unexpected %s while args is %c\n", ts(t), *args); - return -1; - } - idx++; - if (*++args == '\0') break; - t = yylex(); - if (t == ')') goto CheckArgs_end; - if (t != ',') {WINE_WARN("missing ,\n");return -1;} - if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;} - } - } - if (yylex() != ')') {WINE_WARN("missing )\n");return -1;} - -CheckArgs_end: - while (len > idx) pa[--len] = NULL; - return idx; -} - -/****************************************************************** - * MACRO_CallBoolFunc - * - * Invokes boolean function fn, which arguments are defined by args - * stores bool result into ret - */ -static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret) -{ - void* pa[2]; - int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); - - if (idx < 0) return 0; - if (!fn) return 1; - - WINE_TRACE("calling with %u pmts\n", idx); - - switch (strlen(args)) - { - case 0: *ret = (void*)(fn)(); break; - case 1: *ret = (void*)(fn)(pa[0]); break; - default: WINE_FIXME("NIY\n"); - } - - return 1; -} - -/****************************************************************** - * MACRO_CallVoidFunc - * - * - */ -static int MACRO_CallVoidFunc(FARPROC fn, const char* args) -{ - void* pa[6]; - int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); - - if (idx < 0) return 0; - if (!fn) return 1; - - WINE_TRACE("calling %p with %u pmts\n", fn, idx); - - switch (strlen(args)) - { - case 0: (fn)(); break; - case 1: (fn)(pa[0]); break; - case 2: (fn)(pa[0],pa[1]); break; - case 3: (fn)(pa[0],pa[1],pa[2]); break; - case 4: (fn)(pa[0],pa[1],pa[2],pa[3]); break; - case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]); break; - case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]); break; - default: WINE_FIXME("NIY\n"); - } - - return 1; -} - -BOOL MACRO_ExecuteMacro(LPCSTR macro) -{ - struct lex_data curr_lex_data, *prev_lex_data; - BOOL ret = TRUE; - int t; - - WINE_TRACE("%s\n", wine_dbgstr_a(macro)); - - prev_lex_data = lex_data; - lex_data = &curr_lex_data; - - memset(lex_data, 0, sizeof(*lex_data)); - lex_data->macroptr = macro; - - while ((t = yylex()) != EMPTY) - { - switch (t) - { - case VOID_FUNCTION: - WINE_TRACE("got type void func(%s)\n", yylval.proto); - MACRO_CallVoidFunc(yylval.function, yylval.proto); - break; - case BOOL_FUNCTION: - WINE_WARN("got type bool func(%s)\n", yylval.proto); - break; - default: - WINE_WARN("got unexpected type %s\n", ts(t)); - return 0; - } - switch (t = yylex()) - { - case EMPTY: goto done; - case ';': break; - default: ret = FALSE; goto done; - } - } - -done: - for (t = 0; t < lex_data->cache_used; t++) - HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]); - lex_data = prev_lex_data; - - return ret; -} - -#ifndef yywrap -int yywrap(void) { return 1; } -#endif +/* A lexical scanner generated by flex */ + +/* Scanner skeleton version: + * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $ + */ + +#define FLEX_SCANNER +#define YY_FLEX_MAJOR_VERSION 2 +#define YY_FLEX_MINOR_VERSION 5 + +#include + + +/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */ +#ifdef c_plusplus +#ifndef __cplusplus +#define __cplusplus +#endif +#endif + + +#ifdef __cplusplus + +#include +#include + +/* Use prototypes in function declarations. */ +#define YY_USE_PROTOS + +/* The "const" storage-class-modifier is valid. */ +#define YY_USE_CONST + +#else /* ! __cplusplus */ + +#if __STDC__ + +#define YY_USE_PROTOS +#define YY_USE_CONST + +#endif /* __STDC__ */ +#endif /* ! __cplusplus */ + +#ifdef __TURBOC__ + #pragma warn -rch + #pragma warn -use +#include +#include +#define YY_USE_CONST +#define YY_USE_PROTOS +#endif + +#ifdef YY_USE_CONST +#define yyconst const +#else +#define yyconst +#endif + + +#ifdef YY_USE_PROTOS +#define YY_PROTO(proto) proto +#else +#define YY_PROTO(proto) () +#endif + +/* Returned upon end-of-file. */ +#define YY_NULL 0 + +/* Promotes a possibly negative, possibly signed char to an unsigned + * integer for use as an array index. If the signed char is negative, + * we want to instead treat it as an 8-bit unsigned char, hence the + * double cast. + */ +#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c) + +/* Enter a start condition. This macro really ought to take a parameter, + * but we do it the disgusting crufty way forced on us by the ()-less + * definition of BEGIN. + */ +#define BEGIN yy_start = 1 + 2 * + +/* Translate the current start state into a value that can be later handed + * to BEGIN to return to the state. The YYSTATE alias is for lex + * compatibility. + */ +#define YY_START ((yy_start - 1) / 2) +#define YYSTATE YY_START + +/* Action number for EOF rule of a given start state. */ +#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1) + +/* Special action meaning "start processing a new file". */ +#define YY_NEW_FILE yyrestart( yyin ) + +#define YY_END_OF_BUFFER_CHAR 0 + +/* Size of default input buffer. */ +#define YY_BUF_SIZE 16384 + +typedef struct yy_buffer_state *YY_BUFFER_STATE; + +extern int yyleng; +extern FILE *yyin, *yyout; + +#define EOB_ACT_CONTINUE_SCAN 0 +#define EOB_ACT_END_OF_FILE 1 +#define EOB_ACT_LAST_MATCH 2 + +/* The funky do-while in the following #define is used to turn the definition + * int a single C statement (which needs a semi-colon terminator). This + * avoids problems with code like: + * + * if ( condition_holds ) + * yyless( 5 ); + * else + * do_something_else(); + * + * Prior to using the do-while the compiler would get upset at the + * "else" because it interpreted the "if" statement as being all + * done when it reached the ';' after the yyless() call. + */ + +/* Return all but the first 'n' matched characters back to the input stream. */ + +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + *yy_cp = yy_hold_char; \ + YY_RESTORE_YY_MORE_OFFSET \ + yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \ + YY_DO_BEFORE_ACTION; /* set up yytext again */ \ + } \ + while ( 0 ) + +#define unput(c) yyunput( c, yytext_ptr ) + +/* The following is because we cannot portably get our hands on size_t + * (without autoconf's help, which isn't available because we want + * flex-generated scanners to compile on their own). + */ +typedef unsigned int yy_size_t; + + +struct yy_buffer_state + { + FILE *yy_input_file; + + char *yy_ch_buf; /* input buffer */ + char *yy_buf_pos; /* current position in input buffer */ + + /* Size of input buffer in bytes, not including room for EOB + * characters. + */ + yy_size_t yy_buf_size; + + /* Number of characters read into yy_ch_buf, not including EOB + * characters. + */ + int yy_n_chars; + + /* Whether we "own" the buffer - i.e., we know we created it, + * and can realloc() it to grow it, and should free() it to + * delete it. + */ + int yy_is_our_buffer; + + /* Whether this is an "interactive" input source; if so, and + * if we're using stdio for input, then we want to use getc() + * instead of fread(), to make sure we stop fetching input after + * each newline. + */ + int yy_is_interactive; + + /* Whether we're considered to be at the beginning of a line. + * If so, '^' rules will be active on the next match, otherwise + * not. + */ + int yy_at_bol; + + /* Whether to try to fill the input buffer when we reach the + * end of it. + */ + int yy_fill_buffer; + + int yy_buffer_status; +#define YY_BUFFER_NEW 0 +#define YY_BUFFER_NORMAL 1 + /* When an EOF's been seen but there's still some text to process + * then we mark the buffer as YY_EOF_PENDING, to indicate that we + * shouldn't try reading from the input source any more. We might + * still have a bunch of tokens to match, though, because of + * possible backing-up. + * + * When we actually see the EOF, we change the status to "new" + * (via yyrestart()), so that the user can continue scanning by + * just pointing yyin at a new input file. + */ +#define YY_BUFFER_EOF_PENDING 2 + }; + +static YY_BUFFER_STATE yy_current_buffer = 0; + +/* We provide macros for accessing buffer states in case in the + * future we want to put the buffer states in a more general + * "scanner state". + */ +#define YY_CURRENT_BUFFER yy_current_buffer + + +/* yy_hold_char holds the character lost when yytext is formed. */ +static char yy_hold_char; + +static int yy_n_chars; /* number of characters read into yy_ch_buf */ + + +int yyleng; + +/* Points to current character in buffer. */ +static char *yy_c_buf_p = (char *) 0; +static int yy_init = 1; /* whether we need to initialize */ +static int yy_start = 0; /* start state number */ + +/* Flag which is used to allow yywrap()'s to do buffer switches + * instead of setting up a fresh yyin. A bit of a hack ... + */ +static int yy_did_buffer_switch_on_eof; + +void yyrestart YY_PROTO(( FILE *input_file )); + +void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer )); +void yy_load_buffer_state YY_PROTO(( void )); +YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size )); +void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b )); +void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file )); +void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b )); +#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer ) + +YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size )); +YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str )); +YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len )); + +static void *yy_flex_alloc YY_PROTO(( yy_size_t )); +static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t )); +static void yy_flex_free YY_PROTO(( void * )); + +#define yy_new_buffer yy_create_buffer + +#define yy_set_interactive(is_interactive) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_is_interactive = is_interactive; \ + } + +#define yy_set_bol(at_bol) \ + { \ + if ( ! yy_current_buffer ) \ + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \ + yy_current_buffer->yy_at_bol = at_bol; \ + } + +#define YY_AT_BOL() (yy_current_buffer->yy_at_bol) + +typedef unsigned char YY_CHAR; +FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0; +typedef int yy_state_type; +extern char *yytext; +#define yytext_ptr yytext + +static yy_state_type yy_get_previous_state YY_PROTO(( void )); +static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state )); +static int yy_get_next_buffer YY_PROTO(( void )); +static void yy_fatal_error YY_PROTO(( yyconst char msg[] )); + +/* Done after the current pattern has been matched and before the + * corresponding action - sets up yytext. + */ +#define YY_DO_BEFORE_ACTION \ + yytext_ptr = yy_bp; \ + yyleng = (int) (yy_cp - yy_bp); \ + yy_hold_char = *yy_cp; \ + *yy_cp = '\0'; \ + yy_c_buf_p = yy_cp; + +#define YY_NUM_RULES 14 +#define YY_END_OF_BUFFER 15 +static yyconst short int yy_accept[28] = + { 0, + 0, 0, 0, 0, 15, 13, 14, 12, 5, 6, + 13, 1, 1, 3, 4, 10, 8, 9, 10, 7, + 1, 1, 0, 3, 11, 2, 0 + } ; + +static yyconst int yy_ec[256] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 2, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 3, 1, 4, 1, 1, 1, 1, 5, 1, + 1, 1, 6, 1, 6, 1, 1, 7, 8, 8, + 8, 8, 8, 8, 8, 8, 8, 1, 1, 1, + 1, 1, 1, 1, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 10, 9, 9, + 1, 11, 1, 1, 12, 13, 14, 14, 14, 14, + + 14, 14, 9, 9, 9, 9, 9, 9, 9, 9, + 9, 9, 9, 9, 9, 9, 9, 9, 9, 10, + 9, 9, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 1 + } ; + +static yyconst int yy_meta[15] = + { 0, + 1, 2, 1, 1, 1, 1, 3, 3, 4, 5, + 1, 4, 1, 6 + } ; + +static yyconst short int yy_base[33] = + { 0, + 0, 0, 13, 25, 25, 62, 62, 62, 62, 62, + 12, 13, 14, 0, 62, 62, 62, 62, 0, 62, + 6, 24, 0, 0, 62, 0, 62, 38, 42, 45, + 51, 55 + } ; + +static yyconst short int yy_def[33] = + { 0, + 27, 1, 28, 28, 27, 27, 27, 27, 27, 27, + 27, 29, 27, 30, 27, 27, 27, 27, 31, 27, + 29, 27, 32, 30, 27, 32, 0, 27, 27, 27, + 27, 27 + } ; + +static yyconst short int yy_nxt[77] = + { 0, + 6, 7, 8, 9, 10, 11, 12, 13, 14, 14, + 6, 6, 15, 14, 7, 23, 17, 18, 21, 22, + 22, 22, 23, 19, 27, 20, 7, 27, 17, 18, + 22, 22, 27, 27, 27, 19, 27, 20, 16, 16, + 16, 16, 16, 16, 22, 27, 22, 24, 24, 24, + 24, 25, 27, 25, 25, 25, 25, 26, 27, 27, + 26, 5, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27 + } ; + +static yyconst short int yy_chk[77] = + { 0, + 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, + 1, 1, 1, 1, 3, 21, 3, 3, 11, 11, + 13, 13, 12, 3, 5, 3, 4, 0, 4, 4, + 22, 22, 0, 0, 0, 4, 0, 4, 28, 28, + 28, 28, 28, 28, 29, 0, 29, 30, 30, 30, + 30, 31, 0, 31, 31, 31, 31, 32, 0, 0, + 32, 27, 27, 27, 27, 27, 27, 27, 27, 27, + 27, 27, 27, 27, 27, 27 + } ; + +static yy_state_type yy_last_accepting_state; +static char *yy_last_accepting_cpos; + +/* The intent behind this definition is that it'll catch + * any uses of REJECT which flex missed. + */ +#define REJECT reject_used_but_not_detected +#define yymore() yymore_used_but_not_detected +#define YY_MORE_ADJ 0 +#define YY_RESTORE_YY_MORE_OFFSET +char *yytext; +#line 1 "macro.lex.l" +#define INITIAL 0 +#line 2 "macro.lex.l" +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * Copyright 2002,2008 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +#define YY_NO_INPUT 1 +#define YY_NO_UNPUT 1 +#define quote 1 + +#line 26 "macro.lex.l" +#include "config.h" +#include + +#ifndef HAVE_UNISTD_H +#define YY_NO_UNISTD_H +#endif + +#include "macro.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +struct lex_data { + LPCSTR macroptr; + LPSTR strptr; + int quote_stack[32]; + unsigned quote_stk_idx; + LPSTR cache_string[32]; + int cache_used; +}; +static struct lex_data* lex_data = NULL; + +struct lexret yylval; + +#define YY_INPUT(buf,result,max_size)\ + if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++; + +#line 440 "lex.yy.c" + +/* Macros after this point can all be overridden by user definitions in + * section 1. + */ + +#ifndef YY_SKIP_YYWRAP +#ifdef __cplusplus +extern "C" int yywrap YY_PROTO(( void )); +#else +extern int yywrap YY_PROTO(( void )); +#endif +#endif + +#ifndef YY_NO_UNPUT +static void yyunput YY_PROTO(( int c, char *buf_ptr )); +#endif + +#ifndef yytext_ptr +static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int )); +#endif + +#ifdef YY_NEED_STRLEN +static int yy_flex_strlen YY_PROTO(( yyconst char * )); +#endif + +#ifndef YY_NO_INPUT +#ifdef __cplusplus +static int yyinput YY_PROTO(( void )); +#else +static int input YY_PROTO(( void )); +#endif +#endif + +#if YY_STACK_USED +static int yy_start_stack_ptr = 0; +static int yy_start_stack_depth = 0; +static int *yy_start_stack = 0; +#ifndef YY_NO_PUSH_STATE +static void yy_push_state YY_PROTO(( int new_state )); +#endif +#ifndef YY_NO_POP_STATE +static void yy_pop_state YY_PROTO(( void )); +#endif +#ifndef YY_NO_TOP_STATE +static int yy_top_state YY_PROTO(( void )); +#endif + +#else +#define YY_NO_PUSH_STATE 1 +#define YY_NO_POP_STATE 1 +#define YY_NO_TOP_STATE 1 +#endif + +#ifdef YY_MALLOC_DECL +YY_MALLOC_DECL +#else +#if __STDC__ +#ifndef __cplusplus +#include +#endif +#else +/* Just try to get by without declaring the routines. This will fail + * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int) + * or sizeof(void*) != sizeof(int). + */ +#endif +#endif + +/* Amount of stuff to slurp up with each read. */ +#ifndef YY_READ_BUF_SIZE +#define YY_READ_BUF_SIZE 8192 +#endif + +/* Copy whatever the last rule matched to the standard output. */ + +#ifndef ECHO +/* This used to be an fputs(), but since the string might contain NUL's, + * we now use fwrite(). + */ +#define ECHO (void) fwrite( yytext, yyleng, 1, yyout ) +#endif + +/* Gets input and stuffs it into "buf". number of characters read, or YY_NULL, + * is returned in "result". + */ +#ifndef YY_INPUT +#define YY_INPUT(buf,result,max_size) \ + if ( yy_current_buffer->yy_is_interactive ) \ + { \ + int c = '*', n; \ + for ( n = 0; n < max_size && \ + (c = getc( yyin )) != EOF && c != '\n'; ++n ) \ + buf[n] = (char) c; \ + if ( c == '\n' ) \ + buf[n++] = (char) c; \ + if ( c == EOF && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); \ + result = n; \ + } \ + else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \ + && ferror( yyin ) ) \ + YY_FATAL_ERROR( "input in flex scanner failed" ); +#endif + +/* No semi-colon after return; correct usage is to write "yyterminate();" - + * we don't want an extra ';' after the "return" because that will cause + * some compilers to complain about unreachable statements. + */ +#ifndef yyterminate +#define yyterminate() return YY_NULL +#endif + +/* Number of entries by which start-condition stack grows. */ +#ifndef YY_START_STACK_INCR +#define YY_START_STACK_INCR 25 +#endif + +/* Report a fatal error. */ +#ifndef YY_FATAL_ERROR +#define YY_FATAL_ERROR(msg) yy_fatal_error( msg ) +#endif + +/* Default declaration of generated scanner - a define so the user can + * easily add parameters. + */ +#ifndef YY_DECL +#define YY_DECL int yylex YY_PROTO(( void )) +#endif + +/* Code executed at the beginning of each rule, after yytext and yyleng + * have been set up. + */ +#ifndef YY_USER_ACTION +#define YY_USER_ACTION +#endif + +/* Code executed at the end of each rule. */ +#ifndef YY_BREAK +#define YY_BREAK break; +#endif + +#define YY_RULE_SETUP \ + YY_USER_ACTION + +YY_DECL + { + register yy_state_type yy_current_state; + register char *yy_cp, *yy_bp; + register int yy_act; + +#line 55 "macro.lex.l" + + +#line 594 "lex.yy.c" + + if ( yy_init ) + { + yy_init = 0; + +#ifdef YY_USER_INIT + YY_USER_INIT; +#endif + + if ( ! yy_start ) + yy_start = 1; /* first start state */ + + if ( ! yyin ) + yyin = stdin; + + if ( ! yyout ) + yyout = stdout; + + if ( ! yy_current_buffer ) + yy_current_buffer = + yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_load_buffer_state(); + } + + while ( 1 ) /* loops until end-of-file is reached */ + { + yy_cp = yy_c_buf_p; + + /* Support of yytext. */ + *yy_cp = yy_hold_char; + + /* yy_bp points to the position in yy_ch_buf of the start of + * the current run. + */ + yy_bp = yy_cp; + + yy_current_state = yy_start; +yy_match: + do + { + register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)]; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 28 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + ++yy_cp; + } + while ( yy_base[yy_current_state] != 62 ); + +yy_find_action: + yy_act = yy_accept[yy_current_state]; + if ( yy_act == 0 ) + { /* have to back up */ + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + yy_act = yy_accept[yy_current_state]; + } + + YY_DO_BEFORE_ACTION; + + +do_action: /* This label is used only to access EOF actions. */ + + + switch ( yy_act ) + { /* beginning of action switch */ + case 0: /* must back up */ + /* undo the effects of YY_DO_BEFORE_ACTION */ + *yy_cp = yy_hold_char; + yy_cp = yy_last_accepting_cpos; + yy_current_state = yy_last_accepting_state; + goto yy_find_action; + +case 1: +YY_RULE_SETUP +#line 57 "macro.lex.l" +yylval.integer = strtol(yytext, NULL, 10); return INTEGER; + YY_BREAK +case 2: +YY_RULE_SETUP +#line 58 "macro.lex.l" +yylval.integer = strtol(yytext, NULL, 16); return INTEGER; + YY_BREAK +case 3: +YY_RULE_SETUP +#line 60 "macro.lex.l" +return MACRO_Lookup(yytext, &yylval); + YY_BREAK +case 4: +#line 63 "macro.lex.l" +case 5: +#line 64 "macro.lex.l" +case 6: +#line 65 "macro.lex.l" +case 7: +#line 66 "macro.lex.l" +case 8: +#line 67 "macro.lex.l" +case 9: +YY_RULE_SETUP +#line 67 "macro.lex.l" +{ + if (lex_data->quote_stk_idx == 0 || + (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') || + (yytext[0] == '`')) + { + /* opening a new one */ + if (lex_data->quote_stk_idx == 0) + { + assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0])); + lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1); + yylval.string = lex_data->strptr; + lex_data->cache_used++; + BEGIN(quote); + } + else *lex_data->strptr++ = yytext[0]; + lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0]; + assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0])); + } + else + { + if (yytext[0] == '`') assert(0); + /* close the current quote */ + if (--lex_data->quote_stk_idx == 0) + { + BEGIN INITIAL; + *lex_data->strptr++ = '\0'; + return STRING; + } + else *lex_data->strptr++ = yytext[0]; + } +} + YY_BREAK +case 10: +YY_RULE_SETUP +#line 99 "macro.lex.l" +*lex_data->strptr++ = yytext[0]; + YY_BREAK +case 11: +YY_RULE_SETUP +#line 100 "macro.lex.l" +*lex_data->strptr++ = yytext[1]; + YY_BREAK +case YY_STATE_EOF(quote): +#line 101 "macro.lex.l" +return 0; + YY_BREAK +case 12: +YY_RULE_SETUP +#line 103 "macro.lex.l" + + YY_BREAK +case 13: +YY_RULE_SETUP +#line 104 "macro.lex.l" +return yytext[0]; + YY_BREAK +case 14: +YY_RULE_SETUP +#line 105 "macro.lex.l" +ECHO; + YY_BREAK +#line 766 "lex.yy.c" +case YY_STATE_EOF(INITIAL): + yyterminate(); + + case YY_END_OF_BUFFER: + { + /* Amount of text matched not including the EOB char. */ + int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1; + + /* Undo the effects of YY_DO_BEFORE_ACTION. */ + *yy_cp = yy_hold_char; + YY_RESTORE_YY_MORE_OFFSET + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW ) + { + /* We're scanning a new file or input source. It's + * possible that this happened because the user + * just pointed yyin at a new source and called + * yylex(). If so, then we have to assure + * consistency between yy_current_buffer and our + * globals. Here is the right place to do so, because + * this is the first action (other than possibly a + * back-up) that will match for the new input source. + */ + yy_n_chars = yy_current_buffer->yy_n_chars; + yy_current_buffer->yy_input_file = yyin; + yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL; + } + + /* Note that here we test for yy_c_buf_p "<=" to the position + * of the first EOB in the buffer, since yy_c_buf_p will + * already have been incremented past the NUL character + * (since all states make transitions on EOB to the + * end-of-buffer state). Contrast this with the test + * in input(). + */ + if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + { /* This was really a NUL. */ + yy_state_type yy_next_state; + + yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + /* Okay, we're now positioned to make the NUL + * transition. We couldn't have + * yy_get_previous_state() go ahead and do it + * for us because it doesn't know how to deal + * with the possibility of jamming (and we don't + * want to build jamming into it because then it + * will run more slowly). + */ + + yy_next_state = yy_try_NUL_trans( yy_current_state ); + + yy_bp = yytext_ptr + YY_MORE_ADJ; + + if ( yy_next_state ) + { + /* Consume the NUL. */ + yy_cp = ++yy_c_buf_p; + yy_current_state = yy_next_state; + goto yy_match; + } + + else + { + yy_cp = yy_c_buf_p; + goto yy_find_action; + } + } + + else switch ( yy_get_next_buffer() ) + { + case EOB_ACT_END_OF_FILE: + { + yy_did_buffer_switch_on_eof = 0; + + if ( yywrap() ) + { + /* Note: because we've taken care in + * yy_get_next_buffer() to have set up + * yytext, we can now set up + * yy_c_buf_p so that if some total + * hoser (like flex itself) wants to + * call the scanner after we return the + * YY_NULL, it'll still work - another + * YY_NULL will get returned. + */ + yy_c_buf_p = yytext_ptr + YY_MORE_ADJ; + + yy_act = YY_STATE_EOF(YY_START); + goto do_action; + } + + else + { + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; + } + break; + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = + yytext_ptr + yy_amount_of_matched_text; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_match; + + case EOB_ACT_LAST_MATCH: + yy_c_buf_p = + &yy_current_buffer->yy_ch_buf[yy_n_chars]; + + yy_current_state = yy_get_previous_state(); + + yy_cp = yy_c_buf_p; + yy_bp = yytext_ptr + YY_MORE_ADJ; + goto yy_find_action; + } + break; + } + + default: + YY_FATAL_ERROR( + "fatal flex scanner internal error--no action found" ); + } /* end of action switch */ + } /* end of scanning one token */ + } /* end of yylex */ + + +/* yy_get_next_buffer - try to read in a new buffer + * + * Returns a code representing an action: + * EOB_ACT_LAST_MATCH - + * EOB_ACT_CONTINUE_SCAN - continue scanning from current position + * EOB_ACT_END_OF_FILE - end of file + */ + +static int yy_get_next_buffer() + { + register char *dest = yy_current_buffer->yy_ch_buf; + register char *source = yytext_ptr; + register int number_to_move, i; + int ret_val; + + if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] ) + YY_FATAL_ERROR( + "fatal flex scanner internal error--end of buffer missed" ); + + if ( yy_current_buffer->yy_fill_buffer == 0 ) + { /* Don't try to fill the buffer, so this is an EOF. */ + if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 ) + { + /* We matched a single character, the EOB, so + * treat this as a final EOF. + */ + return EOB_ACT_END_OF_FILE; + } + + else + { + /* We matched some text prior to the EOB, first + * process it. + */ + return EOB_ACT_LAST_MATCH; + } + } + + /* Try to read more data. */ + + /* First move last chars to start of buffer. */ + number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1; + + for ( i = 0; i < number_to_move; ++i ) + *(dest++) = *(source++); + + if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING ) + /* don't do the read, it's not guaranteed to return an EOF, + * just force an EOF + */ + yy_current_buffer->yy_n_chars = yy_n_chars = 0; + + else + { + int num_to_read = + yy_current_buffer->yy_buf_size - number_to_move - 1; + + while ( num_to_read <= 0 ) + { /* Not enough room in the buffer - grow it. */ +#ifdef YY_USES_REJECT + YY_FATAL_ERROR( +"input buffer overflow, can't enlarge buffer because scanner uses REJECT" ); +#else + + /* just a shorter name for the current buffer */ + YY_BUFFER_STATE b = yy_current_buffer; + + int yy_c_buf_p_offset = + (int) (yy_c_buf_p - b->yy_ch_buf); + + if ( b->yy_is_our_buffer ) + { + int new_size = b->yy_buf_size * 2; + + if ( new_size <= 0 ) + b->yy_buf_size += b->yy_buf_size / 8; + else + b->yy_buf_size *= 2; + + b->yy_ch_buf = (char *) + /* Include room in for 2 EOB chars. */ + yy_flex_realloc( (void *) b->yy_ch_buf, + b->yy_buf_size + 2 ); + } + else + /* Can't grow it, we don't own it. */ + b->yy_ch_buf = 0; + + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( + "fatal error - scanner input buffer overflow" ); + + yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset]; + + num_to_read = yy_current_buffer->yy_buf_size - + number_to_move - 1; +#endif + } + + if ( num_to_read > YY_READ_BUF_SIZE ) + num_to_read = YY_READ_BUF_SIZE; + + /* Read in more data. */ + YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]), + yy_n_chars, num_to_read ); + + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + if ( yy_n_chars == 0 ) + { + if ( number_to_move == YY_MORE_ADJ ) + { + ret_val = EOB_ACT_END_OF_FILE; + yyrestart( yyin ); + } + + else + { + ret_val = EOB_ACT_LAST_MATCH; + yy_current_buffer->yy_buffer_status = + YY_BUFFER_EOF_PENDING; + } + } + + else + ret_val = EOB_ACT_CONTINUE_SCAN; + + yy_n_chars += number_to_move; + yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR; + yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR; + + yytext_ptr = &yy_current_buffer->yy_ch_buf[0]; + + return ret_val; + } + + +/* yy_get_previous_state - get the state just before the EOB char was reached */ + +static yy_state_type yy_get_previous_state() + { + register yy_state_type yy_current_state; + register char *yy_cp; + + yy_current_state = yy_start; + + for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp ) + { + register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1); + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 28 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + } + + return yy_current_state; + } + + +/* yy_try_NUL_trans - try to make a transition on the NUL character + * + * synopsis + * next_state = yy_try_NUL_trans( current_state ); + */ + +#ifdef YY_USE_PROTOS +static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state ) +#else +static yy_state_type yy_try_NUL_trans( yy_current_state ) +yy_state_type yy_current_state; +#endif + { + register int yy_is_jam; + register char *yy_cp = yy_c_buf_p; + + register YY_CHAR yy_c = 1; + if ( yy_accept[yy_current_state] ) + { + yy_last_accepting_state = yy_current_state; + yy_last_accepting_cpos = yy_cp; + } + while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state ) + { + yy_current_state = (int) yy_def[yy_current_state]; + if ( yy_current_state >= 28 ) + yy_c = yy_meta[(unsigned int) yy_c]; + } + yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c]; + yy_is_jam = (yy_current_state == 27); + + return yy_is_jam ? 0 : yy_current_state; + } + + +#ifndef YY_NO_UNPUT +#ifdef YY_USE_PROTOS +static void yyunput( int c, register char *yy_bp ) +#else +static void yyunput( c, yy_bp ) +int c; +register char *yy_bp; +#endif + { + register char *yy_cp = yy_c_buf_p; + + /* undo effects of setting up yytext */ + *yy_cp = yy_hold_char; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + { /* need to shift things up to make room */ + /* +2 for EOB chars. */ + register int number_to_move = yy_n_chars + 2; + register char *dest = &yy_current_buffer->yy_ch_buf[ + yy_current_buffer->yy_buf_size + 2]; + register char *source = + &yy_current_buffer->yy_ch_buf[number_to_move]; + + while ( source > yy_current_buffer->yy_ch_buf ) + *--dest = *--source; + + yy_cp += (int) (dest - source); + yy_bp += (int) (dest - source); + yy_current_buffer->yy_n_chars = + yy_n_chars = yy_current_buffer->yy_buf_size; + + if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 ) + YY_FATAL_ERROR( "flex scanner push-back overflow" ); + } + + *--yy_cp = (char) c; + + + yytext_ptr = yy_bp; + yy_hold_char = *yy_cp; + yy_c_buf_p = yy_cp; + } +#endif /* ifndef YY_NO_UNPUT */ + + +#ifdef __cplusplus +static int yyinput() +#else +static int input() +#endif + { + int c; + + *yy_c_buf_p = yy_hold_char; + + if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR ) + { + /* yy_c_buf_p now points to the character we want to return. + * If this occurs *before* the EOB characters, then it's a + * valid NUL; if not, then we've hit the end of the buffer. + */ + if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] ) + /* This was really a NUL. */ + *yy_c_buf_p = '\0'; + + else + { /* need more input */ + int offset = yy_c_buf_p - yytext_ptr; + ++yy_c_buf_p; + + switch ( yy_get_next_buffer() ) + { + case EOB_ACT_LAST_MATCH: + /* This happens because yy_g_n_b() + * sees that we've accumulated a + * token and flags that we need to + * try matching the token before + * proceeding. But for input(), + * there's no matching to consider. + * So convert the EOB_ACT_LAST_MATCH + * to EOB_ACT_END_OF_FILE. + */ + + /* Reset buffer status. */ + yyrestart( yyin ); + + /* fall through */ + + case EOB_ACT_END_OF_FILE: + { + if ( yywrap() ) + return EOF; + + if ( ! yy_did_buffer_switch_on_eof ) + YY_NEW_FILE; +#ifdef __cplusplus + return yyinput(); +#else + return input(); +#endif + } + + case EOB_ACT_CONTINUE_SCAN: + yy_c_buf_p = yytext_ptr + offset; + break; + } + } + } + + c = *(unsigned char *) yy_c_buf_p; /* cast for 8-bit char's */ + *yy_c_buf_p = '\0'; /* preserve yytext */ + yy_hold_char = *++yy_c_buf_p; + + + return c; + } + + +#ifdef YY_USE_PROTOS +void yyrestart( FILE *input_file ) +#else +void yyrestart( input_file ) +FILE *input_file; +#endif + { + if ( ! yy_current_buffer ) + yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); + + yy_init_buffer( yy_current_buffer, input_file ); + yy_load_buffer_state(); + } + + +#ifdef YY_USE_PROTOS +void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer ) +#else +void yy_switch_to_buffer( new_buffer ) +YY_BUFFER_STATE new_buffer; +#endif + { + if ( yy_current_buffer == new_buffer ) + return; + + if ( yy_current_buffer ) + { + /* Flush out information for old buffer. */ + *yy_c_buf_p = yy_hold_char; + yy_current_buffer->yy_buf_pos = yy_c_buf_p; + yy_current_buffer->yy_n_chars = yy_n_chars; + } + + yy_current_buffer = new_buffer; + yy_load_buffer_state(); + + /* We don't actually know whether we did this switch during + * EOF (yywrap()) processing, but the only time this flag + * is looked at is after yywrap() is called, so it's safe + * to go ahead and always set it. + */ + yy_did_buffer_switch_on_eof = 1; + } + + +#ifdef YY_USE_PROTOS +void yy_load_buffer_state( void ) +#else +void yy_load_buffer_state() +#endif + { + yy_n_chars = yy_current_buffer->yy_n_chars; + yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos; + yyin = yy_current_buffer->yy_input_file; + yy_hold_char = *yy_c_buf_p; + } + + +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_create_buffer( FILE *file, int size ) +#else +YY_BUFFER_STATE yy_create_buffer( file, size ) +FILE *file; +int size; +#endif + { + YY_BUFFER_STATE b; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_buf_size = size; + + /* yy_ch_buf has to be 2 characters longer than the size given because + * we need to put in 2 end-of-buffer characters. + */ + b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 ); + if ( ! b->yy_ch_buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" ); + + b->yy_is_our_buffer = 1; + + yy_init_buffer( b, file ); + + return b; + } + + +#ifdef YY_USE_PROTOS +void yy_delete_buffer( YY_BUFFER_STATE b ) +#else +void yy_delete_buffer( b ) +YY_BUFFER_STATE b; +#endif + { + if ( ! b ) + return; + + if ( b == yy_current_buffer ) + yy_current_buffer = (YY_BUFFER_STATE) 0; + + if ( b->yy_is_our_buffer ) + yy_flex_free( (void *) b->yy_ch_buf ); + + yy_flex_free( (void *) b ); + } + + +#ifndef YY_ALWAYS_INTERACTIVE +#ifndef YY_NEVER_INTERACTIVE +extern int isatty YY_PROTO(( int )); +#endif +#endif + +#ifdef YY_USE_PROTOS +void yy_init_buffer( YY_BUFFER_STATE b, FILE *file ) +#else +void yy_init_buffer( b, file ) +YY_BUFFER_STATE b; +FILE *file; +#endif + + + { + yy_flush_buffer( b ); + + b->yy_input_file = file; + b->yy_fill_buffer = 1; + +#if YY_ALWAYS_INTERACTIVE + b->yy_is_interactive = 1; +#else +#if YY_NEVER_INTERACTIVE + b->yy_is_interactive = 0; +#else + b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0; +#endif +#endif + } + + +#ifdef YY_USE_PROTOS +void yy_flush_buffer( YY_BUFFER_STATE b ) +#else +void yy_flush_buffer( b ) +YY_BUFFER_STATE b; +#endif + + { + if ( ! b ) + return; + + b->yy_n_chars = 0; + + /* We always need two end-of-buffer characters. The first causes + * a transition to the end-of-buffer state. The second causes + * a jam in that state. + */ + b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR; + b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR; + + b->yy_buf_pos = &b->yy_ch_buf[0]; + + b->yy_at_bol = 1; + b->yy_buffer_status = YY_BUFFER_NEW; + + if ( b == yy_current_buffer ) + yy_load_buffer_state(); + } + + +#ifndef YY_NO_SCAN_BUFFER +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size ) +#else +YY_BUFFER_STATE yy_scan_buffer( base, size ) +char *base; +yy_size_t size; +#endif + { + YY_BUFFER_STATE b; + + if ( size < 2 || + base[size-2] != YY_END_OF_BUFFER_CHAR || + base[size-1] != YY_END_OF_BUFFER_CHAR ) + /* They forgot to leave room for the EOB's. */ + return 0; + + b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) ); + if ( ! b ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" ); + + b->yy_buf_size = size - 2; /* "- 2" to take care of EOB's */ + b->yy_buf_pos = b->yy_ch_buf = base; + b->yy_is_our_buffer = 0; + b->yy_input_file = 0; + b->yy_n_chars = b->yy_buf_size; + b->yy_is_interactive = 0; + b->yy_at_bol = 1; + b->yy_fill_buffer = 0; + b->yy_buffer_status = YY_BUFFER_NEW; + + yy_switch_to_buffer( b ); + + return b; + } +#endif + + +#ifndef YY_NO_SCAN_STRING +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str ) +#else +YY_BUFFER_STATE yy_scan_string( yy_str ) +yyconst char *yy_str; +#endif + { + int len; + for ( len = 0; yy_str[len]; ++len ) + ; + + return yy_scan_bytes( yy_str, len ); + } +#endif + + +#ifndef YY_NO_SCAN_BYTES +#ifdef YY_USE_PROTOS +YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len ) +#else +YY_BUFFER_STATE yy_scan_bytes( bytes, len ) +yyconst char *bytes; +int len; +#endif + { + YY_BUFFER_STATE b; + char *buf; + yy_size_t n; + int i; + + /* Get memory for full buffer, including space for trailing EOB's. */ + n = len + 2; + buf = (char *) yy_flex_alloc( n ); + if ( ! buf ) + YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" ); + + for ( i = 0; i < len; ++i ) + buf[i] = bytes[i]; + + buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR; + + b = yy_scan_buffer( buf, n ); + if ( ! b ) + YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" ); + + /* It's okay to grow etc. this buffer, and we should throw it + * away when we're done. + */ + b->yy_is_our_buffer = 1; + + return b; + } +#endif + + +#ifndef YY_NO_PUSH_STATE +#ifdef YY_USE_PROTOS +static void yy_push_state( int new_state ) +#else +static void yy_push_state( new_state ) +int new_state; +#endif + { + if ( yy_start_stack_ptr >= yy_start_stack_depth ) + { + yy_size_t new_size; + + yy_start_stack_depth += YY_START_STACK_INCR; + new_size = yy_start_stack_depth * sizeof( int ); + + if ( ! yy_start_stack ) + yy_start_stack = (int *) yy_flex_alloc( new_size ); + + else + yy_start_stack = (int *) yy_flex_realloc( + (void *) yy_start_stack, new_size ); + + if ( ! yy_start_stack ) + YY_FATAL_ERROR( + "out of memory expanding start-condition stack" ); + } + + yy_start_stack[yy_start_stack_ptr++] = YY_START; + + BEGIN(new_state); + } +#endif + + +#ifndef YY_NO_POP_STATE +static void yy_pop_state() + { + if ( --yy_start_stack_ptr < 0 ) + YY_FATAL_ERROR( "start-condition stack underflow" ); + + BEGIN(yy_start_stack[yy_start_stack_ptr]); + } +#endif + + +#ifndef YY_NO_TOP_STATE +static int yy_top_state() + { + return yy_start_stack[yy_start_stack_ptr - 1]; + } +#endif + +#ifndef YY_EXIT_FAILURE +#define YY_EXIT_FAILURE 2 +#endif + +#ifdef YY_USE_PROTOS +static void yy_fatal_error( yyconst char msg[] ) +#else +static void yy_fatal_error( msg ) +char msg[]; +#endif + { + (void) fprintf( stderr, "%s\n", msg ); + exit( YY_EXIT_FAILURE ); + } + + + +/* Redefine yyless() so it works in section 3 code. */ + +#undef yyless +#define yyless(n) \ + do \ + { \ + /* Undo effects of setting up yytext. */ \ + yytext[yyleng] = yy_hold_char; \ + yy_c_buf_p = yytext + n; \ + yy_hold_char = *yy_c_buf_p; \ + *yy_c_buf_p = '\0'; \ + yyleng = n; \ + } \ + while ( 0 ) + + +/* Internal utility routines. */ + +#ifndef yytext_ptr +#ifdef YY_USE_PROTOS +static void yy_flex_strncpy( char *s1, yyconst char *s2, int n ) +#else +static void yy_flex_strncpy( s1, s2, n ) +char *s1; +yyconst char *s2; +int n; +#endif + { + register int i; + for ( i = 0; i < n; ++i ) + s1[i] = s2[i]; + } +#endif + +#ifdef YY_NEED_STRLEN +#ifdef YY_USE_PROTOS +static int yy_flex_strlen( yyconst char *s ) +#else +static int yy_flex_strlen( s ) +yyconst char *s; +#endif + { + register int n; + for ( n = 0; s[n]; ++n ) + ; + + return n; + } +#endif + + +#ifdef YY_USE_PROTOS +static void *yy_flex_alloc( yy_size_t size ) +#else +static void *yy_flex_alloc( size ) +yy_size_t size; +#endif + { + return (void *) malloc( size ); + } + +#ifdef YY_USE_PROTOS +static void *yy_flex_realloc( void *ptr, yy_size_t size ) +#else +static void *yy_flex_realloc( ptr, size ) +void *ptr; +yy_size_t size; +#endif + { + /* The cast to (char *) in the following accommodates both + * implementations that use char* generic pointers, and those + * that use void* generic pointers. It works with the latter + * because both ANSI C and C++ allow castless assignment from + * any pointer type to void*, and deal with argument conversions + * as though doing an assignment. + */ + return (void *) realloc( (char *) ptr, size ); + } + +#ifdef YY_USE_PROTOS +static void yy_flex_free( void *ptr ) +#else +static void yy_flex_free( ptr ) +void *ptr; +#endif + { + free( ptr ); + } + +#if YY_MAIN +int main() + { + yylex(); + return 0; + } +#endif +#line 105 "macro.lex.l" + + +#if 0 +/* all code for testing macros */ +#include "winhelp.h" +static CHAR szTestMacro[256]; + +static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_COMMAND && wParam == IDOK) + { + GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro)); + EndDialog(hDlg, IDOK); + return TRUE; + } + return FALSE; +} + +void macro_test(void) +{ + WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance); + DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg); + FreeProcInstance(lpfnDlg); + macro = szTestMacro; +} +#endif + +/* small helper function for debug messages */ +static const char* ts(int t) +{ + static char c[2] = {0,0}; + + switch (t) + { + case EMPTY: return "EMPTY"; + case VOID_FUNCTION: return "VOID_FUNCTION"; + case BOOL_FUNCTION: return "BOOL_FUNCTION"; + case INTEGER: return "INTEGER"; + case STRING: return "STRING"; + case IDENTIFIER: return "IDENTIFIER"; + default: c[0] = (char)t; return c; + } +} + +static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret); + +/****************************************************************** + * MACRO_CheckArgs + * + * checks number of arguments against prototype, and stores arguments on + * stack pa for later call + * returns -1 on error, otherwise the number of pushed parameters + */ +static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args) +{ + int t; + unsigned int len = 0, idx = 0; + + WINE_TRACE("Checking %s\n", args); + + if (yylex() != '(') {WINE_WARN("missing (\n");return -1;} + + if (*args) + { + len = strlen(args); + for (;;) + { + t = yylex(); + WINE_TRACE("Got %s <=> %c\n", ts(t), *args); + + switch (*args) + { + case 'S': + if (t != STRING) + {WINE_WARN("missing S\n");return -1;} + pa[idx] = (void*)yylval.string; + break; + case 'U': + case 'I': + if (t != INTEGER) + {WINE_WARN("missing U\n");return -1;} + pa[idx] = LongToPtr(yylval.integer); + break; + case 'B': + if (t != BOOL_FUNCTION) + {WINE_WARN("missing B\n");return -1;} + if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0) + return -1; + break; + default: + WINE_WARN("unexpected %s while args is %c\n", ts(t), *args); + return -1; + } + idx++; + if (*++args == '\0') break; + t = yylex(); + if (t == ')') goto CheckArgs_end; + if (t != ',') {WINE_WARN("missing ,\n");return -1;} + if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;} + } + } + if (yylex() != ')') {WINE_WARN("missing )\n");return -1;} + +CheckArgs_end: + while (len > idx) pa[--len] = NULL; + return idx; +} + +/****************************************************************** + * MACRO_CallBoolFunc + * + * Invokes boolean function fn, which arguments are defined by args + * stores bool result into ret + */ +static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret) +{ + void* pa[2]; + int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); + + if (idx < 0) return 0; + if (!fn) return 1; + + WINE_TRACE("calling with %u pmts\n", idx); + + switch (strlen(args)) + { + case 0: *ret = (void*)(fn)(); break; + case 1: *ret = (void*)(fn)(pa[0]); break; + default: WINE_FIXME("NIY\n"); + } + + return 1; +} + +/****************************************************************** + * MACRO_CallVoidFunc + * + * + */ +static int MACRO_CallVoidFunc(FARPROC fn, const char* args) +{ + void* pa[6]; + int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); + + if (idx < 0) return 0; + if (!fn) return 1; + + WINE_TRACE("calling %p with %u pmts\n", fn, idx); + + switch (strlen(args)) + { + case 0: (fn)(); break; + case 1: (fn)(pa[0]); break; + case 2: (fn)(pa[0],pa[1]); break; + case 3: (fn)(pa[0],pa[1],pa[2]); break; + case 4: (fn)(pa[0],pa[1],pa[2],pa[3]); break; + case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]); break; + case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]); break; + default: WINE_FIXME("NIY\n"); + } + + return 1; +} + +BOOL MACRO_ExecuteMacro(LPCSTR macro) +{ + struct lex_data curr_lex_data, *prev_lex_data; + BOOL ret = TRUE; + int t; + + WINE_TRACE("%s\n", wine_dbgstr_a(macro)); + + prev_lex_data = lex_data; + lex_data = &curr_lex_data; + + memset(lex_data, 0, sizeof(*lex_data)); + lex_data->macroptr = macro; + + while ((t = yylex()) != EMPTY) + { + switch (t) + { + case VOID_FUNCTION: + WINE_TRACE("got type void func(%s)\n", yylval.proto); + MACRO_CallVoidFunc(yylval.function, yylval.proto); + break; + case BOOL_FUNCTION: + WINE_WARN("got type bool func(%s)\n", yylval.proto); + break; + default: + WINE_WARN("got unexpected type %s\n", ts(t)); + return 0; + } + switch (t = yylex()) + { + case EMPTY: goto done; + case ';': break; + default: ret = FALSE; goto done; + } + } + +done: + for (t = 0; t < lex_data->cache_used; t++) + HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]); + lex_data = prev_lex_data; + + return ret; +} + +#ifndef yywrap +int yywrap(void) { return 1; } +#endif diff --git a/reactos/base/applications/winhlp32/macro.c b/reactos/base/applications/winhlp32/macro.c index 3108b02ea1e..0eeaa9b2b27 100644 --- a/reactos/base/applications/winhlp32/macro.c +++ b/reactos/base/applications/winhlp32/macro.c @@ -1,960 +1,960 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * Copyright 2002, 2008 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define WIN32_LEAN_AND_MEAN - -#include - -#include "windows.h" -#include "commdlg.h" -#include "winhelp.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -/**************************************************/ -/* Macro table */ -/**************************************************/ -struct MacroDesc { - const char* name; - const char* alias; - BOOL isBool; - const char* arguments; - FARPROC fn; -}; - -static struct MacroDesc*MACRO_Loaded /* = NULL */; -static unsigned MACRO_NumLoaded /* = 0 */; - -/******* helper functions *******/ - -static WINHELP_BUTTON** MACRO_LookupButton(WINHELP_WINDOW* win, LPCSTR name) -{ - WINHELP_BUTTON** b; - - for (b = &win->first_button; *b; b = &(*b)->next) - if (!lstrcmpi(name, (*b)->lpszID)) break; - return b; -} - -/******* real macro implementation *******/ - -void CALLBACK MACRO_CreateButton(LPCSTR id, LPCSTR name, LPCSTR macro) -{ - WINHELP_WINDOW *win = Globals.active_win; - WINHELP_BUTTON *button, **b; - LONG size; - LPSTR ptr; - - WINE_TRACE("(\"%s\", \"%s\", %s)\n", id, name, macro); - - size = sizeof(WINHELP_BUTTON) + lstrlen(id) + lstrlen(name) + lstrlen(macro) + 3; - - button = HeapAlloc(GetProcessHeap(), 0, size); - if (!button) return; - - button->next = 0; - button->hWnd = 0; - - ptr = (char*)button + sizeof(WINHELP_BUTTON); - - lstrcpy(ptr, id); - button->lpszID = ptr; - ptr += lstrlen(id) + 1; - - lstrcpy(ptr, name); - button->lpszName = ptr; - ptr += lstrlen(name) + 1; - - lstrcpy(ptr, macro); - button->lpszMacro = ptr; - - button->wParam = WH_FIRST_BUTTON; - for (b = &win->first_button; *b; b = &(*b)->next) - button->wParam = max(button->wParam, (*b)->wParam + 1); - *b = button; - - WINHELP_LayoutMainWindow(win); -} - -static void CALLBACK MACRO_DestroyButton(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -void CALLBACK MACRO_DisableButton(LPCSTR id) -{ - WINHELP_BUTTON** b; - - WINE_TRACE("(\"%s\")\n", id); - - b = MACRO_LookupButton(Globals.active_win, id); - if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} - - EnableWindow((*b)->hWnd, FALSE); -} - -static void CALLBACK MACRO_EnableButton(LPCSTR id) -{ - WINHELP_BUTTON** b; - - WINE_TRACE("(\"%s\")\n", id); - - b = MACRO_LookupButton(Globals.active_win, id); - if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} - - EnableWindow((*b)->hWnd, TRUE); -} - -void CALLBACK MACRO_JumpContents(LPCSTR lpszPath, LPCSTR lpszWindow) -{ - HLPFILE* hlpfile; - - WINE_TRACE("(\"%s\", \"%s\")\n", lpszPath, lpszWindow); - if ((hlpfile = WINHELP_LookupHelpFile(lpszPath))) - WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, 0, - WINHELP_GetWindowInfo(hlpfile, lpszWindow), - SW_NORMAL); -} - - -void CALLBACK MACRO_About(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_AddAccelerator(LONG u1, LONG u2, LPCSTR str) -{ - WINE_FIXME("(%u, %u, \"%s\")\n", u1, u2, str); -} - -static void CALLBACK MACRO_ALink(LPCSTR str1, LONG u, LPCSTR str2) -{ - WINE_FIXME("(\"%s\", %u, \"%s\")\n", str1, u, str2); -} - -void CALLBACK MACRO_Annotate(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_AppendItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4) -{ - WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\")\n", str1, str2, str3, str4); -} - -static void CALLBACK MACRO_Back(void) -{ - WINHELP_WINDOW* win = Globals.active_win; - - WINE_TRACE("()\n"); - - if (win && win->back.index >= 2) - WINHELP_CreateHelpWindow(&win->back.set[--win->back.index - 1], SW_SHOW, FALSE); -} - -static void CALLBACK MACRO_BackFlush(void) -{ - WINHELP_WINDOW* win = Globals.active_win; - - WINE_TRACE("()\n"); - - if (win) WINHELP_DeleteBackSet(win); -} - -void CALLBACK MACRO_BookmarkDefine(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_BookmarkMore(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_BrowseButtons(void) -{ - HLPFILE_PAGE* page = Globals.active_win->page; - ULONG relative; - - WINE_TRACE("()\n"); - - MACRO_CreateButton("BTN_PREV", "&<<", "Prev()"); - MACRO_CreateButton("BTN_NEXT", "&>>", "Next()"); - - if (!HLPFILE_PageByOffset(page->file, page->browse_bwd, &relative)) - MACRO_DisableButton("BTN_PREV"); - if (!HLPFILE_PageByOffset(page->file, page->browse_fwd, &relative)) - MACRO_DisableButton("BTN_NEXT"); -} - -static void CALLBACK MACRO_ChangeButtonBinding(LPCSTR id, LPCSTR macro) -{ - WINHELP_WINDOW* win = Globals.active_win; - WINHELP_BUTTON* button; - WINHELP_BUTTON** b; - LONG size; - LPSTR ptr; - - WINE_TRACE("(\"%s\", \"%s\")\n", id, macro); - - b = MACRO_LookupButton(win, id); - if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} - - size = sizeof(WINHELP_BUTTON) + lstrlen(id) + - lstrlen((*b)->lpszName) + lstrlen(macro) + 3; - - button = HeapAlloc(GetProcessHeap(), 0, size); - if (!button) return; - - button->next = (*b)->next; - button->hWnd = (*b)->hWnd; - button->wParam = (*b)->wParam; - - ptr = (char*)button + sizeof(WINHELP_BUTTON); - - lstrcpy(ptr, id); - button->lpszID = ptr; - ptr += lstrlen(id) + 1; - - lstrcpy(ptr, (*b)->lpszName); - button->lpszName = ptr; - ptr += lstrlen((*b)->lpszName) + 1; - - lstrcpy(ptr, macro); - button->lpszMacro = ptr; - - *b = button; - - WINHELP_LayoutMainWindow(win); -} - -static void CALLBACK MACRO_ChangeEnable(LPCSTR id, LPCSTR macro) -{ - WINE_TRACE("(\"%s\", \"%s\")\n", id, macro); - - MACRO_ChangeButtonBinding(id, macro); - MACRO_EnableButton(id); -} - -static void CALLBACK MACRO_ChangeItemBinding(LPCSTR str1, LPCSTR str2) -{ - WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); -} - -static void CALLBACK MACRO_CheckItem(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_CloseSecondarys(void) -{ - WINHELP_WINDOW *win; - - WINE_TRACE("()\n"); - for (win = Globals.win_list; win; win = win->next) - if (win->lpszName && lstrcmpi(win->lpszName, "main")) - DestroyWindow(win->hMainWnd); -} - -static void CALLBACK MACRO_CloseWindow(LPCSTR lpszWindow) -{ - WINHELP_WINDOW *win; - - WINE_TRACE("(\"%s\")\n", lpszWindow); - - if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main"; - - for (win = Globals.win_list; win; win = win->next) - if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow)) - DestroyWindow(win->hMainWnd); -} - -static void CALLBACK MACRO_Compare(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_Contents(void) -{ - WINE_TRACE("()\n"); - - if (Globals.active_win->page) - MACRO_JumpContents(Globals.active_win->page->file->lpszPath, NULL); -} - -static void CALLBACK MACRO_ControlPanel(LPCSTR str1, LPCSTR str2, LONG u) -{ - WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u); -} - -void CALLBACK MACRO_CopyDialog(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_CopyTopic(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_DeleteItem(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_DeleteMark(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_DisableItem(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_EnableItem(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_EndMPrint(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_ExecFile(LPCSTR str1, LPCSTR str2, LONG u, LPCSTR str3) -{ - WINE_FIXME("(\"%s\", \"%s\", %u, \"%s\")\n", str1, str2, u, str3); -} - -static void CALLBACK MACRO_ExecProgram(LPCSTR str, LONG u) -{ - WINE_FIXME("(\"%s\", %u)\n", str, u); -} - -void CALLBACK MACRO_Exit(void) -{ - WINE_TRACE("()\n"); - - while (Globals.win_list) - DestroyWindow(Globals.win_list->hMainWnd); -} - -static void CALLBACK MACRO_ExtAbleItem(LPCSTR str, LONG u) -{ - WINE_FIXME("(\"%s\", %u)\n", str, u); -} - -static void CALLBACK MACRO_ExtInsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u1, LONG u2) -{ - WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, str4, u1, u2); -} - -static void CALLBACK MACRO_ExtInsertMenu(LPCSTR str1, LPCSTR str2, LPCSTR str3, LONG u1, LONG u2) -{ - WINE_FIXME("(\"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, u1, u2); -} - -static BOOL CALLBACK MACRO_FileExist(LPCSTR str) -{ - WINE_TRACE("(\"%s\")\n", str); - return GetFileAttributes(str) != INVALID_FILE_ATTRIBUTES; -} - -void CALLBACK MACRO_FileOpen(void) -{ - char szFile[MAX_PATH]; - - if (WINHELP_GetOpenFileName(szFile, MAX_PATH)) - { - MACRO_JumpContents(szFile, "main"); - } -} - -static void CALLBACK MACRO_Find(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_Finder(void) -{ - WINHELP_CreateIndexWindow(FALSE); -} - -static void CALLBACK MACRO_FloatingMenu(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_Flush(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_FocusWindow(LPCSTR lpszWindow) -{ - WINHELP_WINDOW *win; - - WINE_TRACE("(\"%s\")\n", lpszWindow); - - if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main"; - - for (win = Globals.win_list; win; win = win->next) - if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow)) - SetFocus(win->hMainWnd); -} - -static void CALLBACK MACRO_Generate(LPCSTR str, LONG w, LONG l) -{ - WINE_FIXME("(\"%s\", %x, %x)\n", str, w, l); -} - -static void CALLBACK MACRO_GotoMark(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -void CALLBACK MACRO_HelpOn(void) -{ - LPCSTR file; - - WINE_TRACE("()\n"); - file = Globals.active_win->page->file->help_on_file; - if (!file) - file = (Globals.wVersion > 4) ? "winhlp32.hlp" : "winhelp.hlp"; - - MACRO_JumpContents(file, NULL); -} - -void CALLBACK MACRO_HelpOnTop(void) -{ - WINE_FIXME("()\n"); -} - -void CALLBACK MACRO_History(void) -{ - WINE_TRACE("()\n"); - - if (Globals.active_win && !Globals.active_win->hHistoryWnd) - { - HWND hWnd = CreateWindow(HISTORY_WIN_CLASS_NAME, "History", WS_OVERLAPPEDWINDOW, - 0, 0, 0, 0, 0, 0, Globals.hInstance, Globals.active_win); - ShowWindow(hWnd, SW_NORMAL); - } -} - -static void CALLBACK MACRO_IfThen(BOOL b, LPCSTR t) -{ - if (b) MACRO_ExecuteMacro(t); -} - -static void CALLBACK MACRO_IfThenElse(BOOL b, LPCSTR t, LPCSTR f) -{ - if (b) MACRO_ExecuteMacro(t); else MACRO_ExecuteMacro(f); -} - -static BOOL CALLBACK MACRO_InitMPrint(void) -{ - WINE_FIXME("()\n"); - return FALSE; -} - -static void CALLBACK MACRO_InsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u) -{ - WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u)\n", str1, str2, str3, str4, u); -} - -static void CALLBACK MACRO_InsertMenu(LPCSTR str1, LPCSTR str2, LONG u) -{ - WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u); -} - -static BOOL CALLBACK MACRO_IsBook(void) -{ - WINE_TRACE("()\n"); - return Globals.isBook; -} - -static BOOL CALLBACK MACRO_IsMark(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); - return FALSE; -} - -static BOOL CALLBACK MACRO_IsNotMark(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); - return TRUE; -} - -void CALLBACK MACRO_JumpContext(LPCSTR lpszPath, LPCSTR lpszWindow, LONG context) -{ - HLPFILE* hlpfile; - - WINE_TRACE("(\"%s\", \"%s\", %d)\n", lpszPath, lpszWindow, context); - hlpfile = WINHELP_LookupHelpFile(lpszPath); - /* Some madness: what user calls 'context', hlpfile calls 'map' */ - WINHELP_OpenHelpWindow(HLPFILE_PageByMap, hlpfile, context, - WINHELP_GetWindowInfo(hlpfile, lpszWindow), - SW_NORMAL); -} - -void CALLBACK MACRO_JumpHash(LPCSTR lpszPath, LPCSTR lpszWindow, LONG lHash) -{ - HLPFILE* hlpfile; - - WINE_TRACE("(\"%s\", \"%s\", %u)\n", lpszPath, lpszWindow, lHash); - hlpfile = WINHELP_LookupHelpFile(lpszPath); - WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash, - WINHELP_GetWindowInfo(hlpfile, lpszWindow), - SW_NORMAL); -} - -static void CALLBACK MACRO_JumpHelpOn(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_JumpID(LPCSTR lpszPathWindow, LPCSTR topic_id) -{ - LPSTR ptr; - - WINE_TRACE("(\"%s\", \"%s\")\n", lpszPathWindow, topic_id); - if ((ptr = strchr(lpszPathWindow, '>')) != NULL) - { - LPSTR tmp; - size_t sz = ptr - lpszPathWindow; - - tmp = HeapAlloc(GetProcessHeap(), 0, sz + 1); - if (tmp) - { - memcpy(tmp, lpszPathWindow, sz); - tmp[sz] = '\0'; - MACRO_JumpHash(tmp, ptr + 1, HLPFILE_Hash(topic_id)); - HeapFree(GetProcessHeap(), 0, tmp); - } - } - else - MACRO_JumpHash(lpszPathWindow, NULL, HLPFILE_Hash(topic_id)); -} - -/* FIXME: this macros is wrong - * it should only contain 2 strings, path & window are coded as path>window - */ -static void CALLBACK MACRO_JumpKeyword(LPCSTR lpszPath, LPCSTR lpszWindow, LPCSTR keyword) -{ - WINE_FIXME("(\"%s\", \"%s\", \"%s\")\n", lpszPath, lpszWindow, keyword); -} - -static void CALLBACK MACRO_KLink(LPCSTR str1, LONG u, LPCSTR str2, LPCSTR str3) -{ - WINE_FIXME("(\"%s\", %u, \"%s\", \"%s\")\n", str1, u, str2, str3); -} - -static void CALLBACK MACRO_Menu(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_MPrintHash(LONG u) -{ - WINE_FIXME("(%u)\n", u); -} - -static void CALLBACK MACRO_MPrintID(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_Next(void) -{ - WINHELP_WNDPAGE wp; - - WINE_TRACE("()\n"); - wp.page = Globals.active_win->page; - wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_fwd, &wp.relative); - if (wp.page) - { - wp.page->file->wRefCount++; - wp.wininfo = Globals.active_win->info; - WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE); - } -} - -static void CALLBACK MACRO_NoShow(void) -{ - WINE_FIXME("()\n"); -} - -void CALLBACK MACRO_PopupContext(LPCSTR str, LONG u) -{ - WINE_FIXME("(\"%s\", %u)\n", str, u); -} - -static void CALLBACK MACRO_PopupHash(LPCSTR str, LONG u) -{ - WINE_FIXME("(\"%s\", %u)\n", str, u); -} - -static void CALLBACK MACRO_PopupId(LPCSTR str1, LPCSTR str2) -{ - WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); -} - -static void CALLBACK MACRO_PositionWindow(LONG i1, LONG i2, LONG u1, LONG u2, LONG u3, LPCSTR str) -{ - WINE_FIXME("(%i, %i, %u, %u, %u, \"%s\")\n", i1, i2, u1, u2, u3, str); -} - -static void CALLBACK MACRO_Prev(void) -{ - WINHELP_WNDPAGE wp; - - WINE_TRACE("()\n"); - wp.page = Globals.active_win->page; - wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_bwd, &wp.relative); - if (wp.page) - { - wp.page->file->wRefCount++; - wp.wininfo = Globals.active_win->info; - WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE); - } -} - -void CALLBACK MACRO_Print(void) -{ - PRINTDLG printer; - - WINE_TRACE("()\n"); - - printer.lStructSize = sizeof(printer); - printer.hwndOwner = Globals.active_win->hMainWnd; - printer.hInstance = Globals.hInstance; - printer.hDevMode = 0; - printer.hDevNames = 0; - printer.hDC = 0; - printer.Flags = 0; - printer.nFromPage = 0; - printer.nToPage = 0; - printer.nMinPage = 0; - printer.nMaxPage = 0; - printer.nCopies = 0; - printer.lCustData = 0; - printer.lpfnPrintHook = 0; - printer.lpfnSetupHook = 0; - printer.lpPrintTemplateName = 0; - printer.lpSetupTemplateName = 0; - printer.hPrintTemplate = 0; - printer.hSetupTemplate = 0; - - if (PrintDlgA(&printer)) { - WINE_FIXME("Print()\n"); - } -} - -void CALLBACK MACRO_PrinterSetup(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_RegisterRoutine(LPCSTR dll_name, LPCSTR proc, LPCSTR args) -{ - FARPROC fn = NULL; - int size; - WINHELP_DLL* dll; - - WINE_TRACE("(\"%s\", \"%s\", \"%s\")\n", dll_name, proc, args); - - /* FIXME: are the registered DLLs global or linked to the current file ??? - * We assume globals (as we did for macros, but is this really the case ???) - */ - for (dll = Globals.dlls; dll; dll = dll->next) - { - if (!strcmp(dll->name, dll_name)) break; - } - if (!dll) - { - HANDLE hLib = LoadLibrary(dll_name); - - /* FIXME: the library will not be unloaded until exit of program - * We don't send the DW_TERM message - */ - WINE_TRACE("Loading %s\n", dll_name); - /* FIXME: should look in the directory where current hlpfile - * is loaded from - */ - if (hLib == NULL) - { - /* FIXME: internationalisation for error messages */ - WINE_FIXME("Cannot find dll %s\n", dll_name); - } - else if ((dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*dll)))) - { - dll->hLib = hLib; - dll->name = strdup(dll_name); /* FIXME */ - dll->next = Globals.dlls; - Globals.dlls = dll; - dll->handler = (WINHELP_LDLLHandler)GetProcAddress(dll->hLib, "LDLLHandler"); - dll->class = dll->handler ? (dll->handler)(DW_WHATMSG, 0, 0) : DC_NOMSG; - WINE_TRACE("Got class %x for DLL %s\n", dll->class, dll_name); - if (dll->class & DC_INITTERM) dll->handler(DW_INIT, 0, 0); - if (dll->class & DC_CALLBACKS) dll->handler(DW_CALLBACKS, (DWORD)Callbacks, 0); - } - else WINE_WARN("OOM\n"); - } - if (dll && !(fn = GetProcAddress(dll->hLib, proc))) - { - /* FIXME: internationalisation for error messages */ - WINE_FIXME("Cannot find proc %s in dll %s\n", dll_name, proc); - } - - size = ++MACRO_NumLoaded * sizeof(struct MacroDesc); - if (!MACRO_Loaded) MACRO_Loaded = HeapAlloc(GetProcessHeap(), 0, size); - else MACRO_Loaded = HeapReAlloc(GetProcessHeap(), 0, MACRO_Loaded, size); - MACRO_Loaded[MACRO_NumLoaded - 1].name = strdup(proc); /* FIXME */ - MACRO_Loaded[MACRO_NumLoaded - 1].alias = NULL; - MACRO_Loaded[MACRO_NumLoaded - 1].isBool = 0; - MACRO_Loaded[MACRO_NumLoaded - 1].arguments = strdup(args); /* FIXME */ - MACRO_Loaded[MACRO_NumLoaded - 1].fn = fn; - WINE_TRACE("Added %s(%s) at %p\n", proc, args, fn); -} - -static void CALLBACK MACRO_RemoveAccelerator(LONG u1, LONG u2) -{ - WINE_FIXME("(%u, %u)\n", u1, u2); -} - -static void CALLBACK MACRO_ResetMenu(void) -{ - WINE_FIXME("()\n"); -} - -static void CALLBACK MACRO_SaveMark(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_Search(void) -{ - WINHELP_CreateIndexWindow(TRUE); -} - -void CALLBACK MACRO_SetContents(LPCSTR str, LONG u) -{ - WINE_FIXME("(\"%s\", %u)\n", str, u); -} - -static void CALLBACK MACRO_SetHelpOnFile(LPCSTR str) -{ - WINE_TRACE("(\"%s\")\n", str); - - HeapFree(GetProcessHeap(), 0, Globals.active_win->page->file->help_on_file); - Globals.active_win->page->file->help_on_file = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); - if (Globals.active_win->page->file->help_on_file) - strcpy(Globals.active_win->page->file->help_on_file, str); -} - -static void CALLBACK MACRO_SetPopupColor(LONG r, LONG g, LONG b) -{ - WINE_TRACE("(%x, %x, %x)\n", r, g, b); - Globals.active_win->page->file->has_popup_color = TRUE; - Globals.active_win->page->file->popup_color = RGB(r, g, b); -} - -static void CALLBACK MACRO_ShellExecute(LPCSTR str1, LPCSTR str2, LONG u1, LONG u2, LPCSTR str3, LPCSTR str4) -{ - WINE_FIXME("(\"%s\", \"%s\", %u, %u, \"%s\", \"%s\")\n", str1, str2, u1, u2, str3, str4); -} - -static void CALLBACK MACRO_ShortCut(LPCSTR str1, LPCSTR str2, LONG w, LONG l, LPCSTR str) -{ - WINE_FIXME("(\"%s\", \"%s\", %x, %x, \"%s\")\n", str1, str2, w, l, str); -} - -static void CALLBACK MACRO_TCard(LONG u) -{ - WINE_FIXME("(%u)\n", u); -} - -static void CALLBACK MACRO_Test(LONG u) -{ - WINE_FIXME("(%u)\n", u); -} - -static BOOL CALLBACK MACRO_TestALink(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); - return FALSE; -} - -static BOOL CALLBACK MACRO_TestKLink(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); - return FALSE; -} - -static void CALLBACK MACRO_UncheckItem(LPCSTR str) -{ - WINE_FIXME("(\"%s\")\n", str); -} - -static void CALLBACK MACRO_UpdateWindow(LPCSTR str1, LPCSTR str2) -{ - WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); -} - - -/**************************************************/ -/* Macro table */ -/**************************************************/ - -/* types: - * U: 32 bit unsigned int - * I: 32 bit signed int - * S: string - * v: unknown (32 bit entity) - */ - -static struct MacroDesc MACRO_Builtins[] = { - {"About", NULL, 0, "", (FARPROC)MACRO_About}, - {"AddAccelerator", "AA", 0, "UUS", (FARPROC)MACRO_AddAccelerator}, - {"ALink", "AL", 0, "SUS", (FARPROC)MACRO_ALink}, - {"Annotate", NULL, 0, "", (FARPROC)MACRO_Annotate}, - {"AppendItem", NULL, 0, "SSSS", (FARPROC)MACRO_AppendItem}, - {"Back", NULL, 0, "", (FARPROC)MACRO_Back}, - {"BackFlush", "BF", 0, "", (FARPROC)MACRO_BackFlush}, - {"BookmarkDefine", NULL, 0, "", (FARPROC)MACRO_BookmarkDefine}, - {"BookmarkMore", NULL, 0, "", (FARPROC)MACRO_BookmarkMore}, - {"BrowseButtons", NULL, 0, "", (FARPROC)MACRO_BrowseButtons}, - {"ChangeButtonBinding", "CBB",0, "SS", (FARPROC)MACRO_ChangeButtonBinding}, - {"ChangeEnable", "CE", 0, "SS", (FARPROC)MACRO_ChangeEnable}, - {"ChangeItemBinding", "CIB",0, "SS", (FARPROC)MACRO_ChangeItemBinding}, - {"CheckItem", "CI", 0, "S", (FARPROC)MACRO_CheckItem}, - {"CloseSecondarys", "CS", 0, "", (FARPROC)MACRO_CloseSecondarys}, - {"CloseWindow", "CW", 0, "S", (FARPROC)MACRO_CloseWindow}, - {"Compare", NULL, 0, "S", (FARPROC)MACRO_Compare}, - {"Contents", NULL, 0, "", (FARPROC)MACRO_Contents}, - {"ControlPanel", NULL, 0, "SSU", (FARPROC)MACRO_ControlPanel}, - {"CopyDialog", NULL, 0, "", (FARPROC)MACRO_CopyDialog}, - {"CopyTopic", "CT", 0, "", (FARPROC)MACRO_CopyTopic}, - {"CreateButton", "CB", 0, "SSS", (FARPROC)MACRO_CreateButton}, - {"DeleteItem", NULL, 0, "S", (FARPROC)MACRO_DeleteItem}, - {"DeleteMark", NULL, 0, "S", (FARPROC)MACRO_DeleteMark}, - {"DestroyButton", NULL, 0, "S", (FARPROC)MACRO_DestroyButton}, - {"DisableButton", "DB", 0, "S", (FARPROC)MACRO_DisableButton}, - {"DisableItem", "DI", 0, "S", (FARPROC)MACRO_DisableItem}, - {"EnableButton", "EB", 0, "S", (FARPROC)MACRO_EnableButton}, - {"EnableItem", "EI", 0, "S", (FARPROC)MACRO_EnableItem}, - {"EndMPrint", NULL, 0, "", (FARPROC)MACRO_EndMPrint}, - {"ExecFile", "EF", 0, "SSUS", (FARPROC)MACRO_ExecFile}, - {"ExecProgram", "EP", 0, "SU", (FARPROC)MACRO_ExecProgram}, - {"Exit", NULL, 0, "", (FARPROC)MACRO_Exit}, - {"ExtAbleItem", NULL, 0, "SU", (FARPROC)MACRO_ExtAbleItem}, - {"ExtInsertItem", NULL, 0, "SSSSUU", (FARPROC)MACRO_ExtInsertItem}, - {"ExtInsertMenu", NULL, 0, "SSSUU", (FARPROC)MACRO_ExtInsertMenu}, - {"FileExist", "FE", 1, "S", (FARPROC)MACRO_FileExist}, - {"FileOpen", "FO", 0, "", (FARPROC)MACRO_FileOpen}, - {"Find", NULL, 0, "", (FARPROC)MACRO_Find}, - {"Finder", "FD", 0, "", (FARPROC)MACRO_Finder}, - {"FloatingMenu", NULL, 0, "", (FARPROC)MACRO_FloatingMenu}, - {"Flush", "FH", 0, "", (FARPROC)MACRO_Flush}, - {"FocusWindow", NULL, 0, "S", (FARPROC)MACRO_FocusWindow}, - {"Generate", NULL, 0, "SUU", (FARPROC)MACRO_Generate}, - {"GotoMark", NULL, 0, "S", (FARPROC)MACRO_GotoMark}, - {"HelpOn", NULL, 0, "", (FARPROC)MACRO_HelpOn}, - {"HelpOnTop", NULL, 0, "", (FARPROC)MACRO_HelpOnTop}, - {"History", NULL, 0, "", (FARPROC)MACRO_History}, - {"InitMPrint", NULL, 1, "", (FARPROC)MACRO_InitMPrint}, - {"InsertItem", NULL, 0, "SSSSU", (FARPROC)MACRO_InsertItem}, - {"InsertMenu", NULL, 0, "SSU", (FARPROC)MACRO_InsertMenu}, - {"IfThen", "IF", 0, "BS", (FARPROC)MACRO_IfThen}, - {"IfThenElse", "IE", 0, "BSS", (FARPROC)MACRO_IfThenElse}, - {"IsBook", NULL, 1, "", (FARPROC)MACRO_IsBook}, - {"IsMark", NULL, 1, "S", (FARPROC)MACRO_IsMark}, - {"IsNotMark", "NM", 1, "S", (FARPROC)MACRO_IsNotMark}, - {"JumpContents", NULL, 0, "SS", (FARPROC)MACRO_JumpContents}, - {"JumpContext", "JC", 0, "SSU", (FARPROC)MACRO_JumpContext}, - {"JumpHash", "JH", 0, "SSU", (FARPROC)MACRO_JumpHash}, - {"JumpHelpOn", NULL, 0, "", (FARPROC)MACRO_JumpHelpOn}, - {"JumpID", "JI", 0, "SS", (FARPROC)MACRO_JumpID}, - {"JumpKeyword", "JK", 0, "SSS", (FARPROC)MACRO_JumpKeyword}, - {"KLink", "KL", 0, "SUSS", (FARPROC)MACRO_KLink}, - {"Menu", "MU", 0, "", (FARPROC)MACRO_Menu}, - {"MPrintHash", NULL, 0, "U", (FARPROC)MACRO_MPrintHash}, - {"MPrintID", NULL, 0, "S", (FARPROC)MACRO_MPrintID}, - {"Next", NULL, 0, "", (FARPROC)MACRO_Next}, - {"NoShow", NULL, 0, "", (FARPROC)MACRO_NoShow}, - {"PopupContext", "PC", 0, "SU", (FARPROC)MACRO_PopupContext}, - {"PopupHash", NULL, 0, "SU", (FARPROC)MACRO_PopupHash}, - {"PopupId", "PI", 0, "SS", (FARPROC)MACRO_PopupId}, - {"PositionWindow", "PW", 0, "IIUUUS", (FARPROC)MACRO_PositionWindow}, - {"Prev", NULL, 0, "", (FARPROC)MACRO_Prev}, - {"Print", NULL, 0, "", (FARPROC)MACRO_Print}, - {"PrinterSetup", NULL, 0, "", (FARPROC)MACRO_PrinterSetup}, - {"RegisterRoutine", "RR", 0, "SSS", (FARPROC)MACRO_RegisterRoutine}, - {"RemoveAccelerator", "RA", 0, "UU", (FARPROC)MACRO_RemoveAccelerator}, - {"ResetMenu", NULL, 0, "", (FARPROC)MACRO_ResetMenu}, - {"SaveMark", NULL, 0, "S", (FARPROC)MACRO_SaveMark}, - {"Search", NULL, 0, "", (FARPROC)MACRO_Search}, - {"SetContents", NULL, 0, "SU", (FARPROC)MACRO_SetContents}, - {"SetHelpOnFile", NULL, 0, "S", (FARPROC)MACRO_SetHelpOnFile}, - {"SetPopupColor", "SPC",0, "UUU", (FARPROC)MACRO_SetPopupColor}, - {"ShellExecute", "SE", 0, "SSUUSS", (FARPROC)MACRO_ShellExecute}, - {"ShortCut", "SH", 0, "SSUUS", (FARPROC)MACRO_ShortCut}, - {"TCard", NULL, 0, "U", (FARPROC)MACRO_TCard}, - {"Test", NULL, 0, "U", (FARPROC)MACRO_Test}, - {"TestALink", NULL, 1, "S", (FARPROC)MACRO_TestALink}, - {"TestKLink", NULL, 1, "S", (FARPROC)MACRO_TestKLink}, - {"UncheckItem", "UI", 0, "S", (FARPROC)MACRO_UncheckItem}, - {"UpdateWindow", "UW", 0, "SS", (FARPROC)MACRO_UpdateWindow}, - {NULL, NULL, 0, NULL, NULL} -}; - -static int MACRO_DoLookUp(struct MacroDesc* start, const char* name, struct lexret* lr, unsigned len) -{ - struct MacroDesc* md; - - for (md = start; md->name && len != 0; md++, len--) - { - if (strcasecmp(md->name, name) == 0 || (md->alias != NULL && strcasecmp(md->alias, name) == 0)) - { - lr->proto = md->arguments; - lr->function = md->fn; - return md->isBool ? BOOL_FUNCTION : VOID_FUNCTION; - } - } - return EMPTY; -} - -int MACRO_Lookup(const char* name, struct lexret* lr) -{ - int ret; - - if ((ret = MACRO_DoLookUp(MACRO_Builtins, name, lr, -1)) != EMPTY) - return ret; - if (MACRO_Loaded && (ret = MACRO_DoLookUp(MACRO_Loaded, name, lr, MACRO_NumLoaded)) != EMPTY) - return ret; - - lr->string = name; - return IDENTIFIER; -} +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * Copyright 2002, 2008 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define WIN32_LEAN_AND_MEAN + +#include + +#include "windows.h" +#include "commdlg.h" +#include "winhelp.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +/**************************************************/ +/* Macro table */ +/**************************************************/ +struct MacroDesc { + const char* name; + const char* alias; + BOOL isBool; + const char* arguments; + FARPROC fn; +}; + +static struct MacroDesc*MACRO_Loaded /* = NULL */; +static unsigned MACRO_NumLoaded /* = 0 */; + +/******* helper functions *******/ + +static WINHELP_BUTTON** MACRO_LookupButton(WINHELP_WINDOW* win, LPCSTR name) +{ + WINHELP_BUTTON** b; + + for (b = &win->first_button; *b; b = &(*b)->next) + if (!lstrcmpi(name, (*b)->lpszID)) break; + return b; +} + +/******* real macro implementation *******/ + +void CALLBACK MACRO_CreateButton(LPCSTR id, LPCSTR name, LPCSTR macro) +{ + WINHELP_WINDOW *win = Globals.active_win; + WINHELP_BUTTON *button, **b; + LONG size; + LPSTR ptr; + + WINE_TRACE("(\"%s\", \"%s\", %s)\n", id, name, macro); + + size = sizeof(WINHELP_BUTTON) + lstrlen(id) + lstrlen(name) + lstrlen(macro) + 3; + + button = HeapAlloc(GetProcessHeap(), 0, size); + if (!button) return; + + button->next = 0; + button->hWnd = 0; + + ptr = (char*)button + sizeof(WINHELP_BUTTON); + + lstrcpy(ptr, id); + button->lpszID = ptr; + ptr += lstrlen(id) + 1; + + lstrcpy(ptr, name); + button->lpszName = ptr; + ptr += lstrlen(name) + 1; + + lstrcpy(ptr, macro); + button->lpszMacro = ptr; + + button->wParam = WH_FIRST_BUTTON; + for (b = &win->first_button; *b; b = &(*b)->next) + button->wParam = max(button->wParam, (*b)->wParam + 1); + *b = button; + + WINHELP_LayoutMainWindow(win); +} + +static void CALLBACK MACRO_DestroyButton(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +void CALLBACK MACRO_DisableButton(LPCSTR id) +{ + WINHELP_BUTTON** b; + + WINE_TRACE("(\"%s\")\n", id); + + b = MACRO_LookupButton(Globals.active_win, id); + if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} + + EnableWindow((*b)->hWnd, FALSE); +} + +static void CALLBACK MACRO_EnableButton(LPCSTR id) +{ + WINHELP_BUTTON** b; + + WINE_TRACE("(\"%s\")\n", id); + + b = MACRO_LookupButton(Globals.active_win, id); + if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} + + EnableWindow((*b)->hWnd, TRUE); +} + +void CALLBACK MACRO_JumpContents(LPCSTR lpszPath, LPCSTR lpszWindow) +{ + HLPFILE* hlpfile; + + WINE_TRACE("(\"%s\", \"%s\")\n", lpszPath, lpszWindow); + if ((hlpfile = WINHELP_LookupHelpFile(lpszPath))) + WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, 0, + WINHELP_GetWindowInfo(hlpfile, lpszWindow), + SW_NORMAL); +} + + +void CALLBACK MACRO_About(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_AddAccelerator(LONG u1, LONG u2, LPCSTR str) +{ + WINE_FIXME("(%u, %u, \"%s\")\n", u1, u2, str); +} + +static void CALLBACK MACRO_ALink(LPCSTR str1, LONG u, LPCSTR str2) +{ + WINE_FIXME("(\"%s\", %u, \"%s\")\n", str1, u, str2); +} + +void CALLBACK MACRO_Annotate(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_AppendItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4) +{ + WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\")\n", str1, str2, str3, str4); +} + +static void CALLBACK MACRO_Back(void) +{ + WINHELP_WINDOW* win = Globals.active_win; + + WINE_TRACE("()\n"); + + if (win && win->back.index >= 2) + WINHELP_CreateHelpWindow(&win->back.set[--win->back.index - 1], SW_SHOW, FALSE); +} + +static void CALLBACK MACRO_BackFlush(void) +{ + WINHELP_WINDOW* win = Globals.active_win; + + WINE_TRACE("()\n"); + + if (win) WINHELP_DeleteBackSet(win); +} + +void CALLBACK MACRO_BookmarkDefine(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_BookmarkMore(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_BrowseButtons(void) +{ + HLPFILE_PAGE* page = Globals.active_win->page; + ULONG relative; + + WINE_TRACE("()\n"); + + MACRO_CreateButton("BTN_PREV", "&<<", "Prev()"); + MACRO_CreateButton("BTN_NEXT", "&>>", "Next()"); + + if (!HLPFILE_PageByOffset(page->file, page->browse_bwd, &relative)) + MACRO_DisableButton("BTN_PREV"); + if (!HLPFILE_PageByOffset(page->file, page->browse_fwd, &relative)) + MACRO_DisableButton("BTN_NEXT"); +} + +static void CALLBACK MACRO_ChangeButtonBinding(LPCSTR id, LPCSTR macro) +{ + WINHELP_WINDOW* win = Globals.active_win; + WINHELP_BUTTON* button; + WINHELP_BUTTON** b; + LONG size; + LPSTR ptr; + + WINE_TRACE("(\"%s\", \"%s\")\n", id, macro); + + b = MACRO_LookupButton(win, id); + if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;} + + size = sizeof(WINHELP_BUTTON) + lstrlen(id) + + lstrlen((*b)->lpszName) + lstrlen(macro) + 3; + + button = HeapAlloc(GetProcessHeap(), 0, size); + if (!button) return; + + button->next = (*b)->next; + button->hWnd = (*b)->hWnd; + button->wParam = (*b)->wParam; + + ptr = (char*)button + sizeof(WINHELP_BUTTON); + + lstrcpy(ptr, id); + button->lpszID = ptr; + ptr += lstrlen(id) + 1; + + lstrcpy(ptr, (*b)->lpszName); + button->lpszName = ptr; + ptr += lstrlen((*b)->lpszName) + 1; + + lstrcpy(ptr, macro); + button->lpszMacro = ptr; + + *b = button; + + WINHELP_LayoutMainWindow(win); +} + +static void CALLBACK MACRO_ChangeEnable(LPCSTR id, LPCSTR macro) +{ + WINE_TRACE("(\"%s\", \"%s\")\n", id, macro); + + MACRO_ChangeButtonBinding(id, macro); + MACRO_EnableButton(id); +} + +static void CALLBACK MACRO_ChangeItemBinding(LPCSTR str1, LPCSTR str2) +{ + WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); +} + +static void CALLBACK MACRO_CheckItem(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_CloseSecondarys(void) +{ + WINHELP_WINDOW *win; + + WINE_TRACE("()\n"); + for (win = Globals.win_list; win; win = win->next) + if (win->lpszName && lstrcmpi(win->lpszName, "main")) + DestroyWindow(win->hMainWnd); +} + +static void CALLBACK MACRO_CloseWindow(LPCSTR lpszWindow) +{ + WINHELP_WINDOW *win; + + WINE_TRACE("(\"%s\")\n", lpszWindow); + + if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main"; + + for (win = Globals.win_list; win; win = win->next) + if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow)) + DestroyWindow(win->hMainWnd); +} + +static void CALLBACK MACRO_Compare(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_Contents(void) +{ + WINE_TRACE("()\n"); + + if (Globals.active_win->page) + MACRO_JumpContents(Globals.active_win->page->file->lpszPath, NULL); +} + +static void CALLBACK MACRO_ControlPanel(LPCSTR str1, LPCSTR str2, LONG u) +{ + WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u); +} + +void CALLBACK MACRO_CopyDialog(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_CopyTopic(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_DeleteItem(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_DeleteMark(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_DisableItem(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_EnableItem(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_EndMPrint(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_ExecFile(LPCSTR str1, LPCSTR str2, LONG u, LPCSTR str3) +{ + WINE_FIXME("(\"%s\", \"%s\", %u, \"%s\")\n", str1, str2, u, str3); +} + +static void CALLBACK MACRO_ExecProgram(LPCSTR str, LONG u) +{ + WINE_FIXME("(\"%s\", %u)\n", str, u); +} + +void CALLBACK MACRO_Exit(void) +{ + WINE_TRACE("()\n"); + + while (Globals.win_list) + DestroyWindow(Globals.win_list->hMainWnd); +} + +static void CALLBACK MACRO_ExtAbleItem(LPCSTR str, LONG u) +{ + WINE_FIXME("(\"%s\", %u)\n", str, u); +} + +static void CALLBACK MACRO_ExtInsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u1, LONG u2) +{ + WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, str4, u1, u2); +} + +static void CALLBACK MACRO_ExtInsertMenu(LPCSTR str1, LPCSTR str2, LPCSTR str3, LONG u1, LONG u2) +{ + WINE_FIXME("(\"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, u1, u2); +} + +static BOOL CALLBACK MACRO_FileExist(LPCSTR str) +{ + WINE_TRACE("(\"%s\")\n", str); + return GetFileAttributes(str) != INVALID_FILE_ATTRIBUTES; +} + +void CALLBACK MACRO_FileOpen(void) +{ + char szFile[MAX_PATH]; + + if (WINHELP_GetOpenFileName(szFile, MAX_PATH)) + { + MACRO_JumpContents(szFile, "main"); + } +} + +static void CALLBACK MACRO_Find(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_Finder(void) +{ + WINHELP_CreateIndexWindow(FALSE); +} + +static void CALLBACK MACRO_FloatingMenu(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_Flush(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_FocusWindow(LPCSTR lpszWindow) +{ + WINHELP_WINDOW *win; + + WINE_TRACE("(\"%s\")\n", lpszWindow); + + if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main"; + + for (win = Globals.win_list; win; win = win->next) + if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow)) + SetFocus(win->hMainWnd); +} + +static void CALLBACK MACRO_Generate(LPCSTR str, LONG w, LONG l) +{ + WINE_FIXME("(\"%s\", %x, %x)\n", str, w, l); +} + +static void CALLBACK MACRO_GotoMark(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +void CALLBACK MACRO_HelpOn(void) +{ + LPCSTR file; + + WINE_TRACE("()\n"); + file = Globals.active_win->page->file->help_on_file; + if (!file) + file = (Globals.wVersion > 4) ? "winhlp32.hlp" : "winhelp.hlp"; + + MACRO_JumpContents(file, NULL); +} + +void CALLBACK MACRO_HelpOnTop(void) +{ + WINE_FIXME("()\n"); +} + +void CALLBACK MACRO_History(void) +{ + WINE_TRACE("()\n"); + + if (Globals.active_win && !Globals.active_win->hHistoryWnd) + { + HWND hWnd = CreateWindow(HISTORY_WIN_CLASS_NAME, "History", WS_OVERLAPPEDWINDOW, + 0, 0, 0, 0, 0, 0, Globals.hInstance, Globals.active_win); + ShowWindow(hWnd, SW_NORMAL); + } +} + +static void CALLBACK MACRO_IfThen(BOOL b, LPCSTR t) +{ + if (b) MACRO_ExecuteMacro(t); +} + +static void CALLBACK MACRO_IfThenElse(BOOL b, LPCSTR t, LPCSTR f) +{ + if (b) MACRO_ExecuteMacro(t); else MACRO_ExecuteMacro(f); +} + +static BOOL CALLBACK MACRO_InitMPrint(void) +{ + WINE_FIXME("()\n"); + return FALSE; +} + +static void CALLBACK MACRO_InsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u) +{ + WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u)\n", str1, str2, str3, str4, u); +} + +static void CALLBACK MACRO_InsertMenu(LPCSTR str1, LPCSTR str2, LONG u) +{ + WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u); +} + +static BOOL CALLBACK MACRO_IsBook(void) +{ + WINE_TRACE("()\n"); + return Globals.isBook; +} + +static BOOL CALLBACK MACRO_IsMark(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); + return FALSE; +} + +static BOOL CALLBACK MACRO_IsNotMark(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); + return TRUE; +} + +void CALLBACK MACRO_JumpContext(LPCSTR lpszPath, LPCSTR lpszWindow, LONG context) +{ + HLPFILE* hlpfile; + + WINE_TRACE("(\"%s\", \"%s\", %d)\n", lpszPath, lpszWindow, context); + hlpfile = WINHELP_LookupHelpFile(lpszPath); + /* Some madness: what user calls 'context', hlpfile calls 'map' */ + WINHELP_OpenHelpWindow(HLPFILE_PageByMap, hlpfile, context, + WINHELP_GetWindowInfo(hlpfile, lpszWindow), + SW_NORMAL); +} + +void CALLBACK MACRO_JumpHash(LPCSTR lpszPath, LPCSTR lpszWindow, LONG lHash) +{ + HLPFILE* hlpfile; + + WINE_TRACE("(\"%s\", \"%s\", %u)\n", lpszPath, lpszWindow, lHash); + hlpfile = WINHELP_LookupHelpFile(lpszPath); + WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash, + WINHELP_GetWindowInfo(hlpfile, lpszWindow), + SW_NORMAL); +} + +static void CALLBACK MACRO_JumpHelpOn(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_JumpID(LPCSTR lpszPathWindow, LPCSTR topic_id) +{ + LPSTR ptr; + + WINE_TRACE("(\"%s\", \"%s\")\n", lpszPathWindow, topic_id); + if ((ptr = strchr(lpszPathWindow, '>')) != NULL) + { + LPSTR tmp; + size_t sz = ptr - lpszPathWindow; + + tmp = HeapAlloc(GetProcessHeap(), 0, sz + 1); + if (tmp) + { + memcpy(tmp, lpszPathWindow, sz); + tmp[sz] = '\0'; + MACRO_JumpHash(tmp, ptr + 1, HLPFILE_Hash(topic_id)); + HeapFree(GetProcessHeap(), 0, tmp); + } + } + else + MACRO_JumpHash(lpszPathWindow, NULL, HLPFILE_Hash(topic_id)); +} + +/* FIXME: this macros is wrong + * it should only contain 2 strings, path & window are coded as path>window + */ +static void CALLBACK MACRO_JumpKeyword(LPCSTR lpszPath, LPCSTR lpszWindow, LPCSTR keyword) +{ + WINE_FIXME("(\"%s\", \"%s\", \"%s\")\n", lpszPath, lpszWindow, keyword); +} + +static void CALLBACK MACRO_KLink(LPCSTR str1, LONG u, LPCSTR str2, LPCSTR str3) +{ + WINE_FIXME("(\"%s\", %u, \"%s\", \"%s\")\n", str1, u, str2, str3); +} + +static void CALLBACK MACRO_Menu(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_MPrintHash(LONG u) +{ + WINE_FIXME("(%u)\n", u); +} + +static void CALLBACK MACRO_MPrintID(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_Next(void) +{ + WINHELP_WNDPAGE wp; + + WINE_TRACE("()\n"); + wp.page = Globals.active_win->page; + wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_fwd, &wp.relative); + if (wp.page) + { + wp.page->file->wRefCount++; + wp.wininfo = Globals.active_win->info; + WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE); + } +} + +static void CALLBACK MACRO_NoShow(void) +{ + WINE_FIXME("()\n"); +} + +void CALLBACK MACRO_PopupContext(LPCSTR str, LONG u) +{ + WINE_FIXME("(\"%s\", %u)\n", str, u); +} + +static void CALLBACK MACRO_PopupHash(LPCSTR str, LONG u) +{ + WINE_FIXME("(\"%s\", %u)\n", str, u); +} + +static void CALLBACK MACRO_PopupId(LPCSTR str1, LPCSTR str2) +{ + WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); +} + +static void CALLBACK MACRO_PositionWindow(LONG i1, LONG i2, LONG u1, LONG u2, LONG u3, LPCSTR str) +{ + WINE_FIXME("(%i, %i, %u, %u, %u, \"%s\")\n", i1, i2, u1, u2, u3, str); +} + +static void CALLBACK MACRO_Prev(void) +{ + WINHELP_WNDPAGE wp; + + WINE_TRACE("()\n"); + wp.page = Globals.active_win->page; + wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_bwd, &wp.relative); + if (wp.page) + { + wp.page->file->wRefCount++; + wp.wininfo = Globals.active_win->info; + WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE); + } +} + +void CALLBACK MACRO_Print(void) +{ + PRINTDLG printer; + + WINE_TRACE("()\n"); + + printer.lStructSize = sizeof(printer); + printer.hwndOwner = Globals.active_win->hMainWnd; + printer.hInstance = Globals.hInstance; + printer.hDevMode = 0; + printer.hDevNames = 0; + printer.hDC = 0; + printer.Flags = 0; + printer.nFromPage = 0; + printer.nToPage = 0; + printer.nMinPage = 0; + printer.nMaxPage = 0; + printer.nCopies = 0; + printer.lCustData = 0; + printer.lpfnPrintHook = 0; + printer.lpfnSetupHook = 0; + printer.lpPrintTemplateName = 0; + printer.lpSetupTemplateName = 0; + printer.hPrintTemplate = 0; + printer.hSetupTemplate = 0; + + if (PrintDlgA(&printer)) { + WINE_FIXME("Print()\n"); + } +} + +void CALLBACK MACRO_PrinterSetup(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_RegisterRoutine(LPCSTR dll_name, LPCSTR proc, LPCSTR args) +{ + FARPROC fn = NULL; + int size; + WINHELP_DLL* dll; + + WINE_TRACE("(\"%s\", \"%s\", \"%s\")\n", dll_name, proc, args); + + /* FIXME: are the registered DLLs global or linked to the current file ??? + * We assume globals (as we did for macros, but is this really the case ???) + */ + for (dll = Globals.dlls; dll; dll = dll->next) + { + if (!strcmp(dll->name, dll_name)) break; + } + if (!dll) + { + HANDLE hLib = LoadLibrary(dll_name); + + /* FIXME: the library will not be unloaded until exit of program + * We don't send the DW_TERM message + */ + WINE_TRACE("Loading %s\n", dll_name); + /* FIXME: should look in the directory where current hlpfile + * is loaded from + */ + if (hLib == NULL) + { + /* FIXME: internationalisation for error messages */ + WINE_FIXME("Cannot find dll %s\n", dll_name); + } + else if ((dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*dll)))) + { + dll->hLib = hLib; + dll->name = strdup(dll_name); /* FIXME */ + dll->next = Globals.dlls; + Globals.dlls = dll; + dll->handler = (WINHELP_LDLLHandler)GetProcAddress(dll->hLib, "LDLLHandler"); + dll->class = dll->handler ? (dll->handler)(DW_WHATMSG, 0, 0) : DC_NOMSG; + WINE_TRACE("Got class %x for DLL %s\n", dll->class, dll_name); + if (dll->class & DC_INITTERM) dll->handler(DW_INIT, 0, 0); + if (dll->class & DC_CALLBACKS) dll->handler(DW_CALLBACKS, (DWORD)Callbacks, 0); + } + else WINE_WARN("OOM\n"); + } + if (dll && !(fn = GetProcAddress(dll->hLib, proc))) + { + /* FIXME: internationalisation for error messages */ + WINE_FIXME("Cannot find proc %s in dll %s\n", dll_name, proc); + } + + size = ++MACRO_NumLoaded * sizeof(struct MacroDesc); + if (!MACRO_Loaded) MACRO_Loaded = HeapAlloc(GetProcessHeap(), 0, size); + else MACRO_Loaded = HeapReAlloc(GetProcessHeap(), 0, MACRO_Loaded, size); + MACRO_Loaded[MACRO_NumLoaded - 1].name = strdup(proc); /* FIXME */ + MACRO_Loaded[MACRO_NumLoaded - 1].alias = NULL; + MACRO_Loaded[MACRO_NumLoaded - 1].isBool = 0; + MACRO_Loaded[MACRO_NumLoaded - 1].arguments = strdup(args); /* FIXME */ + MACRO_Loaded[MACRO_NumLoaded - 1].fn = fn; + WINE_TRACE("Added %s(%s) at %p\n", proc, args, fn); +} + +static void CALLBACK MACRO_RemoveAccelerator(LONG u1, LONG u2) +{ + WINE_FIXME("(%u, %u)\n", u1, u2); +} + +static void CALLBACK MACRO_ResetMenu(void) +{ + WINE_FIXME("()\n"); +} + +static void CALLBACK MACRO_SaveMark(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_Search(void) +{ + WINHELP_CreateIndexWindow(TRUE); +} + +void CALLBACK MACRO_SetContents(LPCSTR str, LONG u) +{ + WINE_FIXME("(\"%s\", %u)\n", str, u); +} + +static void CALLBACK MACRO_SetHelpOnFile(LPCSTR str) +{ + WINE_TRACE("(\"%s\")\n", str); + + HeapFree(GetProcessHeap(), 0, Globals.active_win->page->file->help_on_file); + Globals.active_win->page->file->help_on_file = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1); + if (Globals.active_win->page->file->help_on_file) + strcpy(Globals.active_win->page->file->help_on_file, str); +} + +static void CALLBACK MACRO_SetPopupColor(LONG r, LONG g, LONG b) +{ + WINE_TRACE("(%x, %x, %x)\n", r, g, b); + Globals.active_win->page->file->has_popup_color = TRUE; + Globals.active_win->page->file->popup_color = RGB(r, g, b); +} + +static void CALLBACK MACRO_ShellExecute(LPCSTR str1, LPCSTR str2, LONG u1, LONG u2, LPCSTR str3, LPCSTR str4) +{ + WINE_FIXME("(\"%s\", \"%s\", %u, %u, \"%s\", \"%s\")\n", str1, str2, u1, u2, str3, str4); +} + +static void CALLBACK MACRO_ShortCut(LPCSTR str1, LPCSTR str2, LONG w, LONG l, LPCSTR str) +{ + WINE_FIXME("(\"%s\", \"%s\", %x, %x, \"%s\")\n", str1, str2, w, l, str); +} + +static void CALLBACK MACRO_TCard(LONG u) +{ + WINE_FIXME("(%u)\n", u); +} + +static void CALLBACK MACRO_Test(LONG u) +{ + WINE_FIXME("(%u)\n", u); +} + +static BOOL CALLBACK MACRO_TestALink(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); + return FALSE; +} + +static BOOL CALLBACK MACRO_TestKLink(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); + return FALSE; +} + +static void CALLBACK MACRO_UncheckItem(LPCSTR str) +{ + WINE_FIXME("(\"%s\")\n", str); +} + +static void CALLBACK MACRO_UpdateWindow(LPCSTR str1, LPCSTR str2) +{ + WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2); +} + + +/**************************************************/ +/* Macro table */ +/**************************************************/ + +/* types: + * U: 32 bit unsigned int + * I: 32 bit signed int + * S: string + * v: unknown (32 bit entity) + */ + +static struct MacroDesc MACRO_Builtins[] = { + {"About", NULL, 0, "", (FARPROC)MACRO_About}, + {"AddAccelerator", "AA", 0, "UUS", (FARPROC)MACRO_AddAccelerator}, + {"ALink", "AL", 0, "SUS", (FARPROC)MACRO_ALink}, + {"Annotate", NULL, 0, "", (FARPROC)MACRO_Annotate}, + {"AppendItem", NULL, 0, "SSSS", (FARPROC)MACRO_AppendItem}, + {"Back", NULL, 0, "", (FARPROC)MACRO_Back}, + {"BackFlush", "BF", 0, "", (FARPROC)MACRO_BackFlush}, + {"BookmarkDefine", NULL, 0, "", (FARPROC)MACRO_BookmarkDefine}, + {"BookmarkMore", NULL, 0, "", (FARPROC)MACRO_BookmarkMore}, + {"BrowseButtons", NULL, 0, "", (FARPROC)MACRO_BrowseButtons}, + {"ChangeButtonBinding", "CBB",0, "SS", (FARPROC)MACRO_ChangeButtonBinding}, + {"ChangeEnable", "CE", 0, "SS", (FARPROC)MACRO_ChangeEnable}, + {"ChangeItemBinding", "CIB",0, "SS", (FARPROC)MACRO_ChangeItemBinding}, + {"CheckItem", "CI", 0, "S", (FARPROC)MACRO_CheckItem}, + {"CloseSecondarys", "CS", 0, "", (FARPROC)MACRO_CloseSecondarys}, + {"CloseWindow", "CW", 0, "S", (FARPROC)MACRO_CloseWindow}, + {"Compare", NULL, 0, "S", (FARPROC)MACRO_Compare}, + {"Contents", NULL, 0, "", (FARPROC)MACRO_Contents}, + {"ControlPanel", NULL, 0, "SSU", (FARPROC)MACRO_ControlPanel}, + {"CopyDialog", NULL, 0, "", (FARPROC)MACRO_CopyDialog}, + {"CopyTopic", "CT", 0, "", (FARPROC)MACRO_CopyTopic}, + {"CreateButton", "CB", 0, "SSS", (FARPROC)MACRO_CreateButton}, + {"DeleteItem", NULL, 0, "S", (FARPROC)MACRO_DeleteItem}, + {"DeleteMark", NULL, 0, "S", (FARPROC)MACRO_DeleteMark}, + {"DestroyButton", NULL, 0, "S", (FARPROC)MACRO_DestroyButton}, + {"DisableButton", "DB", 0, "S", (FARPROC)MACRO_DisableButton}, + {"DisableItem", "DI", 0, "S", (FARPROC)MACRO_DisableItem}, + {"EnableButton", "EB", 0, "S", (FARPROC)MACRO_EnableButton}, + {"EnableItem", "EI", 0, "S", (FARPROC)MACRO_EnableItem}, + {"EndMPrint", NULL, 0, "", (FARPROC)MACRO_EndMPrint}, + {"ExecFile", "EF", 0, "SSUS", (FARPROC)MACRO_ExecFile}, + {"ExecProgram", "EP", 0, "SU", (FARPROC)MACRO_ExecProgram}, + {"Exit", NULL, 0, "", (FARPROC)MACRO_Exit}, + {"ExtAbleItem", NULL, 0, "SU", (FARPROC)MACRO_ExtAbleItem}, + {"ExtInsertItem", NULL, 0, "SSSSUU", (FARPROC)MACRO_ExtInsertItem}, + {"ExtInsertMenu", NULL, 0, "SSSUU", (FARPROC)MACRO_ExtInsertMenu}, + {"FileExist", "FE", 1, "S", (FARPROC)MACRO_FileExist}, + {"FileOpen", "FO", 0, "", (FARPROC)MACRO_FileOpen}, + {"Find", NULL, 0, "", (FARPROC)MACRO_Find}, + {"Finder", "FD", 0, "", (FARPROC)MACRO_Finder}, + {"FloatingMenu", NULL, 0, "", (FARPROC)MACRO_FloatingMenu}, + {"Flush", "FH", 0, "", (FARPROC)MACRO_Flush}, + {"FocusWindow", NULL, 0, "S", (FARPROC)MACRO_FocusWindow}, + {"Generate", NULL, 0, "SUU", (FARPROC)MACRO_Generate}, + {"GotoMark", NULL, 0, "S", (FARPROC)MACRO_GotoMark}, + {"HelpOn", NULL, 0, "", (FARPROC)MACRO_HelpOn}, + {"HelpOnTop", NULL, 0, "", (FARPROC)MACRO_HelpOnTop}, + {"History", NULL, 0, "", (FARPROC)MACRO_History}, + {"InitMPrint", NULL, 1, "", (FARPROC)MACRO_InitMPrint}, + {"InsertItem", NULL, 0, "SSSSU", (FARPROC)MACRO_InsertItem}, + {"InsertMenu", NULL, 0, "SSU", (FARPROC)MACRO_InsertMenu}, + {"IfThen", "IF", 0, "BS", (FARPROC)MACRO_IfThen}, + {"IfThenElse", "IE", 0, "BSS", (FARPROC)MACRO_IfThenElse}, + {"IsBook", NULL, 1, "", (FARPROC)MACRO_IsBook}, + {"IsMark", NULL, 1, "S", (FARPROC)MACRO_IsMark}, + {"IsNotMark", "NM", 1, "S", (FARPROC)MACRO_IsNotMark}, + {"JumpContents", NULL, 0, "SS", (FARPROC)MACRO_JumpContents}, + {"JumpContext", "JC", 0, "SSU", (FARPROC)MACRO_JumpContext}, + {"JumpHash", "JH", 0, "SSU", (FARPROC)MACRO_JumpHash}, + {"JumpHelpOn", NULL, 0, "", (FARPROC)MACRO_JumpHelpOn}, + {"JumpID", "JI", 0, "SS", (FARPROC)MACRO_JumpID}, + {"JumpKeyword", "JK", 0, "SSS", (FARPROC)MACRO_JumpKeyword}, + {"KLink", "KL", 0, "SUSS", (FARPROC)MACRO_KLink}, + {"Menu", "MU", 0, "", (FARPROC)MACRO_Menu}, + {"MPrintHash", NULL, 0, "U", (FARPROC)MACRO_MPrintHash}, + {"MPrintID", NULL, 0, "S", (FARPROC)MACRO_MPrintID}, + {"Next", NULL, 0, "", (FARPROC)MACRO_Next}, + {"NoShow", NULL, 0, "", (FARPROC)MACRO_NoShow}, + {"PopupContext", "PC", 0, "SU", (FARPROC)MACRO_PopupContext}, + {"PopupHash", NULL, 0, "SU", (FARPROC)MACRO_PopupHash}, + {"PopupId", "PI", 0, "SS", (FARPROC)MACRO_PopupId}, + {"PositionWindow", "PW", 0, "IIUUUS", (FARPROC)MACRO_PositionWindow}, + {"Prev", NULL, 0, "", (FARPROC)MACRO_Prev}, + {"Print", NULL, 0, "", (FARPROC)MACRO_Print}, + {"PrinterSetup", NULL, 0, "", (FARPROC)MACRO_PrinterSetup}, + {"RegisterRoutine", "RR", 0, "SSS", (FARPROC)MACRO_RegisterRoutine}, + {"RemoveAccelerator", "RA", 0, "UU", (FARPROC)MACRO_RemoveAccelerator}, + {"ResetMenu", NULL, 0, "", (FARPROC)MACRO_ResetMenu}, + {"SaveMark", NULL, 0, "S", (FARPROC)MACRO_SaveMark}, + {"Search", NULL, 0, "", (FARPROC)MACRO_Search}, + {"SetContents", NULL, 0, "SU", (FARPROC)MACRO_SetContents}, + {"SetHelpOnFile", NULL, 0, "S", (FARPROC)MACRO_SetHelpOnFile}, + {"SetPopupColor", "SPC",0, "UUU", (FARPROC)MACRO_SetPopupColor}, + {"ShellExecute", "SE", 0, "SSUUSS", (FARPROC)MACRO_ShellExecute}, + {"ShortCut", "SH", 0, "SSUUS", (FARPROC)MACRO_ShortCut}, + {"TCard", NULL, 0, "U", (FARPROC)MACRO_TCard}, + {"Test", NULL, 0, "U", (FARPROC)MACRO_Test}, + {"TestALink", NULL, 1, "S", (FARPROC)MACRO_TestALink}, + {"TestKLink", NULL, 1, "S", (FARPROC)MACRO_TestKLink}, + {"UncheckItem", "UI", 0, "S", (FARPROC)MACRO_UncheckItem}, + {"UpdateWindow", "UW", 0, "SS", (FARPROC)MACRO_UpdateWindow}, + {NULL, NULL, 0, NULL, NULL} +}; + +static int MACRO_DoLookUp(struct MacroDesc* start, const char* name, struct lexret* lr, unsigned len) +{ + struct MacroDesc* md; + + for (md = start; md->name && len != 0; md++, len--) + { + if (strcasecmp(md->name, name) == 0 || (md->alias != NULL && strcasecmp(md->alias, name) == 0)) + { + lr->proto = md->arguments; + lr->function = md->fn; + return md->isBool ? BOOL_FUNCTION : VOID_FUNCTION; + } + } + return EMPTY; +} + +int MACRO_Lookup(const char* name, struct lexret* lr) +{ + int ret; + + if ((ret = MACRO_DoLookUp(MACRO_Builtins, name, lr, -1)) != EMPTY) + return ret; + if (MACRO_Loaded && (ret = MACRO_DoLookUp(MACRO_Loaded, name, lr, MACRO_NumLoaded)) != EMPTY) + return ret; + + lr->string = name; + return IDENTIFIER; +} diff --git a/reactos/base/applications/winhlp32/macro.h b/reactos/base/applications/winhlp32/macro.h index 7af99b679c7..8b157197ca5 100644 --- a/reactos/base/applications/winhlp32/macro.h +++ b/reactos/base/applications/winhlp32/macro.h @@ -1,62 +1,62 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * Copyright 2002 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include - -#include "windef.h" -#include "winbase.h" - -struct lexret { - LPCSTR proto; - BOOL bool; - LONG integer; - LPCSTR string; - FARPROC function; -}; - -extern struct lexret yylval; - -BOOL MACRO_ExecuteMacro(LPCSTR); -int MACRO_Lookup(const char* name, struct lexret* lr); - -enum token_types {EMPTY, VOID_FUNCTION, BOOL_FUNCTION, INTEGER, STRING, IDENTIFIER}; -void CALLBACK MACRO_About(void); -void CALLBACK MACRO_Annotate(void); -void CALLBACK MACRO_BookmarkDefine(void); -void CALLBACK MACRO_CopyDialog(void); -void CALLBACK MACRO_CreateButton(LPCSTR, LPCSTR, LPCSTR); -void CALLBACK MACRO_DisableButton(LPCSTR); -void CALLBACK MACRO_Exit(void); -void CALLBACK MACRO_FileOpen(void); -void CALLBACK MACRO_HelpOn(void); -void CALLBACK MACRO_HelpOnTop(void); -void CALLBACK MACRO_History(void); -void CALLBACK MACRO_JumpContents(LPCSTR, LPCSTR); -void CALLBACK MACRO_JumpContext(LPCSTR, LPCSTR, LONG); -void CALLBACK MACRO_JumpHash(LPCSTR, LPCSTR, LONG); -void CALLBACK MACRO_PopupContext(LPCSTR, LONG); -void CALLBACK MACRO_Print(void); -void CALLBACK MACRO_PrinterSetup(void); -void CALLBACK MACRO_SetContents(LPCSTR, LONG); - -/* Local Variables: */ -/* c-file-style: "GNU" */ -/* End: */ +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * Copyright 2002 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include + +#include "windef.h" +#include "winbase.h" + +struct lexret { + LPCSTR proto; + BOOL bool; + LONG integer; + LPCSTR string; + FARPROC function; +}; + +extern struct lexret yylval; + +BOOL MACRO_ExecuteMacro(LPCSTR); +int MACRO_Lookup(const char* name, struct lexret* lr); + +enum token_types {EMPTY, VOID_FUNCTION, BOOL_FUNCTION, INTEGER, STRING, IDENTIFIER}; +void CALLBACK MACRO_About(void); +void CALLBACK MACRO_Annotate(void); +void CALLBACK MACRO_BookmarkDefine(void); +void CALLBACK MACRO_CopyDialog(void); +void CALLBACK MACRO_CreateButton(LPCSTR, LPCSTR, LPCSTR); +void CALLBACK MACRO_DisableButton(LPCSTR); +void CALLBACK MACRO_Exit(void); +void CALLBACK MACRO_FileOpen(void); +void CALLBACK MACRO_HelpOn(void); +void CALLBACK MACRO_HelpOnTop(void); +void CALLBACK MACRO_History(void); +void CALLBACK MACRO_JumpContents(LPCSTR, LPCSTR); +void CALLBACK MACRO_JumpContext(LPCSTR, LPCSTR, LONG); +void CALLBACK MACRO_JumpHash(LPCSTR, LPCSTR, LONG); +void CALLBACK MACRO_PopupContext(LPCSTR, LONG); +void CALLBACK MACRO_Print(void); +void CALLBACK MACRO_PrinterSetup(void); +void CALLBACK MACRO_SetContents(LPCSTR, LONG); + +/* Local Variables: */ +/* c-file-style: "GNU" */ +/* End: */ diff --git a/reactos/base/applications/winhlp32/macro.lex.l b/reactos/base/applications/winhlp32/macro.lex.l index 0594a2d6fc5..f3366b02bbd 100644 --- a/reactos/base/applications/winhlp32/macro.lex.l +++ b/reactos/base/applications/winhlp32/macro.lex.l @@ -1,316 +1,316 @@ -%{ /* -*-C-*- */ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * Copyright 2002,2008 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ -%} -%option noinput nounput interactive 8bit -%x quote -%{ -#include "config.h" -#include - -#ifndef HAVE_UNISTD_H -#define YY_NO_UNISTD_H -#endif - -#include "macro.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -struct lex_data { - LPCSTR macroptr; - LPSTR strptr; - int quote_stack[32]; - unsigned quote_stk_idx; - LPSTR cache_string[32]; - int cache_used; -}; -static struct lex_data* lex_data = NULL; - -struct lexret yylval; - -#define YY_INPUT(buf,result,max_size)\ - if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++; - -%} -%% - -[-+]?[0-9]+ yylval.integer = strtol(yytext, NULL, 10); return INTEGER; -[-+]?0[xX][0-9a-f]+ yylval.integer = strtol(yytext, NULL, 16); return INTEGER; - -[a-zA-Z][_0-9a-zA-Z]* return MACRO_Lookup(yytext, &yylval); - -\` | -\" | -\' | -\` | -\" | -\' { - if (lex_data->quote_stk_idx == 0 || - (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') || - (yytext[0] == '`')) - { - /* opening a new one */ - if (lex_data->quote_stk_idx == 0) - { - assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0])); - lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1); - yylval.string = lex_data->strptr; - lex_data->cache_used++; - BEGIN(quote); - } - else *lex_data->strptr++ = yytext[0]; - lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0]; - assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0])); - } - else - { - if (yytext[0] == '`') assert(0); - /* close the current quote */ - if (--lex_data->quote_stk_idx == 0) - { - BEGIN INITIAL; - *lex_data->strptr++ = '\0'; - return STRING; - } - else *lex_data->strptr++ = yytext[0]; - } -} - -. *lex_data->strptr++ = yytext[0]; -\\. *lex_data->strptr++ = yytext[1]; -<> return 0; - -" " -. return yytext[0]; -%% - -#if 0 -/* all code for testing macros */ -#include "winhelp.h" -static CHAR szTestMacro[256]; - -static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (msg == WM_COMMAND && wParam == IDOK) - { - GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro)); - EndDialog(hDlg, IDOK); - return TRUE; - } - return FALSE; -} - -void macro_test(void) -{ - WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance); - DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg); - FreeProcInstance(lpfnDlg); - macro = szTestMacro; -} -#endif - -/* small helper function for debug messages */ -static const char* ts(int t) -{ - static char c[2] = {0,0}; - - switch (t) - { - case EMPTY: return "EMPTY"; - case VOID_FUNCTION: return "VOID_FUNCTION"; - case BOOL_FUNCTION: return "BOOL_FUNCTION"; - case INTEGER: return "INTEGER"; - case STRING: return "STRING"; - case IDENTIFIER: return "IDENTIFIER"; - default: c[0] = (char)t; return c; - } -} - -static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret); - -/****************************************************************** - * MACRO_CheckArgs - * - * checks number of arguments against prototype, and stores arguments on - * stack pa for later call - * returns -1 on error, otherwise the number of pushed parameters - */ -static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args) -{ - int t; - unsigned int len = 0, idx = 0; - - WINE_TRACE("Checking %s\n", args); - - if (yylex() != '(') {WINE_WARN("missing (\n");return -1;} - - if (*args) - { - len = strlen(args); - for (;;) - { - t = yylex(); - WINE_TRACE("Got %s <=> %c\n", ts(t), *args); - - switch (*args) - { - case 'S': - if (t != STRING) - {WINE_WARN("missing S\n");return -1;} - pa[idx] = (void*)yylval.string; - break; - case 'U': - case 'I': - if (t != INTEGER) - {WINE_WARN("missing U\n");return -1;} - pa[idx] = LongToPtr(yylval.integer); - break; - case 'B': - if (t != BOOL_FUNCTION) - {WINE_WARN("missing B\n");return -1;} - if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0) - return -1; - break; - default: - WINE_WARN("unexpected %s while args is %c\n", ts(t), *args); - return -1; - } - idx++; - if (*++args == '\0') break; - t = yylex(); - if (t == ')') goto CheckArgs_end; - if (t != ',') {WINE_WARN("missing ,\n");return -1;} - if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;} - } - } - if (yylex() != ')') {WINE_WARN("missing )\n");return -1;} - -CheckArgs_end: - while (len > idx) pa[--len] = NULL; - return idx; -} - -/****************************************************************** - * MACRO_CallBoolFunc - * - * Invokes boolean function fn, which arguments are defined by args - * stores bool result into ret - */ -static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret) -{ - void* pa[2]; - int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); - - if (idx < 0) return 0; - if (!fn) return 1; - - WINE_TRACE("calling with %u pmts\n", idx); - - switch (strlen(args)) - { - case 0: *ret = (void*)(fn)(); break; - case 1: *ret = (void*)(fn)(pa[0]); break; - default: WINE_FIXME("NIY\n"); - } - - return 1; -} - -/****************************************************************** - * MACRO_CallVoidFunc - * - * - */ -static int MACRO_CallVoidFunc(FARPROC fn, const char* args) -{ - void* pa[6]; - int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); - - if (idx < 0) return 0; - if (!fn) return 1; - - WINE_TRACE("calling %p with %u pmts\n", fn, idx); - - switch (strlen(args)) - { - case 0: (fn)(); break; - case 1: (fn)(pa[0]); break; - case 2: (fn)(pa[0],pa[1]); break; - case 3: (fn)(pa[0],pa[1],pa[2]); break; - case 4: (fn)(pa[0],pa[1],pa[2],pa[3]); break; - case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]); break; - case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]); break; - default: WINE_FIXME("NIY\n"); - } - - return 1; -} - -BOOL MACRO_ExecuteMacro(LPCSTR macro) -{ - struct lex_data curr_lex_data, *prev_lex_data; - BOOL ret = TRUE; - int t; - - WINE_TRACE("%s\n", wine_dbgstr_a(macro)); - - prev_lex_data = lex_data; - lex_data = &curr_lex_data; - - memset(lex_data, 0, sizeof(*lex_data)); - lex_data->macroptr = macro; - - while ((t = yylex()) != EMPTY) - { - switch (t) - { - case VOID_FUNCTION: - WINE_TRACE("got type void func(%s)\n", yylval.proto); - MACRO_CallVoidFunc(yylval.function, yylval.proto); - break; - case BOOL_FUNCTION: - WINE_WARN("got type bool func(%s)\n", yylval.proto); - break; - default: - WINE_WARN("got unexpected type %s\n", ts(t)); - return 0; - } - switch (t = yylex()) - { - case EMPTY: goto done; - case ';': break; - default: ret = FALSE; goto done; - } - } - -done: - for (t = 0; t < lex_data->cache_used; t++) - HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]); - lex_data = prev_lex_data; - - return ret; -} - -#ifndef yywrap -int yywrap(void) { return 1; } -#endif +%{ /* -*-C-*- */ +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * Copyright 2002,2008 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ +%} +%option noinput nounput interactive 8bit +%x quote +%{ +#include "config.h" +#include + +#ifndef HAVE_UNISTD_H +#define YY_NO_UNISTD_H +#endif + +#include "macro.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +struct lex_data { + LPCSTR macroptr; + LPSTR strptr; + int quote_stack[32]; + unsigned quote_stk_idx; + LPSTR cache_string[32]; + int cache_used; +}; +static struct lex_data* lex_data = NULL; + +struct lexret yylval; + +#define YY_INPUT(buf,result,max_size)\ + if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++; + +%} +%% + +[-+]?[0-9]+ yylval.integer = strtol(yytext, NULL, 10); return INTEGER; +[-+]?0[xX][0-9a-f]+ yylval.integer = strtol(yytext, NULL, 16); return INTEGER; + +[a-zA-Z][_0-9a-zA-Z]* return MACRO_Lookup(yytext, &yylval); + +\` | +\" | +\' | +\` | +\" | +\' { + if (lex_data->quote_stk_idx == 0 || + (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') || + (yytext[0] == '`')) + { + /* opening a new one */ + if (lex_data->quote_stk_idx == 0) + { + assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0])); + lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1); + yylval.string = lex_data->strptr; + lex_data->cache_used++; + BEGIN(quote); + } + else *lex_data->strptr++ = yytext[0]; + lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0]; + assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0])); + } + else + { + if (yytext[0] == '`') assert(0); + /* close the current quote */ + if (--lex_data->quote_stk_idx == 0) + { + BEGIN INITIAL; + *lex_data->strptr++ = '\0'; + return STRING; + } + else *lex_data->strptr++ = yytext[0]; + } +} + +. *lex_data->strptr++ = yytext[0]; +\\. *lex_data->strptr++ = yytext[1]; +<> return 0; + +" " +. return yytext[0]; +%% + +#if 0 +/* all code for testing macros */ +#include "winhelp.h" +static CHAR szTestMacro[256]; + +static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (msg == WM_COMMAND && wParam == IDOK) + { + GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro)); + EndDialog(hDlg, IDOK); + return TRUE; + } + return FALSE; +} + +void macro_test(void) +{ + WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance); + DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg); + FreeProcInstance(lpfnDlg); + macro = szTestMacro; +} +#endif + +/* small helper function for debug messages */ +static const char* ts(int t) +{ + static char c[2] = {0,0}; + + switch (t) + { + case EMPTY: return "EMPTY"; + case VOID_FUNCTION: return "VOID_FUNCTION"; + case BOOL_FUNCTION: return "BOOL_FUNCTION"; + case INTEGER: return "INTEGER"; + case STRING: return "STRING"; + case IDENTIFIER: return "IDENTIFIER"; + default: c[0] = (char)t; return c; + } +} + +static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret); + +/****************************************************************** + * MACRO_CheckArgs + * + * checks number of arguments against prototype, and stores arguments on + * stack pa for later call + * returns -1 on error, otherwise the number of pushed parameters + */ +static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args) +{ + int t; + unsigned int len = 0, idx = 0; + + WINE_TRACE("Checking %s\n", args); + + if (yylex() != '(') {WINE_WARN("missing (\n");return -1;} + + if (*args) + { + len = strlen(args); + for (;;) + { + t = yylex(); + WINE_TRACE("Got %s <=> %c\n", ts(t), *args); + + switch (*args) + { + case 'S': + if (t != STRING) + {WINE_WARN("missing S\n");return -1;} + pa[idx] = (void*)yylval.string; + break; + case 'U': + case 'I': + if (t != INTEGER) + {WINE_WARN("missing U\n");return -1;} + pa[idx] = LongToPtr(yylval.integer); + break; + case 'B': + if (t != BOOL_FUNCTION) + {WINE_WARN("missing B\n");return -1;} + if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0) + return -1; + break; + default: + WINE_WARN("unexpected %s while args is %c\n", ts(t), *args); + return -1; + } + idx++; + if (*++args == '\0') break; + t = yylex(); + if (t == ')') goto CheckArgs_end; + if (t != ',') {WINE_WARN("missing ,\n");return -1;} + if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;} + } + } + if (yylex() != ')') {WINE_WARN("missing )\n");return -1;} + +CheckArgs_end: + while (len > idx) pa[--len] = NULL; + return idx; +} + +/****************************************************************** + * MACRO_CallBoolFunc + * + * Invokes boolean function fn, which arguments are defined by args + * stores bool result into ret + */ +static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret) +{ + void* pa[2]; + int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); + + if (idx < 0) return 0; + if (!fn) return 1; + + WINE_TRACE("calling with %u pmts\n", idx); + + switch (strlen(args)) + { + case 0: *ret = (void*)(fn)(); break; + case 1: *ret = (void*)(fn)(pa[0]); break; + default: WINE_FIXME("NIY\n"); + } + + return 1; +} + +/****************************************************************** + * MACRO_CallVoidFunc + * + * + */ +static int MACRO_CallVoidFunc(FARPROC fn, const char* args) +{ + void* pa[6]; + int idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args); + + if (idx < 0) return 0; + if (!fn) return 1; + + WINE_TRACE("calling %p with %u pmts\n", fn, idx); + + switch (strlen(args)) + { + case 0: (fn)(); break; + case 1: (fn)(pa[0]); break; + case 2: (fn)(pa[0],pa[1]); break; + case 3: (fn)(pa[0],pa[1],pa[2]); break; + case 4: (fn)(pa[0],pa[1],pa[2],pa[3]); break; + case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]); break; + case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]); break; + default: WINE_FIXME("NIY\n"); + } + + return 1; +} + +BOOL MACRO_ExecuteMacro(LPCSTR macro) +{ + struct lex_data curr_lex_data, *prev_lex_data; + BOOL ret = TRUE; + int t; + + WINE_TRACE("%s\n", wine_dbgstr_a(macro)); + + prev_lex_data = lex_data; + lex_data = &curr_lex_data; + + memset(lex_data, 0, sizeof(*lex_data)); + lex_data->macroptr = macro; + + while ((t = yylex()) != EMPTY) + { + switch (t) + { + case VOID_FUNCTION: + WINE_TRACE("got type void func(%s)\n", yylval.proto); + MACRO_CallVoidFunc(yylval.function, yylval.proto); + break; + case BOOL_FUNCTION: + WINE_WARN("got type bool func(%s)\n", yylval.proto); + break; + default: + WINE_WARN("got unexpected type %s\n", ts(t)); + return 0; + } + switch (t = yylex()) + { + case EMPTY: goto done; + case ';': break; + default: ret = FALSE; goto done; + } + } + +done: + for (t = 0; t < lex_data->cache_used; t++) + HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]); + lex_data = prev_lex_data; + + return ret; +} + +#ifndef yywrap +int yywrap(void) { return 1; } +#endif diff --git a/reactos/base/applications/winhlp32/string.c b/reactos/base/applications/winhlp32/string.c index ba9713d5b18..b9319484d41 100644 --- a/reactos/base/applications/winhlp32/string.c +++ b/reactos/base/applications/winhlp32/string.c @@ -1,34 +1,34 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -/* Class names */ - -const char MAIN_WIN_CLASS_NAME[] = "MS_WINHELP"; -const char BUTTON_BOX_WIN_CLASS_NAME[] = "WHButtonBox"; -const char SHADOW_WIN_CLASS_NAME[] = "WHShadow"; -const char HISTORY_WIN_CLASS_NAME[] = "WHHistory"; -const char STRING_BUTTON[] = "BUTTON"; - -/* Resource names */ -const char STRING_DIALOG_TEST[] = "DIALOG_TEST"; - -/* Local Variables: */ -/* c-file-style: "GNU" */ -/* End: */ +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +/* Class names */ + +const char MAIN_WIN_CLASS_NAME[] = "MS_WINHELP"; +const char BUTTON_BOX_WIN_CLASS_NAME[] = "WHButtonBox"; +const char SHADOW_WIN_CLASS_NAME[] = "WHShadow"; +const char HISTORY_WIN_CLASS_NAME[] = "WHHistory"; +const char STRING_BUTTON[] = "BUTTON"; + +/* Resource names */ +const char STRING_DIALOG_TEST[] = "DIALOG_TEST"; + +/* Local Variables: */ +/* c-file-style: "GNU" */ +/* End: */ diff --git a/reactos/base/applications/winhlp32/winhelp.c b/reactos/base/applications/winhlp32/winhelp.c index 6f293ea15fc..15e17f66e71 100644 --- a/reactos/base/applications/winhlp32/winhelp.c +++ b/reactos/base/applications/winhlp32/winhelp.c @@ -1,1720 +1,1720 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * 2002 Sylvain Petreolle - * 2002, 2008 Eric Pouech - * 2004 Ken Belleau - * 2008 Kirill K. Smirnov - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#include -#include -#include -#include -#include - -#define NONAMELESSUNION -#define NONAMELESSSTRUCT - -#include "windef.h" -#include "winbase.h" -#include "wingdi.h" -#include "winuser.h" -#include "commdlg.h" -#include "winhelp.h" -#include "winhelp_res.h" -#include "shellapi.h" -#include "richedit.h" -#include "commctrl.h" - -#include "wine/debug.h" - -WINE_DEFAULT_DEBUG_CHANNEL(winhelp); - -WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL}; - -#define CTL_ID_BUTTON 0x700 -#define CTL_ID_TEXT 0x701 - - -/*********************************************************************** - * - * WINHELP_InitFonts - */ -static void WINHELP_InitFonts(HWND hWnd) -{ - WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - LOGFONT logfontlist[] = { - {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, - { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}}; -#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist)) - - static HFONT fonts[FONTS_LEN]; - static BOOL init = 0; - - win->fonts_len = FONTS_LEN; - win->fonts = fonts; - - if (!init) - { - UINT i; - - for (i = 0; i < FONTS_LEN; i++) - { - fonts[i] = CreateFontIndirect(&logfontlist[i]); - } - - init = 1; - } -} - -static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff, - LONG cb, LONG* pcb) -{ - struct RtfData* rd = (struct RtfData*)cookie; - - if (rd->where >= rd->ptr) return 1; - if (rd->where + cb > rd->ptr) - cb = rd->ptr - rd->where; - memcpy(buff, rd->where, cb); - rd->where += cb; - *pcb = cb; - return 0; -} - -static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative) -{ - /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */ - SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)""); - SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0); - SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color); - /* set word-wrap to window size (undocumented) */ - SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0); - if (win->page) - { - struct RtfData rd; - EDITSTREAM es; - unsigned cp = 0; - POINTL ptl; - POINT pt; - - - if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative)) - { - rd.where = rd.data; - es.dwCookie = (DWORD_PTR)&rd; - es.dwError = 0; - es.pfnCallback = WINHELP_RtfStreamIn; - - SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es); - cp = rd.char_pos_rel; - } - /* FIXME: else leaking potentially the rd.first_link chain */ - HeapFree(GetProcessHeap(), 0, rd.data); - SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0); - pt.x = 0; pt.y = ptl.y; - SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt); - } - SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0); - InvalidateRect(hTextWnd, NULL, TRUE); -} - -/*********************************************************************** - * - * WINHELP_GetOpenFileName - */ -BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len) -{ - OPENFILENAME openfilename; - CHAR szDir[MAX_PATH]; - CHAR szzFilter[2 * MAX_STRING_LEN + 100]; - LPSTR p = szzFilter; - - WINE_TRACE("()\n"); - - LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN); - p += strlen(p) + 1; - lstrcpy(p, "*.hlp"); - p += strlen(p) + 1; - LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN); - p += strlen(p) + 1; - lstrcpy(p, "*.*"); - p += strlen(p) + 1; - *p = '\0'; - - GetCurrentDirectory(sizeof(szDir), szDir); - - lpszFile[0]='\0'; - - openfilename.lStructSize = sizeof(OPENFILENAME); - openfilename.hwndOwner = NULL; - openfilename.hInstance = Globals.hInstance; - openfilename.lpstrFilter = szzFilter; - openfilename.lpstrCustomFilter = 0; - openfilename.nMaxCustFilter = 0; - openfilename.nFilterIndex = 1; - openfilename.lpstrFile = lpszFile; - openfilename.nMaxFile = len; - openfilename.lpstrFileTitle = 0; - openfilename.nMaxFileTitle = 0; - openfilename.lpstrInitialDir = szDir; - openfilename.lpstrTitle = 0; - openfilename.Flags = 0; - openfilename.nFileOffset = 0; - openfilename.nFileExtension = 0; - openfilename.lpstrDefExt = 0; - openfilename.lCustData = 0; - openfilename.lpfnHook = 0; - openfilename.lpTemplateName = 0; - - return GetOpenFileName(&openfilename); -} - -/*********************************************************************** - * - * WINHELP_MessageBoxIDS_s - */ -static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type) -{ - CHAR text[MAX_STRING_LEN]; - CHAR newtext[MAX_STRING_LEN + MAX_PATH]; - - LoadString(Globals.hInstance, ids_text, text, sizeof(text)); - wsprintf(newtext, text, str); - - return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type); -} - -/*********************************************************************** - * - * WINHELP_LookupHelpFile - */ -HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile) -{ - HLPFILE* hlpfile; - char szFullName[MAX_PATH]; - char szAddPath[MAX_PATH]; - char *p; - - /* - * NOTE: This is needed by popup windows only. - * In other cases it's not needed but does not hurt though. - */ - if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) - { - strcpy(szAddPath, Globals.active_win->page->file->lpszPath); - p = strrchr(szAddPath, '\\'); - if (p) *p = 0; - } - - /* - * FIXME: Should we swap conditions? - */ - if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) && - !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL)) - { - if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR, - MB_YESNO|MB_ICONQUESTION) != IDYES) - return NULL; - if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH)) - return NULL; - } - hlpfile = HLPFILE_ReadHlpFile(szFullName); - if (!hlpfile) - WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile, - STID_WHERROR, MB_OK|MB_ICONSTOP); - return hlpfile; -} - -/****************************************************************** - * WINHELP_GetWindowInfo - * - * - */ -HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name) -{ - static HLPFILE_WINDOWINFO mwi; - unsigned int i; - - if (!name || !name[0]) - name = Globals.active_win->lpszName; - - if (hlpfile) - for (i = 0; i < hlpfile->numWindows; i++) - if (!strcmp(hlpfile->windows[i].name, name)) - return &hlpfile->windows[i]; - - if (strcmp(name, "main") != 0) - { - WINE_FIXME("Couldn't find window info for %s\n", name); - assert(0); - return NULL; - } - if (!mwi.name[0]) - { - strcpy(mwi.type, "primary"); - strcpy(mwi.name, "main"); - if (!LoadString(Globals.hInstance, STID_WINE_HELP, - mwi.caption, sizeof(mwi.caption))) - strcpy(mwi.caption, hlpfile->lpszTitle); - mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT; - mwi.style = SW_SHOW; - mwi.win_style = WS_OVERLAPPEDWINDOW; - mwi.sr_color = mwi.sr_color = 0xFFFFFF; - } - return &mwi; -} - -/****************************************************************** - * HLPFILE_GetPopupWindowInfo - * - * - */ -static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, - WINHELP_WINDOW* parent, LPARAM mouse) -{ - static HLPFILE_WINDOWINFO wi; - - RECT parent_rect; - - wi.type[0] = wi.name[0] = wi.caption[0] = '\0'; - - /* Calculate horizontal size and position of a popup window */ - GetWindowRect(parent->hMainWnd, &parent_rect); - wi.size.cx = (parent_rect.right - parent_rect.left) / 2; - wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */ - - wi.origin.x = (short)LOWORD(mouse); - wi.origin.y = (short)HIWORD(mouse); - ClientToScreen(parent->hMainWnd, &wi.origin); - wi.origin.x -= wi.size.cx / 2; - wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx); - wi.origin.x = max(wi.origin.x, 0); - - wi.style = SW_SHOW; - wi.win_style = WS_POPUP | WS_BORDER; - if (parent->page->file->has_popup_color) - wi.sr_color = parent->page->file->popup_color; - else - wi.sr_color = parent->info->sr_color; - wi.nsr_color = 0xFFFFFF; - - return &wi; -} - -typedef struct -{ - WORD size; - WORD command; - LONG data; - LONG reserved; - WORD ofsFilename; - WORD ofsData; -} WINHELP,*LPWINHELP; - -static BOOL WINHELP_HasWorkingWindow(void) -{ - if (!Globals.active_win) return FALSE; - if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE; - return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL; -} - -/****************************************************************** - * WINHELP_HandleCommand - * - * - */ -static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam) -{ - COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam; - WINHELP* wh; - - if (cds->dwData != 0xA1DE505) - { - WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData); - return 0; - } - - wh = (WINHELP*)cds->lpData; - - if (wh) - { - char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL; - - WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n", - wh->size, wh->command, wh->data, ptr); - switch (wh->command) - { - case HELP_CONTEXT: - if (ptr) - { - MACRO_JumpContext(ptr, "main", wh->data); - } - if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); - break; - case HELP_QUIT: - MACRO_Exit(); - break; - case HELP_CONTENTS: - if (ptr) - { - MACRO_JumpContents(ptr, "main"); - } - if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); - break; - case HELP_HELPONHELP: - MACRO_HelpOn(); - if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); - break; - /* case HELP_SETINDEX: */ - case HELP_SETCONTENTS: - if (ptr) - { - MACRO_SetContents(ptr, wh->data); - } - break; - case HELP_CONTEXTPOPUP: - if (ptr) - { - MACRO_PopupContext(ptr, wh->data); - } - break; - /* case HELP_FORCEFILE:*/ - /* case HELP_CONTEXTMENU: */ - case HELP_FINDER: - /* in fact, should be the topic dialog box */ - WINE_FIXME("HELP_FINDER: stub\n"); - if (ptr) - { - MACRO_JumpHash(ptr, "main", 0); - } - break; - /* case HELP_WM_HELP: */ - /* case HELP_SETPOPUP_POS: */ - /* case HELP_KEY: */ - /* case HELP_COMMAND: */ - /* case HELP_PARTIALKEY: */ - /* case HELP_MULTIKEY: */ - /* case HELP_SETWINPOS: */ - default: - WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command); - break; - } - } - /* Always return success for now */ - return 1; -} - -void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win) -{ - RECT rect, button_box_rect; - INT text_top = 0; - HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON); - HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); - - GetClientRect(win->hMainWnd, &rect); - - /* Update button box and text Window */ - SetWindowPos(hButtonBoxWnd, HWND_TOP, - rect.left, rect.top, - rect.right - rect.left, - rect.bottom - rect.top, 0); - - if (GetWindowRect(hButtonBoxWnd, &button_box_rect)) - text_top = rect.top + button_box_rect.bottom - button_box_rect.top; - - SetWindowPos(hTextWnd, HWND_TOP, - rect.left, text_top, - rect.right - rect.left, - rect.bottom - text_top, 0); - -} - -/****************************************************************** - * WINHELP_DeleteButtons - * - */ -static void WINHELP_DeleteButtons(WINHELP_WINDOW* win) -{ - WINHELP_BUTTON* b; - WINHELP_BUTTON* bp; - - for (b = win->first_button; b; b = bp) - { - DestroyWindow(b->hWnd); - bp = b->next; - HeapFree(GetProcessHeap(), 0, b); - } - win->first_button = NULL; -} - -/****************************************************************** - * WINHELP_DeleteBackSet - * - */ -void WINHELP_DeleteBackSet(WINHELP_WINDOW* win) -{ - unsigned int i; - - for (i = 0; i < win->back.index; i++) - { - HLPFILE_FreeHlpFile(win->back.set[i].page->file); - win->back.set[i].page = NULL; - } - win->back.index = 0; -} - -/****************************************************************** - * WINHELP_DeletePageLinks - * - */ -static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page) -{ - HLPFILE_LINK* curr; - HLPFILE_LINK* next; - - for (curr = page->first_link; curr; curr = next) - { - next = curr->next; - HeapFree(GetProcessHeap(), 0, curr); - } -} - -/*********************************************************************** - * - * WINHELP_DeleteWindow - */ -static void WINHELP_DeleteWindow(WINHELP_WINDOW* win) -{ - WINHELP_WINDOW** w; - - for (w = &Globals.win_list; *w; w = &(*w)->next) - { - if (*w == win) - { - *w = win->next; - break; - } - } - - if (Globals.active_win == win) - { - Globals.active_win = Globals.win_list; - if (Globals.win_list) - SetActiveWindow(Globals.win_list->hMainWnd); - } - - if (win == Globals.active_popup) - Globals.active_popup = NULL; - - WINHELP_DeleteButtons(win); - - if (win->page) WINHELP_DeletePageLinks(win->page); - if (win->hShadowWnd) DestroyWindow(win->hShadowWnd); - if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd); - - DeleteObject(win->hBrush); - - WINHELP_DeleteBackSet(win); - - if (win->page) HLPFILE_FreeHlpFile(win->page->file); - HeapFree(GetProcessHeap(), 0, win); -} - -static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage) -{ - if (wpage->wininfo->caption[0]) return wpage->wininfo->caption; - return wpage->page->file->lpszTitle; -} - -static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage) -{ - unsigned num; - - if (!Globals.history.index || Globals.history.set[0].page != wpage->page) - { - num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]); - /* we're full, remove latest entry */ - if (Globals.history.index == num) - { - HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file); - Globals.history.index--; - } - memmove(&Globals.history.set[1], &Globals.history.set[0], - Globals.history.index * sizeof(Globals.history.set[0])); - Globals.history.set[0] = *wpage; - Globals.history.index++; - wpage->page->file->wRefCount++; - } - if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); - - num = sizeof(win->back.set) / sizeof(win->back.set[0]); - if (win->back.index == num) - { - /* we're full, remove latest entry */ - HLPFILE_FreeHlpFile(win->back.set[0].page->file); - memmove(&win->back.set[0], &win->back.set[1], - (num - 1) * sizeof(win->back.set[0])); - win->back.index--; - } - win->back.set[win->back.index++] = *wpage; - wpage->page->file->wRefCount++; -} - -/*********************************************************************** - * - * WINHELP_CreateHelpWindow - */ -BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember) -{ - WINHELP_WINDOW* win = NULL; - BOOL bPrimary, bPopup, bReUsed = FALSE; - LPSTR name; - HICON hIcon; - HWND hTextWnd = NULL; - - bPrimary = !lstrcmpi(wpage->wininfo->name, "main"); - bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP); - - if (!bPopup) - { - for (win = Globals.win_list; win; win = win->next) - { - if (!lstrcmpi(win->lpszName, wpage->wininfo->name)) - { - POINT pt = {0, 0}; - SIZE sz = {0, 0}; - DWORD flags = SWP_NOSIZE | SWP_NOMOVE; - - WINHELP_DeleteButtons(win); - bReUsed = TRUE; - SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage)); - if (wpage->wininfo->origin.x != CW_USEDEFAULT && - wpage->wininfo->origin.y != CW_USEDEFAULT) - { - pt = wpage->wininfo->origin; - flags &= ~SWP_NOSIZE; - } - if (wpage->wininfo->size.cx != CW_USEDEFAULT && - wpage->wininfo->size.cy != CW_USEDEFAULT) - { - sz = wpage->wininfo->size; - flags &= ~SWP_NOMOVE; - } - SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags); - - if (wpage->page && win->page && wpage->page->file != win->page->file) - WINHELP_DeleteBackSet(win); - WINHELP_InitFonts(win->hMainWnd); - - win->page = wpage->page; - win->info = wpage->wininfo; - hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); - WINHELP_SetupText(hTextWnd, win, wpage->relative); - - InvalidateRect(win->hMainWnd, NULL, TRUE); - if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); - - break; - } - } - } - - if (!win) - { - /* Initialize WINHELP_WINDOW struct */ - win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, - sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1); - if (!win) return FALSE; - win->next = Globals.win_list; - Globals.win_list = win; - - name = (char*)win + sizeof(WINHELP_WINDOW); - lstrcpy(name, wpage->wininfo->name); - win->lpszName = name; - win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND); - win->back.index = 0; - win->font_scale = 1; - } - win->page = wpage->page; - win->info = wpage->wininfo; - - if (!bPopup && wpage->page && remember) - { - WINHELP_RememberPage(win, wpage); - } - - if (bPopup) - Globals.active_popup = win; - else - Globals.active_win = win; - - /* Initialize default pushbuttons */ - if (bPrimary && wpage->page) - { - CHAR buffer[MAX_STRING_LEN]; - - LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer)); - MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()"); - LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer)); - MACRO_CreateButton("BTN_INDEX", buffer, "Finder()"); - LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer)); - MACRO_CreateButton("BTN_BACK", buffer, "Back()"); - if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK"); - } - - if (!bReUsed) - { - win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME, - WINHELP_GetCaption(wpage), - bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style, - wpage->wininfo->origin.x, wpage->wininfo->origin.y, - wpage->wininfo->size.cx, wpage->wininfo->size.cy, - bPopup ? Globals.active_win->hMainWnd : NULL, - bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0, - Globals.hInstance, win); - if (!bPopup) - /* Create button box and text Window */ - CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE, - 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL); - - hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL, - ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE, - 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL); - SendMessage(hTextWnd, EM_SETEVENTMASK, 0, - SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS); - } - - hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL; - if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP)); - SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon); - - /* Initialize file specific pushbuttons */ - if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page) - { - HLPFILE_MACRO *macro; - for (macro = wpage->page->file->first_macro; macro; macro = macro->next) - MACRO_ExecuteMacro(macro->lpszMacro); - - for (macro = wpage->page->first_macro; macro; macro = macro->next) - MACRO_ExecuteMacro(macro->lpszMacro); - } - - if (bPopup) - { - DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0); - RECT rect; - - win->font_scale = Globals.active_win->font_scale; - WINHELP_SetupText(hTextWnd, win, wpage->relative); - - /* we need the window to be shown for richedit to compute the size */ - ShowWindow(win->hMainWnd, nCmdShow); - SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE); - SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0); - SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask); - - GetWindowRect(win->hMainWnd, &rect); - win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME, - "", WS_POPUP | WS_VISIBLE, - rect.left + SHADOW_DX, rect.top + SHADOW_DY, - rect.right - rect.left, - rect.bottom - rect.top, - Globals.active_win->hMainWnd, 0, - Globals.hInstance, NULL); - SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0, - SWP_NOSIZE | SWP_NOMOVE); - } - else - { - WINHELP_SetupText(hTextWnd, win, wpage->relative); - WINHELP_LayoutMainWindow(win); - ShowWindow(win->hMainWnd, nCmdShow); - } - - return TRUE; -} - -/****************************************************************** - * WINHELP_OpenHelpWindow - * Main function to search for a page and display it in a window - */ -BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*), - HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi, - int nCmdShow) -{ - WINHELP_WNDPAGE wpage; - - wpage.page = lookup(hlpfile, val, &wpage.relative); - if (wpage.page) wpage.page->file->wRefCount++; - wpage.wininfo = wi; - return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE); -} - -/*********************************************************************** - * - * WINHELP_FindLink - */ -static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos) -{ - HLPFILE_LINK* link; - POINTL mouse_ptl, char_ptl, char_next_ptl; - DWORD cp; - - if (!win->page) return NULL; - - mouse_ptl.x = (short)LOWORD(pos); - mouse_ptl.y = (short)HIWORD(pos); - cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS, - 0, (LPARAM)&mouse_ptl); - - for (link = win->page->first_link; link; link = link->next) - { - if (link->cpMin <= cp && cp <= link->cpMax) - { - /* check whether we're at end of line */ - SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, - (LPARAM)&char_ptl, cp); - SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, - (LPARAM)&char_next_ptl, cp + 1); - if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x) - link = NULL; - break; - } - } - return link; -} - -/****************************************************************** - * WINHELP_HandleTextMouse - * - */ -static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam) -{ - HLPFILE* hlpfile; - HLPFILE_LINK* link; - BOOL ret = FALSE; - - switch (msg) - { - case WM_MOUSEMOVE: - if (WINHELP_FindLink(win, lParam)) - SetCursor(win->hHandCur); - else - SetCursor(LoadCursor(0, IDC_ARROW)); - break; - - case WM_LBUTTONDOWN: - if ((win->current_link = WINHELP_FindLink(win, lParam))) - ret = TRUE; - break; - - case WM_LBUTTONUP: - if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link) - { - HLPFILE_WINDOWINFO* wi; - - switch (link->cookie) - { - case hlp_link_link: - if ((hlpfile = WINHELP_LookupHelpFile(link->string))) - { - if (link->window == -1) - wi = win->info; - else if (link->window < hlpfile->numWindows) - wi = &hlpfile->windows[link->window]; - else - { - WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows); - break; - } - WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL); - } - break; - case hlp_link_popup: - if ((hlpfile = WINHELP_LookupHelpFile(link->string))) - WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, - WINHELP_GetPopupWindowInfo(hlpfile, win, lParam), - SW_NORMAL); - break; - case hlp_link_macro: - MACRO_ExecuteMacro(link->string); - break; - default: - WINE_FIXME("Unknown link cookie %d\n", link->cookie); - } - ret = TRUE; - } - win->current_link = NULL; - break; - } - return ret; -} - -/*********************************************************************** - * - * WINHELP_CheckPopup - */ -static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret) -{ - HWND hPopup; - - if (!Globals.active_popup) return FALSE; - - switch (msg) - { - case WM_NOTIFY: - { - MSGFILTER* msgf = (MSGFILTER*)lParam; - if (msgf->nmhdr.code == EN_MSGFILTER) - { - if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL)) - return FALSE; - if (lret) *lret = 1; - return TRUE; - } - } - break; - case WM_ACTIVATE: - if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd || - (HWND)lParam == Globals.active_popup->hMainWnd || - GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd) - break; - case WM_LBUTTONUP: - case WM_LBUTTONDOWN: - if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN) - return FALSE; - /* fall through */ - case WM_MBUTTONDOWN: - case WM_RBUTTONDOWN: - case WM_NCLBUTTONDOWN: - case WM_NCMBUTTONDOWN: - case WM_NCRBUTTONDOWN: - hPopup = Globals.active_popup->hMainWnd; - Globals.active_popup = NULL; - DestroyWindow(hPopup); - return TRUE; - } - return FALSE; -} - -/*********************************************************************** - * - * WINHELP_ButtonWndProc - */ -static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0; - - if (msg == WM_KEYDOWN) - { - switch (wParam) - { - case VK_UP: - case VK_DOWN: - case VK_PRIOR: - case VK_NEXT: - case VK_ESCAPE: - return SendMessage(GetParent(hWnd), msg, wParam, lParam); - } - } - - return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam); -} - -/*********************************************************************** - * - * WINHELP_ButtonBoxWndProc - */ -static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WINDOWPOS *winpos; - WINHELP_WINDOW *win; - WINHELP_BUTTON *button; - SIZE button_size; - INT x, y; - - if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L; - - switch (msg) - { - case WM_WINDOWPOSCHANGING: - winpos = (WINDOWPOS*) lParam; - win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0); - - /* Update buttons */ - button_size.cx = 0; - button_size.cy = 0; - for (button = win->first_button; button; button = button->next) - { - HDC hDc; - SIZE textsize; - if (!button->hWnd) - { - button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName, - WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, - 0, 0, 0, 0, - hWnd, (HMENU) button->wParam, - Globals.hInstance, 0); - if (button->hWnd) - { - if (Globals.button_proc == NULL) - { - NONCLIENTMETRICSW ncm; - Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC); - - ncm.cbSize = sizeof(NONCLIENTMETRICSW); - SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, - sizeof(NONCLIENTMETRICSW), &ncm, 0); - Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont); - } - SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc); - if (Globals.hButtonFont) - SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE); - } - } - hDc = GetDC(button->hWnd); - GetTextExtentPoint(hDc, button->lpszName, - lstrlen(button->lpszName), &textsize); - ReleaseDC(button->hWnd, hDc); - - button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX); - button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY); - } - - x = 0; - y = 0; - for (button = win->first_button; button; button = button->next) - { - SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0); - - if (x + 2 * button_size.cx <= winpos->cx) - x += button_size.cx; - else - x = 0, y += button_size.cy; - } - winpos->cy = y + (x ? button_size.cy : 0); - break; - - case WM_COMMAND: - SendMessage(GetParent(hWnd), msg, wParam, lParam); - break; - - case WM_KEYDOWN: - switch (wParam) - { - case VK_UP: - case VK_DOWN: - case VK_PRIOR: - case VK_NEXT: - case VK_ESCAPE: - return SendMessage(GetParent(hWnd), msg, wParam, lParam); - } - break; - } - - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -/****************************************************************** - * WINHELP_HistoryWndProc - * - * - */ -static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WINHELP_WINDOW* win; - PAINTSTRUCT ps; - HDC hDc; - TEXTMETRIC tm; - unsigned int i; - RECT r; - - switch (msg) - { - case WM_NCCREATE: - win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams; - SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win); - win->hHistoryWnd = hWnd; - break; - case WM_CREATE: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - hDc = GetDC(hWnd); - GetTextMetrics(hDc, &tm); - GetWindowRect(hWnd, &r); - - r.right = r.left + 30 * tm.tmAveCharWidth; - r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight; - AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE); - if (r.left < 0) {r.right -= r.left; r.left = 0;} - if (r.top < 0) {r.bottom -= r.top; r.top = 0;} - - MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE); - ReleaseDC(hWnd, hDc); - break; - case WM_LBUTTONDOWN: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - hDc = GetDC(hWnd); - GetTextMetrics(hDc, &tm); - i = HIWORD(lParam) / tm.tmHeight; - if (i < Globals.history.index) - WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE); - ReleaseDC(hWnd, hDc); - break; - case WM_PAINT: - hDc = BeginPaint(hWnd, &ps); - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - GetTextMetrics(hDc, &tm); - - for (i = 0; i < Globals.history.index; i++) - { - if (Globals.history.set[i].page->file == Globals.active_win->page->file) - { - TextOut(hDc, 0, i * tm.tmHeight, - Globals.history.set[i].page->lpszTitle, - strlen(Globals.history.set[i].page->lpszTitle)); - } - else - { - char buffer[1024]; - const char* ptr1; - const char* ptr2; - unsigned len; - - ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\'); - if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath; - else ptr1++; - ptr2 = strrchr(ptr1, '.'); - len = ptr2 ? ptr2 - ptr1 : strlen(ptr1); - if (len > sizeof(buffer)) len = sizeof(buffer); - memcpy(buffer, ptr1, len); - if (len < sizeof(buffer)) buffer[len++] = ':'; - strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len); - buffer[sizeof(buffer) - 1] = '\0'; - TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer)); - } - } - EndPaint(hWnd, &ps); - break; - case WM_DESTROY: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - if (hWnd == win->hHistoryWnd) - win->hHistoryWnd = 0; - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -/*********************************************************************** - * - * WINHELP_ShadowWndProc - */ -static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0; - return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam); -} - -/************************************************************************** - * cb_KWBTree - * - * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file. - * - */ -static void cb_KWBTree(void *p, void **next, void *cookie) -{ - HWND hListWnd = (HWND)cookie; - int count; - - WINE_TRACE("Adding '%s' to search list\n", (char *)p); - SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p); - count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0); - SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p); - *next = (char*)p + strlen((char*)p) + 7; -} - -struct index_data -{ - HLPFILE* hlpfile; - BOOL jump; - ULONG offset; -}; - -/************************************************************************** - * WINHELP_IndexDlgProc - * - */ -static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static struct index_data* id; - int sel; - - switch (msg) - { - case WM_INITDIALOG: - id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam; - HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree, - GetDlgItem(hWnd, IDC_INDEXLIST)); - id->jump = FALSE; - id->offset = 1; - return TRUE; - case WM_COMMAND: - switch (HIWORD(wParam)) - { - case LBN_DBLCLK: - if (LOWORD(wParam) == IDC_INDEXLIST) - SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0); - break; - } - break; - case WM_NOTIFY: - switch (((NMHDR*)lParam)->code) - { - case PSN_APPLY: - sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0); - if (sel != LB_ERR) - { - BYTE *p; - int count; - - p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST, - LB_GETITEMDATA, sel, 0); - count = *(short*)((char *)p + strlen((char *)p) + 1); - if (count > 1) - { - MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP); - SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); - return TRUE; - } - id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3); - id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9); - if (id->offset == 0xFFFFFFFF) - { - MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP); - SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); - return TRUE; - } - id->jump = TRUE; - SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); - } - return TRUE; - default: - return FALSE; - } - break; - default: - break; - } - return FALSE; -} - -/************************************************************************** - * WINHELP_SearchDlgProc - * - */ -static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - static struct index_data* id; - - switch (msg) - { - case WM_INITDIALOG: - id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam; - return TRUE; - case WM_NOTIFY: - switch (((NMHDR*)lParam)->code) - { - case PSN_APPLY: - SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); - return TRUE; - default: - return FALSE; - } - break; - default: - break; - } - return FALSE; -} - -/*********************************************************************** - * - * WINHELP_MainWndProc - */ -static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) -{ - WINHELP_WINDOW *win; - WINHELP_BUTTON *button; - RECT rect; - INT curPos, min, max, dy, keyDelta; - HWND hTextWnd; - LRESULT ret; - - if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret; - - switch (msg) - { - case WM_NCCREATE: - win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams; - SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win); - if (!win->page && Globals.isBook) - PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0); - win->hMainWnd = hWnd; - break; - - case WM_WINDOWPOSCHANGED: - WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0)); - break; - - case WM_COMMAND: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - switch (wParam) - { - /* Menu FILE */ - case MNID_FILE_OPEN: MACRO_FileOpen(); break; - case MNID_FILE_PRINT: MACRO_Print(); break; - case MNID_FILE_SETUP: MACRO_PrinterSetup(); break; - case MNID_FILE_EXIT: MACRO_Exit(); break; - - /* Menu EDIT */ - case MNID_EDIT_COPYDLG: - SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); - break; - case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break; - - /* Menu Bookmark */ - case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break; - - /* Menu Help */ - case MNID_HELP_HELPON: MACRO_HelpOn(); break; - case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break; - case MNID_HELP_ABOUT: MACRO_About(); break; - case MNID_HELP_WINE: ShellAbout(hWnd, "WINE", "Help", 0); break; - - /* Context help */ - case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break; - case MNID_CTXT_COPY: MACRO_CopyDialog(); break; - case MNID_CTXT_PRINT: MACRO_Print(); break; - case MNID_OPTS_HISTORY: MACRO_History(); break; - case MNID_OPTS_FONTS_SMALL: - case MNID_CTXT_FONTS_SMALL: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - if (win->font_scale != 0) - { - win->font_scale = 0; - WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); - } - break; - case MNID_OPTS_FONTS_NORMAL: - case MNID_CTXT_FONTS_NORMAL: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - if (win->font_scale != 1) - { - win->font_scale = 1; - WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); - } - break; - case MNID_OPTS_FONTS_LARGE: - case MNID_CTXT_FONTS_LARGE: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - if (win->font_scale != 2) - { - win->font_scale = 2; - WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); - } - break; - case MNID_OPTS_HELP_DEFAULT: - case MNID_OPTS_HELP_VISIBLE: - case MNID_OPTS_HELP_NONVISIBLE: - case MNID_OPTS_SYSTEM_COLORS: - case MNID_CTXT_HELP_DEFAULT: - case MNID_CTXT_HELP_VISIBLE: - case MNID_CTXT_HELP_NONVISIBLE: - case MNID_CTXT_SYSTEM_COLORS: - /* FIXME: NIY */ - - default: - /* Buttons */ - for (button = win->first_button; button; button = button->next) - if (wParam == button->wParam) break; - if (button) - MACRO_ExecuteMacro(button->lpszMacro); - else if (!HIWORD(wParam)) - MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED), - MAKEINTRESOURCE(STID_WHERROR), MB_OK); - break; - } - break; -/* EPP case WM_DESTROY: */ -/* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */ -/* EPP break; */ - case WM_COPYDATA: - return WINHELP_HandleCommand((HWND)wParam, lParam); - - case WM_CHAR: - if (wParam == 3) - { - SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); - return 0; - } - break; - - case WM_KEYDOWN: - keyDelta = 0; - - switch (wParam) - { - case VK_UP: - case VK_DOWN: - keyDelta = GetSystemMetrics(SM_CXVSCROLL); - if (wParam == VK_UP) - keyDelta = -keyDelta; - - case VK_PRIOR: - case VK_NEXT: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); - curPos = GetScrollPos(hTextWnd, SB_VERT); - GetScrollRange(hTextWnd, SB_VERT, &min, &max); - - if (keyDelta == 0) - { - GetClientRect(hTextWnd, &rect); - keyDelta = (rect.bottom - rect.top) / 2; - if (wParam == VK_PRIOR) - keyDelta = -keyDelta; - } - - curPos += keyDelta; - if (curPos > max) - curPos = max; - else if (curPos < min) - curPos = min; - - dy = GetScrollPos(hTextWnd, SB_VERT) - curPos; - SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE); - ScrollWindow(hTextWnd, 0, dy, NULL, NULL); - UpdateWindow(hTextWnd); - return 0; - - case VK_ESCAPE: - MACRO_Exit(); - return 0; - } - break; - - case WM_NOTIFY: - if (wParam == CTL_ID_TEXT) - { - RECT rc; - - switch (((NMHDR*)lParam)->code) - { - case EN_MSGFILTER: - { - const MSGFILTER* msgf = (const MSGFILTER*)lParam; - switch (msgf->msg) - { - case WM_KEYUP: - if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd); - break; - case WM_RBUTTONDOWN: - { - HMENU hMenu; - POINT pt; - - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU); - switch (win->font_scale) - { - case 0: - CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL, - MF_BYCOMMAND|MF_CHECKED); - break; - default: - WINE_FIXME("Unsupported %d\n", win->font_scale); - case 1: - CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL, - MF_BYCOMMAND|MF_CHECKED); - break; - case 2: - CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE, - MF_BYCOMMAND|MF_CHECKED); - break; - } - pt.x = (int)(short)LOWORD(msgf->lParam); - pt.y = (int)(short)HIWORD(msgf->lParam); - ClientToScreen(msgf->nmhdr.hwndFrom, &pt); - TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN, - pt.x, pt.y, 0, hWnd, NULL); - DestroyMenu(hMenu); - } - break; - default: - return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0), - msgf->msg, msgf->lParam); - } - } - break; - - case EN_REQUESTRESIZE: - rc = ((REQRESIZE*)lParam)->rc; - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE), - FALSE); - SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0, - rc.right - rc.left, rc.bottom - rc.top, - SWP_NOMOVE | SWP_NOZORDER); - WINHELP_LayoutMainWindow(win); - break; - } - } - break; - - case WM_INITMENUPOPUP: - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL, - MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0); - CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL, - MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0); - CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE, - MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0); - break; - - case WM_NCDESTROY: - { - BOOL bExit; - win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); - bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main")); - WINHELP_DeleteWindow(win); - - if (bExit) MACRO_Exit(); - if (!Globals.win_list) - PostQuitMessage(0); - } - break; - } - return DefWindowProc(hWnd, msg, wParam, lParam); -} - -/************************************************************************** - * WINHELP_CreateIndexWindow - * - * Displays a dialog with keywords of current help file. - * - */ -BOOL WINHELP_CreateIndexWindow(BOOL is_search) -{ - HPROPSHEETPAGE psPage[3]; - PROPSHEETPAGE psp; - PROPSHEETHEADER psHead; - struct index_data id; - char buf[256]; - - if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) - id.hlpfile = Globals.active_win->page->file; - else - return FALSE; - - if (id.hlpfile->kwbtree == NULL) - { - WINE_TRACE("No index provided\n"); - return FALSE; - } - - InitCommonControls(); - - id.jump = FALSE; - memset(&psp, 0, sizeof(psp)); - psp.dwSize = sizeof(psp); - psp.dwFlags = 0; - psp.hInstance = Globals.hInstance; - - psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX); - psp.lParam = (LPARAM)&id; - psp.pfnDlgProc = WINHELP_IndexDlgProc; - psPage[0] = CreatePropertySheetPage(&psp); - - psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH); - psp.lParam = (LPARAM)&id; - psp.pfnDlgProc = WINHELP_SearchDlgProc; - psPage[1] = CreatePropertySheetPage(&psp); - - memset(&psHead, 0, sizeof(psHead)); - psHead.dwSize = sizeof(psHead); - - LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf)); - strcat(buf, Globals.active_win->info->caption); - - psHead.pszCaption = buf; - psHead.nPages = 2; - psHead.u2.nStartPage = is_search ? 1 : 0; - psHead.hwndParent = Globals.active_win->hMainWnd; - psHead.u3.phpage = psPage; - psHead.dwFlags = PSH_NOAPPLYNOW; - - PropertySheet(&psHead); - if (id.jump) - { - WINE_TRACE("got %d as an offset\n", id.offset); - WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset, - Globals.active_win->info, SW_NORMAL); - } - return TRUE; -} - -/*********************************************************************** - * - * RegisterWinClasses - */ -static BOOL WINHELP_RegisterWinClasses(void) -{ - WNDCLASS class_main, class_button_box, class_shadow, class_history; - - class_main.style = CS_HREDRAW | CS_VREDRAW; - class_main.lpfnWndProc = WINHELP_MainWndProc; - class_main.cbClsExtra = 0; - class_main.cbWndExtra = sizeof(WINHELP_WINDOW *); - class_main.hInstance = Globals.hInstance; - class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP)); - class_main.hCursor = LoadCursor(0, IDC_ARROW); - class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); - class_main.lpszMenuName = 0; - class_main.lpszClassName = MAIN_WIN_CLASS_NAME; - - class_button_box = class_main; - class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc; - class_button_box.cbWndExtra = 0; - class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); - class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME; - - class_shadow = class_main; - class_shadow.lpfnWndProc = WINHELP_ShadowWndProc; - class_shadow.cbWndExtra = 0; - class_shadow.hbrBackground = (HBRUSH)(COLOR_3DDKSHADOW+1); - class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME; - - class_history = class_main; - class_history.lpfnWndProc = WINHELP_HistoryWndProc; - class_history.lpszClassName = HISTORY_WIN_CLASS_NAME; - - return (RegisterClass(&class_main) && - RegisterClass(&class_button_box) && - RegisterClass(&class_shadow) && - RegisterClass(&class_history)); -} - -/*********************************************************************** - * - * WinMain - */ -int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show) -{ - MSG msg; - LONG lHash = 0; - HLPFILE* hlpfile; - static CHAR default_wndname[] = "main"; - LPSTR wndname = default_wndname; - WINHELP_DLL* dll; - - Globals.hInstance = hInstance; - - if (LoadLibrary("riched20.dll") == NULL) - return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT), - MAKEINTRESOURCE(STID_WHERROR), MB_OK); - - /* Get options */ - while (*cmdline && (*cmdline == ' ' || *cmdline == '-')) - { - CHAR option; - LPCSTR topic_id; - if (*cmdline++ == ' ') continue; - - option = *cmdline; - if (option) cmdline++; - while (*cmdline && *cmdline == ' ') cmdline++; - switch (option) - { - case 'i': - case 'I': - topic_id = cmdline; - while (*cmdline && *cmdline != ' ') cmdline++; - if (*cmdline) *cmdline++ = '\0'; - lHash = HLPFILE_Hash(topic_id); - break; - - case '3': - case '4': - Globals.wVersion = option - '0'; - break; - - case 'x': - show = SW_HIDE; - Globals.isBook = FALSE; - break; - - default: - WINE_FIXME("Unsupported cmd line: %s\n", cmdline); - break; - } - } - - /* Create primary window */ - if (!WINHELP_RegisterWinClasses()) - { - WINE_FIXME("Couldn't register classes\n"); - return 0; - } - - if (*cmdline) - { - char* ptr; - if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"'))) - { - cmdline++; - *ptr = '\0'; - } - if ((ptr = strchr(cmdline, '>'))) - { - *ptr = '\0'; - wndname = ptr + 1; - } - hlpfile = WINHELP_LookupHelpFile(cmdline); - if (!hlpfile) return 0; - } - else hlpfile = NULL; - WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash, - WINHELP_GetWindowInfo(hlpfile, wndname), show); - - /* Message loop */ - while (GetMessage(&msg, 0, 0, 0)) - { - TranslateMessage(&msg); - DispatchMessage(&msg); - } - for (dll = Globals.dlls; dll; dll = dll->next) - { - if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0); - } - return 0; -} +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * 2002 Sylvain Petreolle + * 2002, 2008 Eric Pouech + * 2004 Ken Belleau + * 2008 Kirill K. Smirnov + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#include +#include +#include +#include +#include + +#define NONAMELESSUNION +#define NONAMELESSSTRUCT + +#include "windef.h" +#include "winbase.h" +#include "wingdi.h" +#include "winuser.h" +#include "commdlg.h" +#include "winhelp.h" +#include "winhelp_res.h" +#include "shellapi.h" +#include "richedit.h" +#include "commctrl.h" + +#include "wine/debug.h" + +WINE_DEFAULT_DEBUG_CHANNEL(winhelp); + +WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL}; + +#define CTL_ID_BUTTON 0x700 +#define CTL_ID_TEXT 0x701 + + +/*********************************************************************** + * + * WINHELP_InitFonts + */ +static void WINHELP_InitFonts(HWND hWnd) +{ + WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + LOGFONT logfontlist[] = { + {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}, + { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}}; +#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist)) + + static HFONT fonts[FONTS_LEN]; + static BOOL init = 0; + + win->fonts_len = FONTS_LEN; + win->fonts = fonts; + + if (!init) + { + UINT i; + + for (i = 0; i < FONTS_LEN; i++) + { + fonts[i] = CreateFontIndirect(&logfontlist[i]); + } + + init = 1; + } +} + +static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff, + LONG cb, LONG* pcb) +{ + struct RtfData* rd = (struct RtfData*)cookie; + + if (rd->where >= rd->ptr) return 1; + if (rd->where + cb > rd->ptr) + cb = rd->ptr - rd->where; + memcpy(buff, rd->where, cb); + rd->where += cb; + *pcb = cb; + return 0; +} + +static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative) +{ + /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */ + SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)""); + SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0); + SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color); + /* set word-wrap to window size (undocumented) */ + SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0); + if (win->page) + { + struct RtfData rd; + EDITSTREAM es; + unsigned cp = 0; + POINTL ptl; + POINT pt; + + + if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative)) + { + rd.where = rd.data; + es.dwCookie = (DWORD_PTR)&rd; + es.dwError = 0; + es.pfnCallback = WINHELP_RtfStreamIn; + + SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es); + cp = rd.char_pos_rel; + } + /* FIXME: else leaking potentially the rd.first_link chain */ + HeapFree(GetProcessHeap(), 0, rd.data); + SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0); + pt.x = 0; pt.y = ptl.y; + SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt); + } + SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0); + InvalidateRect(hTextWnd, NULL, TRUE); +} + +/*********************************************************************** + * + * WINHELP_GetOpenFileName + */ +BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len) +{ + OPENFILENAME openfilename; + CHAR szDir[MAX_PATH]; + CHAR szzFilter[2 * MAX_STRING_LEN + 100]; + LPSTR p = szzFilter; + + WINE_TRACE("()\n"); + + LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN); + p += strlen(p) + 1; + lstrcpy(p, "*.hlp"); + p += strlen(p) + 1; + LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN); + p += strlen(p) + 1; + lstrcpy(p, "*.*"); + p += strlen(p) + 1; + *p = '\0'; + + GetCurrentDirectory(sizeof(szDir), szDir); + + lpszFile[0]='\0'; + + openfilename.lStructSize = sizeof(OPENFILENAME); + openfilename.hwndOwner = NULL; + openfilename.hInstance = Globals.hInstance; + openfilename.lpstrFilter = szzFilter; + openfilename.lpstrCustomFilter = 0; + openfilename.nMaxCustFilter = 0; + openfilename.nFilterIndex = 1; + openfilename.lpstrFile = lpszFile; + openfilename.nMaxFile = len; + openfilename.lpstrFileTitle = 0; + openfilename.nMaxFileTitle = 0; + openfilename.lpstrInitialDir = szDir; + openfilename.lpstrTitle = 0; + openfilename.Flags = 0; + openfilename.nFileOffset = 0; + openfilename.nFileExtension = 0; + openfilename.lpstrDefExt = 0; + openfilename.lCustData = 0; + openfilename.lpfnHook = 0; + openfilename.lpTemplateName = 0; + + return GetOpenFileName(&openfilename); +} + +/*********************************************************************** + * + * WINHELP_MessageBoxIDS_s + */ +static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type) +{ + CHAR text[MAX_STRING_LEN]; + CHAR newtext[MAX_STRING_LEN + MAX_PATH]; + + LoadString(Globals.hInstance, ids_text, text, sizeof(text)); + wsprintf(newtext, text, str); + + return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type); +} + +/*********************************************************************** + * + * WINHELP_LookupHelpFile + */ +HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile) +{ + HLPFILE* hlpfile; + char szFullName[MAX_PATH]; + char szAddPath[MAX_PATH]; + char *p; + + /* + * NOTE: This is needed by popup windows only. + * In other cases it's not needed but does not hurt though. + */ + if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) + { + strcpy(szAddPath, Globals.active_win->page->file->lpszPath); + p = strrchr(szAddPath, '\\'); + if (p) *p = 0; + } + + /* + * FIXME: Should we swap conditions? + */ + if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) && + !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL)) + { + if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR, + MB_YESNO|MB_ICONQUESTION) != IDYES) + return NULL; + if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH)) + return NULL; + } + hlpfile = HLPFILE_ReadHlpFile(szFullName); + if (!hlpfile) + WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile, + STID_WHERROR, MB_OK|MB_ICONSTOP); + return hlpfile; +} + +/****************************************************************** + * WINHELP_GetWindowInfo + * + * + */ +HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name) +{ + static HLPFILE_WINDOWINFO mwi; + unsigned int i; + + if (!name || !name[0]) + name = Globals.active_win->lpszName; + + if (hlpfile) + for (i = 0; i < hlpfile->numWindows; i++) + if (!strcmp(hlpfile->windows[i].name, name)) + return &hlpfile->windows[i]; + + if (strcmp(name, "main") != 0) + { + WINE_FIXME("Couldn't find window info for %s\n", name); + assert(0); + return NULL; + } + if (!mwi.name[0]) + { + strcpy(mwi.type, "primary"); + strcpy(mwi.name, "main"); + if (!LoadString(Globals.hInstance, STID_WINE_HELP, + mwi.caption, sizeof(mwi.caption))) + strcpy(mwi.caption, hlpfile->lpszTitle); + mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT; + mwi.style = SW_SHOW; + mwi.win_style = WS_OVERLAPPEDWINDOW; + mwi.sr_color = mwi.sr_color = 0xFFFFFF; + } + return &mwi; +} + +/****************************************************************** + * HLPFILE_GetPopupWindowInfo + * + * + */ +static HLPFILE_WINDOWINFO* WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile, + WINHELP_WINDOW* parent, LPARAM mouse) +{ + static HLPFILE_WINDOWINFO wi; + + RECT parent_rect; + + wi.type[0] = wi.name[0] = wi.caption[0] = '\0'; + + /* Calculate horizontal size and position of a popup window */ + GetWindowRect(parent->hMainWnd, &parent_rect); + wi.size.cx = (parent_rect.right - parent_rect.left) / 2; + wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */ + + wi.origin.x = (short)LOWORD(mouse); + wi.origin.y = (short)HIWORD(mouse); + ClientToScreen(parent->hMainWnd, &wi.origin); + wi.origin.x -= wi.size.cx / 2; + wi.origin.x = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx); + wi.origin.x = max(wi.origin.x, 0); + + wi.style = SW_SHOW; + wi.win_style = WS_POPUP | WS_BORDER; + if (parent->page->file->has_popup_color) + wi.sr_color = parent->page->file->popup_color; + else + wi.sr_color = parent->info->sr_color; + wi.nsr_color = 0xFFFFFF; + + return &wi; +} + +typedef struct +{ + WORD size; + WORD command; + LONG data; + LONG reserved; + WORD ofsFilename; + WORD ofsData; +} WINHELP,*LPWINHELP; + +static BOOL WINHELP_HasWorkingWindow(void) +{ + if (!Globals.active_win) return FALSE; + if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE; + return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL; +} + +/****************************************************************** + * WINHELP_HandleCommand + * + * + */ +static LRESULT WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam) +{ + COPYDATASTRUCT* cds = (COPYDATASTRUCT*)lParam; + WINHELP* wh; + + if (cds->dwData != 0xA1DE505) + { + WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData); + return 0; + } + + wh = (WINHELP*)cds->lpData; + + if (wh) + { + char* ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL; + + WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n", + wh->size, wh->command, wh->data, ptr); + switch (wh->command) + { + case HELP_CONTEXT: + if (ptr) + { + MACRO_JumpContext(ptr, "main", wh->data); + } + if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); + break; + case HELP_QUIT: + MACRO_Exit(); + break; + case HELP_CONTENTS: + if (ptr) + { + MACRO_JumpContents(ptr, "main"); + } + if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); + break; + case HELP_HELPONHELP: + MACRO_HelpOn(); + if (!WINHELP_HasWorkingWindow()) MACRO_Exit(); + break; + /* case HELP_SETINDEX: */ + case HELP_SETCONTENTS: + if (ptr) + { + MACRO_SetContents(ptr, wh->data); + } + break; + case HELP_CONTEXTPOPUP: + if (ptr) + { + MACRO_PopupContext(ptr, wh->data); + } + break; + /* case HELP_FORCEFILE:*/ + /* case HELP_CONTEXTMENU: */ + case HELP_FINDER: + /* in fact, should be the topic dialog box */ + WINE_FIXME("HELP_FINDER: stub\n"); + if (ptr) + { + MACRO_JumpHash(ptr, "main", 0); + } + break; + /* case HELP_WM_HELP: */ + /* case HELP_SETPOPUP_POS: */ + /* case HELP_KEY: */ + /* case HELP_COMMAND: */ + /* case HELP_PARTIALKEY: */ + /* case HELP_MULTIKEY: */ + /* case HELP_SETWINPOS: */ + default: + WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command); + break; + } + } + /* Always return success for now */ + return 1; +} + +void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win) +{ + RECT rect, button_box_rect; + INT text_top = 0; + HWND hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON); + HWND hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); + + GetClientRect(win->hMainWnd, &rect); + + /* Update button box and text Window */ + SetWindowPos(hButtonBoxWnd, HWND_TOP, + rect.left, rect.top, + rect.right - rect.left, + rect.bottom - rect.top, 0); + + if (GetWindowRect(hButtonBoxWnd, &button_box_rect)) + text_top = rect.top + button_box_rect.bottom - button_box_rect.top; + + SetWindowPos(hTextWnd, HWND_TOP, + rect.left, text_top, + rect.right - rect.left, + rect.bottom - text_top, 0); + +} + +/****************************************************************** + * WINHELP_DeleteButtons + * + */ +static void WINHELP_DeleteButtons(WINHELP_WINDOW* win) +{ + WINHELP_BUTTON* b; + WINHELP_BUTTON* bp; + + for (b = win->first_button; b; b = bp) + { + DestroyWindow(b->hWnd); + bp = b->next; + HeapFree(GetProcessHeap(), 0, b); + } + win->first_button = NULL; +} + +/****************************************************************** + * WINHELP_DeleteBackSet + * + */ +void WINHELP_DeleteBackSet(WINHELP_WINDOW* win) +{ + unsigned int i; + + for (i = 0; i < win->back.index; i++) + { + HLPFILE_FreeHlpFile(win->back.set[i].page->file); + win->back.set[i].page = NULL; + } + win->back.index = 0; +} + +/****************************************************************** + * WINHELP_DeletePageLinks + * + */ +static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page) +{ + HLPFILE_LINK* curr; + HLPFILE_LINK* next; + + for (curr = page->first_link; curr; curr = next) + { + next = curr->next; + HeapFree(GetProcessHeap(), 0, curr); + } +} + +/*********************************************************************** + * + * WINHELP_DeleteWindow + */ +static void WINHELP_DeleteWindow(WINHELP_WINDOW* win) +{ + WINHELP_WINDOW** w; + + for (w = &Globals.win_list; *w; w = &(*w)->next) + { + if (*w == win) + { + *w = win->next; + break; + } + } + + if (Globals.active_win == win) + { + Globals.active_win = Globals.win_list; + if (Globals.win_list) + SetActiveWindow(Globals.win_list->hMainWnd); + } + + if (win == Globals.active_popup) + Globals.active_popup = NULL; + + WINHELP_DeleteButtons(win); + + if (win->page) WINHELP_DeletePageLinks(win->page); + if (win->hShadowWnd) DestroyWindow(win->hShadowWnd); + if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd); + + DeleteObject(win->hBrush); + + WINHELP_DeleteBackSet(win); + + if (win->page) HLPFILE_FreeHlpFile(win->page->file); + HeapFree(GetProcessHeap(), 0, win); +} + +static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage) +{ + if (wpage->wininfo->caption[0]) return wpage->wininfo->caption; + return wpage->page->file->lpszTitle; +} + +static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage) +{ + unsigned num; + + if (!Globals.history.index || Globals.history.set[0].page != wpage->page) + { + num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]); + /* we're full, remove latest entry */ + if (Globals.history.index == num) + { + HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file); + Globals.history.index--; + } + memmove(&Globals.history.set[1], &Globals.history.set[0], + Globals.history.index * sizeof(Globals.history.set[0])); + Globals.history.set[0] = *wpage; + Globals.history.index++; + wpage->page->file->wRefCount++; + } + if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); + + num = sizeof(win->back.set) / sizeof(win->back.set[0]); + if (win->back.index == num) + { + /* we're full, remove latest entry */ + HLPFILE_FreeHlpFile(win->back.set[0].page->file); + memmove(&win->back.set[0], &win->back.set[1], + (num - 1) * sizeof(win->back.set[0])); + win->back.index--; + } + win->back.set[win->back.index++] = *wpage; + wpage->page->file->wRefCount++; +} + +/*********************************************************************** + * + * WINHELP_CreateHelpWindow + */ +BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember) +{ + WINHELP_WINDOW* win = NULL; + BOOL bPrimary, bPopup, bReUsed = FALSE; + LPSTR name; + HICON hIcon; + HWND hTextWnd = NULL; + + bPrimary = !lstrcmpi(wpage->wininfo->name, "main"); + bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP); + + if (!bPopup) + { + for (win = Globals.win_list; win; win = win->next) + { + if (!lstrcmpi(win->lpszName, wpage->wininfo->name)) + { + POINT pt = {0, 0}; + SIZE sz = {0, 0}; + DWORD flags = SWP_NOSIZE | SWP_NOMOVE; + + WINHELP_DeleteButtons(win); + bReUsed = TRUE; + SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage)); + if (wpage->wininfo->origin.x != CW_USEDEFAULT && + wpage->wininfo->origin.y != CW_USEDEFAULT) + { + pt = wpage->wininfo->origin; + flags &= ~SWP_NOSIZE; + } + if (wpage->wininfo->size.cx != CW_USEDEFAULT && + wpage->wininfo->size.cy != CW_USEDEFAULT) + { + sz = wpage->wininfo->size; + flags &= ~SWP_NOMOVE; + } + SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags); + + if (wpage->page && win->page && wpage->page->file != win->page->file) + WINHELP_DeleteBackSet(win); + WINHELP_InitFonts(win->hMainWnd); + + win->page = wpage->page; + win->info = wpage->wininfo; + hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); + WINHELP_SetupText(hTextWnd, win, wpage->relative); + + InvalidateRect(win->hMainWnd, NULL, TRUE); + if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE); + + break; + } + } + } + + if (!win) + { + /* Initialize WINHELP_WINDOW struct */ + win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, + sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1); + if (!win) return FALSE; + win->next = Globals.win_list; + Globals.win_list = win; + + name = (char*)win + sizeof(WINHELP_WINDOW); + lstrcpy(name, wpage->wininfo->name); + win->lpszName = name; + win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND); + win->back.index = 0; + win->font_scale = 1; + } + win->page = wpage->page; + win->info = wpage->wininfo; + + if (!bPopup && wpage->page && remember) + { + WINHELP_RememberPage(win, wpage); + } + + if (bPopup) + Globals.active_popup = win; + else + Globals.active_win = win; + + /* Initialize default pushbuttons */ + if (bPrimary && wpage->page) + { + CHAR buffer[MAX_STRING_LEN]; + + LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer)); + MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()"); + LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer)); + MACRO_CreateButton("BTN_INDEX", buffer, "Finder()"); + LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer)); + MACRO_CreateButton("BTN_BACK", buffer, "Back()"); + if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK"); + } + + if (!bReUsed) + { + win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME, + WINHELP_GetCaption(wpage), + bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style, + wpage->wininfo->origin.x, wpage->wininfo->origin.y, + wpage->wininfo->size.cx, wpage->wininfo->size.cy, + bPopup ? Globals.active_win->hMainWnd : NULL, + bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0, + Globals.hInstance, win); + if (!bPopup) + /* Create button box and text Window */ + CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE, + 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL); + + hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL, + ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE, + 0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL); + SendMessage(hTextWnd, EM_SETEVENTMASK, 0, + SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS); + } + + hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL; + if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP)); + SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon); + + /* Initialize file specific pushbuttons */ + if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page) + { + HLPFILE_MACRO *macro; + for (macro = wpage->page->file->first_macro; macro; macro = macro->next) + MACRO_ExecuteMacro(macro->lpszMacro); + + for (macro = wpage->page->first_macro; macro; macro = macro->next) + MACRO_ExecuteMacro(macro->lpszMacro); + } + + if (bPopup) + { + DWORD mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0); + RECT rect; + + win->font_scale = Globals.active_win->font_scale; + WINHELP_SetupText(hTextWnd, win, wpage->relative); + + /* we need the window to be shown for richedit to compute the size */ + ShowWindow(win->hMainWnd, nCmdShow); + SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE); + SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0); + SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask); + + GetWindowRect(win->hMainWnd, &rect); + win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME, + "", WS_POPUP | WS_VISIBLE, + rect.left + SHADOW_DX, rect.top + SHADOW_DY, + rect.right - rect.left, + rect.bottom - rect.top, + Globals.active_win->hMainWnd, 0, + Globals.hInstance, NULL); + SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0, + SWP_NOSIZE | SWP_NOMOVE); + } + else + { + WINHELP_SetupText(hTextWnd, win, wpage->relative); + WINHELP_LayoutMainWindow(win); + ShowWindow(win->hMainWnd, nCmdShow); + } + + return TRUE; +} + +/****************************************************************** + * WINHELP_OpenHelpWindow + * Main function to search for a page and display it in a window + */ +BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*), + HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi, + int nCmdShow) +{ + WINHELP_WNDPAGE wpage; + + wpage.page = lookup(hlpfile, val, &wpage.relative); + if (wpage.page) wpage.page->file->wRefCount++; + wpage.wininfo = wi; + return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE); +} + +/*********************************************************************** + * + * WINHELP_FindLink + */ +static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos) +{ + HLPFILE_LINK* link; + POINTL mouse_ptl, char_ptl, char_next_ptl; + DWORD cp; + + if (!win->page) return NULL; + + mouse_ptl.x = (short)LOWORD(pos); + mouse_ptl.y = (short)HIWORD(pos); + cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS, + 0, (LPARAM)&mouse_ptl); + + for (link = win->page->first_link; link; link = link->next) + { + if (link->cpMin <= cp && cp <= link->cpMax) + { + /* check whether we're at end of line */ + SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, + (LPARAM)&char_ptl, cp); + SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR, + (LPARAM)&char_next_ptl, cp + 1); + if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x) + link = NULL; + break; + } + } + return link; +} + +/****************************************************************** + * WINHELP_HandleTextMouse + * + */ +static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam) +{ + HLPFILE* hlpfile; + HLPFILE_LINK* link; + BOOL ret = FALSE; + + switch (msg) + { + case WM_MOUSEMOVE: + if (WINHELP_FindLink(win, lParam)) + SetCursor(win->hHandCur); + else + SetCursor(LoadCursor(0, IDC_ARROW)); + break; + + case WM_LBUTTONDOWN: + if ((win->current_link = WINHELP_FindLink(win, lParam))) + ret = TRUE; + break; + + case WM_LBUTTONUP: + if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link) + { + HLPFILE_WINDOWINFO* wi; + + switch (link->cookie) + { + case hlp_link_link: + if ((hlpfile = WINHELP_LookupHelpFile(link->string))) + { + if (link->window == -1) + wi = win->info; + else if (link->window < hlpfile->numWindows) + wi = &hlpfile->windows[link->window]; + else + { + WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows); + break; + } + WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL); + } + break; + case hlp_link_popup: + if ((hlpfile = WINHELP_LookupHelpFile(link->string))) + WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, + WINHELP_GetPopupWindowInfo(hlpfile, win, lParam), + SW_NORMAL); + break; + case hlp_link_macro: + MACRO_ExecuteMacro(link->string); + break; + default: + WINE_FIXME("Unknown link cookie %d\n", link->cookie); + } + ret = TRUE; + } + win->current_link = NULL; + break; + } + return ret; +} + +/*********************************************************************** + * + * WINHELP_CheckPopup + */ +static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret) +{ + HWND hPopup; + + if (!Globals.active_popup) return FALSE; + + switch (msg) + { + case WM_NOTIFY: + { + MSGFILTER* msgf = (MSGFILTER*)lParam; + if (msgf->nmhdr.code == EN_MSGFILTER) + { + if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL)) + return FALSE; + if (lret) *lret = 1; + return TRUE; + } + } + break; + case WM_ACTIVATE: + if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd || + (HWND)lParam == Globals.active_popup->hMainWnd || + GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd) + break; + case WM_LBUTTONUP: + case WM_LBUTTONDOWN: + if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN) + return FALSE; + /* fall through */ + case WM_MBUTTONDOWN: + case WM_RBUTTONDOWN: + case WM_NCLBUTTONDOWN: + case WM_NCMBUTTONDOWN: + case WM_NCRBUTTONDOWN: + hPopup = Globals.active_popup->hMainWnd; + Globals.active_popup = NULL; + DestroyWindow(hPopup); + return TRUE; + } + return FALSE; +} + +/*********************************************************************** + * + * WINHELP_ButtonWndProc + */ +static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0; + + if (msg == WM_KEYDOWN) + { + switch (wParam) + { + case VK_UP: + case VK_DOWN: + case VK_PRIOR: + case VK_NEXT: + case VK_ESCAPE: + return SendMessage(GetParent(hWnd), msg, wParam, lParam); + } + } + + return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam); +} + +/*********************************************************************** + * + * WINHELP_ButtonBoxWndProc + */ +static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WINDOWPOS *winpos; + WINHELP_WINDOW *win; + WINHELP_BUTTON *button; + SIZE button_size; + INT x, y; + + if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L; + + switch (msg) + { + case WM_WINDOWPOSCHANGING: + winpos = (WINDOWPOS*) lParam; + win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0); + + /* Update buttons */ + button_size.cx = 0; + button_size.cy = 0; + for (button = win->first_button; button; button = button->next) + { + HDC hDc; + SIZE textsize; + if (!button->hWnd) + { + button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName, + WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON, + 0, 0, 0, 0, + hWnd, (HMENU) button->wParam, + Globals.hInstance, 0); + if (button->hWnd) + { + if (Globals.button_proc == NULL) + { + NONCLIENTMETRICSW ncm; + Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC); + + ncm.cbSize = sizeof(NONCLIENTMETRICSW); + SystemParametersInfoW(SPI_GETNONCLIENTMETRICS, + sizeof(NONCLIENTMETRICSW), &ncm, 0); + Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont); + } + SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc); + if (Globals.hButtonFont) + SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE); + } + } + hDc = GetDC(button->hWnd); + GetTextExtentPoint(hDc, button->lpszName, + lstrlen(button->lpszName), &textsize); + ReleaseDC(button->hWnd, hDc); + + button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX); + button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY); + } + + x = 0; + y = 0; + for (button = win->first_button; button; button = button->next) + { + SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0); + + if (x + 2 * button_size.cx <= winpos->cx) + x += button_size.cx; + else + x = 0, y += button_size.cy; + } + winpos->cy = y + (x ? button_size.cy : 0); + break; + + case WM_COMMAND: + SendMessage(GetParent(hWnd), msg, wParam, lParam); + break; + + case WM_KEYDOWN: + switch (wParam) + { + case VK_UP: + case VK_DOWN: + case VK_PRIOR: + case VK_NEXT: + case VK_ESCAPE: + return SendMessage(GetParent(hWnd), msg, wParam, lParam); + } + break; + } + + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +/****************************************************************** + * WINHELP_HistoryWndProc + * + * + */ +static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WINHELP_WINDOW* win; + PAINTSTRUCT ps; + HDC hDc; + TEXTMETRIC tm; + unsigned int i; + RECT r; + + switch (msg) + { + case WM_NCCREATE: + win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams; + SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win); + win->hHistoryWnd = hWnd; + break; + case WM_CREATE: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + hDc = GetDC(hWnd); + GetTextMetrics(hDc, &tm); + GetWindowRect(hWnd, &r); + + r.right = r.left + 30 * tm.tmAveCharWidth; + r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight; + AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE); + if (r.left < 0) {r.right -= r.left; r.left = 0;} + if (r.top < 0) {r.bottom -= r.top; r.top = 0;} + + MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE); + ReleaseDC(hWnd, hDc); + break; + case WM_LBUTTONDOWN: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + hDc = GetDC(hWnd); + GetTextMetrics(hDc, &tm); + i = HIWORD(lParam) / tm.tmHeight; + if (i < Globals.history.index) + WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE); + ReleaseDC(hWnd, hDc); + break; + case WM_PAINT: + hDc = BeginPaint(hWnd, &ps); + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + GetTextMetrics(hDc, &tm); + + for (i = 0; i < Globals.history.index; i++) + { + if (Globals.history.set[i].page->file == Globals.active_win->page->file) + { + TextOut(hDc, 0, i * tm.tmHeight, + Globals.history.set[i].page->lpszTitle, + strlen(Globals.history.set[i].page->lpszTitle)); + } + else + { + char buffer[1024]; + const char* ptr1; + const char* ptr2; + unsigned len; + + ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\'); + if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath; + else ptr1++; + ptr2 = strrchr(ptr1, '.'); + len = ptr2 ? ptr2 - ptr1 : strlen(ptr1); + if (len > sizeof(buffer)) len = sizeof(buffer); + memcpy(buffer, ptr1, len); + if (len < sizeof(buffer)) buffer[len++] = ':'; + strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len); + buffer[sizeof(buffer) - 1] = '\0'; + TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer)); + } + } + EndPaint(hWnd, &ps); + break; + case WM_DESTROY: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + if (hWnd == win->hHistoryWnd) + win->hHistoryWnd = 0; + break; + } + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +/*********************************************************************** + * + * WINHELP_ShadowWndProc + */ +static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0; + return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam); +} + +/************************************************************************** + * cb_KWBTree + * + * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file. + * + */ +static void cb_KWBTree(void *p, void **next, void *cookie) +{ + HWND hListWnd = (HWND)cookie; + int count; + + WINE_TRACE("Adding '%s' to search list\n", (char *)p); + SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p); + count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0); + SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p); + *next = (char*)p + strlen((char*)p) + 7; +} + +struct index_data +{ + HLPFILE* hlpfile; + BOOL jump; + ULONG offset; +}; + +/************************************************************************** + * WINHELP_IndexDlgProc + * + */ +static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static struct index_data* id; + int sel; + + switch (msg) + { + case WM_INITDIALOG: + id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam; + HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree, + GetDlgItem(hWnd, IDC_INDEXLIST)); + id->jump = FALSE; + id->offset = 1; + return TRUE; + case WM_COMMAND: + switch (HIWORD(wParam)) + { + case LBN_DBLCLK: + if (LOWORD(wParam) == IDC_INDEXLIST) + SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0); + break; + } + break; + case WM_NOTIFY: + switch (((NMHDR*)lParam)->code) + { + case PSN_APPLY: + sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0); + if (sel != LB_ERR) + { + BYTE *p; + int count; + + p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST, + LB_GETITEMDATA, sel, 0); + count = *(short*)((char *)p + strlen((char *)p) + 1); + if (count > 1) + { + MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP); + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); + return TRUE; + } + id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3); + id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9); + if (id->offset == 0xFFFFFFFF) + { + MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP); + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID); + return TRUE; + } + id->jump = TRUE; + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); + } + return TRUE; + default: + return FALSE; + } + break; + default: + break; + } + return FALSE; +} + +/************************************************************************** + * WINHELP_SearchDlgProc + * + */ +static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + static struct index_data* id; + + switch (msg) + { + case WM_INITDIALOG: + id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam; + return TRUE; + case WM_NOTIFY: + switch (((NMHDR*)lParam)->code) + { + case PSN_APPLY: + SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR); + return TRUE; + default: + return FALSE; + } + break; + default: + break; + } + return FALSE; +} + +/*********************************************************************** + * + * WINHELP_MainWndProc + */ +static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam) +{ + WINHELP_WINDOW *win; + WINHELP_BUTTON *button; + RECT rect; + INT curPos, min, max, dy, keyDelta; + HWND hTextWnd; + LRESULT ret; + + if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret; + + switch (msg) + { + case WM_NCCREATE: + win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams; + SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win); + if (!win->page && Globals.isBook) + PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0); + win->hMainWnd = hWnd; + break; + + case WM_WINDOWPOSCHANGED: + WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0)); + break; + + case WM_COMMAND: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + switch (wParam) + { + /* Menu FILE */ + case MNID_FILE_OPEN: MACRO_FileOpen(); break; + case MNID_FILE_PRINT: MACRO_Print(); break; + case MNID_FILE_SETUP: MACRO_PrinterSetup(); break; + case MNID_FILE_EXIT: MACRO_Exit(); break; + + /* Menu EDIT */ + case MNID_EDIT_COPYDLG: + SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); + break; + case MNID_EDIT_ANNOTATE:MACRO_Annotate(); break; + + /* Menu Bookmark */ + case MNID_BKMK_DEFINE: MACRO_BookmarkDefine(); break; + + /* Menu Help */ + case MNID_HELP_HELPON: MACRO_HelpOn(); break; + case MNID_HELP_HELPTOP: MACRO_HelpOnTop(); break; + case MNID_HELP_ABOUT: MACRO_About(); break; + case MNID_HELP_WINE: ShellAbout(hWnd, "WINE", "Help", 0); break; + + /* Context help */ + case MNID_CTXT_ANNOTATE:MACRO_Annotate(); break; + case MNID_CTXT_COPY: MACRO_CopyDialog(); break; + case MNID_CTXT_PRINT: MACRO_Print(); break; + case MNID_OPTS_HISTORY: MACRO_History(); break; + case MNID_OPTS_FONTS_SMALL: + case MNID_CTXT_FONTS_SMALL: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + if (win->font_scale != 0) + { + win->font_scale = 0; + WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); + } + break; + case MNID_OPTS_FONTS_NORMAL: + case MNID_CTXT_FONTS_NORMAL: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + if (win->font_scale != 1) + { + win->font_scale = 1; + WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); + } + break; + case MNID_OPTS_FONTS_LARGE: + case MNID_CTXT_FONTS_LARGE: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + if (win->font_scale != 2) + { + win->font_scale = 2; + WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */); + } + break; + case MNID_OPTS_HELP_DEFAULT: + case MNID_OPTS_HELP_VISIBLE: + case MNID_OPTS_HELP_NONVISIBLE: + case MNID_OPTS_SYSTEM_COLORS: + case MNID_CTXT_HELP_DEFAULT: + case MNID_CTXT_HELP_VISIBLE: + case MNID_CTXT_HELP_NONVISIBLE: + case MNID_CTXT_SYSTEM_COLORS: + /* FIXME: NIY */ + + default: + /* Buttons */ + for (button = win->first_button; button; button = button->next) + if (wParam == button->wParam) break; + if (button) + MACRO_ExecuteMacro(button->lpszMacro); + else if (!HIWORD(wParam)) + MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED), + MAKEINTRESOURCE(STID_WHERROR), MB_OK); + break; + } + break; +/* EPP case WM_DESTROY: */ +/* EPP if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */ +/* EPP break; */ + case WM_COPYDATA: + return WINHELP_HandleCommand((HWND)wParam, lParam); + + case WM_CHAR: + if (wParam == 3) + { + SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0); + return 0; + } + break; + + case WM_KEYDOWN: + keyDelta = 0; + + switch (wParam) + { + case VK_UP: + case VK_DOWN: + keyDelta = GetSystemMetrics(SM_CXVSCROLL); + if (wParam == VK_UP) + keyDelta = -keyDelta; + + case VK_PRIOR: + case VK_NEXT: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT); + curPos = GetScrollPos(hTextWnd, SB_VERT); + GetScrollRange(hTextWnd, SB_VERT, &min, &max); + + if (keyDelta == 0) + { + GetClientRect(hTextWnd, &rect); + keyDelta = (rect.bottom - rect.top) / 2; + if (wParam == VK_PRIOR) + keyDelta = -keyDelta; + } + + curPos += keyDelta; + if (curPos > max) + curPos = max; + else if (curPos < min) + curPos = min; + + dy = GetScrollPos(hTextWnd, SB_VERT) - curPos; + SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE); + ScrollWindow(hTextWnd, 0, dy, NULL, NULL); + UpdateWindow(hTextWnd); + return 0; + + case VK_ESCAPE: + MACRO_Exit(); + return 0; + } + break; + + case WM_NOTIFY: + if (wParam == CTL_ID_TEXT) + { + RECT rc; + + switch (((NMHDR*)lParam)->code) + { + case EN_MSGFILTER: + { + const MSGFILTER* msgf = (const MSGFILTER*)lParam; + switch (msgf->msg) + { + case WM_KEYUP: + if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd); + break; + case WM_RBUTTONDOWN: + { + HMENU hMenu; + POINT pt; + + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU); + switch (win->font_scale) + { + case 0: + CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL, + MF_BYCOMMAND|MF_CHECKED); + break; + default: + WINE_FIXME("Unsupported %d\n", win->font_scale); + case 1: + CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL, + MF_BYCOMMAND|MF_CHECKED); + break; + case 2: + CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE, + MF_BYCOMMAND|MF_CHECKED); + break; + } + pt.x = (int)(short)LOWORD(msgf->lParam); + pt.y = (int)(short)HIWORD(msgf->lParam); + ClientToScreen(msgf->nmhdr.hwndFrom, &pt); + TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN, + pt.x, pt.y, 0, hWnd, NULL); + DestroyMenu(hMenu); + } + break; + default: + return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0), + msgf->msg, msgf->lParam); + } + } + break; + + case EN_REQUESTRESIZE: + rc = ((REQRESIZE*)lParam)->rc; + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE), + FALSE); + SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0, + rc.right - rc.left, rc.bottom - rc.top, + SWP_NOMOVE | SWP_NOZORDER); + WINHELP_LayoutMainWindow(win); + break; + } + } + break; + + case WM_INITMENUPOPUP: + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL, + MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0); + CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL, + MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0); + CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE, + MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0); + break; + + case WM_NCDESTROY: + { + BOOL bExit; + win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0); + bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main")); + WINHELP_DeleteWindow(win); + + if (bExit) MACRO_Exit(); + if (!Globals.win_list) + PostQuitMessage(0); + } + break; + } + return DefWindowProc(hWnd, msg, wParam, lParam); +} + +/************************************************************************** + * WINHELP_CreateIndexWindow + * + * Displays a dialog with keywords of current help file. + * + */ +BOOL WINHELP_CreateIndexWindow(BOOL is_search) +{ + HPROPSHEETPAGE psPage[3]; + PROPSHEETPAGE psp; + PROPSHEETHEADER psHead; + struct index_data id; + char buf[256]; + + if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file) + id.hlpfile = Globals.active_win->page->file; + else + return FALSE; + + if (id.hlpfile->kwbtree == NULL) + { + WINE_TRACE("No index provided\n"); + return FALSE; + } + + InitCommonControls(); + + id.jump = FALSE; + memset(&psp, 0, sizeof(psp)); + psp.dwSize = sizeof(psp); + psp.dwFlags = 0; + psp.hInstance = Globals.hInstance; + + psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX); + psp.lParam = (LPARAM)&id; + psp.pfnDlgProc = WINHELP_IndexDlgProc; + psPage[0] = CreatePropertySheetPage(&psp); + + psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH); + psp.lParam = (LPARAM)&id; + psp.pfnDlgProc = WINHELP_SearchDlgProc; + psPage[1] = CreatePropertySheetPage(&psp); + + memset(&psHead, 0, sizeof(psHead)); + psHead.dwSize = sizeof(psHead); + + LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf)); + strcat(buf, Globals.active_win->info->caption); + + psHead.pszCaption = buf; + psHead.nPages = 2; + psHead.u2.nStartPage = is_search ? 1 : 0; + psHead.hwndParent = Globals.active_win->hMainWnd; + psHead.u3.phpage = psPage; + psHead.dwFlags = PSH_NOAPPLYNOW; + + PropertySheet(&psHead); + if (id.jump) + { + WINE_TRACE("got %d as an offset\n", id.offset); + WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset, + Globals.active_win->info, SW_NORMAL); + } + return TRUE; +} + +/*********************************************************************** + * + * RegisterWinClasses + */ +static BOOL WINHELP_RegisterWinClasses(void) +{ + WNDCLASS class_main, class_button_box, class_shadow, class_history; + + class_main.style = CS_HREDRAW | CS_VREDRAW; + class_main.lpfnWndProc = WINHELP_MainWndProc; + class_main.cbClsExtra = 0; + class_main.cbWndExtra = sizeof(WINHELP_WINDOW *); + class_main.hInstance = Globals.hInstance; + class_main.hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP)); + class_main.hCursor = LoadCursor(0, IDC_ARROW); + class_main.hbrBackground = (HBRUSH)(COLOR_WINDOW+1); + class_main.lpszMenuName = 0; + class_main.lpszClassName = MAIN_WIN_CLASS_NAME; + + class_button_box = class_main; + class_button_box.lpfnWndProc = WINHELP_ButtonBoxWndProc; + class_button_box.cbWndExtra = 0; + class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1); + class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME; + + class_shadow = class_main; + class_shadow.lpfnWndProc = WINHELP_ShadowWndProc; + class_shadow.cbWndExtra = 0; + class_shadow.hbrBackground = (HBRUSH)(COLOR_3DDKSHADOW+1); + class_shadow.lpszClassName = SHADOW_WIN_CLASS_NAME; + + class_history = class_main; + class_history.lpfnWndProc = WINHELP_HistoryWndProc; + class_history.lpszClassName = HISTORY_WIN_CLASS_NAME; + + return (RegisterClass(&class_main) && + RegisterClass(&class_button_box) && + RegisterClass(&class_shadow) && + RegisterClass(&class_history)); +} + +/*********************************************************************** + * + * WinMain + */ +int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show) +{ + MSG msg; + LONG lHash = 0; + HLPFILE* hlpfile; + static CHAR default_wndname[] = "main"; + LPSTR wndname = default_wndname; + WINHELP_DLL* dll; + + Globals.hInstance = hInstance; + + if (LoadLibrary("riched20.dll") == NULL) + return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT), + MAKEINTRESOURCE(STID_WHERROR), MB_OK); + + /* Get options */ + while (*cmdline && (*cmdline == ' ' || *cmdline == '-')) + { + CHAR option; + LPCSTR topic_id; + if (*cmdline++ == ' ') continue; + + option = *cmdline; + if (option) cmdline++; + while (*cmdline && *cmdline == ' ') cmdline++; + switch (option) + { + case 'i': + case 'I': + topic_id = cmdline; + while (*cmdline && *cmdline != ' ') cmdline++; + if (*cmdline) *cmdline++ = '\0'; + lHash = HLPFILE_Hash(topic_id); + break; + + case '3': + case '4': + Globals.wVersion = option - '0'; + break; + + case 'x': + show = SW_HIDE; + Globals.isBook = FALSE; + break; + + default: + WINE_FIXME("Unsupported cmd line: %s\n", cmdline); + break; + } + } + + /* Create primary window */ + if (!WINHELP_RegisterWinClasses()) + { + WINE_FIXME("Couldn't register classes\n"); + return 0; + } + + if (*cmdline) + { + char* ptr; + if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"'))) + { + cmdline++; + *ptr = '\0'; + } + if ((ptr = strchr(cmdline, '>'))) + { + *ptr = '\0'; + wndname = ptr + 1; + } + hlpfile = WINHELP_LookupHelpFile(cmdline); + if (!hlpfile) return 0; + } + else hlpfile = NULL; + WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash, + WINHELP_GetWindowInfo(hlpfile, wndname), show); + + /* Message loop */ + while (GetMessage(&msg, 0, 0, 0)) + { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + for (dll = Globals.dlls; dll; dll = dll->next) + { + if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0); + } + return 0; +} diff --git a/reactos/base/applications/winhlp32/winhelp.h b/reactos/base/applications/winhlp32/winhelp.h index c4bb00f8aa1..feaf6379bbd 100644 --- a/reactos/base/applications/winhlp32/winhelp.h +++ b/reactos/base/applications/winhlp32/winhelp.h @@ -1,167 +1,167 @@ -/* - * Help Viewer - * - * Copyright 1996 Ulrich Schmid - * Copyright 2002 Sylvain Petreolle - * 2002 Eric Pouech - * - * This library is free software; you can redistribute it and/or - * modify it under the terms of the GNU Lesser General Public - * License as published by the Free Software Foundation; either - * version 2.1 of the License, or (at your option) any later version. - * - * This library is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU - * Lesser General Public License for more details. - * - * You should have received a copy of the GNU Lesser General Public - * License along with this library; if not, write to the Free Software - * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA - */ - -#define MAX_LANGUAGE_NUMBER 255 -#define MAX_STRING_LEN 255 - -#define INTERNAL_BORDER_WIDTH 5 -#define POPUP_YDISTANCE 20 -#define SHADOW_DX 10 -#define SHADOW_DY 10 -#define BUTTON_CX 6 -#define BUTTON_CY 6 - -#ifndef RC_INVOKED - -#include - -#include "hlpfile.h" -#include "windef.h" -#include "winbase.h" -#include "macro.h" -#include "winhelp_res.h" - -typedef struct tagHelpButton -{ - HWND hWnd; - - LPCSTR lpszID; - LPCSTR lpszName; - LPCSTR lpszMacro; - - WPARAM wParam; - - RECT rect; - - struct tagHelpButton*next; -} WINHELP_BUTTON; - -typedef struct -{ - HLPFILE_PAGE* page; - HLPFILE_WINDOWINFO* wininfo; - ULONG relative; -} WINHELP_WNDPAGE; - -typedef struct tagPageSet -{ - /* FIXME: for now it's a fixed size */ - WINHELP_WNDPAGE set[40]; - unsigned index; -} WINHELP_PAGESET; - -typedef struct tagWinHelp -{ - LPCSTR lpszName; - - WINHELP_BUTTON* first_button; - HLPFILE_PAGE* page; - - HWND hMainWnd; - HWND hShadowWnd; - HWND hHistoryWnd; - - HFONT* fonts; - UINT fonts_len; - - HCURSOR hHandCur; - - HBRUSH hBrush; - - HLPFILE_WINDOWINFO* info; - HLPFILE_LINK* current_link; - - WINHELP_PAGESET back; - unsigned font_scale; /* 0 = small, 1 = normal, 2 = large */ - - struct tagWinHelp* next; -} WINHELP_WINDOW; - -#define DC_NOMSG 0x00000000 -#define DC_MINMAX 0x00000001 -#define DC_INITTERM 0x00000002 -#define DC_JUMP 0x00000004 -#define DC_ACTIVATE 0x00000008 -#define DC_CALLBACKS 0x00000010 - -#define DW_NOTUSED 0 -#define DW_WHATMSG 1 -#define DW_MINMAX 2 -#define DW_SIZE 3 -#define DW_INIT 4 -#define DW_TERM 5 -#define DW_STARTJUMP 6 -#define DW_ENDJUMP 7 -#define DW_CHGFILE 8 -#define DW_ACTIVATE 9 -#define DW_CALLBACKS 10 - -typedef long (CALLBACK *WINHELP_LDLLHandler)(WORD, LONG, LONG); - -typedef struct tagDll -{ - HANDLE hLib; - const char* name; - WINHELP_LDLLHandler handler; - DWORD class; - struct tagDll* next; -} WINHELP_DLL; - -typedef struct -{ - UINT wVersion; - HANDLE hInstance; - BOOL isBook; - WINHELP_WINDOW* active_win; - WINHELP_WINDOW* active_popup; - WINHELP_WINDOW* win_list; - WNDPROC button_proc; - WINHELP_DLL* dlls; - WINHELP_PAGESET history; - HFONT hButtonFont; -} WINHELP_GLOBALS; - -extern WINHELP_GLOBALS Globals; -extern FARPROC Callbacks[]; - -BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE*, int, BOOL); -BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*)(HLPFILE*, LONG, ULONG*), - HLPFILE*, LONG, HLPFILE_WINDOWINFO*, int); -BOOL WINHELP_GetOpenFileName(LPSTR, int); -BOOL WINHELP_CreateIndexWindow(BOOL); -void WINHELP_DeleteBackSet(WINHELP_WINDOW*); -HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile); -HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name); -void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win); - -extern const char MAIN_WIN_CLASS_NAME[]; -extern const char BUTTON_BOX_WIN_CLASS_NAME[]; -extern const char TEXT_WIN_CLASS_NAME[]; -extern const char SHADOW_WIN_CLASS_NAME[]; -extern const char HISTORY_WIN_CLASS_NAME[]; -extern const char STRING_BUTTON[]; -extern const char STRING_MENU_Xx[]; -extern const char STRING_DIALOG_TEST[]; -#endif - -/* Buttons */ -#define WH_FIRST_BUTTON 500 +/* + * Help Viewer + * + * Copyright 1996 Ulrich Schmid + * Copyright 2002 Sylvain Petreolle + * 2002 Eric Pouech + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU Lesser General Public + * License as published by the Free Software Foundation; either + * version 2.1 of the License, or (at your option) any later version. + * + * This library is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * Lesser General Public License for more details. + * + * You should have received a copy of the GNU Lesser General Public + * License along with this library; if not, write to the Free Software + * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA + */ + +#define MAX_LANGUAGE_NUMBER 255 +#define MAX_STRING_LEN 255 + +#define INTERNAL_BORDER_WIDTH 5 +#define POPUP_YDISTANCE 20 +#define SHADOW_DX 10 +#define SHADOW_DY 10 +#define BUTTON_CX 6 +#define BUTTON_CY 6 + +#ifndef RC_INVOKED + +#include + +#include "hlpfile.h" +#include "windef.h" +#include "winbase.h" +#include "macro.h" +#include "winhelp_res.h" + +typedef struct tagHelpButton +{ + HWND hWnd; + + LPCSTR lpszID; + LPCSTR lpszName; + LPCSTR lpszMacro; + + WPARAM wParam; + + RECT rect; + + struct tagHelpButton*next; +} WINHELP_BUTTON; + +typedef struct +{ + HLPFILE_PAGE* page; + HLPFILE_WINDOWINFO* wininfo; + ULONG relative; +} WINHELP_WNDPAGE; + +typedef struct tagPageSet +{ + /* FIXME: for now it's a fixed size */ + WINHELP_WNDPAGE set[40]; + unsigned index; +} WINHELP_PAGESET; + +typedef struct tagWinHelp +{ + LPCSTR lpszName; + + WINHELP_BUTTON* first_button; + HLPFILE_PAGE* page; + + HWND hMainWnd; + HWND hShadowWnd; + HWND hHistoryWnd; + + HFONT* fonts; + UINT fonts_len; + + HCURSOR hHandCur; + + HBRUSH hBrush; + + HLPFILE_WINDOWINFO* info; + HLPFILE_LINK* current_link; + + WINHELP_PAGESET back; + unsigned font_scale; /* 0 = small, 1 = normal, 2 = large */ + + struct tagWinHelp* next; +} WINHELP_WINDOW; + +#define DC_NOMSG 0x00000000 +#define DC_MINMAX 0x00000001 +#define DC_INITTERM 0x00000002 +#define DC_JUMP 0x00000004 +#define DC_ACTIVATE 0x00000008 +#define DC_CALLBACKS 0x00000010 + +#define DW_NOTUSED 0 +#define DW_WHATMSG 1 +#define DW_MINMAX 2 +#define DW_SIZE 3 +#define DW_INIT 4 +#define DW_TERM 5 +#define DW_STARTJUMP 6 +#define DW_ENDJUMP 7 +#define DW_CHGFILE 8 +#define DW_ACTIVATE 9 +#define DW_CALLBACKS 10 + +typedef long (CALLBACK *WINHELP_LDLLHandler)(WORD, LONG, LONG); + +typedef struct tagDll +{ + HANDLE hLib; + const char* name; + WINHELP_LDLLHandler handler; + DWORD class; + struct tagDll* next; +} WINHELP_DLL; + +typedef struct +{ + UINT wVersion; + HANDLE hInstance; + BOOL isBook; + WINHELP_WINDOW* active_win; + WINHELP_WINDOW* active_popup; + WINHELP_WINDOW* win_list; + WNDPROC button_proc; + WINHELP_DLL* dlls; + WINHELP_PAGESET history; + HFONT hButtonFont; +} WINHELP_GLOBALS; + +extern WINHELP_GLOBALS Globals; +extern FARPROC Callbacks[]; + +BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE*, int, BOOL); +BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*)(HLPFILE*, LONG, ULONG*), + HLPFILE*, LONG, HLPFILE_WINDOWINFO*, int); +BOOL WINHELP_GetOpenFileName(LPSTR, int); +BOOL WINHELP_CreateIndexWindow(BOOL); +void WINHELP_DeleteBackSet(WINHELP_WINDOW*); +HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile); +HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name); +void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win); + +extern const char MAIN_WIN_CLASS_NAME[]; +extern const char BUTTON_BOX_WIN_CLASS_NAME[]; +extern const char TEXT_WIN_CLASS_NAME[]; +extern const char SHADOW_WIN_CLASS_NAME[]; +extern const char HISTORY_WIN_CLASS_NAME[]; +extern const char STRING_BUTTON[]; +extern const char STRING_MENU_Xx[]; +extern const char STRING_DIALOG_TEST[]; +#endif + +/* Buttons */ +#define WH_FIRST_BUTTON 500 diff --git a/reactos/base/applications/winhlp32/winhelp_res.h b/reactos/base/applications/winhlp32/winhelp_res.h index 5869809c910..e1c72ff54e0 100644 --- a/reactos/base/applications/winhlp32/winhelp_res.h +++ b/reactos/base/applications/winhlp32/winhelp_res.h @@ -1,59 +1,59 @@ -#define MNID_FILE_OPEN 0x101 -#define MNID_FILE_PRINT 0x104 -#define MNID_FILE_SETUP 0x106 -#define MNID_FILE_EXIT 0x108 - -#define MNID_EDIT_COPYDLG 0x111 -#define MNID_EDIT_ANNOTATE 0x112 - -#define MNID_BKMK_DEFINE 0x121 - -#define MNID_OPTS_HELP_DEFAULT 0x131 -#define MNID_OPTS_HELP_VISIBLE 0x132 -#define MNID_OPTS_HELP_NONVISIBLE 0x133 -#define MNID_OPTS_HISTORY 0x134 -#define MNID_OPTS_FONTS_SMALL 0x135 -#define MNID_OPTS_FONTS_NORMAL 0x136 -#define MNID_OPTS_FONTS_LARGE 0x137 -#define MNID_OPTS_SYSTEM_COLORS 0x138 - -#define MNID_HELP_HELPON 0x141 -#define MNID_HELP_HELPTOP 0x142 -#define MNID_HELP_ABOUT 0x143 -#define MNID_HELP_WINE 0x144 - -#define MNID_CTXT_ANNOTATE 0x200 -#define MNID_CTXT_COPY 0x201 -#define MNID_CTXT_PRINT 0x202 -#define MNID_CTXT_FONTS_SMALL 0x210 -#define MNID_CTXT_FONTS_NORMAL 0x211 -#define MNID_CTXT_FONTS_LARGE 0x212 -#define MNID_CTXT_HELP_DEFAULT 0x220 -#define MNID_CTXT_HELP_VISIBLE 0x221 -#define MNID_CTXT_HELP_NONVISIBLE 0x222 -#define MNID_CTXT_SYSTEM_COLORS 0x230 - -#define MAIN_MENU 0xF000 -#define CONTEXT_MENU 0xF001 - -#define STID_WINE_HELP 0x120 -#define STID_WHERROR 0x121 -#define STID_WARNING 0x122 -#define STID_INFO 0x123 -#define STID_NOT_IMPLEMENTED 0x124 -#define STID_HLPFILE_ERROR_s 0x125 -#define STID_CONTENTS 0x126 -#define STID_INDEX 0x127 -#define STID_BACK 0x128 -#define STID_ALL_FILES 0x12B -#define STID_HELP_FILES_HLP 0x12C -#define STID_DIALOG_TEST 0x12D -#define STID_FILE_NOT_FOUND_s 0x12E -#define STID_NO_RICHEDIT 0x12F -#define STID_PSH_INDEX 0x130 - -#define IDD_INDEX 0x150 -#define IDC_INDEXLIST 0x151 -#define IDD_SEARCH 0x152 - -#define IDI_WINHELP 0xF00 +#define MNID_FILE_OPEN 0x101 +#define MNID_FILE_PRINT 0x104 +#define MNID_FILE_SETUP 0x106 +#define MNID_FILE_EXIT 0x108 + +#define MNID_EDIT_COPYDLG 0x111 +#define MNID_EDIT_ANNOTATE 0x112 + +#define MNID_BKMK_DEFINE 0x121 + +#define MNID_OPTS_HELP_DEFAULT 0x131 +#define MNID_OPTS_HELP_VISIBLE 0x132 +#define MNID_OPTS_HELP_NONVISIBLE 0x133 +#define MNID_OPTS_HISTORY 0x134 +#define MNID_OPTS_FONTS_SMALL 0x135 +#define MNID_OPTS_FONTS_NORMAL 0x136 +#define MNID_OPTS_FONTS_LARGE 0x137 +#define MNID_OPTS_SYSTEM_COLORS 0x138 + +#define MNID_HELP_HELPON 0x141 +#define MNID_HELP_HELPTOP 0x142 +#define MNID_HELP_ABOUT 0x143 +#define MNID_HELP_WINE 0x144 + +#define MNID_CTXT_ANNOTATE 0x200 +#define MNID_CTXT_COPY 0x201 +#define MNID_CTXT_PRINT 0x202 +#define MNID_CTXT_FONTS_SMALL 0x210 +#define MNID_CTXT_FONTS_NORMAL 0x211 +#define MNID_CTXT_FONTS_LARGE 0x212 +#define MNID_CTXT_HELP_DEFAULT 0x220 +#define MNID_CTXT_HELP_VISIBLE 0x221 +#define MNID_CTXT_HELP_NONVISIBLE 0x222 +#define MNID_CTXT_SYSTEM_COLORS 0x230 + +#define MAIN_MENU 0xF000 +#define CONTEXT_MENU 0xF001 + +#define STID_WINE_HELP 0x120 +#define STID_WHERROR 0x121 +#define STID_WARNING 0x122 +#define STID_INFO 0x123 +#define STID_NOT_IMPLEMENTED 0x124 +#define STID_HLPFILE_ERROR_s 0x125 +#define STID_CONTENTS 0x126 +#define STID_INDEX 0x127 +#define STID_BACK 0x128 +#define STID_ALL_FILES 0x12B +#define STID_HELP_FILES_HLP 0x12C +#define STID_DIALOG_TEST 0x12D +#define STID_FILE_NOT_FOUND_s 0x12E +#define STID_NO_RICHEDIT 0x12F +#define STID_PSH_INDEX 0x130 + +#define IDD_INDEX 0x150 +#define IDC_INDEXLIST 0x151 +#define IDD_SEARCH 0x152 + +#define IDI_WINHELP 0xF00