- SVN maintenance.
authorAleksey Bragin <aleksey@reactos.org>
Sun, 18 Jan 2009 10:22:07 +0000 (10:22 +0000)
committerAleksey Bragin <aleksey@reactos.org>
Sun, 18 Jan 2009 10:22:07 +0000 (10:22 +0000)
svn path=/trunk/; revision=38880

reactos/base/applications/winhlp32/callback.c
reactos/base/applications/winhlp32/hlpfile.c
reactos/base/applications/winhlp32/hlpfile.h
reactos/base/applications/winhlp32/lex.yy.c
reactos/base/applications/winhlp32/macro.c
reactos/base/applications/winhlp32/macro.h
reactos/base/applications/winhlp32/macro.lex.l
reactos/base/applications/winhlp32/string.c
reactos/base/applications/winhlp32/winhelp.c
reactos/base/applications/winhlp32/winhelp.h
reactos/base/applications/winhlp32/winhelp_res.h

index 4d56b0c..0b3e62e 100644 (file)
-/*\r
- * Help Viewer - DLL callback into WineHelp\r
- *\r
- * Copyright 2004 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <stdio.h>\r
-\r
-#include "windows.h"\r
-#include "winhelp.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-static WORD CALLBACK WHD_GetFSError(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static HANDLE CALLBACK WHD_Open(LPSTR name, BYTE flags)\r
-{\r
-    unsigned    mode = 0;\r
-\r
-    WINE_FIXME("(%s %x)\n", wine_dbgstr_a(name), flags);\r
-    switch (flags)\r
-    {\r
-    case 0: mode = GENERIC_READ | GENERIC_WRITE; break;\r
-    case 2: mode = GENERIC_READ; break;\r
-    default: WINE_FIXME("Undocumented flags %x\n", flags);\r
-    }\r
-    return CreateFile(name, mode, FILE_SHARE_READ | FILE_SHARE_WRITE, NULL,\r
-                      OPEN_EXISTING, FILE_ATTRIBUTE_NORMAL, NULL);\r
-}\r
-\r
-static WORD CALLBACK WHD_Close(HANDLE fs)\r
-{\r
-    WINE_FIXME("(%p)\n", fs);\r
-    CloseHandle(fs);\r
-    return 0;\r
-}\r
-\r
-static HANDLE CALLBACK WHD_OpenBag(HANDLE fs, LPSTR name, BYTE flags)\r
-{\r
-    WINE_FIXME("(%p %s %x)\n", fs, name, flags);\r
-    return NULL;\r
-}\r
-\r
-static HANDLE CALLBACK WHD_CloseBag(HANDLE bag)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return NULL;\r
-}\r
-\r
-static LONG CALLBACK WHD_ReadBag(HANDLE bag, BYTE* ptr, LONG len)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static LONG CALLBACK WHD_TellBag(HANDLE bag)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static LONG CALLBACK WHD_SeekBag(HANDLE bag, LONG offset, WORD whence)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static BOOL CALLBACK WHD_IsEofBag(HANDLE bag)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return FALSE;\r
-}\r
-\r
-static LONG CALLBACK WHD_SizeBag(HANDLE bag)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static BOOL CALLBACK WHD_Access(HANDLE fs, LPSTR name, BYTE flags)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return FALSE;\r
-}\r
-\r
-static WORD CALLBACK WHD_LLInfoFromBag(HANDLE bag, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static WORD CALLBACK WHD_LLInfoFromFile(HANDLE fs, LPSTR name, WORD opt, LPWORD p1, LPLONG p2, LPLONG p3)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-static void CALLBACK WHD_Error(int err)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK WHD_ErrorString(LPSTR err)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static ULONG_PTR CALLBACK WHD_GetInfo(WORD what, HWND hnd)\r
-{\r
-    ULONG_PTR ret = 0;\r
-\r
-    WINE_TRACE("(%x %p)\n", what, hnd);\r
-    switch (what)\r
-    {\r
-    case 0: break;\r
-    case 1: /* instance */ ret = (ULONG_PTR)Globals.hInstance; break;\r
-    case 3: /* current window */ ret = (ULONG_PTR)Globals.active_win->hMainWnd; break;\r
-    case 2: /* main window */\r
-    case 4: /* handle to opened file */\r
-    case 5: /* foreground color */\r
-    case 6: /* background color */\r
-    case 7: /* topic number */\r
-    case 8: /* current opened file name */\r
-        WINE_FIXME("NIY %u\n", what);\r
-        break;\r
-    default:\r
-        WINE_FIXME("Undocumented %u\n", what);\r
-        break;\r
-    }\r
-    return ret;\r
-}\r
-\r
-static LONG CALLBACK WHD_API(LPSTR x, WORD xx, DWORD xxx)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return 0;\r
-}\r
-\r
-FARPROC Callbacks[] =\r
-{\r
-    (FARPROC)WHD_GetFSError, \r
-    (FARPROC)WHD_Open, \r
-    (FARPROC)WHD_Close, \r
-    (FARPROC)WHD_OpenBag, \r
-    (FARPROC)WHD_CloseBag,\r
-    (FARPROC)WHD_ReadBag,\r
-    (FARPROC)WHD_TellBag,\r
-    (FARPROC)WHD_SeekBag,\r
-    (FARPROC)WHD_IsEofBag, \r
-    (FARPROC)WHD_SizeBag,\r
-    (FARPROC)WHD_Access,\r
-    (FARPROC)WHD_LLInfoFromBag, \r
-    (FARPROC)WHD_LLInfoFromFile, \r
-    (FARPROC)WHD_Error,\r
-    (FARPROC)WHD_ErrorString,\r
-    (FARPROC)WHD_GetInfo,\r
-    (FARPROC)WHD_API\r
-};\r
+/*
+ * 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 <stdio.h>
+
+#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
+};
index 483be5a..d9bdc7e 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright    1996 Ulrich Schmid\r
- *              2002, 2008 Eric Pouech\r
- *              2007 Kirill K. Smirnov\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#include <stdarg.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "winhelp.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-static inline unsigned short GET_USHORT(const BYTE* buffer, unsigned i)\r
-{\r
-    return (BYTE)buffer[i] + 0x100 * (BYTE)buffer[i + 1];\r
-}\r
-\r
-static inline short GET_SHORT(const BYTE* buffer, unsigned i)\r
-{\r
-    return (BYTE)buffer[i] + 0x100 * (signed char)buffer[i+1];\r
-}\r
-\r
-static inline unsigned GET_UINT(const BYTE* buffer, unsigned i)\r
-{\r
-    return GET_USHORT(buffer, i) + 0x10000 * GET_USHORT(buffer, i + 2);\r
-}\r
-\r
-static HLPFILE *first_hlpfile = 0;\r
-\r
-\r
-/**************************************************************************\r
- * HLPFILE_BPTreeSearch\r
- *\r
- * Searches for an element in B+ tree\r
- *\r
- * PARAMS\r
- *     buf        [I] pointer to the embedded file structured as a B+ tree\r
- *     key        [I] pointer to data to find\r
- *     comp       [I] compare function\r
- *\r
- * RETURNS\r
- *     Pointer to block identified by key, or NULL if failure.\r
- *\r
- */\r
-static void* HLPFILE_BPTreeSearch(BYTE* buf, const void* key,\r
-                           HLPFILE_BPTreeCompare comp)\r
-{\r
-    unsigned magic;\r
-    unsigned page_size;\r
-    unsigned cur_page;\r
-    unsigned level;\r
-    BYTE *pages, *ptr, *newptr;\r
-    int i, entries;\r
-    int ret;\r
-\r
-    magic = GET_USHORT(buf, 9);\r
-    if (magic != 0x293B)\r
-    {\r
-        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);\r
-        return NULL;\r
-    }\r
-    page_size = GET_USHORT(buf, 9+4);\r
-    cur_page  = GET_USHORT(buf, 9+26);\r
-    level     = GET_USHORT(buf, 9+32);\r
-    pages     = buf + 9 + 38;\r
-    while (--level > 0)\r
-    {\r
-        ptr = pages + cur_page*page_size;\r
-        entries = GET_SHORT(ptr, 2);\r
-        ptr += 6;\r
-        for (i = 0; i < entries; i++)\r
-        {\r
-            if (comp(ptr, key, 0, (void **)&newptr) > 0) break;\r
-            ptr = newptr;\r
-        }\r
-        cur_page = GET_USHORT(ptr-2, 0);\r
-    }\r
-    ptr = pages + cur_page*page_size;\r
-    entries = GET_SHORT(ptr, 2);\r
-    ptr += 8;\r
-    for (i = 0; i < entries; i++)\r
-    {\r
-        ret = comp(ptr, key, 1, (void **)&newptr);\r
-        if (ret == 0) return ptr;\r
-        if (ret > 0) return NULL;\r
-        ptr = newptr;\r
-    }\r
-    return NULL;\r
-}\r
-\r
-/**************************************************************************\r
- * HLPFILE_BPTreeEnum\r
- *\r
- * Enumerates elements in B+ tree.\r
- *\r
- * PARAMS\r
- *     buf        [I]  pointer to the embedded file structured as a B+ tree\r
- *     cb         [I]  compare function\r
- *     cookie     [IO] cookie for cb function\r
- */\r
-void HLPFILE_BPTreeEnum(BYTE* buf, HLPFILE_BPTreeCallback cb, void* cookie)\r
-{\r
-    unsigned magic;\r
-    unsigned page_size;\r
-    unsigned cur_page;\r
-    unsigned level;\r
-    BYTE *pages, *ptr, *newptr;\r
-    int i, entries;\r
-\r
-    magic = GET_USHORT(buf, 9);\r
-    if (magic != 0x293B)\r
-    {\r
-        WINE_ERR("Invalid magic in B+ tree: 0x%x\n", magic);\r
-        return;\r
-    }\r
-    page_size = GET_USHORT(buf, 9+4);\r
-    cur_page  = GET_USHORT(buf, 9+26);\r
-    level     = GET_USHORT(buf, 9+32);\r
-    pages     = buf + 9 + 38;\r
-    while (--level > 0)\r
-    {\r
-        ptr = pages + cur_page*page_size;\r
-        cur_page = GET_USHORT(ptr, 4);\r
-    }\r
-    while (cur_page != 0xFFFF)\r
-    {\r
-        ptr = pages + cur_page*page_size;\r
-        entries = GET_SHORT(ptr, 2);\r
-        ptr += 8;\r
-        for (i = 0; i < entries; i++)\r
-        {\r
-            cb(ptr, (void **)&newptr, cookie);\r
-            ptr = newptr;\r
-        }\r
-        cur_page = GET_USHORT(pages+cur_page*page_size, 6);\r
-    }\r
-}\r
-\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_UncompressedLZ77_Size\r
- */\r
-static INT HLPFILE_UncompressedLZ77_Size(const BYTE *ptr, const BYTE *end)\r
-{\r
-    int  i, newsize = 0;\r
-\r
-    while (ptr < end)\r
-    {\r
-        int mask = *ptr++;\r
-        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)\r
-       {\r
-            if (mask & 1)\r
-           {\r
-                int code = GET_USHORT(ptr, 0);\r
-                int len  = 3 + (code >> 12);\r
-                newsize += len;\r
-                ptr     += 2;\r
-           }\r
-            else newsize++, ptr++;\r
-       }\r
-    }\r
-\r
-    return newsize;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_UncompressLZ77\r
- */\r
-static BYTE *HLPFILE_UncompressLZ77(const BYTE *ptr, const BYTE *end, BYTE *newptr)\r
-{\r
-    int i;\r
-\r
-    while (ptr < end)\r
-    {\r
-        int mask = *ptr++;\r
-        for (i = 0; i < 8 && ptr < end; i++, mask >>= 1)\r
-       {\r
-            if (mask & 1)\r
-           {\r
-                int code   = GET_USHORT(ptr, 0);\r
-                int len    = 3 + (code >> 12);\r
-                int offset = code & 0xfff;\r
-                /*\r
-                 * We must copy byte-by-byte here. We cannot use memcpy nor\r
-                 * memmove here. Just example:\r
-                 * a[]={1,2,3,4,5,6,7,8,9,10}\r
-                 * newptr=a+2;\r
-                 * offset=1;\r
-                 * We expect:\r
-                 * {1, 2, 1, 2, 1, 2, 1, 2, 1, 2, 11, 12}\r
-                 */\r
-                for (; len>0; len--, newptr++) *newptr = *(newptr-offset-1);\r
-                ptr    += 2;\r
-           }\r
-            else *newptr++ = *ptr++;\r
-       }\r
-    }\r
-\r
-    return newptr;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_Uncompress2\r
- */\r
-\r
-static void HLPFILE_Uncompress2(HLPFILE* hlpfile, const BYTE *ptr, const BYTE *end, BYTE *newptr, const BYTE *newend)\r
-{\r
-    BYTE *phptr, *phend;\r
-    UINT code;\r
-    UINT index;\r
-\r
-    while (ptr < end && newptr < newend)\r
-    {\r
-        if (!*ptr || *ptr >= 0x10)\r
-            *newptr++ = *ptr++;\r
-        else\r
-       {\r
-            code  = 0x100 * ptr[0] + ptr[1];\r
-            index = (code - 0x100) / 2;\r
-\r
-            phptr = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index];\r
-            phend = (BYTE*)hlpfile->phrases_buffer + hlpfile->phrases_offsets[index + 1];\r
-\r
-            if (newptr + (phend - phptr) > newend)\r
-            {\r
-                WINE_FIXME("buffer overflow %p > %p for %lu bytes\n",\r
-                           newptr, newend, (SIZE_T)(phend - phptr));\r
-                return;\r
-            }\r
-            memcpy(newptr, phptr, phend - phptr);\r
-            newptr += phend - phptr;\r
-            if (code & 1) *newptr++ = ' ';\r
-\r
-            ptr += 2;\r
-       }\r
-    }\r
-    if (newptr > newend) WINE_FIXME("buffer overflow %p > %p\n", newptr, newend);\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_Uncompress3\r
- *\r
- *\r
- */\r
-static BOOL HLPFILE_Uncompress3(HLPFILE* hlpfile, char* dst, const char* dst_end,\r
-                                const BYTE* src, const BYTE* src_end)\r
-{\r
-    unsigned int idx, len;\r
-\r
-    for (; src < src_end; src++)\r
-    {\r
-        if ((*src & 1) == 0)\r
-        {\r
-            idx = *src / 2;\r
-            if (idx > hlpfile->num_phrases)\r
-            {\r
-                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);\r
-                len = 0;\r
-            }\r
-            else\r
-            {\r
-                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];\r
-                if (dst + len <= dst_end)\r
-                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);\r
-            }\r
-        }\r
-        else if ((*src & 0x03) == 0x01)\r
-        {\r
-            idx = (*src + 1) * 64;\r
-            idx += *++src;\r
-            if (idx > hlpfile->num_phrases)\r
-            {\r
-                WINE_ERR("index in phrases %d/%d\n", idx, hlpfile->num_phrases);\r
-                len = 0;\r
-            }\r
-            else\r
-            {\r
-                len = hlpfile->phrases_offsets[idx + 1] - hlpfile->phrases_offsets[idx];\r
-                if (dst + len <= dst_end)\r
-                    memcpy(dst, &hlpfile->phrases_buffer[hlpfile->phrases_offsets[idx]], len);\r
-            }\r
-        }\r
-        else if ((*src & 0x07) == 0x03)\r
-        {\r
-            len = (*src / 8) + 1;\r
-            if (dst + len <= dst_end)\r
-                memcpy(dst, src + 1, len);\r
-            src += len;\r
-        }\r
-        else\r
-        {\r
-            len = (*src / 16) + 1;\r
-            if (dst + len <= dst_end)\r
-                memset(dst, ((*src & 0x0F) == 0x07) ? ' ' : 0, len);\r
-        }\r
-        dst += len;\r
-    }\r
-\r
-    if (dst > dst_end) WINE_ERR("buffer overflow (%p > %p)\n", dst, dst_end);\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_UncompressRLE\r
- *\r
- *\r
- */\r
-static void HLPFILE_UncompressRLE(const BYTE* src, const BYTE* end, BYTE* dst, unsigned dstsz)\r
-{\r
-    BYTE        ch;\r
-    BYTE*       sdst = dst + dstsz;\r
-\r
-    while (src < end)\r
-    {\r
-        ch = *src++;\r
-        if (ch & 0x80)\r
-        {\r
-            ch &= 0x7F;\r
-            if (dst + ch <= sdst)\r
-                memcpy(dst, src, ch);\r
-            src += ch;\r
-        }\r
-        else\r
-        {\r
-            if (dst + ch <= sdst)\r
-                memset(dst, (char)*src, ch);\r
-            src++;\r
-        }\r
-        dst += ch;\r
-    }\r
-    if (dst != sdst)\r
-        WINE_WARN("Buffer X-flow: d(%lu) instead of d(%u)\n",\r
-                  (SIZE_T)(dst - (sdst - dstsz)), dstsz);\r
-}\r
-\r
-\r
-/******************************************************************\r
- *             HLPFILE_PageByOffset\r
- *\r
- *\r
- */\r
-HLPFILE_PAGE *HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative)\r
-{\r
-    HLPFILE_PAGE*       page;\r
-    HLPFILE_PAGE*       found;\r
-\r
-    if (!hlpfile) return 0;\r
-\r
-    WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, offset);\r
-\r
-    if (offset == 0xFFFFFFFF) return NULL;\r
-    page = NULL;\r
-\r
-    for (found = NULL, page = hlpfile->first_page; page; page = page->next)\r
-    {\r
-        if (page->offset <= offset && (!found || found->offset < page->offset))\r
-        {\r
-            *relative = offset - page->offset;\r
-            found = page;\r
-        }\r
-    }\r
-    if (!found)\r
-        WINE_ERR("Page of offset %u not found in file %s\n",\r
-                 offset, hlpfile->lpszPath);\r
-    return found;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_Contents\r
- */\r
-static HLPFILE_PAGE* HLPFILE_Contents(HLPFILE *hlpfile, ULONG* relative)\r
-{\r
-    HLPFILE_PAGE*       page = NULL;\r
-\r
-    if (!hlpfile) return NULL;\r
-\r
-    page = HLPFILE_PageByOffset(hlpfile, hlpfile->contents_start, relative);\r
-    if (!page)\r
-    {\r
-        page = hlpfile->first_page;\r
-        *relative = 0;\r
-    }\r
-    return page;\r
-}\r
-\r
-/**************************************************************************\r
- * comp_PageByHash\r
- *\r
- * HLPFILE_BPTreeCompare function for '|CONTEXT' B+ tree file\r
- *\r
- */\r
-static int comp_PageByHash(void *p, const void *key,\r
-                           int leaf, void** next)\r
-{\r
-    LONG lKey = (LONG_PTR)key;\r
-    LONG lTest = (INT)GET_UINT(p, 0);\r
-\r
-    *next = (char *)p+(leaf?8:6);\r
-    WINE_TRACE("Comparing '%d' with '%d'\n", lKey, lTest);\r
-    if (lTest < lKey) return -1;\r
-    if (lTest > lKey) return 1;\r
-    return 0;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_PageByHash\r
- */\r
-HLPFILE_PAGE *HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative)\r
-{\r
-    BYTE *ptr;\r
-\r
-    if (!hlpfile) return NULL;\r
-    if (!lHash) return HLPFILE_Contents(hlpfile, relative);\r
-\r
-    WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lHash);\r
-\r
-    /* For win 3.0 files hash values are really page numbers */\r
-    if (hlpfile->version <= 16)\r
-    {\r
-        if (lHash >= hlpfile->wTOMapLen) return NULL;\r
-        return HLPFILE_PageByOffset(hlpfile, hlpfile->TOMap[lHash], relative);\r
-    }\r
-\r
-    ptr = HLPFILE_BPTreeSearch(hlpfile->Context, LongToPtr(lHash), comp_PageByHash);\r
-    if (!ptr)\r
-    {\r
-        WINE_ERR("Page of hash %x not found in file %s\n", lHash, hlpfile->lpszPath);\r
-        return NULL;\r
-    }\r
-\r
-    return HLPFILE_PageByOffset(hlpfile, GET_UINT(ptr, 4), relative);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_PageByMap\r
- */\r
-HLPFILE_PAGE *HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative)\r
-{\r
-    unsigned int i;\r
-\r
-    if (!hlpfile) return 0;\r
-\r
-    WINE_TRACE("<%s>[%x]\n", hlpfile->lpszPath, lMap);\r
-\r
-    for (i = 0; i < hlpfile->wMapLen; i++)\r
-    {\r
-        if (hlpfile->Map[i].lMap == lMap)\r
-            return HLPFILE_PageByOffset(hlpfile, hlpfile->Map[i].offset, relative);\r
-    }\r
-\r
-    WINE_ERR("Page of Map %x not found in file %s\n", lMap, hlpfile->lpszPath);\r
-    return NULL;\r
-}\r
-\r
-/**************************************************************************\r
- * comp_FindSubFile\r
- *\r
- * HLPFILE_BPTreeCompare function for HLPFILE directory.\r
- *\r
- */\r
-static int comp_FindSubFile(void *p, const void *key,\r
-                            int leaf, void** next)\r
-{\r
-    *next = (char *)p+strlen(p)+(leaf?5:3);\r
-    WINE_TRACE("Comparing '%s' with '%s'\n", (char *)p, (char *)key);\r
-    return strcmp(p, key);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_FindSubFile\r
- */\r
-static BOOL HLPFILE_FindSubFile(HLPFILE* hlpfile, LPCSTR name, BYTE **subbuf, BYTE **subend)\r
-{\r
-    BYTE *ptr;\r
-\r
-    WINE_TRACE("looking for file '%s'\n", name);\r
-    ptr = HLPFILE_BPTreeSearch(hlpfile->file_buffer + GET_UINT(hlpfile->file_buffer, 4),\r
-                               name, comp_FindSubFile);\r
-    if (!ptr) return FALSE;\r
-    *subbuf = hlpfile->file_buffer + GET_UINT(ptr, strlen(name)+1);\r
-    if (*subbuf >= hlpfile->file_buffer + hlpfile->file_buffer_size)\r
-    {\r
-        WINE_ERR("internal file %s does not fit\n", name);\r
-        return FALSE;\r
-    }\r
-    *subend = *subbuf + GET_UINT(*subbuf, 0);\r
-    if (*subend > hlpfile->file_buffer + hlpfile->file_buffer_size)\r
-    {\r
-        WINE_ERR("internal file %s does not fit\n", name);\r
-        return FALSE;\r
-    }\r
-    if (GET_UINT(*subbuf, 0) < GET_UINT(*subbuf, 4) + 9)\r
-    {\r
-        WINE_ERR("invalid size provided for internal file %s\n", name);\r
-        return FALSE;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_Hash\r
- */\r
-LONG HLPFILE_Hash(LPCSTR lpszContext)\r
-{\r
-    LONG lHash = 0;\r
-    CHAR c;\r
-\r
-    while ((c = *lpszContext++))\r
-    {\r
-        CHAR x = 0;\r
-        if (c >= 'A' && c <= 'Z') x = c - 'A' + 17;\r
-        if (c >= 'a' && c <= 'z') x = c - 'a' + 17;\r
-        if (c >= '1' && c <= '9') x = c - '0';\r
-        if (c == '0') x = 10;\r
-        if (c == '.') x = 12;\r
-        if (c == '_') x = 13;\r
-        if (x) lHash = lHash * 43 + x;\r
-    }\r
-    return lHash;\r
-}\r
-\r
-static LONG fetch_long(const BYTE** ptr)\r
-{\r
-    LONG        ret;\r
-\r
-    if (*(*ptr) & 1)\r
-    {\r
-        ret = (*(const ULONG*)(*ptr) - 0x80000000) / 2;\r
-        (*ptr) += 4;\r
-    }\r
-    else\r
-    {\r
-        ret = (*(const USHORT*)(*ptr) - 0x8000) / 2;\r
-        (*ptr) += 2;\r
-    }\r
-\r
-    return ret;\r
-}\r
-\r
-static ULONG fetch_ulong(const BYTE** ptr)\r
-{\r
-    ULONG        ret;\r
-\r
-    if (*(*ptr) & 1)\r
-    {\r
-        ret = *(const ULONG*)(*ptr) / 2;\r
-        (*ptr) += 4;\r
-    }\r
-    else\r
-    {\r
-        ret = *(const USHORT*)(*ptr) / 2;\r
-        (*ptr) += 2;\r
-    }\r
-    return ret;\r
-}    \r
-\r
-static short fetch_short(const BYTE** ptr)\r
-{\r
-    short       ret;\r
-\r
-    if (*(*ptr) & 1)\r
-    {\r
-        ret = (*(const unsigned short*)(*ptr) - 0x8000) / 2;\r
-        (*ptr) += 2;\r
-    }\r
-    else\r
-    {\r
-        ret = (*(const unsigned char*)(*ptr) - 0x80) / 2;\r
-        (*ptr)++;\r
-    }\r
-    return ret;\r
-}\r
-\r
-static unsigned short fetch_ushort(const BYTE** ptr)\r
-{\r
-    unsigned short ret;\r
-\r
-    if (*(*ptr) & 1)\r
-    {\r
-        ret = *(const unsigned short*)(*ptr) / 2;\r
-        (*ptr) += 2;\r
-    }\r
-    else\r
-    {\r
-        ret = *(const unsigned char*)(*ptr) / 2;\r
-        (*ptr)++;\r
-    }\r
-    return ret;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_DecompressGfx\r
- *\r
- * Decompress the data part of a bitmap or a metafile\r
- */\r
-static const BYTE*      HLPFILE_DecompressGfx(const BYTE* src, unsigned csz, unsigned sz, BYTE packing,\r
-                                              BYTE** alloc)\r
-{\r
-    const BYTE* dst;\r
-    BYTE*       tmp;\r
-    unsigned    sz77;\r
-\r
-    WINE_TRACE("Unpacking (%d) from %u bytes to %u bytes\n", packing, csz, sz);\r
-\r
-    switch (packing)\r
-    {\r
-    case 0: /* uncompressed */\r
-        if (sz != csz)\r
-            WINE_WARN("Bogus gfx sizes (uncompressed): %u / %u\n", sz, csz);\r
-        dst = src;\r
-        *alloc = NULL;\r
-        break;\r
-    case 1: /* RunLen */\r
-        dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz);\r
-        if (!dst) return NULL;\r
-        HLPFILE_UncompressRLE(src, src + csz, *alloc, sz);\r
-        break;\r
-    case 2: /* LZ77 */\r
-        sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz);\r
-        dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz77);\r
-        if (!dst) return NULL;\r
-        HLPFILE_UncompressLZ77(src, src + csz, *alloc);\r
-        if (sz77 != sz)\r
-            WINE_WARN("Bogus gfx sizes (LZ77): %u / %u\n", sz77, sz);\r
-        break;\r
-    case 3: /* LZ77 then RLE */\r
-        sz77 = HLPFILE_UncompressedLZ77_Size(src, src + csz);\r
-        tmp = HeapAlloc(GetProcessHeap(), 0, sz77);\r
-        if (!tmp) return FALSE;\r
-        HLPFILE_UncompressLZ77(src, src + csz, tmp);\r
-        dst = *alloc = HeapAlloc(GetProcessHeap(), 0, sz);\r
-        if (!dst)\r
-        {\r
-            HeapFree(GetProcessHeap(), 0, tmp);\r
-            return FALSE;\r
-        }\r
-        HLPFILE_UncompressRLE(tmp, tmp + sz77, *alloc, sz);\r
-        HeapFree(GetProcessHeap(), 0, tmp);\r
-        break;\r
-    default:\r
-        WINE_FIXME("Unsupported packing %u\n", packing);\r
-        return NULL;\r
-    }\r
-    return dst;\r
-}\r
-\r
-static BOOL HLPFILE_RtfAddRawString(struct RtfData* rd, const char* str, size_t sz)\r
-{\r
-    if (rd->ptr + sz >= rd->data + rd->allocated)\r
-    {\r
-        char*   new = HeapReAlloc(GetProcessHeap(), 0, rd->data, rd->allocated *= 2);\r
-        if (!new) return FALSE;\r
-        rd->ptr = new + (rd->ptr - rd->data);\r
-        rd->data = new;\r
-    }\r
-    memcpy(rd->ptr, str, sz);\r
-    rd->ptr += sz;\r
-\r
-    return TRUE;\r
-}\r
-\r
-static BOOL HLPFILE_RtfAddControl(struct RtfData* rd, const char* str)\r
-{\r
-    if (*str == '\\' || *str == '{') rd->in_text = FALSE;\r
-    else if (*str == '}') rd->in_text = TRUE;\r
-    return HLPFILE_RtfAddRawString(rd, str, strlen(str));\r
-}\r
-\r
-static BOOL HLPFILE_RtfAddText(struct RtfData* rd, const char* str)\r
-{\r
-    const char* p;\r
-    const char* last;\r
-    const char* replace;\r
-    unsigned    rlen;\r
-\r
-    if (!rd->in_text)\r
-    {\r
-        if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE;\r
-        rd->in_text = TRUE;\r
-    }\r
-    for (last = p = str; *p; p++)\r
-    {\r
-        if (*p < 0) /* escape non ASCII chars */\r
-        {\r
-            static char         xx[8];\r
-            rlen = sprintf(xx, "\\'%x", *(const BYTE*)p);\r
-            replace = xx;\r
-        }\r
-        else switch (*p)\r
-        {\r
-        case '{':  rlen = 2; replace = "\\{";  break;\r
-        case '}':  rlen = 2; replace = "\\}";  break;\r
-        case '\\': rlen = 2; replace = "\\\\"; break;\r
-        default:   continue;\r
-        }\r
-        if ((p != last && !HLPFILE_RtfAddRawString(rd, last, p - last)) ||\r
-            !HLPFILE_RtfAddRawString(rd, replace, rlen)) return FALSE;\r
-        last = p + 1;\r
-    }\r
-    return HLPFILE_RtfAddRawString(rd, last, p - last);\r
-}\r
-\r
-/******************************************************************\r
- *             RtfAddHexBytes\r
- *\r
- */\r
-static BOOL HLPFILE_RtfAddHexBytes(struct RtfData* rd, const void* _ptr, unsigned sz)\r
-{\r
-    char        tmp[512];\r
-    unsigned    i, step;\r
-    const BYTE* ptr = _ptr;\r
-    static const char* _2hex = "0123456789abcdef";\r
-\r
-    if (!rd->in_text)\r
-    {\r
-        if (!HLPFILE_RtfAddRawString(rd, " ", 1)) return FALSE;\r
-        rd->in_text = TRUE;\r
-    }\r
-    for (; sz; sz -= step)\r
-    {\r
-        step = min(256, sz);\r
-        for (i = 0; i < step; i++)\r
-        {\r
-            tmp[2 * i + 0] = _2hex[*ptr >> 4];\r
-            tmp[2 * i + 1] = _2hex[*ptr++ & 0xF];\r
-        }\r
-        if (!HLPFILE_RtfAddRawString(rd, tmp, 2 * step)) return FALSE;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_RtfAddTransparentBitmap\r
- *\r
- * We'll transform a transparent bitmap into an metafile that\r
- * we then transform into RTF\r
- */\r
-static BOOL HLPFILE_RtfAddTransparentBitmap(struct RtfData* rd, const BITMAPINFO* bi,\r
-                                            const void* pict, unsigned nc)\r
-{\r
-    HDC                 hdc, hdcMask, hdcMem, hdcEMF;\r
-    HBITMAP             hbm, hbmMask, hbmOldMask, hbmOldMem;\r
-    HENHMETAFILE        hEMF;\r
-    BOOL                ret = FALSE;\r
-    void*               data;\r
-    UINT                sz;\r
-\r
-    hbm = CreateDIBitmap(hdc = GetDC(0), &bi->bmiHeader,\r
-                         CBM_INIT, pict, bi, DIB_RGB_COLORS);\r
-\r
-    hdcMem = CreateCompatibleDC(hdc);\r
-    hbmOldMem = SelectObject(hdcMem, hbm);\r
-\r
-    /* create the mask bitmap from the main bitmap */\r
-    hdcMask = CreateCompatibleDC(hdc);\r
-    hbmMask = CreateBitmap(bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, 1, 1, NULL);\r
-    hbmOldMask = SelectObject(hdcMask, hbmMask);\r
-    SetBkColor(hdcMem,\r
-               RGB(bi->bmiColors[nc - 1].rgbRed,\r
-                   bi->bmiColors[nc - 1].rgbGreen,\r
-                   bi->bmiColors[nc - 1].rgbBlue));\r
-    BitBlt(hdcMask, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCCOPY);\r
-\r
-    /* sets to RGB(0,0,0) the transparent bits in main bitmap */\r
-    SetBkColor(hdcMem, RGB(0,0,0));\r
-    SetTextColor(hdcMem, RGB(255,255,255));\r
-    BitBlt(hdcMem, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMask, 0, 0, SRCAND);\r
-\r
-    SelectObject(hdcMask, hbmOldMask);\r
-    DeleteDC(hdcMask);\r
-\r
-    SelectObject(hdcMem, hbmOldMem);\r
-    DeleteDC(hdcMem);\r
-\r
-    /* we create the bitmap on the fly */\r
-    hdcEMF = CreateEnhMetaFile(NULL, NULL, NULL, NULL);\r
-    hdcMem = CreateCompatibleDC(hdcEMF);\r
-\r
-    /* sets to RGB(0,0,0) the transparent bits in final bitmap */\r
-    hbmOldMem = SelectObject(hdcMem, hbmMask);\r
-    SetBkColor(hdcEMF, RGB(255, 255, 255));\r
-    SetTextColor(hdcEMF, RGB(0, 0, 0));\r
-    BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCAND);\r
-\r
-    /* and copy the remaining bits of main bitmap */\r
-    SelectObject(hdcMem, hbm);\r
-    BitBlt(hdcEMF, 0, 0, bi->bmiHeader.biWidth, bi->bmiHeader.biHeight, hdcMem, 0, 0, SRCPAINT);\r
-    SelectObject(hdcMem, hbmOldMem);\r
-    DeleteDC(hdcMem);\r
-\r
-    /* do the cleanup */\r
-    ReleaseDC(0, hdc);\r
-    DeleteObject(hbmMask);\r
-    DeleteObject(hbm);\r
-\r
-    hEMF = CloseEnhMetaFile(hdcEMF);\r
-\r
-    /* generate rtf stream */\r
-    sz = GetEnhMetaFileBits(hEMF, 0, NULL);\r
-    if (sz && (data = HeapAlloc(GetProcessHeap(), 0, sz)))\r
-    {\r
-        if (sz == GetEnhMetaFileBits(hEMF, sz, data))\r
-        {\r
-            ret = HLPFILE_RtfAddControl(rd, "{\\pict\\emfblip") &&\r
-                HLPFILE_RtfAddHexBytes(rd, data, sz) &&\r
-                HLPFILE_RtfAddControl(rd, "}");\r
-        }\r
-        HeapFree(GetProcessHeap(), 0, data);\r
-    }\r
-    DeleteEnhMetaFile(hEMF);\r
-\r
-    return ret;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_RtfAddBitmap\r
- *\r
- */\r
-static BOOL HLPFILE_RtfAddBitmap(struct RtfData* rd, const BYTE* beg, BYTE type, BYTE pack)\r
-{\r
-    const BYTE*         ptr;\r
-    const BYTE*         pict_beg;\r
-    BYTE*               alloc = NULL;\r
-    BITMAPINFO*         bi;\r
-    ULONG               off, csz;\r
-    unsigned            nc = 0;\r
-    BOOL                clrImportant = FALSE;\r
-    BOOL                ret = FALSE;\r
-    char                tmp[256];\r
-\r
-    bi = HeapAlloc(GetProcessHeap(), 0, sizeof(*bi));\r
-    if (!bi) return FALSE;\r
-\r
-    ptr = beg + 2; /* for type and pack */\r
-\r
-    bi->bmiHeader.biSize          = sizeof(bi->bmiHeader);\r
-    bi->bmiHeader.biXPelsPerMeter = fetch_ulong(&ptr);\r
-    bi->bmiHeader.biYPelsPerMeter = fetch_ulong(&ptr);\r
-    bi->bmiHeader.biPlanes        = fetch_ushort(&ptr);\r
-    bi->bmiHeader.biBitCount      = fetch_ushort(&ptr);\r
-    bi->bmiHeader.biWidth         = fetch_ulong(&ptr);\r
-    bi->bmiHeader.biHeight        = fetch_ulong(&ptr);\r
-    bi->bmiHeader.biClrUsed       = fetch_ulong(&ptr);\r
-    clrImportant  = fetch_ulong(&ptr);\r
-    bi->bmiHeader.biClrImportant  = (clrImportant > 1) ? clrImportant : 0;\r
-    bi->bmiHeader.biCompression   = BI_RGB;\r
-    if (bi->bmiHeader.biBitCount > 32) WINE_FIXME("Unknown bit count %u\n", bi->bmiHeader.biBitCount);\r
-    if (bi->bmiHeader.biPlanes != 1) WINE_FIXME("Unsupported planes %u\n", bi->bmiHeader.biPlanes);\r
-    bi->bmiHeader.biSizeImage = (((bi->bmiHeader.biWidth * bi->bmiHeader.biBitCount + 31) & ~31) / 8) * bi->bmiHeader.biHeight;\r
-    WINE_TRACE("planes=%d bc=%d size=(%d,%d)\n",\r
-               bi->bmiHeader.biPlanes, bi->bmiHeader.biBitCount,\r
-               bi->bmiHeader.biWidth, bi->bmiHeader.biHeight);\r
-\r
-    csz = fetch_ulong(&ptr);\r
-    fetch_ulong(&ptr); /* hotspot size */\r
-\r
-    off = GET_UINT(ptr, 0);     ptr += 4;\r
-    /* GET_UINT(ptr, 0); hotspot offset */ ptr += 4;\r
-\r
-    /* now read palette info */\r
-    if (type == 0x06)\r
-    {\r
-        unsigned i;\r
-\r
-        nc = bi->bmiHeader.biClrUsed;\r
-        /* not quite right, especially for bitfields type of compression */\r
-        if (!nc && bi->bmiHeader.biBitCount <= 8)\r
-            nc = 1 << bi->bmiHeader.biBitCount;\r
-\r
-        bi = HeapReAlloc(GetProcessHeap(), 0, bi, sizeof(*bi) + nc * sizeof(RGBQUAD));\r
-        if (!bi) return FALSE;\r
-        for (i = 0; i < nc; i++)\r
-        {\r
-            bi->bmiColors[i].rgbBlue     = ptr[0];\r
-            bi->bmiColors[i].rgbGreen    = ptr[1];\r
-            bi->bmiColors[i].rgbRed      = ptr[2];\r
-            bi->bmiColors[i].rgbReserved = 0;\r
-            ptr += 4;\r
-        }\r
-    }\r
-    pict_beg = HLPFILE_DecompressGfx(beg + off, csz, bi->bmiHeader.biSizeImage, pack, &alloc);\r
-\r
-    if (clrImportant == 1 && nc > 0)\r
-    {\r
-        ret = HLPFILE_RtfAddTransparentBitmap(rd, bi, pict_beg, nc);\r
-        goto done;\r
-    }\r
-    if (!HLPFILE_RtfAddControl(rd, "{\\pict")) goto done;\r
-    if (type == 0x06)\r
-    {\r
-        sprintf(tmp, "\\dibitmap0\\picw%d\\pich%d",\r
-                bi->bmiHeader.biWidth, bi->bmiHeader.biHeight);\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        if (!HLPFILE_RtfAddHexBytes(rd, bi, sizeof(*bi) + nc * sizeof(RGBQUAD))) goto done;\r
-    }\r
-    else\r
-    {\r
-        sprintf(tmp, "\\wbitmap0\\wbmbitspixel%d\\wbmplanes%d\\picw%d\\pich%d",\r
-                bi->bmiHeader.biBitCount, bi->bmiHeader.biPlanes,\r
-                bi->bmiHeader.biWidth, bi->bmiHeader.biHeight);\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-    }\r
-    if (!HLPFILE_RtfAddHexBytes(rd, pict_beg, bi->bmiHeader.biSizeImage)) goto done;\r
-    if (!HLPFILE_RtfAddControl(rd, "}")) goto done;\r
-\r
-    ret = TRUE;\r
-done:\r
-    HeapFree(GetProcessHeap(), 0, bi);\r
-    HeapFree(GetProcessHeap(), 0, alloc);\r
-\r
-    return ret;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_RtfAddMetaFile\r
- *\r
- */\r
-static BOOL     HLPFILE_RtfAddMetaFile(struct RtfData* rd, const BYTE* beg, BYTE pack)\r
-{\r
-    ULONG size, csize, off, hsoff;\r
-    const BYTE*         ptr;\r
-    const BYTE*         bits;\r
-    BYTE*               alloc = NULL;\r
-    char                tmp[256];\r
-    unsigned            mm;\r
-    BOOL                ret;\r
-\r
-    WINE_TRACE("Loading metafile\n");\r
-\r
-    ptr = beg + 2; /* for type and pack */\r
-\r
-    mm = fetch_ushort(&ptr); /* mapping mode */\r
-    sprintf(tmp, "{\\pict\\wmetafile%d\\picw%d\\pich%d",\r
-            mm, GET_USHORT(ptr, 0), GET_USHORT(ptr, 2));\r
-    if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;\r
-    ptr += 4;\r
-\r
-    size = fetch_ulong(&ptr); /* decompressed size */\r
-    csize = fetch_ulong(&ptr); /* compressed size */\r
-    fetch_ulong(&ptr); /* hotspot size */\r
-    off = GET_UINT(ptr, 0);\r
-    hsoff = GET_UINT(ptr, 4);\r
-    ptr += 8;\r
-\r
-    WINE_TRACE("sz=%u csz=%u offs=%u/%u,%u\n",\r
-               size, csize, off, (ULONG)(ptr - beg), hsoff);\r
-\r
-    bits = HLPFILE_DecompressGfx(beg + off, csize, size, pack, &alloc);\r
-    if (!bits) return FALSE;\r
-\r
-    ret = HLPFILE_RtfAddHexBytes(rd, bits, size) &&\r
-        HLPFILE_RtfAddControl(rd, "}");\r
-\r
-    HeapFree(GetProcessHeap(), 0, alloc);\r
-\r
-    return ret;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_RtfAddGfxByAddr\r
- *\r
- */\r
-static  BOOL    HLPFILE_RtfAddGfxByAddr(struct RtfData* rd, HLPFILE *hlpfile,\r
-                                        const BYTE* ref, ULONG size)\r
-{\r
-    unsigned    i, numpict;\r
-\r
-    numpict = GET_USHORT(ref, 2);\r
-    WINE_TRACE("Got picture magic=%04x #=%d\n", GET_USHORT(ref, 0), numpict);\r
-\r
-    for (i = 0; i < numpict; i++)\r
-    {\r
-        const BYTE*     beg;\r
-        const BYTE*     ptr;\r
-        BYTE            type, pack;\r
-\r
-        WINE_TRACE("Offset[%d] = %x\n", i, GET_UINT(ref, (1 + i) * 4));\r
-        beg = ptr = ref + GET_UINT(ref, (1 + i) * 4);\r
-\r
-        type = *ptr++;\r
-        pack = *ptr++;\r
-\r
-        switch (type)\r
-        {\r
-        case 5: /* device dependent bmp */\r
-        case 6: /* device independent bmp */\r
-            HLPFILE_RtfAddBitmap(rd, beg, type, pack);\r
-            break;\r
-        case 8:\r
-            HLPFILE_RtfAddMetaFile(rd, beg, pack);\r
-            break;\r
-        default: WINE_FIXME("Unknown type %u\n", type); return FALSE;\r
-        }\r
-\r
-        /* FIXME: hotspots */\r
-\r
-        /* FIXME: implement support for multiple picture format */\r
-        if (numpict != 1) WINE_FIXME("Supporting only one bitmap format per logical bitmap (for now). Using first format\n");\r
-        break;\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_RtfAddGfxByIndex\r
- *\r
- *\r
- */\r
-static  BOOL    HLPFILE_RtfAddGfxByIndex(struct RtfData* rd, HLPFILE *hlpfile,\r
-                                         unsigned index)\r
-{\r
-    char        tmp[16];\r
-    BYTE        *ref, *end;\r
-\r
-    WINE_TRACE("Loading picture #%d\n", index);\r
-\r
-    sprintf(tmp, "|bm%u", index);\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, tmp, &ref, &end)) {WINE_WARN("no sub file\n"); return FALSE;}\r
-\r
-    ref += 9;\r
-    return HLPFILE_RtfAddGfxByAddr(rd, hlpfile, ref, end - ref);\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_AllocLink\r
- *\r
- *\r
- */\r
-static HLPFILE_LINK*       HLPFILE_AllocLink(struct RtfData* rd, int cookie,\r
-                                             const char* str, unsigned len, LONG hash,\r
-                                             unsigned clrChange, unsigned wnd)\r
-{\r
-    HLPFILE_LINK*  link;\r
-    char*          link_str;\r
-\r
-    /* FIXME: should build a string table for the attributes.link.lpszPath\r
-     * they are reallocated for each link\r
-     */\r
-    if (len == -1) len = strlen(str);\r
-    link = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_LINK) + len + 1);\r
-    if (!link) return NULL;\r
-\r
-    link->cookie     = cookie;\r
-    link->string     = link_str = (char*)(link + 1);\r
-    memcpy(link_str, str, len);\r
-    link_str[len] = '\0';\r
-    link->hash       = hash;\r
-    link->bClrChange = clrChange ? 1 : 0;\r
-    link->window     = wnd;\r
-    link->next       = rd->first_link;\r
-    rd->first_link   = link;\r
-    link->cpMin      = rd->char_pos;\r
-    link->cpMax      = 0;\r
-    rd->force_color  = clrChange;\r
-    if (rd->current_link) WINE_FIXME("Pending link\n");\r
-    rd->current_link = link;\r
-\r
-    WINE_TRACE("Link[%d] to %s@%08x:%d\n",\r
-               link->cookie, link->string, link->hash, link->window);\r
-    return link;\r
-}\r
-\r
-static unsigned HLPFILE_HalfPointsToTwips(unsigned pts)\r
-{\r
-    static unsigned logPxY;\r
-    if (!logPxY)\r
-    {\r
-        HDC hdc = GetDC(NULL);\r
-        logPxY = GetDeviceCaps(hdc, LOGPIXELSY);\r
-        ReleaseDC(NULL, hdc);\r
-    }\r
-    return MulDiv(pts, 72 * 10, logPxY);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_BrowseParagraph\r
- */\r
-static BOOL HLPFILE_BrowseParagraph(HLPFILE_PAGE* page, struct RtfData* rd,\r
-                                    BYTE *buf, BYTE* end, unsigned* parlen)\r
-{\r
-    UINT               textsize;\r
-    const BYTE        *format, *format_end;\r
-    char              *text, *text_base, *text_end;\r
-    LONG               size, blocksize, datalen;\r
-    unsigned short     bits;\r
-    unsigned           nc, ncol = 1;\r
-    short              table_width;\r
-    BOOL               in_table = FALSE;\r
-    char               tmp[256];\r
-    BOOL               ret = FALSE;\r
-\r
-    if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};\r
-\r
-    *parlen = 0;\r
-    blocksize = GET_UINT(buf, 0);\r
-    size = GET_UINT(buf, 0x4);\r
-    datalen = GET_UINT(buf, 0x10);\r
-    text = text_base = HeapAlloc(GetProcessHeap(), 0, size);\r
-    if (!text) return FALSE;\r
-    if (size > blocksize - datalen)\r
-    {\r
-        /* need to decompress */\r
-        if (page->file->hasPhrases)\r
-            HLPFILE_Uncompress2(page->file, buf + datalen, end, (BYTE*)text, (BYTE*)text + size);\r
-        else if (page->file->hasPhrases40)\r
-            HLPFILE_Uncompress3(page->file, text, text + size, buf + datalen, end);\r
-        else\r
-        {\r
-            WINE_FIXME("Text size is too long, splitting\n");\r
-            size = blocksize - datalen;\r
-            memcpy(text, buf + datalen, size);\r
-        }\r
-    }\r
-    else\r
-        memcpy(text, buf + datalen, size);\r
-\r
-    text_end = text + size;\r
-\r
-    format = buf + 0x15;\r
-    format_end = buf + GET_UINT(buf, 0x10);\r
-\r
-    if (buf[0x14] == 0x20 || buf[0x14] == 0x23)\r
-    {\r
-        fetch_long(&format);\r
-        *parlen = fetch_ushort(&format);\r
-    }\r
-\r
-    if (buf[0x14] == 0x23)\r
-    {\r
-        char    type;\r
-\r
-        in_table = TRUE;\r
-        ncol = *format++;\r
-\r
-        if (!HLPFILE_RtfAddControl(rd, "\\trowd")) goto done;\r
-        type = *format++;\r
-        if (type == 0 || type == 2)\r
-        {\r
-            table_width = GET_SHORT(format, 0);\r
-            format += 2;\r
-        }\r
-        else\r
-            table_width = 32767;\r
-        WINE_TRACE("New table: cols=%d type=%x width=%d\n",\r
-                   ncol, type, table_width);\r
-        if (ncol > 1)\r
-        {\r
-            int     pos;\r
-            sprintf(tmp, "\\trgaph%d\\trleft%d",\r
-                    HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6), table_width, 32767)),\r
-                    HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-            pos = HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 6) / 2, table_width, 32767));\r
-            for (nc = 0; nc < ncol; nc++)\r
-            {\r
-                WINE_TRACE("column(%d/%d) gap=%d width=%d\n",\r
-                           nc, ncol, GET_SHORT(format, nc*4),\r
-                           GET_SHORT(format, nc*4+2));\r
-                pos += GET_SHORT(format, nc * 4) + GET_SHORT(format, nc * 4 + 2);\r
-                sprintf(tmp, "\\cellx%d",\r
-                        HLPFILE_HalfPointsToTwips(MulDiv(pos, table_width, 32767)));\r
-                if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-            }\r
-        }\r
-        else\r
-        {\r
-            WINE_TRACE("column(0/%d) gap=%d width=%d\n",\r
-                       ncol, GET_SHORT(format, 0), GET_SHORT(format, 2));\r
-            sprintf(tmp, "\\trleft%d\\cellx%d ",\r
-                    HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0), table_width, 32767)),\r
-                    HLPFILE_HalfPointsToTwips(MulDiv(GET_SHORT(format, 0) + GET_SHORT(format, 2),\r
-                                      table_width, 32767)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        format += ncol * 4;\r
-    }\r
-\r
-    for (nc = 0; nc < ncol; /**/)\r
-    {\r
-        WINE_TRACE("looking for format at offset %lu in column %d\n", (SIZE_T)(format - (buf + 0x15)), nc);\r
-        if (!HLPFILE_RtfAddControl(rd, "\\pard")) goto done;\r
-        if (in_table)\r
-        {\r
-            nc = GET_SHORT(format, 0);\r
-            if (nc == -1) break;\r
-            format += 5;\r
-            if (!HLPFILE_RtfAddControl(rd, "\\intbl")) goto done;\r
-        }\r
-        else nc++;\r
-        if (buf[0x14] == 0x01)\r
-            format += 6;\r
-        else\r
-            format += 4;\r
-        bits = GET_USHORT(format, 0); format += 2;\r
-        if (bits & 0x0001) fetch_long(&format);\r
-        if (bits & 0x0002)\r
-        {\r
-            sprintf(tmp, "\\sb%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0004)\r
-        {\r
-            sprintf(tmp, "\\sa%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0008)\r
-        {\r
-            sprintf(tmp, "\\sl%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0010)\r
-        {\r
-            sprintf(tmp, "\\li%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0020)\r
-        {\r
-            sprintf(tmp, "\\ri%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0040)\r
-        {\r
-            sprintf(tmp, "\\fi%d", HLPFILE_HalfPointsToTwips(fetch_short(&format)));\r
-            if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-        }\r
-        if (bits & 0x0100)\r
-        {\r
-            BYTE        brdr = *format++;\r
-            short       w;\r
-\r
-            if (brdr & 0x01 && !HLPFILE_RtfAddControl(rd, "\\box")) goto done;\r
-            if (brdr & 0x02 && !HLPFILE_RtfAddControl(rd, "\\brdrt")) goto done;\r
-            if (brdr & 0x04 && !HLPFILE_RtfAddControl(rd, "\\brdrl")) goto done;\r
-            if (brdr & 0x08 && !HLPFILE_RtfAddControl(rd, "\\brdrb")) goto done;\r
-            if (brdr & 0x10 && !HLPFILE_RtfAddControl(rd, "\\brdrr")) goto done;\r
-            if (brdr & 0x20 && !HLPFILE_RtfAddControl(rd, "\\brdrth")) goto done;\r
-            if (!(brdr & 0x20) && !HLPFILE_RtfAddControl(rd, "\\brdrs")) goto done;\r
-            if (brdr & 0x40 && !HLPFILE_RtfAddControl(rd, "\\brdrdb")) goto done;\r
-            /* 0x80: unknown */\r
-\r
-            w = GET_SHORT(format, 0); format += 2;\r
-            if (w)\r
-            {\r
-                sprintf(tmp, "\\brdrw%d", HLPFILE_HalfPointsToTwips(w));\r
-                if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-            }\r
-        }\r
-        if (bits & 0x0200)\r
-        {\r
-            int                 i, ntab = fetch_short(&format);\r
-            unsigned            tab, ts;\r
-            const char*         kind;\r
-\r
-            for (i = 0; i < ntab; i++)\r
-            {\r
-                tab = fetch_ushort(&format);\r
-                ts = (tab & 0x4000) ? fetch_ushort(&format) : 0 /* left */;\r
-                switch (ts)\r
-                {\r
-                default: WINE_FIXME("Unknown tab style %x\n", ts);\r
-                /* fall through */\r
-                case 0: kind = ""; break;\r
-                case 1: kind = "\\tqr"; break;\r
-                case 2: kind = "\\tqc"; break;\r
-                }\r
-                /* FIXME: do kind */\r
-                sprintf(tmp, "%s\\tx%d",\r
-                        kind, HLPFILE_HalfPointsToTwips(tab & 0x3FFF));\r
-                if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-            }\r
-        }\r
-        switch (bits & 0xc00)\r
-        {\r
-        default: WINE_FIXME("Unsupported alignment 0xC00\n"); break;\r
-        case 0: if (!HLPFILE_RtfAddControl(rd, "\\ql")) goto done; break;\r
-        case 0x400: if (!HLPFILE_RtfAddControl(rd, "\\qr")) goto done; break;\r
-        case 0x800: if (!HLPFILE_RtfAddControl(rd, "\\qc")) goto done; break;\r
-        }\r
-\r
-        /* 0x1000 doesn't need space */\r
-        if ((bits & 0x1000) && !HLPFILE_RtfAddControl(rd, "\\keep")) goto done;\r
-        if ((bits & 0xE080) != 0) \r
-            WINE_FIXME("Unsupported bits %04x, potential trouble ahead\n", bits);\r
-\r
-        while (text < text_end && format < format_end)\r
-        {\r
-            WINE_TRACE("Got text: %s (%p/%p - %p/%p)\n", wine_dbgstr_a(text), text, text_end, format, format_end);\r
-            textsize = strlen(text);\r
-            if (textsize)\r
-            {\r
-                if (rd->force_color)\r
-                {\r
-                    if ((rd->current_link->cookie == hlp_link_popup) ?\r
-                        !HLPFILE_RtfAddControl(rd, "{\\uld\\cf1") :\r
-                        !HLPFILE_RtfAddControl(rd, "{\\ul\\cf1")) goto done;\r
-                }\r
-                if (!HLPFILE_RtfAddText(rd, text)) goto done;\r
-                if (rd->force_color && !HLPFILE_RtfAddControl(rd, "}")) goto done;\r
-                rd->char_pos += textsize;\r
-            }\r
-            /* else: null text, keep on storing attributes */\r
-            text += textsize + 1;\r
-\r
-           if (*format == 0xff)\r
-            {\r
-                format++;\r
-                break;\r
-            }\r
-\r
-            WINE_TRACE("format=%02x\n", *format);\r
-            switch (*format)\r
-            {\r
-            case 0x20:\r
-                WINE_FIXME("NIY20\n");\r
-                format += 5;\r
-                break;\r
-\r
-            case 0x21:\r
-                WINE_FIXME("NIY21\n");\r
-                format += 3;\r
-                break;\r
-\r
-           case 0x80:\r
-                {\r
-                    unsigned    font = GET_USHORT(format, 1);\r
-                    unsigned    fs;\r
-\r
-                    WINE_TRACE("Changing font to %d\n", font);\r
-                    format += 3;\r
-                    /* Font size in hlpfile is given in the same units as\r
-                       rtf control word \fs uses (half-points). */\r
-                    switch (rd->font_scale)\r
-                    {\r
-                    case 0: fs = page->file->fonts[font].LogFont.lfHeight - 4; break;\r
-                    default:\r
-                    case 1: fs = page->file->fonts[font].LogFont.lfHeight; break;\r
-                    case 2: fs = page->file->fonts[font].LogFont.lfHeight + 4; break;\r
-                    }\r
-                    /* FIXME: missing at least colors, also bold attribute looses information */\r
-\r
-                    sprintf(tmp, "\\f%d\\cf%d\\fs%d%s%s%s%s",\r
-                            font, font + 2, fs,\r
-                            page->file->fonts[font].LogFont.lfWeight > 400 ? "\\b" : "\\b0",\r
-                            page->file->fonts[font].LogFont.lfItalic ? "\\i" : "\\i0",\r
-                            page->file->fonts[font].LogFont.lfUnderline ? "\\ul" : "\\ul0",\r
-                            page->file->fonts[font].LogFont.lfStrikeOut ? "\\strike" : "\\strike0");\r
-                    if (!HLPFILE_RtfAddControl(rd, tmp)) goto done;\r
-                }\r
-               break;\r
-\r
-           case 0x81:\r
-                if (!HLPFILE_RtfAddControl(rd, "\\line")) goto done;\r
-                format += 1;\r
-                rd->char_pos++;\r
-                break;\r
-\r
-           case 0x82:\r
-                if (in_table)\r
-                {\r
-                    if (format[1] != 0xFF)\r
-                    {\r
-                        if (!HLPFILE_RtfAddControl(rd, "\\par\\intbl")) goto done;\r
-                    }\r
-                    else\r
-                    {\r
-                        if (!HLPFILE_RtfAddControl(rd, "\\cell\\pard\\intbl")) goto done;\r
-                    }\r
-                }\r
-                else if (!HLPFILE_RtfAddControl(rd, "\\par")) goto done;\r
-                format += 1;\r
-                rd->char_pos++;\r
-                break;\r
-\r
-           case 0x83:\r
-                if (!HLPFILE_RtfAddControl(rd, "\\tab")) goto done;\r
-                format += 1;\r
-                rd->char_pos++;\r
-                break;\r
-\r
-#if 0\r
-           case 0x84:\r
-                format += 3;\r
-                break;\r
-#endif\r
-\r
-           case 0x86:\r
-           case 0x87:\r
-           case 0x88:\r
-                {\r
-                    BYTE    type = format[1];\r
-                    LONG    size;\r
-\r
-                    /* FIXME: we don't use 'BYTE    pos = (*format - 0x86);' for the image position */\r
-                    format += 2;\r
-                    size = fetch_long(&format);\r
-\r
-                    switch (type)\r
-                    {\r
-                    case 0x22:\r
-                        fetch_ushort(&format); /* hot spot */\r
-                        /* fall thru */\r
-                    case 0x03:\r
-                        switch (GET_SHORT(format, 0))\r
-                        {\r
-                        case 0:\r
-                            HLPFILE_RtfAddGfxByIndex(rd, page->file, GET_SHORT(format, 2));\r
-                            rd->char_pos++;\r
-                            break;\r
-                        case 1:\r
-                            WINE_FIXME("does it work ??? %x<%u>#%u\n",\r
-                                       GET_SHORT(format, 0),\r
-                                       size, GET_SHORT(format, 2));\r
-                            HLPFILE_RtfAddGfxByAddr(rd, page->file, format + 2, size - 4);\r
-                            rd->char_pos++;\r
-                           break;\r
-                        default:\r
-                            WINE_FIXME("??? %u\n", GET_SHORT(format, 0));\r
-                            break;\r
-                        }\r
-                        break;\r
-                    case 0x05:\r
-                        WINE_FIXME("Got an embedded element %s\n", format + 6);\r
-                        break;\r
-                    default:\r
-                        WINE_FIXME("Got a type %d picture\n", type);\r
-                        break;\r
-                    }\r
-                    format += size;\r
-                }\r
-                break;\r
-\r
-           case 0x89:\r
-                format += 1;\r
-                if (!rd->current_link)\r
-                    WINE_FIXME("No existing link\n");\r
-                rd->current_link->cpMax = rd->char_pos;\r
-                rd->current_link = NULL;\r
-                rd->force_color = FALSE;\r
-                break;\r
-\r
-            case 0x8B:\r
-                if (!HLPFILE_RtfAddControl(rd, "\\~")) goto done;\r
-                format += 1;\r
-                rd->char_pos++;\r
-                break;\r
-\r
-            case 0x8C:\r
-                if (!HLPFILE_RtfAddControl(rd, "\\_")) goto done;\r
-                /* FIXME: it could be that hypen is also in input stream !! */\r
-                format += 1;\r
-                rd->char_pos++;\r
-                break;\r
-\r
-#if 0\r
-           case 0xA9:\r
-                format += 2;\r
-                break;\r
-#endif\r
-\r
-            case 0xC8:\r
-            case 0xCC:\r
-                WINE_TRACE("macro => %s\n", format + 3);\r
-                HLPFILE_AllocLink(rd, hlp_link_macro, (const char*)format + 3,\r
-                                  GET_USHORT(format, 1), 0, !(*format & 4), -1);\r
-                format += 3 + GET_USHORT(format, 1);\r
-                break;\r
-\r
-            case 0xE0:\r
-            case 0xE1:\r
-                WINE_WARN("jump topic 1 => %u\n", GET_UINT(format, 1));\r
-                HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,\r
-                                  page->file->lpszPath, -1, GET_UINT(format, 1), 1, -1);\r
-\r
-\r
-                format += 5;\r
-                break;\r
-\r
-           case 0xE2:\r
-           case 0xE3:\r
-            case 0xE6:\r
-            case 0xE7:\r
-                HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,\r
-                                  page->file->lpszPath, -1, GET_UINT(format, 1),\r
-                                  !(*format & 4), -1);\r
-                format += 5;\r
-                break;\r
-\r
-           case 0xEA:\r
-            case 0xEB:\r
-            case 0xEE:\r
-            case 0xEF:\r
-                {\r
-                    char*       ptr = (char*) format + 8;\r
-                    BYTE        type = format[3];\r
-                    int         wnd = -1;\r
-\r
-                    switch (type)\r
-                    {\r
-                    case 1:\r
-                        wnd = *ptr;\r
-                        /* fall through */\r
-                    case 0:\r
-                        ptr = page->file->lpszPath;\r
-                        break;\r
-                    case 6:\r
-                        for (wnd = page->file->numWindows - 1; wnd >= 0; wnd--)\r
-                        {\r
-                            if (!strcmp(ptr, page->file->windows[wnd].name)) break;\r
-                        }\r
-                        if (wnd == -1)\r
-                            WINE_WARN("Couldn't find window info for %s\n", ptr);\r
-                        ptr += strlen(ptr) + 1;\r
-                        /* fall through */\r
-                    case 4:\r
-                        break;\r
-                    default:\r
-                        WINE_WARN("Unknown link type %d\n", type);\r
-                        break;\r
-                    }\r
-                    HLPFILE_AllocLink(rd, (*format & 1) ? hlp_link_link : hlp_link_popup,\r
-                                      ptr, -1, GET_UINT(format, 4), !(*format & 4), wnd);\r
-                }\r
-                format += 3 + GET_USHORT(format, 1);\r
-                break;\r
-\r
-           default:\r
-                WINE_WARN("format %02x\n", *format);\r
-                format++;\r
-           }\r
-       }\r
-    }\r
-    if (in_table)\r
-    {\r
-        if (!HLPFILE_RtfAddControl(rd, "\\row\\par\\pard\\plain")) goto done;\r
-        rd->char_pos += 2;\r
-    }\r
-    ret = TRUE;\r
-done:\r
-\r
-    HeapFree(GetProcessHeap(), 0, text_base);\r
-    return ret;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_BrowsePage\r
- *\r
- */\r
-BOOL    HLPFILE_BrowsePage(HLPFILE_PAGE* page, struct RtfData* rd,\r
-                           unsigned font_scale, unsigned relative)\r
-{\r
-    HLPFILE     *hlpfile = page->file;\r
-    BYTE        *buf, *end;\r
-    DWORD       ref = page->reference;\r
-    unsigned    index, old_index = -1, offset, count = 0, offs = 0;\r
-    unsigned    cpg, parlen;\r
-    char        tmp[1024];\r
-    const char* ck = NULL;\r
-\r
-    rd->in_text = TRUE;\r
-    rd->data = rd->ptr = HeapAlloc(GetProcessHeap(), 0, rd->allocated = 32768);\r
-    rd->char_pos = 0;\r
-    rd->first_link = rd->current_link = NULL;\r
-    rd->force_color = FALSE;\r
-    rd->font_scale = font_scale;\r
-    rd->relative = relative;\r
-    rd->char_pos_rel = 0;\r
-\r
-    switch (hlpfile->charset)\r
-    {\r
-    case DEFAULT_CHARSET:\r
-    case ANSI_CHARSET:          cpg = 1252; break;\r
-    case SHIFTJIS_CHARSET:      cpg = 932; break;\r
-    case HANGEUL_CHARSET:       cpg = 949; break;\r
-    case GB2312_CHARSET:        cpg = 936; break;\r
-    case CHINESEBIG5_CHARSET:   cpg = 950; break;\r
-    case GREEK_CHARSET:         cpg = 1253; break;\r
-    case TURKISH_CHARSET:       cpg = 1254; break;\r
-    case HEBREW_CHARSET:        cpg = 1255; break;\r
-    case ARABIC_CHARSET:        cpg = 1256; break;\r
-    case BALTIC_CHARSET:        cpg = 1257; break;\r
-    case VIETNAMESE_CHARSET:    cpg = 1258; break;\r
-    case RUSSIAN_CHARSET:       cpg = 1251; break;\r
-    case EE_CHARSET:            cpg = 1250; break;\r
-    case THAI_CHARSET:          cpg = 874; break;\r
-    case JOHAB_CHARSET:         cpg = 1361; break;\r
-    case MAC_CHARSET:           ck = "mac"; break;\r
-    default:\r
-        WINE_FIXME("Unsupported charset %u\n", hlpfile->charset);\r
-        cpg = 1252;\r
-    }\r
-    if (ck)\r
-    {\r
-        sprintf(tmp, "{\\rtf1\\%s\\deff0", ck);\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;\r
-    }\r
-    else\r
-    {\r
-        sprintf(tmp, "{\\rtf1\\ansi\\ansicpg%d\\deff0", cpg);\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;\r
-    }\r
-\r
-    /* generate font table */\r
-    if (!HLPFILE_RtfAddControl(rd, "{\\fonttbl")) return FALSE;\r
-    for (index = 0; index < hlpfile->numFonts; index++)\r
-    {\r
-        const char* family;\r
-        switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0)\r
-        {\r
-        case FF_MODERN:     family = "modern";  break;\r
-        case FF_ROMAN:      family = "roman";   break;\r
-        case FF_SWISS:      family = "swiss";   break;\r
-        case FF_SCRIPT:     family = "script";  break;\r
-        case FF_DECORATIVE: family = "decor";   break;\r
-        default:            family = "nil";     break;\r
-        }\r
-        sprintf(tmp, "{\\f%d\\f%s\\fprq%d\\fcharset%d %s;}",\r
-                index, family,\r
-                hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0x0F,\r
-                hlpfile->fonts[index].LogFont.lfCharSet,\r
-                hlpfile->fonts[index].LogFont.lfFaceName);\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;\r
-    }\r
-    if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;\r
-    /* generate color table */\r
-    if (!HLPFILE_RtfAddControl(rd, "{\\colortbl ;\\red0\\green128\\blue0;")) return FALSE;\r
-    for (index = 0; index < hlpfile->numFonts; index++)\r
-    {\r
-        const char* family;\r
-        switch (hlpfile->fonts[index].LogFont.lfPitchAndFamily & 0xF0)\r
-        {\r
-        case FF_MODERN:     family = "modern";  break;\r
-        case FF_ROMAN:      family = "roman";   break;\r
-        case FF_SWISS:      family = "swiss";   break;\r
-        case FF_SCRIPT:     family = "script";  break;\r
-        case FF_DECORATIVE: family = "decor";   break;\r
-        default:            family = "nil";     break;\r
-        }\r
-        sprintf(tmp, "\\red%d\\green%d\\blue%d;",\r
-                GetRValue(hlpfile->fonts[index].color),\r
-                GetGValue(hlpfile->fonts[index].color),\r
-                GetBValue(hlpfile->fonts[index].color));\r
-        if (!HLPFILE_RtfAddControl(rd, tmp)) return FALSE;\r
-    }\r
-    if (!HLPFILE_RtfAddControl(rd, "}")) return FALSE;\r
-\r
-    do\r
-    {\r
-        if (hlpfile->version <= 16)\r
-        {\r
-            index  = (ref - 0x0C) / hlpfile->dsize;\r
-            offset = (ref - 0x0C) % hlpfile->dsize;\r
-        }\r
-        else\r
-        {\r
-            index  = (ref - 0x0C) >> 14;\r
-            offset = (ref - 0x0C) & 0x3FFF;\r
-        }\r
-\r
-        if (hlpfile->version <= 16 && index != old_index && old_index != -1)\r
-        {\r
-            /* we jumped to the next block, adjust pointers */\r
-            ref -= 12;\r
-            offset -= 12;\r
-        }\r
-\r
-        if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}\r
-        buf = hlpfile->topic_map[index] + offset;\r
-        if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}\r
-        end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);\r
-        if (index != old_index) {offs = 0; old_index = index;}\r
-\r
-        switch (buf[0x14])\r
-        {\r
-        case 0x02:\r
-            if (count++) goto done;\r
-            break;\r
-        case 0x01:\r
-        case 0x20:\r
-        case 0x23:\r
-            if (!HLPFILE_BrowseParagraph(page, rd, buf, end, &parlen)) return FALSE;\r
-            if (relative > index * 0x8000 + offs)\r
-                rd->char_pos_rel = rd->char_pos;\r
-            offs += parlen;\r
-            break;\r
-        default:\r
-            WINE_ERR("buf[0x14] = %x\n", buf[0x14]);\r
-        }\r
-        if (hlpfile->version <= 16)\r
-        {\r
-            ref += GET_UINT(buf, 0xc);\r
-            if (GET_UINT(buf, 0xc) == 0)\r
-                break;\r
-        }\r
-        else\r
-            ref = GET_UINT(buf, 0xc);\r
-    } while (ref != 0xffffffff);\r
-done:\r
-    page->first_link = rd->first_link;\r
-    return HLPFILE_RtfAddControl(rd, "}");\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_ReadFont\r
- *\r
- *\r
- */\r
-static BOOL HLPFILE_ReadFont(HLPFILE* hlpfile)\r
-{\r
-    BYTE        *ref, *end;\r
-    unsigned    i, len, idx;\r
-    unsigned    face_num, dscr_num, face_offset, dscr_offset;\r
-    BYTE        flag, family;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|FONT", &ref, &end))\r
-    {\r
-        WINE_WARN("no subfile FONT\n");\r
-        hlpfile->numFonts = 0;\r
-        hlpfile->fonts = NULL;\r
-        return FALSE;\r
-    }\r
-\r
-    ref += 9;\r
-\r
-    face_num    = GET_USHORT(ref, 0);\r
-    dscr_num    = GET_USHORT(ref, 2);\r
-    face_offset = GET_USHORT(ref, 4);\r
-    dscr_offset = GET_USHORT(ref, 6);\r
-\r
-    WINE_TRACE("Got NumFacenames=%u@%u NumDesc=%u@%u\n",\r
-               face_num, face_offset, dscr_num, dscr_offset);\r
-\r
-    hlpfile->numFonts = dscr_num;\r
-    hlpfile->fonts = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_FONT) * dscr_num);\r
-\r
-    len = (dscr_offset - face_offset) / face_num;\r
-/* EPP     for (i = face_offset; i < dscr_offset; i += len) */\r
-/* EPP         WINE_FIXME("[%d]: %*s\n", i / len, len, ref + i); */\r
-    for (i = 0; i < dscr_num; i++)\r
-    {\r
-        flag = ref[dscr_offset + i * 11 + 0];\r
-        family = ref[dscr_offset + i * 11 + 2];\r
-\r
-        hlpfile->fonts[i].LogFont.lfHeight = ref[dscr_offset + i * 11 + 1];\r
-        hlpfile->fonts[i].LogFont.lfWidth = 0;\r
-        hlpfile->fonts[i].LogFont.lfEscapement = 0;\r
-        hlpfile->fonts[i].LogFont.lfOrientation = 0;\r
-        hlpfile->fonts[i].LogFont.lfWeight = (flag & 1) ? 700 : 400;\r
-        hlpfile->fonts[i].LogFont.lfItalic = (flag & 2) ? TRUE : FALSE;\r
-        hlpfile->fonts[i].LogFont.lfUnderline = (flag & 4) ? TRUE : FALSE;\r
-        hlpfile->fonts[i].LogFont.lfStrikeOut = (flag & 8) ? TRUE : FALSE;\r
-        hlpfile->fonts[i].LogFont.lfCharSet = hlpfile->charset;\r
-        hlpfile->fonts[i].LogFont.lfOutPrecision = OUT_DEFAULT_PRECIS;\r
-        hlpfile->fonts[i].LogFont.lfClipPrecision = CLIP_DEFAULT_PRECIS;\r
-        hlpfile->fonts[i].LogFont.lfQuality = DEFAULT_QUALITY;\r
-        hlpfile->fonts[i].LogFont.lfPitchAndFamily = DEFAULT_PITCH;\r
-\r
-        switch (family)\r
-        {\r
-        case 0x01: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_MODERN;     break;\r
-        case 0x02: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_ROMAN;      break;\r
-        case 0x03: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SWISS;      break;\r
-        case 0x04: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_SCRIPT;     break;\r
-        case 0x05: hlpfile->fonts[i].LogFont.lfPitchAndFamily |= FF_DECORATIVE; break;\r
-        default: WINE_FIXME("Unknown family %u\n", family);\r
-        }\r
-        idx = GET_USHORT(ref, dscr_offset + i * 11 + 3);\r
-\r
-        if (idx < face_num)\r
-        {\r
-            memcpy(hlpfile->fonts[i].LogFont.lfFaceName, ref + face_offset + idx * len, min(len, LF_FACESIZE - 1));\r
-            hlpfile->fonts[i].LogFont.lfFaceName[min(len, LF_FACESIZE - 1)] = '\0';\r
-        }\r
-        else\r
-        {\r
-            WINE_FIXME("Too high face ref (%u/%u)\n", idx, face_num);\r
-            strcpy(hlpfile->fonts[i].LogFont.lfFaceName, "Helv");\r
-        }\r
-        hlpfile->fonts[i].hFont = 0;\r
-        hlpfile->fonts[i].color = RGB(ref[dscr_offset + i * 11 + 5],\r
-                                      ref[dscr_offset + i * 11 + 6],\r
-                                      ref[dscr_offset + i * 11 + 7]);\r
-#define X(b,s) ((flag & (1 << b)) ? "-"s: "")\r
-        WINE_TRACE("Font[%d]: flags=%02x%s%s%s%s%s%s pSize=%u family=%u face=%s[%u] color=%08x\n",\r
-                   i, flag,\r
-                   X(0, "bold"),\r
-                   X(1, "italic"),\r
-                   X(2, "underline"),\r
-                   X(3, "strikeOut"),\r
-                   X(4, "dblUnderline"),\r
-                   X(5, "smallCaps"),\r
-                   ref[dscr_offset + i * 11 + 1],\r
-                   family,\r
-                   hlpfile->fonts[i].LogFont.lfFaceName, idx,\r
-                   GET_UINT(ref, dscr_offset + i * 11 + 5) & 0x00FFFFFF);\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_ReadFileToBuffer\r
- */\r
-static BOOL HLPFILE_ReadFileToBuffer(HLPFILE* hlpfile, HFILE hFile)\r
-{\r
-    BYTE  header[16], dummy[1];\r
-\r
-    if (_hread(hFile, header, 16) != 16) {WINE_WARN("header\n"); return FALSE;};\r
-\r
-    /* sanity checks */\r
-    if (GET_UINT(header, 0) != 0x00035F3F)\r
-    {WINE_WARN("wrong header\n"); return FALSE;};\r
-\r
-    hlpfile->file_buffer_size = GET_UINT(header, 12);\r
-    hlpfile->file_buffer = HeapAlloc(GetProcessHeap(), 0, hlpfile->file_buffer_size + 1);\r
-    if (!hlpfile->file_buffer) return FALSE;\r
-\r
-    memcpy(hlpfile->file_buffer, header, 16);\r
-    if (_hread(hFile, hlpfile->file_buffer + 16, hlpfile->file_buffer_size - 16) !=hlpfile->file_buffer_size - 16)\r
-    {WINE_WARN("filesize1\n"); return FALSE;};\r
-\r
-    if (_hread(hFile, dummy, 1) != 0) WINE_WARN("filesize2\n");\r
-\r
-    hlpfile->file_buffer[hlpfile->file_buffer_size] = '\0'; /* FIXME: was '0', sounds backwards to me */\r
-\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_SystemCommands\r
- */\r
-static BOOL HLPFILE_SystemCommands(HLPFILE* hlpfile)\r
-{\r
-    BYTE *buf, *ptr, *end;\r
-    HLPFILE_MACRO *macro, **m;\r
-    LPSTR p;\r
-    unsigned short magic, minor, major, flags;\r
-\r
-    hlpfile->lpszTitle = NULL;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|SYSTEM", &buf, &end)) return FALSE;\r
-\r
-    magic = GET_USHORT(buf + 9, 0);\r
-    minor = GET_USHORT(buf + 9, 2);\r
-    major = GET_USHORT(buf + 9, 4);\r
-    /* gen date on 4 bytes */\r
-    flags = GET_USHORT(buf + 9, 10);\r
-    WINE_TRACE("Got system header: magic=%04x version=%d.%d flags=%04x\n",\r
-               magic, major, minor, flags);\r
-    if (magic != 0x036C || major != 1)\r
-    {WINE_WARN("Wrong system header\n"); return FALSE;}\r
-    if (minor <= 16)\r
-    {\r
-        hlpfile->tbsize = 0x800;\r
-        hlpfile->compressed = 0;\r
-    }\r
-    else if (flags == 0)\r
-    {\r
-        hlpfile->tbsize = 0x1000;\r
-        hlpfile->compressed = 0;\r
-    }\r
-    else if (flags == 4)\r
-    {\r
-        hlpfile->tbsize = 0x1000;\r
-        hlpfile->compressed = 1;\r
-    }\r
-    else\r
-    {\r
-        hlpfile->tbsize = 0x800;\r
-        hlpfile->compressed = 1;\r
-    }\r
-\r
-    if (hlpfile->compressed)\r
-        hlpfile->dsize = 0x4000;\r
-    else\r
-        hlpfile->dsize = hlpfile->tbsize - 0x0C;\r
-\r
-    hlpfile->version = minor;\r
-    hlpfile->flags = flags;\r
-    hlpfile->charset = DEFAULT_CHARSET;\r
-\r
-    if (hlpfile->version <= 16)\r
-    {\r
-        char *str = (char*)buf + 0x15;\r
-\r
-        hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);\r
-        if (!hlpfile->lpszTitle) return FALSE;\r
-        lstrcpy(hlpfile->lpszTitle, str);\r
-        WINE_TRACE("Title: %s\n", hlpfile->lpszTitle);\r
-        /* Nothing more to parse */\r
-        return TRUE;\r
-    }\r
-    for (ptr = buf + 0x15; ptr + 4 <= end; ptr += GET_USHORT(ptr, 2) + 4)\r
-    {\r
-        char *str = (char*) ptr + 4;\r
-        switch (GET_USHORT(ptr, 0))\r
-       {\r
-       case 1:\r
-            if (hlpfile->lpszTitle) {WINE_WARN("title\n"); break;}\r
-            hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);\r
-            if (!hlpfile->lpszTitle) return FALSE;\r
-            lstrcpy(hlpfile->lpszTitle, str);\r
-            WINE_TRACE("Title: %s\n", hlpfile->lpszTitle);\r
-            break;\r
-\r
-       case 2:\r
-            if (hlpfile->lpszCopyright) {WINE_WARN("copyright\n"); break;}\r
-            hlpfile->lpszCopyright = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);\r
-            if (!hlpfile->lpszCopyright) return FALSE;\r
-            lstrcpy(hlpfile->lpszCopyright, str);\r
-            WINE_TRACE("Copyright: %s\n", hlpfile->lpszCopyright);\r
-            break;\r
-\r
-       case 3:\r
-            if (GET_USHORT(ptr, 2) != 4) {WINE_WARN("system3\n");break;}\r
-            hlpfile->contents_start = GET_UINT(ptr, 4);\r
-            WINE_TRACE("Setting contents start at %08lx\n", hlpfile->contents_start);\r
-            break;\r
-\r
-       case 4:\r
-            macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + lstrlen(str) + 1);\r
-            if (!macro) break;\r
-            p = (char*)macro + sizeof(HLPFILE_MACRO);\r
-            lstrcpy(p, str);\r
-            macro->lpszMacro = p;\r
-            macro->next = 0;\r
-            for (m = &hlpfile->first_macro; *m; m = &(*m)->next);\r
-            *m = macro;\r
-            break;\r
-\r
-        case 5:\r
-            if (GET_USHORT(ptr, 4 + 4) != 1)\r
-                WINE_FIXME("More than one icon, picking up first\n");\r
-            /* 0x16 is sizeof(CURSORICONDIR), see user32/user_private.h */\r
-            hlpfile->hIcon = CreateIconFromResourceEx(ptr + 4 + 0x16,\r
-                                                      GET_USHORT(ptr, 2) - 0x16, TRUE,\r
-                                                      0x30000, 0, 0, 0);\r
-            break;\r
-\r
-        case 6:\r
-            if (GET_USHORT(ptr, 2) != 90) {WINE_WARN("system6\n");break;}\r
-\r
-           if (hlpfile->windows) \r
-               hlpfile->windows = HeapReAlloc(GetProcessHeap(), 0, hlpfile->windows, \r
-                                           sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows);\r
-           else \r
-               hlpfile->windows = HeapAlloc(GetProcessHeap(), 0, \r
-                                           sizeof(HLPFILE_WINDOWINFO) * ++hlpfile->numWindows);\r
-           \r
-            if (hlpfile->windows)\r
-            {\r
-                unsigned flags = GET_USHORT(ptr, 4);\r
-                HLPFILE_WINDOWINFO* wi = &hlpfile->windows[hlpfile->numWindows - 1];\r
-\r
-                if (flags & 0x0001) strcpy(wi->type, &str[2]);\r
-                else wi->type[0] = '\0';\r
-                if (flags & 0x0002) strcpy(wi->name, &str[12]);\r
-                else wi->name[0] = '\0';\r
-                if (flags & 0x0004) strcpy(wi->caption, &str[21]);\r
-                else lstrcpynA(wi->caption, hlpfile->lpszTitle, sizeof(wi->caption));\r
-                wi->origin.x = (flags & 0x0008) ? GET_USHORT(ptr, 76) : CW_USEDEFAULT;\r
-                wi->origin.y = (flags & 0x0010) ? GET_USHORT(ptr, 78) : CW_USEDEFAULT;\r
-                wi->size.cx = (flags & 0x0020) ? GET_USHORT(ptr, 80) : CW_USEDEFAULT;\r
-                wi->size.cy = (flags & 0x0040) ? GET_USHORT(ptr, 82) : CW_USEDEFAULT;\r
-                wi->style = (flags & 0x0080) ? GET_USHORT(ptr, 84) : SW_SHOW;\r
-                wi->win_style = WS_OVERLAPPEDWINDOW;\r
-                wi->sr_color = (flags & 0x0100) ? GET_UINT(ptr, 86) : 0xFFFFFF;\r
-                wi->nsr_color = (flags & 0x0200) ? GET_UINT(ptr, 90) : 0xFFFFFF;\r
-                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",\r
-                           flags & 0x0001 ? 'T' : 't',\r
-                           flags & 0x0002 ? 'N' : 'n',\r
-                           flags & 0x0004 ? 'C' : 'c',\r
-                           flags & 0x0008 ? 'X' : 'x',\r
-                           flags & 0x0010 ? 'Y' : 'y',\r
-                           flags & 0x0020 ? 'W' : 'w',\r
-                           flags & 0x0040 ? 'H' : 'h',\r
-                           flags & 0x0080 ? 'S' : 's',\r
-                           wi->type, wi->name, wi->caption, wi->origin.x, wi->origin.y,\r
-                           wi->size.cx, wi->size.cy);\r
-            }\r
-            break;\r
-        case 8:\r
-            WINE_WARN("Citation: '%s'\n", ptr + 4);\r
-            break;\r
-        case 11:\r
-            hlpfile->charset = ptr[4];\r
-            WINE_TRACE("Charset: %d\n", hlpfile->charset);\r
-            break;\r
-       default:\r
-            WINE_WARN("Unsupported SystemRecord[%d]\n", GET_USHORT(ptr, 0));\r
-       }\r
-    }\r
-    if (!hlpfile->lpszTitle)\r
-        hlpfile->lpszTitle = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 1);\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_GetContext\r
- */\r
-static BOOL HLPFILE_GetContext(HLPFILE *hlpfile)\r
-{\r
-    BYTE                *cbuf, *cend;\r
-    unsigned            clen;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|CONTEXT",  &cbuf, &cend))\r
-    {WINE_WARN("context0\n"); return FALSE;}\r
-\r
-    clen = cend - cbuf;\r
-    hlpfile->Context = HeapAlloc(GetProcessHeap(), 0, clen);\r
-    if (!hlpfile->Context) return FALSE;\r
-    memcpy(hlpfile->Context, cbuf, clen);\r
-\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_GetKeywords\r
- */\r
-static BOOL HLPFILE_GetKeywords(HLPFILE *hlpfile)\r
-{\r
-    BYTE                *cbuf, *cend;\r
-    unsigned            clen;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|KWBTREE", &cbuf, &cend)) return FALSE;\r
-    clen = cend - cbuf;\r
-    hlpfile->kwbtree = HeapAlloc(GetProcessHeap(), 0, clen);\r
-    if (!hlpfile->kwbtree) return FALSE;\r
-    memcpy(hlpfile->kwbtree, cbuf, clen);\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|KWDATA", &cbuf, &cend))\r
-    {\r
-        WINE_ERR("corrupted help file: kwbtree present but kwdata absent\n");\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->kwbtree);\r
-        return FALSE;\r
-    }\r
-    clen = cend - cbuf;\r
-    hlpfile->kwdata = HeapAlloc(GetProcessHeap(), 0, clen);\r
-    if (!hlpfile->kwdata)\r
-    {\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->kwdata);\r
-        return FALSE;\r
-    }\r
-    memcpy(hlpfile->kwdata, cbuf, clen);\r
-\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_GetMap\r
- */\r
-static BOOL HLPFILE_GetMap(HLPFILE *hlpfile)\r
-{\r
-    BYTE                *cbuf, *cend;\r
-    unsigned            entries, i;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|CTXOMAP",  &cbuf, &cend))\r
-    {WINE_WARN("no map section\n"); return FALSE;}\r
-\r
-    entries = GET_USHORT(cbuf, 9);\r
-    hlpfile->Map = HeapAlloc(GetProcessHeap(), 0, entries * sizeof(HLPFILE_MAP));\r
-    if (!hlpfile->Map) return FALSE;\r
-    hlpfile->wMapLen = entries;\r
-    for (i = 0; i < entries; i++)\r
-    {\r
-        hlpfile->Map[i].lMap = GET_UINT(cbuf+11,i*8);\r
-        hlpfile->Map[i].offset = GET_UINT(cbuf+11,i*8+4);\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_GetTOMap\r
- */\r
-static BOOL HLPFILE_GetTOMap(HLPFILE *hlpfile)\r
-{\r
-    BYTE                *cbuf, *cend;\r
-    unsigned            clen;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|TOMAP",  &cbuf, &cend))\r
-    {WINE_WARN("no tomap section\n"); return FALSE;}\r
-\r
-    clen = cend - cbuf - 9;\r
-    hlpfile->TOMap = HeapAlloc(GetProcessHeap(), 0, clen);\r
-    if (!hlpfile->TOMap) return FALSE;\r
-    memcpy(hlpfile->TOMap, cbuf+9, clen);\r
-    hlpfile->wTOMapLen = clen/4;\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           DeleteMacro\r
- */\r
-static void HLPFILE_DeleteMacro(HLPFILE_MACRO* macro)\r
-{\r
-    HLPFILE_MACRO*      next;\r
-\r
-    while (macro)\r
-    {\r
-        next = macro->next;\r
-        HeapFree(GetProcessHeap(), 0, macro);\r
-        macro = next;\r
-    }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           DeletePage\r
- */\r
-static void HLPFILE_DeletePage(HLPFILE_PAGE* page)\r
-{\r
-    HLPFILE_PAGE* next;\r
-\r
-    while (page)\r
-    {\r
-        next = page->next;\r
-        HLPFILE_DeleteMacro(page->first_macro);\r
-        HeapFree(GetProcessHeap(), 0, page);\r
-        page = next;\r
-    }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_FreeHlpFile\r
- */\r
-void HLPFILE_FreeHlpFile(HLPFILE* hlpfile)\r
-{\r
-    unsigned i;\r
-\r
-    if (!hlpfile || --hlpfile->wRefCount > 0) return;\r
-\r
-    if (hlpfile->next) hlpfile->next->prev = hlpfile->prev;\r
-    if (hlpfile->prev) hlpfile->prev->next = hlpfile->next;\r
-    else first_hlpfile = hlpfile->next;\r
-\r
-    if (hlpfile->numFonts)\r
-    {\r
-        for (i = 0; i < hlpfile->numFonts; i++)\r
-        {\r
-            DeleteObject(hlpfile->fonts[i].hFont);\r
-        }\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->fonts);\r
-    }\r
-\r
-    if (hlpfile->numBmps)\r
-    {\r
-        for (i = 0; i < hlpfile->numBmps; i++)\r
-        {\r
-            DeleteObject(hlpfile->bmps[i]);\r
-        }\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->bmps);\r
-    }\r
-\r
-    HLPFILE_DeletePage(hlpfile->first_page);\r
-    HLPFILE_DeleteMacro(hlpfile->first_macro);\r
-\r
-    DestroyIcon(hlpfile->hIcon);\r
-    if (hlpfile->numWindows)    HeapFree(GetProcessHeap(), 0, hlpfile->windows);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->Context);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->Map);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->lpszTitle);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->lpszCopyright);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->file_buffer);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->topic_map);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile->help_on_file);\r
-    HeapFree(GetProcessHeap(), 0, hlpfile);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_UncompressLZ77_Phrases\r
- */\r
-static BOOL HLPFILE_UncompressLZ77_Phrases(HLPFILE* hlpfile)\r
-{\r
-    UINT i, num, dec_size, head_size;\r
-    BYTE *buf, *end;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|Phrases", &buf, &end)) return FALSE;\r
-\r
-    if (hlpfile->version <= 16)\r
-        head_size = 13;\r
-    else\r
-        head_size = 17;\r
-\r
-    num = hlpfile->num_phrases = GET_USHORT(buf, 9);\r
-    if (buf + 2 * num + 0x13 >= end) {WINE_WARN("1a\n"); return FALSE;};\r
-\r
-    if (hlpfile->version <= 16)\r
-        dec_size = end - buf - 15 - 2 * num;\r
-    else\r
-        dec_size = HLPFILE_UncompressedLZ77_Size(buf + 0x13 + 2 * num, end);\r
-\r
-    hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));\r
-    hlpfile->phrases_buffer  = HeapAlloc(GetProcessHeap(), 0, dec_size);\r
-    if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer)\r
-    {\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);\r
-        return FALSE;\r
-    }\r
-\r
-    for (i = 0; i <= num; i++)\r
-        hlpfile->phrases_offsets[i] = GET_USHORT(buf, head_size + 2 * i) - 2 * num - 2;\r
-\r
-    if (hlpfile->version <= 16)\r
-        memcpy(hlpfile->phrases_buffer, buf + 15 + 2*num, dec_size);\r
-    else\r
-        HLPFILE_UncompressLZ77(buf + 0x13 + 2 * num, end, (BYTE*)hlpfile->phrases_buffer);\r
-\r
-    hlpfile->hasPhrases = TRUE;\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_Uncompress_Phrases40\r
- */\r
-static BOOL HLPFILE_Uncompress_Phrases40(HLPFILE* hlpfile)\r
-{\r
-    UINT num;\r
-    INT dec_size, cpr_size;\r
-    BYTE *buf_idx, *end_idx;\r
-    BYTE *buf_phs, *end_phs;\r
-    LONG* ptr, mask = 0;\r
-    unsigned int i;\r
-    unsigned short bc, n;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|PhrIndex", &buf_idx, &end_idx) ||\r
-        !HLPFILE_FindSubFile(hlpfile, "|PhrImage", &buf_phs, &end_phs)) return FALSE;\r
-\r
-    ptr = (LONG*)(buf_idx + 9 + 28);\r
-    bc = GET_USHORT(buf_idx, 9 + 24) & 0x0F;\r
-    num = hlpfile->num_phrases = GET_USHORT(buf_idx, 9 + 4);\r
-\r
-    WINE_TRACE("Index: Magic=%08x #entries=%u CpsdSize=%u PhrImgSize=%u\n"\r
-               "\tPhrImgCprsdSize=%u 0=%u bc=%x ukn=%x\n",\r
-               GET_UINT(buf_idx, 9 + 0),\r
-               GET_UINT(buf_idx, 9 + 4),\r
-               GET_UINT(buf_idx, 9 + 8),\r
-               GET_UINT(buf_idx, 9 + 12),\r
-               GET_UINT(buf_idx, 9 + 16),\r
-               GET_UINT(buf_idx, 9 + 20),\r
-               GET_USHORT(buf_idx, 9 + 24),\r
-               GET_USHORT(buf_idx, 9 + 26));\r
-\r
-    dec_size = GET_UINT(buf_idx, 9 + 12);\r
-    cpr_size = GET_UINT(buf_idx, 9 + 16);\r
-\r
-    if (dec_size != cpr_size &&\r
-        dec_size != HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs))\r
-    {\r
-        WINE_WARN("size mismatch %u %u\n",\r
-                  dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs));\r
-        dec_size = max(dec_size, HLPFILE_UncompressedLZ77_Size(buf_phs + 9, end_phs));\r
-    }\r
-\r
-    hlpfile->phrases_offsets = HeapAlloc(GetProcessHeap(), 0, sizeof(unsigned) * (num + 1));\r
-    hlpfile->phrases_buffer  = HeapAlloc(GetProcessHeap(), 0, dec_size);\r
-    if (!hlpfile->phrases_offsets || !hlpfile->phrases_buffer)\r
-    {\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->phrases_offsets);\r
-        HeapFree(GetProcessHeap(), 0, hlpfile->phrases_buffer);\r
-        return FALSE;\r
-    }\r
-\r
-#define getbit() (ptr += (mask < 0), mask = mask*2 + (mask<=0), (*ptr & mask) != 0)\r
-\r
-    hlpfile->phrases_offsets[0] = 0;\r
-    for (i = 0; i < num; i++)\r
-    {\r
-        for (n = 1; getbit(); n += 1 << bc);\r
-        if (getbit()) n++;\r
-        if (bc > 1 && getbit()) n += 2;\r
-        if (bc > 2 && getbit()) n += 4;\r
-        if (bc > 3 && getbit()) n += 8;\r
-        if (bc > 4 && getbit()) n += 16;\r
-        hlpfile->phrases_offsets[i + 1] = hlpfile->phrases_offsets[i] + n;\r
-    }\r
-#undef getbit\r
-\r
-    if (dec_size == cpr_size)\r
-        memcpy(hlpfile->phrases_buffer, buf_phs + 9, dec_size);\r
-    else\r
-        HLPFILE_UncompressLZ77(buf_phs + 9, end_phs, (BYTE*)hlpfile->phrases_buffer);\r
-\r
-    hlpfile->hasPhrases40 = TRUE;\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_Uncompress_Topic\r
- */\r
-static BOOL HLPFILE_Uncompress_Topic(HLPFILE* hlpfile)\r
-{\r
-    BYTE *buf, *ptr, *end, *newptr;\r
-    unsigned int i, newsize = 0;\r
-    unsigned int topic_size;\r
-\r
-    if (!HLPFILE_FindSubFile(hlpfile, "|TOPIC", &buf, &end))\r
-    {WINE_WARN("topic0\n"); return FALSE;}\r
-\r
-    buf += 9; /* Skip file header */\r
-    topic_size = end - buf;\r
-    if (hlpfile->compressed)\r
-    {\r
-        hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1;\r
-\r
-        for (i = 0; i < hlpfile->topic_maplen; i++)\r
-        {\r
-            ptr = buf + i * hlpfile->tbsize;\r
-\r
-            /* I don't know why, it's necessary for printman.hlp */\r
-            if (ptr + 0x44 > end) ptr = end - 0x44;\r
-\r
-            newsize += HLPFILE_UncompressedLZ77_Size(ptr + 0xc, min(end, ptr + hlpfile->tbsize));\r
-        }\r
-\r
-        hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0,\r
-                                       hlpfile->topic_maplen * sizeof(hlpfile->topic_map[0]) + newsize);\r
-        if (!hlpfile->topic_map) return FALSE;\r
-        newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen);\r
-        hlpfile->topic_end = newptr + newsize;\r
-\r
-        for (i = 0; i < hlpfile->topic_maplen; i++)\r
-        {\r
-            ptr = buf + i * hlpfile->tbsize;\r
-            if (ptr + 0x44 > end) ptr = end - 0x44;\r
-\r
-            hlpfile->topic_map[i] = newptr;\r
-            newptr = HLPFILE_UncompressLZ77(ptr + 0xc, min(end, ptr + hlpfile->tbsize), newptr);\r
-        }\r
-    }\r
-    else\r
-    {\r
-        /* basically, we need to copy the TopicBlockSize byte pages\r
-         * (removing the first 0x0C) in one single area in memory\r
-         */\r
-        hlpfile->topic_maplen = (topic_size - 1) / hlpfile->tbsize + 1;\r
-        hlpfile->topic_map = HeapAlloc(GetProcessHeap(), 0,\r
-                                       hlpfile->topic_maplen * (sizeof(hlpfile->topic_map[0]) + hlpfile->dsize));\r
-        if (!hlpfile->topic_map) return FALSE;\r
-        newptr = (BYTE*)(hlpfile->topic_map + hlpfile->topic_maplen);\r
-        hlpfile->topic_end = newptr + topic_size;\r
-\r
-        for (i = 0; i < hlpfile->topic_maplen; i++)\r
-        {\r
-            hlpfile->topic_map[i] = newptr + i * hlpfile->dsize;\r
-            memcpy(hlpfile->topic_map[i], buf + i * hlpfile->tbsize + 0x0C, hlpfile->dsize);\r
-        }\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_AddPage\r
- */\r
-static BOOL HLPFILE_AddPage(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned ref, unsigned offset)\r
-{\r
-    HLPFILE_PAGE* page;\r
-    const BYTE*   title;\r
-    UINT          titlesize, blocksize, datalen;\r
-    char*         ptr;\r
-    HLPFILE_MACRO*macro;\r
-\r
-    blocksize = GET_UINT(buf, 0);\r
-    datalen = GET_UINT(buf, 0x10);\r
-    title = buf + datalen;\r
-    if (title > end) {WINE_WARN("page2\n"); return FALSE;};\r
-\r
-    titlesize = GET_UINT(buf, 4);\r
-    page = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_PAGE) + titlesize + 1);\r
-    if (!page) return FALSE;\r
-    page->lpszTitle = (char*)page + sizeof(HLPFILE_PAGE);\r
-\r
-    if (titlesize > blocksize - datalen)\r
-    {\r
-        /* need to decompress */\r
-        if (hlpfile->hasPhrases)\r
-            HLPFILE_Uncompress2(hlpfile, title, end, (BYTE*)page->lpszTitle, (BYTE*)page->lpszTitle + titlesize);\r
-        else if (hlpfile->hasPhrases40)\r
-            HLPFILE_Uncompress3(hlpfile, page->lpszTitle, page->lpszTitle + titlesize, title, end);\r
-        else\r
-        {\r
-            WINE_FIXME("Text size is too long, splitting\n");\r
-            titlesize = blocksize - datalen;\r
-            memcpy(page->lpszTitle, title, titlesize);\r
-        }\r
-    }\r
-    else\r
-        memcpy(page->lpszTitle, title, titlesize);\r
-\r
-    page->lpszTitle[titlesize] = '\0';\r
-\r
-    if (hlpfile->first_page)\r
-    {\r
-        hlpfile->last_page->next = page;\r
-        page->prev = hlpfile->last_page;\r
-        hlpfile->last_page = page;\r
-    }\r
-    else\r
-    {\r
-        hlpfile->first_page = page;\r
-        hlpfile->last_page = page;\r
-        page->prev = NULL;\r
-    }\r
-\r
-    page->file            = hlpfile;\r
-    page->next            = NULL;\r
-    page->first_macro     = NULL;\r
-    page->first_link      = NULL;\r
-    page->wNumber         = GET_UINT(buf, 0x21);\r
-    page->offset          = offset;\r
-    page->reference       = ref;\r
-\r
-    page->browse_bwd = GET_UINT(buf, 0x19);\r
-    page->browse_fwd = GET_UINT(buf, 0x1D);\r
-\r
-    if (hlpfile->version <= 16)\r
-    {\r
-        if (page->browse_bwd == 0xFFFF || page->browse_bwd == 0xFFFFFFFF)\r
-            page->browse_bwd = 0xFFFFFFFF;\r
-        else\r
-            page->browse_bwd = hlpfile->TOMap[page->browse_bwd];\r
-\r
-        if (page->browse_fwd == 0xFFFF || page->browse_fwd == 0xFFFFFFFF)\r
-            page->browse_fwd = 0xFFFFFFFF;\r
-        else\r
-            page->browse_fwd = hlpfile->TOMap[page->browse_fwd];\r
-    }\r
-\r
-    WINE_TRACE("Added page[%d]: title='%s' %08x << %08x >> %08x\n",\r
-               page->wNumber, page->lpszTitle,\r
-               page->browse_bwd, page->offset, page->browse_fwd);\r
-\r
-    /* now load macros */\r
-    ptr = page->lpszTitle + strlen(page->lpszTitle) + 1;\r
-    while (ptr < page->lpszTitle + titlesize)\r
-    {\r
-        unsigned len = strlen(ptr);\r
-        char*    macro_str;\r
-\r
-        WINE_TRACE("macro: %s\n", ptr);\r
-        macro = HeapAlloc(GetProcessHeap(), 0, sizeof(HLPFILE_MACRO) + len + 1);\r
-        macro->lpszMacro = macro_str = (char*)(macro + 1);\r
-        memcpy(macro_str, ptr, len + 1);\r
-        /* FIXME: shall we really link macro in reverse order ??\r
-         * may produce strange results when played at page opening\r
-         */\r
-        macro->next = page->first_macro;\r
-        page->first_macro = macro;\r
-        ptr += len + 1;\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_SkipParagraph\r
- */\r
-static BOOL HLPFILE_SkipParagraph(HLPFILE *hlpfile, const BYTE *buf, const BYTE *end, unsigned* len)\r
-{\r
-    const BYTE  *tmp;\r
-\r
-    if (!hlpfile->first_page) {WINE_WARN("no page\n"); return FALSE;};\r
-    if (buf + 0x19 > end) {WINE_WARN("header too small\n"); return FALSE;};\r
-\r
-    tmp = buf + 0x15;\r
-    if (buf[0x14] == 0x20 || buf[0x14] == 0x23)\r
-    {\r
-        fetch_long(&tmp);\r
-        *len = fetch_ushort(&tmp);\r
-    }\r
-    else *len = end-buf-15;\r
-\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_DoReadHlpFile\r
- */\r
-static BOOL HLPFILE_DoReadHlpFile(HLPFILE *hlpfile, LPCSTR lpszPath)\r
-{\r
-    BOOL        ret;\r
-    HFILE       hFile;\r
-    OFSTRUCT    ofs;\r
-    BYTE*       buf;\r
-    DWORD       ref = 0x0C;\r
-    unsigned    index, old_index, offset, len, offs, topicoffset;\r
-\r
-    hFile = OpenFile(lpszPath, &ofs, OF_READ);\r
-    if (hFile == HFILE_ERROR) return FALSE;\r
-\r
-    ret = HLPFILE_ReadFileToBuffer(hlpfile, hFile);\r
-    _lclose(hFile);\r
-    if (!ret) return FALSE;\r
-\r
-    if (!HLPFILE_SystemCommands(hlpfile)) return FALSE;\r
-\r
-    if (hlpfile->version <= 16 && !HLPFILE_GetTOMap(hlpfile)) return FALSE;\r
-\r
-    /* load phrases support */\r
-    if (!HLPFILE_UncompressLZ77_Phrases(hlpfile))\r
-        HLPFILE_Uncompress_Phrases40(hlpfile);\r
-\r
-    if (!HLPFILE_Uncompress_Topic(hlpfile)) return FALSE;\r
-    if (!HLPFILE_ReadFont(hlpfile)) return FALSE;\r
-\r
-    buf = hlpfile->topic_map[0];\r
-    old_index = -1;\r
-    offs = 0;\r
-    do\r
-    {\r
-        BYTE*   end;\r
-\r
-        if (hlpfile->version <= 16)\r
-        {\r
-            index  = (ref - 0x0C) / hlpfile->dsize;\r
-            offset = (ref - 0x0C) % hlpfile->dsize;\r
-        }\r
-        else\r
-        {\r
-            index  = (ref - 0x0C) >> 14;\r
-            offset = (ref - 0x0C) & 0x3FFF;\r
-        }\r
-\r
-        if (hlpfile->version <= 16 && index != old_index && old_index != -1)\r
-        {\r
-            /* we jumped to the next block, adjust pointers */\r
-            ref -= 12;\r
-            offset -= 12;\r
-        }\r
-\r
-        WINE_TRACE("ref=%08x => [%u/%u]\n", ref, index, offset);\r
-\r
-        if (index >= hlpfile->topic_maplen) {WINE_WARN("maplen\n"); break;}\r
-        buf = hlpfile->topic_map[index] + offset;\r
-        if (buf + 0x15 >= hlpfile->topic_end) {WINE_WARN("extra\n"); break;}\r
-        end = min(buf + GET_UINT(buf, 0), hlpfile->topic_end);\r
-        if (index != old_index) {offs = 0; old_index = index;}\r
-\r
-        switch (buf[0x14])\r
-       {\r
-       case 0x02:\r
-            if (hlpfile->version <= 16)\r
-                topicoffset = ref + index * 12;\r
-            else\r
-                topicoffset = index * 0x8000 + offs;\r
-            if (!HLPFILE_AddPage(hlpfile, buf, end, ref, topicoffset)) return FALSE;\r
-            break;\r
-\r
-       case 0x01:\r
-       case 0x20:\r
-       case 0x23:\r
-            if (!HLPFILE_SkipParagraph(hlpfile, buf, end, &len)) return FALSE;\r
-            offs += len;\r
-            break;\r
-\r
-       default:\r
-            WINE_ERR("buf[0x14] = %x\n", buf[0x14]);\r
-       }\r
-\r
-        if (hlpfile->version <= 16)\r
-        {\r
-            ref += GET_UINT(buf, 0xc);\r
-            if (GET_UINT(buf, 0xc) == 0)\r
-                break;\r
-        }\r
-        else\r
-            ref = GET_UINT(buf, 0xc);\r
-    } while (ref != 0xffffffff);\r
-\r
-    HLPFILE_GetKeywords(hlpfile);\r
-    HLPFILE_GetMap(hlpfile);\r
-    if (hlpfile->version <= 16) return TRUE;\r
-    return HLPFILE_GetContext(hlpfile);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           HLPFILE_ReadHlpFile\r
- */\r
-HLPFILE *HLPFILE_ReadHlpFile(LPCSTR lpszPath)\r
-{\r
-    HLPFILE*      hlpfile;\r
-\r
-    for (hlpfile = first_hlpfile; hlpfile; hlpfile = hlpfile->next)\r
-    {\r
-        if (!strcmp(lpszPath, hlpfile->lpszPath))\r
-        {\r
-            hlpfile->wRefCount++;\r
-            return hlpfile;\r
-        }\r
-    }\r
-\r
-    hlpfile = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
-                        sizeof(HLPFILE) + lstrlen(lpszPath) + 1);\r
-    if (!hlpfile) return 0;\r
-\r
-    hlpfile->lpszPath           = (char*)hlpfile + sizeof(HLPFILE);\r
-    hlpfile->contents_start     = 0xFFFFFFFF;\r
-    hlpfile->next               = first_hlpfile;\r
-    hlpfile->wRefCount          = 1;\r
-\r
-    strcpy(hlpfile->lpszPath, lpszPath);\r
-\r
-    first_hlpfile = hlpfile;\r
-    if (hlpfile->next) hlpfile->next->prev = hlpfile;\r
-\r
-    if (!HLPFILE_DoReadHlpFile(hlpfile, lpszPath))\r
-    {\r
-        HLPFILE_FreeHlpFile(hlpfile);\r
-        hlpfile = 0;\r
-    }\r
-\r
-    return hlpfile;\r
-}\r
+/*
+ * 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 <stdarg.h>
+#include <stdio.h>
+#include <string.h>
+
+#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;
+}
index 590c0bc..0e3f35e 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright    1996 Ulrich Schmid\r
- *              2002, 2008 Eric Pouech\r
- *              2007 Kirill K. Smirnov\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-struct tagHelpFile;\r
-\r
-typedef struct \r
-{\r
-    char        type[10];\r
-    char        name[9];\r
-    char        caption[51];\r
-    POINT       origin;\r
-    SIZE        size;\r
-    int         style;\r
-    DWORD       win_style;\r
-    COLORREF    sr_color;       /* color for scrollable region */\r
-    COLORREF    nsr_color;      /* color for non scrollable region */\r
-} HLPFILE_WINDOWINFO;\r
-\r
-typedef struct tagHlpFileLink\r
-{\r
-    enum {hlp_link_link, hlp_link_popup, hlp_link_macro} cookie;\r
-    LPCSTR      string;         /* name of the file to for the link (NULL if same file) */\r
-    LONG        hash;           /* topic index */\r
-    unsigned    bClrChange : 1; /* true if the link is green & underlined */\r
-    unsigned    window;         /* window number for displaying the link (-1 is current) */\r
-    DWORD       cpMin;\r
-    DWORD       cpMax;\r
-    struct tagHlpFileLink* next;\r
-} HLPFILE_LINK;\r
-\r
-typedef struct tagHlpFileMacro\r
-{\r
-    LPCSTR                      lpszMacro;\r
-    struct tagHlpFileMacro*     next;\r
-} HLPFILE_MACRO;\r
-\r
-typedef struct tagHlpFilePage\r
-{\r
-    LPSTR                       lpszTitle;\r
-    HLPFILE_MACRO*              first_macro;\r
-\r
-    HLPFILE_LINK*               first_link;\r
-\r
-    unsigned                    wNumber;\r
-    unsigned                    offset;\r
-    DWORD                       reference;\r
-    struct tagHlpFilePage*      next;\r
-    struct tagHlpFilePage*      prev;\r
-\r
-    DWORD                       browse_bwd;\r
-    DWORD                       browse_fwd;\r
-\r
-    struct tagHlpFileFile*      file;\r
-} HLPFILE_PAGE;\r
-\r
-typedef struct\r
-{\r
-    LONG                        lMap;\r
-    unsigned long               offset;\r
-} HLPFILE_MAP;\r
-\r
-typedef struct\r
-{\r
-    LOGFONT                     LogFont;\r
-    HFONT                       hFont;\r
-    COLORREF                    color;\r
-} HLPFILE_FONT;\r
-\r
-typedef struct tagHlpFileFile\r
-{\r
-    BYTE*                       file_buffer;\r
-    UINT                        file_buffer_size;\r
-    LPSTR                       lpszPath;\r
-    LPSTR                       lpszTitle;\r
-    LPSTR                       lpszCopyright;\r
-    HLPFILE_PAGE*               first_page;\r
-    HLPFILE_PAGE*               last_page;\r
-    HLPFILE_MACRO*              first_macro;\r
-    BYTE*                       Context;\r
-    BYTE*                       kwbtree;\r
-    BYTE*                       kwdata;\r
-    unsigned                    wMapLen;\r
-    HLPFILE_MAP*                Map;\r
-    unsigned                    wTOMapLen;\r
-    unsigned*                   TOMap;\r
-    unsigned long               contents_start;\r
-\r
-    struct tagHlpFileFile*      prev;\r
-    struct tagHlpFileFile*      next;\r
-\r
-    unsigned                    wRefCount;\r
-\r
-    unsigned short              version;\r
-    unsigned short              flags;\r
-    unsigned short              charset;\r
-    unsigned short              tbsize;     /* topic block size */\r
-    unsigned short              dsize;      /* decompress size */\r
-    unsigned short              compressed;\r
-    unsigned                    hasPhrases;   /* file has |Phrases */\r
-    unsigned                    hasPhrases40; /* file has |PhrIndex/|PhrImage */\r
-    UINT                        num_phrases;\r
-    unsigned*                   phrases_offsets;\r
-    char*                       phrases_buffer;\r
-\r
-    BYTE**                      topic_map;\r
-    BYTE*                       topic_end;\r
-    UINT                        topic_maplen;\r
-\r
-    unsigned                    numBmps;\r
-    HBITMAP*                    bmps;\r
-\r
-    unsigned                    numFonts;\r
-    HLPFILE_FONT*               fonts;\r
-\r
-    unsigned                    numWindows;\r
-    HLPFILE_WINDOWINFO*         windows;\r
-    HICON                       hIcon;\r
-\r
-    BOOL                        has_popup_color;\r
-    COLORREF                    popup_color;\r
-\r
-    LPSTR                       help_on_file;\r
-} HLPFILE;\r
-\r
-/*\r
- * Compare function type for HLPFILE_BPTreeSearch function.\r
- *\r
- * PARAMS\r
- *     p       [I] pointer to testing block (key + data)\r
- *     key     [I] pointer to key value to look for\r
- *     leaf    [I] whether this function called for index of leaf page\r
- *     next    [O] pointer to pointer to next block\r
- */\r
-typedef int (*HLPFILE_BPTreeCompare)(void *p, const void *key,\r
-                                     int leaf, void **next);\r
-\r
-/*\r
- * Callback function type for HLPFILE_BPTreeEnum function.\r
- *\r
- * PARAMS\r
- *     p       [I]  pointer to data block\r
- *     next    [O]  pointer to pointer to next block\r
- *     cookie  [IO] cookie data\r
- */\r
-typedef void (*HLPFILE_BPTreeCallback)(void *p, void **next, void *cookie);\r
-\r
-HLPFILE*      HLPFILE_ReadHlpFile(LPCSTR lpszPath);\r
-HLPFILE_PAGE* HLPFILE_PageByHash(HLPFILE* hlpfile, LONG lHash, ULONG* relative);\r
-HLPFILE_PAGE* HLPFILE_PageByMap(HLPFILE* hlpfile, LONG lMap, ULONG* relative);\r
-HLPFILE_PAGE* HLPFILE_PageByOffset(HLPFILE* hlpfile, LONG offset, ULONG* relative);\r
-LONG          HLPFILE_Hash(LPCSTR lpszContext);\r
-void          HLPFILE_FreeHlpFile(HLPFILE*);\r
-\r
-void  HLPFILE_BPTreeEnum(BYTE*, HLPFILE_BPTreeCallback cb, void *cookie);\r
-\r
-struct RtfData {\r
-    BOOL        in_text;\r
-    char*       data;           /* RTF stream start */\r
-    char*       ptr;            /* current position in stream */\r
-    unsigned    allocated;      /* overall allocated size */\r
-    unsigned    char_pos;       /* current char position (in richedit) */\r
-    char*       where;          /* pointer to feed back richedit */\r
-    unsigned    font_scale;     /* how to scale fonts */\r
-    HLPFILE_LINK*first_link;\r
-    HLPFILE_LINK*current_link;\r
-    BOOL        force_color;\r
-    unsigned    relative;       /* offset within page to lookup for */\r
-    unsigned    char_pos_rel;   /* char_pos correspondinf to relative */\r
-};\r
-\r
-BOOL          HLPFILE_BrowsePage(HLPFILE_PAGE*, struct RtfData* rd,\r
-                                 unsigned font_scale, unsigned relative);\r
+/*
+ * 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);
index c91bc9e..b1d60a8 100644 (file)
-/* A lexical scanner generated by flex */\r
-\r
-/* Scanner skeleton version:\r
- * $Header: /home/daffy/u0/vern/flex/RCS/flex.skl,v 2.91 96/09/10 16:58:48 vern Exp $\r
- */\r
-\r
-#define FLEX_SCANNER\r
-#define YY_FLEX_MAJOR_VERSION 2\r
-#define YY_FLEX_MINOR_VERSION 5\r
-\r
-#include <stdio.h>\r
-\r
-\r
-/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */\r
-#ifdef c_plusplus\r
-#ifndef __cplusplus\r
-#define __cplusplus\r
-#endif\r
-#endif\r
-\r
-\r
-#ifdef __cplusplus\r
-\r
-#include <stdlib.h>\r
-#include <unistd.h>\r
-\r
-/* Use prototypes in function declarations. */\r
-#define YY_USE_PROTOS\r
-\r
-/* The "const" storage-class-modifier is valid. */\r
-#define YY_USE_CONST\r
-\r
-#else  /* ! __cplusplus */\r
-\r
-#if __STDC__\r
-\r
-#define YY_USE_PROTOS\r
-#define YY_USE_CONST\r
-\r
-#endif /* __STDC__ */\r
-#endif /* ! __cplusplus */\r
-\r
-#ifdef __TURBOC__\r
- #pragma warn -rch\r
- #pragma warn -use\r
-#include <io.h>\r
-#include <stdlib.h>\r
-#define YY_USE_CONST\r
-#define YY_USE_PROTOS\r
-#endif\r
-\r
-#ifdef YY_USE_CONST\r
-#define yyconst const\r
-#else\r
-#define yyconst\r
-#endif\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-#define YY_PROTO(proto) proto\r
-#else\r
-#define YY_PROTO(proto) ()\r
-#endif\r
-\r
-/* Returned upon end-of-file. */\r
-#define YY_NULL 0\r
-\r
-/* Promotes a possibly negative, possibly signed char to an unsigned\r
- * integer for use as an array index.  If the signed char is negative,\r
- * we want to instead treat it as an 8-bit unsigned char, hence the\r
- * double cast.\r
- */\r
-#define YY_SC_TO_UI(c) ((unsigned int) (unsigned char) c)\r
-\r
-/* Enter a start condition.  This macro really ought to take a parameter,\r
- * but we do it the disgusting crufty way forced on us by the ()-less\r
- * definition of BEGIN.\r
- */\r
-#define BEGIN yy_start = 1 + 2 *\r
-\r
-/* Translate the current start state into a value that can be later handed\r
- * to BEGIN to return to the state.  The YYSTATE alias is for lex\r
- * compatibility.\r
- */\r
-#define YY_START ((yy_start - 1) / 2)\r
-#define YYSTATE YY_START\r
-\r
-/* Action number for EOF rule of a given start state. */\r
-#define YY_STATE_EOF(state) (YY_END_OF_BUFFER + state + 1)\r
-\r
-/* Special action meaning "start processing a new file". */\r
-#define YY_NEW_FILE yyrestart( yyin )\r
-\r
-#define YY_END_OF_BUFFER_CHAR 0\r
-\r
-/* Size of default input buffer. */\r
-#define YY_BUF_SIZE 16384\r
-\r
-typedef struct yy_buffer_state *YY_BUFFER_STATE;\r
-\r
-extern int yyleng;\r
-extern FILE *yyin, *yyout;\r
-\r
-#define EOB_ACT_CONTINUE_SCAN 0\r
-#define EOB_ACT_END_OF_FILE 1\r
-#define EOB_ACT_LAST_MATCH 2\r
-\r
-/* The funky do-while in the following #define is used to turn the definition\r
- * int a single C statement (which needs a semi-colon terminator).  This\r
- * avoids problems with code like:\r
- *\r
- *     if ( condition_holds )\r
- *             yyless( 5 );\r
- *     else\r
- *             do_something_else();\r
- *\r
- * Prior to using the do-while the compiler would get upset at the\r
- * "else" because it interpreted the "if" statement as being all\r
- * done when it reached the ';' after the yyless() call.\r
- */\r
-\r
-/* Return all but the first 'n' matched characters back to the input stream. */\r
-\r
-#define yyless(n) \\r
-       do \\r
-               { \\r
-               /* Undo effects of setting up yytext. */ \\r
-               *yy_cp = yy_hold_char; \\r
-               YY_RESTORE_YY_MORE_OFFSET \\r
-               yy_c_buf_p = yy_cp = yy_bp + n - YY_MORE_ADJ; \\r
-               YY_DO_BEFORE_ACTION; /* set up yytext again */ \\r
-               } \\r
-       while ( 0 )\r
-\r
-#define unput(c) yyunput( c, yytext_ptr )\r
-\r
-/* The following is because we cannot portably get our hands on size_t\r
- * (without autoconf's help, which isn't available because we want\r
- * flex-generated scanners to compile on their own).\r
- */\r
-typedef unsigned int yy_size_t;\r
-\r
-\r
-struct yy_buffer_state\r
-       {\r
-       FILE *yy_input_file;\r
-\r
-       char *yy_ch_buf;                /* input buffer */\r
-       char *yy_buf_pos;               /* current position in input buffer */\r
-\r
-       /* Size of input buffer in bytes, not including room for EOB\r
-        * characters.\r
-        */\r
-       yy_size_t yy_buf_size;\r
-\r
-       /* Number of characters read into yy_ch_buf, not including EOB\r
-        * characters.\r
-        */\r
-       int yy_n_chars;\r
-\r
-       /* Whether we "own" the buffer - i.e., we know we created it,\r
-        * and can realloc() it to grow it, and should free() it to\r
-        * delete it.\r
-        */\r
-       int yy_is_our_buffer;\r
-\r
-       /* Whether this is an "interactive" input source; if so, and\r
-        * if we're using stdio for input, then we want to use getc()\r
-        * instead of fread(), to make sure we stop fetching input after\r
-        * each newline.\r
-        */\r
-       int yy_is_interactive;\r
-\r
-       /* Whether we're considered to be at the beginning of a line.\r
-        * If so, '^' rules will be active on the next match, otherwise\r
-        * not.\r
-        */\r
-       int yy_at_bol;\r
-\r
-       /* Whether to try to fill the input buffer when we reach the\r
-        * end of it.\r
-        */\r
-       int yy_fill_buffer;\r
-\r
-       int yy_buffer_status;\r
-#define YY_BUFFER_NEW 0\r
-#define YY_BUFFER_NORMAL 1\r
-       /* When an EOF's been seen but there's still some text to process\r
-        * then we mark the buffer as YY_EOF_PENDING, to indicate that we\r
-        * shouldn't try reading from the input source any more.  We might\r
-        * still have a bunch of tokens to match, though, because of\r
-        * possible backing-up.\r
-        *\r
-        * When we actually see the EOF, we change the status to "new"\r
-        * (via yyrestart()), so that the user can continue scanning by\r
-        * just pointing yyin at a new input file.\r
-        */\r
-#define YY_BUFFER_EOF_PENDING 2\r
-       };\r
-\r
-static YY_BUFFER_STATE yy_current_buffer = 0;\r
-\r
-/* We provide macros for accessing buffer states in case in the\r
- * future we want to put the buffer states in a more general\r
- * "scanner state".\r
- */\r
-#define YY_CURRENT_BUFFER yy_current_buffer\r
-\r
-\r
-/* yy_hold_char holds the character lost when yytext is formed. */\r
-static char yy_hold_char;\r
-\r
-static int yy_n_chars;         /* number of characters read into yy_ch_buf */\r
-\r
-\r
-int yyleng;\r
-\r
-/* Points to current character in buffer. */\r
-static char *yy_c_buf_p = (char *) 0;\r
-static int yy_init = 1;                /* whether we need to initialize */\r
-static int yy_start = 0;       /* start state number */\r
-\r
-/* Flag which is used to allow yywrap()'s to do buffer switches\r
- * instead of setting up a fresh yyin.  A bit of a hack ...\r
- */\r
-static int yy_did_buffer_switch_on_eof;\r
-\r
-void yyrestart YY_PROTO(( FILE *input_file ));\r
-\r
-void yy_switch_to_buffer YY_PROTO(( YY_BUFFER_STATE new_buffer ));\r
-void yy_load_buffer_state YY_PROTO(( void ));\r
-YY_BUFFER_STATE yy_create_buffer YY_PROTO(( FILE *file, int size ));\r
-void yy_delete_buffer YY_PROTO(( YY_BUFFER_STATE b ));\r
-void yy_init_buffer YY_PROTO(( YY_BUFFER_STATE b, FILE *file ));\r
-void yy_flush_buffer YY_PROTO(( YY_BUFFER_STATE b ));\r
-#define YY_FLUSH_BUFFER yy_flush_buffer( yy_current_buffer )\r
-\r
-YY_BUFFER_STATE yy_scan_buffer YY_PROTO(( char *base, yy_size_t size ));\r
-YY_BUFFER_STATE yy_scan_string YY_PROTO(( yyconst char *yy_str ));\r
-YY_BUFFER_STATE yy_scan_bytes YY_PROTO(( yyconst char *bytes, int len ));\r
-\r
-static void *yy_flex_alloc YY_PROTO(( yy_size_t ));\r
-static void *yy_flex_realloc YY_PROTO(( void *, yy_size_t ));\r
-static void yy_flex_free YY_PROTO(( void * ));\r
-\r
-#define yy_new_buffer yy_create_buffer\r
-\r
-#define yy_set_interactive(is_interactive) \\r
-       { \\r
-       if ( ! yy_current_buffer ) \\r
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\r
-       yy_current_buffer->yy_is_interactive = is_interactive; \\r
-       }\r
-\r
-#define yy_set_bol(at_bol) \\r
-       { \\r
-       if ( ! yy_current_buffer ) \\r
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE ); \\r
-       yy_current_buffer->yy_at_bol = at_bol; \\r
-       }\r
-\r
-#define YY_AT_BOL() (yy_current_buffer->yy_at_bol)\r
-\r
-typedef unsigned char YY_CHAR;\r
-FILE *yyin = (FILE *) 0, *yyout = (FILE *) 0;\r
-typedef int yy_state_type;\r
-extern char *yytext;\r
-#define yytext_ptr yytext\r
-\r
-static yy_state_type yy_get_previous_state YY_PROTO(( void ));\r
-static yy_state_type yy_try_NUL_trans YY_PROTO(( yy_state_type current_state ));\r
-static int yy_get_next_buffer YY_PROTO(( void ));\r
-static void yy_fatal_error YY_PROTO(( yyconst char msg[] ));\r
-\r
-/* Done after the current pattern has been matched and before the\r
- * corresponding action - sets up yytext.\r
- */\r
-#define YY_DO_BEFORE_ACTION \\r
-       yytext_ptr = yy_bp; \\r
-       yyleng = (int) (yy_cp - yy_bp); \\r
-       yy_hold_char = *yy_cp; \\r
-       *yy_cp = '\0'; \\r
-       yy_c_buf_p = yy_cp;\r
-\r
-#define YY_NUM_RULES 14\r
-#define YY_END_OF_BUFFER 15\r
-static yyconst short int yy_accept[28] =\r
-    {   0,\r
-        0,    0,    0,    0,   15,   13,   14,   12,    5,    6,\r
-       13,    1,    1,    3,    4,   10,    8,    9,   10,    7,\r
-        1,    1,    0,    3,   11,    2,    0\r
-    } ;\r
-\r
-static yyconst int yy_ec[256] =\r
-    {   0,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    2,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    3,    1,    4,    1,    1,    1,    1,    5,    1,\r
-        1,    1,    6,    1,    6,    1,    1,    7,    8,    8,\r
-        8,    8,    8,    8,    8,    8,    8,    1,    1,    1,\r
-        1,    1,    1,    1,    9,    9,    9,    9,    9,    9,\r
-        9,    9,    9,    9,    9,    9,    9,    9,    9,    9,\r
-        9,    9,    9,    9,    9,    9,    9,   10,    9,    9,\r
-        1,   11,    1,    1,   12,   13,   14,   14,   14,   14,\r
-\r
-       14,   14,    9,    9,    9,    9,    9,    9,    9,    9,\r
-        9,    9,    9,    9,    9,    9,    9,    9,    9,   10,\r
-        9,    9,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    1\r
-    } ;\r
-\r
-static yyconst int yy_meta[15] =\r
-    {   0,\r
-        1,    2,    1,    1,    1,    1,    3,    3,    4,    5,\r
-        1,    4,    1,    6\r
-    } ;\r
-\r
-static yyconst short int yy_base[33] =\r
-    {   0,\r
-        0,    0,   13,   25,   25,   62,   62,   62,   62,   62,\r
-       12,   13,   14,    0,   62,   62,   62,   62,    0,   62,\r
-        6,   24,    0,    0,   62,    0,   62,   38,   42,   45,\r
-       51,   55\r
-    } ;\r
-\r
-static yyconst short int yy_def[33] =\r
-    {   0,\r
-       27,    1,   28,   28,   27,   27,   27,   27,   27,   27,\r
-       27,   29,   27,   30,   27,   27,   27,   27,   31,   27,\r
-       29,   27,   32,   30,   27,   32,    0,   27,   27,   27,\r
-       27,   27\r
-    } ;\r
-\r
-static yyconst short int yy_nxt[77] =\r
-    {   0,\r
-        6,    7,    8,    9,   10,   11,   12,   13,   14,   14,\r
-        6,    6,   15,   14,    7,   23,   17,   18,   21,   22,\r
-       22,   22,   23,   19,   27,   20,    7,   27,   17,   18,\r
-       22,   22,   27,   27,   27,   19,   27,   20,   16,   16,\r
-       16,   16,   16,   16,   22,   27,   22,   24,   24,   24,\r
-       24,   25,   27,   25,   25,   25,   25,   26,   27,   27,\r
-       26,    5,   27,   27,   27,   27,   27,   27,   27,   27,\r
-       27,   27,   27,   27,   27,   27\r
-    } ;\r
-\r
-static yyconst short int yy_chk[77] =\r
-    {   0,\r
-        1,    1,    1,    1,    1,    1,    1,    1,    1,    1,\r
-        1,    1,    1,    1,    3,   21,    3,    3,   11,   11,\r
-       13,   13,   12,    3,    5,    3,    4,    0,    4,    4,\r
-       22,   22,    0,    0,    0,    4,    0,    4,   28,   28,\r
-       28,   28,   28,   28,   29,    0,   29,   30,   30,   30,\r
-       30,   31,    0,   31,   31,   31,   31,   32,    0,    0,\r
-       32,   27,   27,   27,   27,   27,   27,   27,   27,   27,\r
-       27,   27,   27,   27,   27,   27\r
-    } ;\r
-\r
-static yy_state_type yy_last_accepting_state;\r
-static char *yy_last_accepting_cpos;\r
-\r
-/* The intent behind this definition is that it'll catch\r
- * any uses of REJECT which flex missed.\r
- */\r
-#define REJECT reject_used_but_not_detected\r
-#define yymore() yymore_used_but_not_detected\r
-#define YY_MORE_ADJ 0\r
-#define YY_RESTORE_YY_MORE_OFFSET\r
-char *yytext;\r
-#line 1 "macro.lex.l"\r
-#define INITIAL 0\r
-#line 2 "macro.lex.l"\r
-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid\r
- * Copyright 2002,2008 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-#define YY_NO_INPUT 1\r
-#define YY_NO_UNPUT 1\r
-#define quote 1\r
-\r
-#line 26 "macro.lex.l"\r
-#include "config.h"\r
-#include <assert.h>\r
-\r
-#ifndef HAVE_UNISTD_H\r
-#define YY_NO_UNISTD_H\r
-#endif\r
-\r
-#include "macro.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-struct lex_data {\r
-    LPCSTR   macroptr;\r
-    LPSTR    strptr;\r
-    int      quote_stack[32];\r
-    unsigned quote_stk_idx;\r
-    LPSTR    cache_string[32];\r
-    int      cache_used;\r
-};\r
-static struct lex_data* lex_data = NULL;\r
-\r
-struct lexret  yylval;\r
-\r
-#define YY_INPUT(buf,result,max_size)\\r
-  if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++;\r
-\r
-#line 440 "lex.yy.c"\r
-\r
-/* Macros after this point can all be overridden by user definitions in\r
- * section 1.\r
- */\r
-\r
-#ifndef YY_SKIP_YYWRAP\r
-#ifdef __cplusplus\r
-extern "C" int yywrap YY_PROTO(( void ));\r
-#else\r
-extern int yywrap YY_PROTO(( void ));\r
-#endif\r
-#endif\r
-\r
-#ifndef YY_NO_UNPUT\r
-static void yyunput YY_PROTO(( int c, char *buf_ptr ));\r
-#endif\r
-\r
-#ifndef yytext_ptr\r
-static void yy_flex_strncpy YY_PROTO(( char *, yyconst char *, int ));\r
-#endif\r
-\r
-#ifdef YY_NEED_STRLEN\r
-static int yy_flex_strlen YY_PROTO(( yyconst char * ));\r
-#endif\r
-\r
-#ifndef YY_NO_INPUT\r
-#ifdef __cplusplus\r
-static int yyinput YY_PROTO(( void ));\r
-#else\r
-static int input YY_PROTO(( void ));\r
-#endif\r
-#endif\r
-\r
-#if YY_STACK_USED\r
-static int yy_start_stack_ptr = 0;\r
-static int yy_start_stack_depth = 0;\r
-static int *yy_start_stack = 0;\r
-#ifndef YY_NO_PUSH_STATE\r
-static void yy_push_state YY_PROTO(( int new_state ));\r
-#endif\r
-#ifndef YY_NO_POP_STATE\r
-static void yy_pop_state YY_PROTO(( void ));\r
-#endif\r
-#ifndef YY_NO_TOP_STATE\r
-static int yy_top_state YY_PROTO(( void ));\r
-#endif\r
-\r
-#else\r
-#define YY_NO_PUSH_STATE 1\r
-#define YY_NO_POP_STATE 1\r
-#define YY_NO_TOP_STATE 1\r
-#endif\r
-\r
-#ifdef YY_MALLOC_DECL\r
-YY_MALLOC_DECL\r
-#else\r
-#if __STDC__\r
-#ifndef __cplusplus\r
-#include <stdlib.h>\r
-#endif\r
-#else\r
-/* Just try to get by without declaring the routines.  This will fail\r
- * miserably on non-ANSI systems for which sizeof(size_t) != sizeof(int)\r
- * or sizeof(void*) != sizeof(int).\r
- */\r
-#endif\r
-#endif\r
-\r
-/* Amount of stuff to slurp up with each read. */\r
-#ifndef YY_READ_BUF_SIZE\r
-#define YY_READ_BUF_SIZE 8192\r
-#endif\r
-\r
-/* Copy whatever the last rule matched to the standard output. */\r
-\r
-#ifndef ECHO\r
-/* This used to be an fputs(), but since the string might contain NUL's,\r
- * we now use fwrite().\r
- */\r
-#define ECHO (void) fwrite( yytext, yyleng, 1, yyout )\r
-#endif\r
-\r
-/* Gets input and stuffs it into "buf".  number of characters read, or YY_NULL,\r
- * is returned in "result".\r
- */\r
-#ifndef YY_INPUT\r
-#define YY_INPUT(buf,result,max_size) \\r
-       if ( yy_current_buffer->yy_is_interactive ) \\r
-               { \\r
-               int c = '*', n; \\r
-               for ( n = 0; n < max_size && \\r
-                            (c = getc( yyin )) != EOF && c != '\n'; ++n ) \\r
-                       buf[n] = (char) c; \\r
-               if ( c == '\n' ) \\r
-                       buf[n++] = (char) c; \\r
-               if ( c == EOF && ferror( yyin ) ) \\r
-                       YY_FATAL_ERROR( "input in flex scanner failed" ); \\r
-               result = n; \\r
-               } \\r
-       else if ( ((result = fread( buf, 1, max_size, yyin )) == 0) \\r
-                 && ferror( yyin ) ) \\r
-               YY_FATAL_ERROR( "input in flex scanner failed" );\r
-#endif\r
-\r
-/* No semi-colon after return; correct usage is to write "yyterminate();" -\r
- * we don't want an extra ';' after the "return" because that will cause\r
- * some compilers to complain about unreachable statements.\r
- */\r
-#ifndef yyterminate\r
-#define yyterminate() return YY_NULL\r
-#endif\r
-\r
-/* Number of entries by which start-condition stack grows. */\r
-#ifndef YY_START_STACK_INCR\r
-#define YY_START_STACK_INCR 25\r
-#endif\r
-\r
-/* Report a fatal error. */\r
-#ifndef YY_FATAL_ERROR\r
-#define YY_FATAL_ERROR(msg) yy_fatal_error( msg )\r
-#endif\r
-\r
-/* Default declaration of generated scanner - a define so the user can\r
- * easily add parameters.\r
- */\r
-#ifndef YY_DECL\r
-#define YY_DECL int yylex YY_PROTO(( void ))\r
-#endif\r
-\r
-/* Code executed at the beginning of each rule, after yytext and yyleng\r
- * have been set up.\r
- */\r
-#ifndef YY_USER_ACTION\r
-#define YY_USER_ACTION\r
-#endif\r
-\r
-/* Code executed at the end of each rule. */\r
-#ifndef YY_BREAK\r
-#define YY_BREAK break;\r
-#endif\r
-\r
-#define YY_RULE_SETUP \\r
-       YY_USER_ACTION\r
-\r
-YY_DECL\r
-       {\r
-       register yy_state_type yy_current_state;\r
-       register char *yy_cp, *yy_bp;\r
-       register int yy_act;\r
-\r
-#line 55 "macro.lex.l"\r
-\r
-\r
-#line 594 "lex.yy.c"\r
-\r
-       if ( yy_init )\r
-               {\r
-               yy_init = 0;\r
-\r
-#ifdef YY_USER_INIT\r
-               YY_USER_INIT;\r
-#endif\r
-\r
-               if ( ! yy_start )\r
-                       yy_start = 1;   /* first start state */\r
-\r
-               if ( ! yyin )\r
-                       yyin = stdin;\r
-\r
-               if ( ! yyout )\r
-                       yyout = stdout;\r
-\r
-               if ( ! yy_current_buffer )\r
-                       yy_current_buffer =\r
-                               yy_create_buffer( yyin, YY_BUF_SIZE );\r
-\r
-               yy_load_buffer_state();\r
-               }\r
-\r
-       while ( 1 )             /* loops until end-of-file is reached */\r
-               {\r
-               yy_cp = yy_c_buf_p;\r
-\r
-               /* Support of yytext. */\r
-               *yy_cp = yy_hold_char;\r
-\r
-               /* yy_bp points to the position in yy_ch_buf of the start of\r
-                * the current run.\r
-                */\r
-               yy_bp = yy_cp;\r
-\r
-               yy_current_state = yy_start;\r
-yy_match:\r
-               do\r
-                       {\r
-                       register YY_CHAR yy_c = yy_ec[YY_SC_TO_UI(*yy_cp)];\r
-                       if ( yy_accept[yy_current_state] )\r
-                               {\r
-                               yy_last_accepting_state = yy_current_state;\r
-                               yy_last_accepting_cpos = yy_cp;\r
-                               }\r
-                       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )\r
-                               {\r
-                               yy_current_state = (int) yy_def[yy_current_state];\r
-                               if ( yy_current_state >= 28 )\r
-                                       yy_c = yy_meta[(unsigned int) yy_c];\r
-                               }\r
-                       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];\r
-                       ++yy_cp;\r
-                       }\r
-               while ( yy_base[yy_current_state] != 62 );\r
-\r
-yy_find_action:\r
-               yy_act = yy_accept[yy_current_state];\r
-               if ( yy_act == 0 )\r
-                       { /* have to back up */\r
-                       yy_cp = yy_last_accepting_cpos;\r
-                       yy_current_state = yy_last_accepting_state;\r
-                       yy_act = yy_accept[yy_current_state];\r
-                       }\r
-\r
-               YY_DO_BEFORE_ACTION;\r
-\r
-\r
-do_action:     /* This label is used only to access EOF actions. */\r
-\r
-\r
-               switch ( yy_act )\r
-       { /* beginning of action switch */\r
-                       case 0: /* must back up */\r
-                       /* undo the effects of YY_DO_BEFORE_ACTION */\r
-                       *yy_cp = yy_hold_char;\r
-                       yy_cp = yy_last_accepting_cpos;\r
-                       yy_current_state = yy_last_accepting_state;\r
-                       goto yy_find_action;\r
-\r
-case 1:\r
-YY_RULE_SETUP\r
-#line 57 "macro.lex.l"\r
-yylval.integer = strtol(yytext, NULL, 10);     return INTEGER;\r
-       YY_BREAK\r
-case 2:\r
-YY_RULE_SETUP\r
-#line 58 "macro.lex.l"\r
-yylval.integer = strtol(yytext, NULL, 16);     return INTEGER;\r
-       YY_BREAK\r
-case 3:\r
-YY_RULE_SETUP\r
-#line 60 "macro.lex.l"\r
-return MACRO_Lookup(yytext, &yylval);\r
-       YY_BREAK\r
-case 4:\r
-#line 63 "macro.lex.l"\r
-case 5:\r
-#line 64 "macro.lex.l"\r
-case 6:\r
-#line 65 "macro.lex.l"\r
-case 7:\r
-#line 66 "macro.lex.l"\r
-case 8:\r
-#line 67 "macro.lex.l"\r
-case 9:\r
-YY_RULE_SETUP\r
-#line 67 "macro.lex.l"\r
-{\r
-    if (lex_data->quote_stk_idx == 0 ||\r
-        (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') ||\r
-        (yytext[0] == '`'))\r
-    {\r
-        /* opening a new one */\r
-        if (lex_data->quote_stk_idx == 0)\r
-        {\r
-            assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0]));\r
-            lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1);\r
-            yylval.string = lex_data->strptr;\r
-            lex_data->cache_used++;\r
-            BEGIN(quote);\r
-        }\r
-        else *lex_data->strptr++ = yytext[0];\r
-        lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0];\r
-        assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0]));\r
-    }\r
-    else\r
-    {\r
-        if (yytext[0] == '`') assert(0);\r
-        /* close the current quote */\r
-        if (--lex_data->quote_stk_idx == 0)\r
-        {\r
-            BEGIN INITIAL;\r
-            *lex_data->strptr++ = '\0';\r
-            return STRING;\r
-        }\r
-        else *lex_data->strptr++ = yytext[0];\r
-    }\r
-}\r
-       YY_BREAK\r
-case 10:\r
-YY_RULE_SETUP\r
-#line 99 "macro.lex.l"\r
-*lex_data->strptr++ = yytext[0];\r
-       YY_BREAK\r
-case 11:\r
-YY_RULE_SETUP\r
-#line 100 "macro.lex.l"\r
-*lex_data->strptr++ = yytext[1];\r
-       YY_BREAK\r
-case YY_STATE_EOF(quote):\r
-#line 101 "macro.lex.l"\r
-return 0;\r
-       YY_BREAK\r
-case 12:\r
-YY_RULE_SETUP\r
-#line 103 "macro.lex.l"\r
-\r
-       YY_BREAK\r
-case 13:\r
-YY_RULE_SETUP\r
-#line 104 "macro.lex.l"\r
-return yytext[0];\r
-       YY_BREAK\r
-case 14:\r
-YY_RULE_SETUP\r
-#line 105 "macro.lex.l"\r
-ECHO;\r
-       YY_BREAK\r
-#line 766 "lex.yy.c"\r
-case YY_STATE_EOF(INITIAL):\r
-       yyterminate();\r
-\r
-       case YY_END_OF_BUFFER:\r
-               {\r
-               /* Amount of text matched not including the EOB char. */\r
-               int yy_amount_of_matched_text = (int) (yy_cp - yytext_ptr) - 1;\r
-\r
-               /* Undo the effects of YY_DO_BEFORE_ACTION. */\r
-               *yy_cp = yy_hold_char;\r
-               YY_RESTORE_YY_MORE_OFFSET\r
-\r
-               if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_NEW )\r
-                       {\r
-                       /* We're scanning a new file or input source.  It's\r
-                        * possible that this happened because the user\r
-                        * just pointed yyin at a new source and called\r
-                        * yylex().  If so, then we have to assure\r
-                        * consistency between yy_current_buffer and our\r
-                        * globals.  Here is the right place to do so, because\r
-                        * this is the first action (other than possibly a\r
-                        * back-up) that will match for the new input source.\r
-                        */\r
-                       yy_n_chars = yy_current_buffer->yy_n_chars;\r
-                       yy_current_buffer->yy_input_file = yyin;\r
-                       yy_current_buffer->yy_buffer_status = YY_BUFFER_NORMAL;\r
-                       }\r
-\r
-               /* Note that here we test for yy_c_buf_p "<=" to the position\r
-                * of the first EOB in the buffer, since yy_c_buf_p will\r
-                * already have been incremented past the NUL character\r
-                * (since all states make transitions on EOB to the\r
-                * end-of-buffer state).  Contrast this with the test\r
-                * in input().\r
-                */\r
-               if ( yy_c_buf_p <= &yy_current_buffer->yy_ch_buf[yy_n_chars] )\r
-                       { /* This was really a NUL. */\r
-                       yy_state_type yy_next_state;\r
-\r
-                       yy_c_buf_p = yytext_ptr + yy_amount_of_matched_text;\r
-\r
-                       yy_current_state = yy_get_previous_state();\r
-\r
-                       /* Okay, we're now positioned to make the NUL\r
-                        * transition.  We couldn't have\r
-                        * yy_get_previous_state() go ahead and do it\r
-                        * for us because it doesn't know how to deal\r
-                        * with the possibility of jamming (and we don't\r
-                        * want to build jamming into it because then it\r
-                        * will run more slowly).\r
-                        */\r
-\r
-                       yy_next_state = yy_try_NUL_trans( yy_current_state );\r
-\r
-                       yy_bp = yytext_ptr + YY_MORE_ADJ;\r
-\r
-                       if ( yy_next_state )\r
-                               {\r
-                               /* Consume the NUL. */\r
-                               yy_cp = ++yy_c_buf_p;\r
-                               yy_current_state = yy_next_state;\r
-                               goto yy_match;\r
-                               }\r
-\r
-                       else\r
-                               {\r
-                               yy_cp = yy_c_buf_p;\r
-                               goto yy_find_action;\r
-                               }\r
-                       }\r
-\r
-               else switch ( yy_get_next_buffer() )\r
-                       {\r
-                       case EOB_ACT_END_OF_FILE:\r
-                               {\r
-                               yy_did_buffer_switch_on_eof = 0;\r
-\r
-                               if ( yywrap() )\r
-                                       {\r
-                                       /* Note: because we've taken care in\r
-                                        * yy_get_next_buffer() to have set up\r
-                                        * yytext, we can now set up\r
-                                        * yy_c_buf_p so that if some total\r
-                                        * hoser (like flex itself) wants to\r
-                                        * call the scanner after we return the\r
-                                        * YY_NULL, it'll still work - another\r
-                                        * YY_NULL will get returned.\r
-                                        */\r
-                                       yy_c_buf_p = yytext_ptr + YY_MORE_ADJ;\r
-\r
-                                       yy_act = YY_STATE_EOF(YY_START);\r
-                                       goto do_action;\r
-                                       }\r
-\r
-                               else\r
-                                       {\r
-                                       if ( ! yy_did_buffer_switch_on_eof )\r
-                                               YY_NEW_FILE;\r
-                                       }\r
-                               break;\r
-                               }\r
-\r
-                       case EOB_ACT_CONTINUE_SCAN:\r
-                               yy_c_buf_p =\r
-                                       yytext_ptr + yy_amount_of_matched_text;\r
-\r
-                               yy_current_state = yy_get_previous_state();\r
-\r
-                               yy_cp = yy_c_buf_p;\r
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;\r
-                               goto yy_match;\r
-\r
-                       case EOB_ACT_LAST_MATCH:\r
-                               yy_c_buf_p =\r
-                               &yy_current_buffer->yy_ch_buf[yy_n_chars];\r
-\r
-                               yy_current_state = yy_get_previous_state();\r
-\r
-                               yy_cp = yy_c_buf_p;\r
-                               yy_bp = yytext_ptr + YY_MORE_ADJ;\r
-                               goto yy_find_action;\r
-                       }\r
-               break;\r
-               }\r
-\r
-       default:\r
-               YY_FATAL_ERROR(\r
-                       "fatal flex scanner internal error--no action found" );\r
-       } /* end of action switch */\r
-               } /* end of scanning one token */\r
-       } /* end of yylex */\r
-\r
-\r
-/* yy_get_next_buffer - try to read in a new buffer\r
- *\r
- * Returns a code representing an action:\r
- *     EOB_ACT_LAST_MATCH -\r
- *     EOB_ACT_CONTINUE_SCAN - continue scanning from current position\r
- *     EOB_ACT_END_OF_FILE - end of file\r
- */\r
-\r
-static int yy_get_next_buffer()\r
-       {\r
-       register char *dest = yy_current_buffer->yy_ch_buf;\r
-       register char *source = yytext_ptr;\r
-       register int number_to_move, i;\r
-       int ret_val;\r
-\r
-       if ( yy_c_buf_p > &yy_current_buffer->yy_ch_buf[yy_n_chars + 1] )\r
-               YY_FATAL_ERROR(\r
-               "fatal flex scanner internal error--end of buffer missed" );\r
-\r
-       if ( yy_current_buffer->yy_fill_buffer == 0 )\r
-               { /* Don't try to fill the buffer, so this is an EOF. */\r
-               if ( yy_c_buf_p - yytext_ptr - YY_MORE_ADJ == 1 )\r
-                       {\r
-                       /* We matched a single character, the EOB, so\r
-                        * treat this as a final EOF.\r
-                        */\r
-                       return EOB_ACT_END_OF_FILE;\r
-                       }\r
-\r
-               else\r
-                       {\r
-                       /* We matched some text prior to the EOB, first\r
-                        * process it.\r
-                        */\r
-                       return EOB_ACT_LAST_MATCH;\r
-                       }\r
-               }\r
-\r
-       /* Try to read more data. */\r
-\r
-       /* First move last chars to start of buffer. */\r
-       number_to_move = (int) (yy_c_buf_p - yytext_ptr) - 1;\r
-\r
-       for ( i = 0; i < number_to_move; ++i )\r
-               *(dest++) = *(source++);\r
-\r
-       if ( yy_current_buffer->yy_buffer_status == YY_BUFFER_EOF_PENDING )\r
-               /* don't do the read, it's not guaranteed to return an EOF,\r
-                * just force an EOF\r
-                */\r
-               yy_current_buffer->yy_n_chars = yy_n_chars = 0;\r
-\r
-       else\r
-               {\r
-               int num_to_read =\r
-                       yy_current_buffer->yy_buf_size - number_to_move - 1;\r
-\r
-               while ( num_to_read <= 0 )\r
-                       { /* Not enough room in the buffer - grow it. */\r
-#ifdef YY_USES_REJECT\r
-                       YY_FATAL_ERROR(\r
-"input buffer overflow, can't enlarge buffer because scanner uses REJECT" );\r
-#else\r
-\r
-                       /* just a shorter name for the current buffer */\r
-                       YY_BUFFER_STATE b = yy_current_buffer;\r
-\r
-                       int yy_c_buf_p_offset =\r
-                               (int) (yy_c_buf_p - b->yy_ch_buf);\r
-\r
-                       if ( b->yy_is_our_buffer )\r
-                               {\r
-                               int new_size = b->yy_buf_size * 2;\r
-\r
-                               if ( new_size <= 0 )\r
-                                       b->yy_buf_size += b->yy_buf_size / 8;\r
-                               else\r
-                                       b->yy_buf_size *= 2;\r
-\r
-                               b->yy_ch_buf = (char *)\r
-                                       /* Include room in for 2 EOB chars. */\r
-                                       yy_flex_realloc( (void *) b->yy_ch_buf,\r
-                                                        b->yy_buf_size + 2 );\r
-                               }\r
-                       else\r
-                               /* Can't grow it, we don't own it. */\r
-                               b->yy_ch_buf = 0;\r
-\r
-                       if ( ! b->yy_ch_buf )\r
-                               YY_FATAL_ERROR(\r
-                               "fatal error - scanner input buffer overflow" );\r
-\r
-                       yy_c_buf_p = &b->yy_ch_buf[yy_c_buf_p_offset];\r
-\r
-                       num_to_read = yy_current_buffer->yy_buf_size -\r
-                                               number_to_move - 1;\r
-#endif\r
-                       }\r
-\r
-               if ( num_to_read > YY_READ_BUF_SIZE )\r
-                       num_to_read = YY_READ_BUF_SIZE;\r
-\r
-               /* Read in more data. */\r
-               YY_INPUT( (&yy_current_buffer->yy_ch_buf[number_to_move]),\r
-                       yy_n_chars, num_to_read );\r
-\r
-               yy_current_buffer->yy_n_chars = yy_n_chars;\r
-               }\r
-\r
-       if ( yy_n_chars == 0 )\r
-               {\r
-               if ( number_to_move == YY_MORE_ADJ )\r
-                       {\r
-                       ret_val = EOB_ACT_END_OF_FILE;\r
-                       yyrestart( yyin );\r
-                       }\r
-\r
-               else\r
-                       {\r
-                       ret_val = EOB_ACT_LAST_MATCH;\r
-                       yy_current_buffer->yy_buffer_status =\r
-                               YY_BUFFER_EOF_PENDING;\r
-                       }\r
-               }\r
-\r
-       else\r
-               ret_val = EOB_ACT_CONTINUE_SCAN;\r
-\r
-       yy_n_chars += number_to_move;\r
-       yy_current_buffer->yy_ch_buf[yy_n_chars] = YY_END_OF_BUFFER_CHAR;\r
-       yy_current_buffer->yy_ch_buf[yy_n_chars + 1] = YY_END_OF_BUFFER_CHAR;\r
-\r
-       yytext_ptr = &yy_current_buffer->yy_ch_buf[0];\r
-\r
-       return ret_val;\r
-       }\r
-\r
-\r
-/* yy_get_previous_state - get the state just before the EOB char was reached */\r
-\r
-static yy_state_type yy_get_previous_state()\r
-       {\r
-       register yy_state_type yy_current_state;\r
-       register char *yy_cp;\r
-\r
-       yy_current_state = yy_start;\r
-\r
-       for ( yy_cp = yytext_ptr + YY_MORE_ADJ; yy_cp < yy_c_buf_p; ++yy_cp )\r
-               {\r
-               register YY_CHAR yy_c = (*yy_cp ? yy_ec[YY_SC_TO_UI(*yy_cp)] : 1);\r
-               if ( yy_accept[yy_current_state] )\r
-                       {\r
-                       yy_last_accepting_state = yy_current_state;\r
-                       yy_last_accepting_cpos = yy_cp;\r
-                       }\r
-               while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )\r
-                       {\r
-                       yy_current_state = (int) yy_def[yy_current_state];\r
-                       if ( yy_current_state >= 28 )\r
-                               yy_c = yy_meta[(unsigned int) yy_c];\r
-                       }\r
-               yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];\r
-               }\r
-\r
-       return yy_current_state;\r
-       }\r
-\r
-\r
-/* yy_try_NUL_trans - try to make a transition on the NUL character\r
- *\r
- * synopsis\r
- *     next_state = yy_try_NUL_trans( current_state );\r
- */\r
-\r
-#ifdef YY_USE_PROTOS\r
-static yy_state_type yy_try_NUL_trans( yy_state_type yy_current_state )\r
-#else\r
-static yy_state_type yy_try_NUL_trans( yy_current_state )\r
-yy_state_type yy_current_state;\r
-#endif\r
-       {\r
-       register int yy_is_jam;\r
-       register char *yy_cp = yy_c_buf_p;\r
-\r
-       register YY_CHAR yy_c = 1;\r
-       if ( yy_accept[yy_current_state] )\r
-               {\r
-               yy_last_accepting_state = yy_current_state;\r
-               yy_last_accepting_cpos = yy_cp;\r
-               }\r
-       while ( yy_chk[yy_base[yy_current_state] + yy_c] != yy_current_state )\r
-               {\r
-               yy_current_state = (int) yy_def[yy_current_state];\r
-               if ( yy_current_state >= 28 )\r
-                       yy_c = yy_meta[(unsigned int) yy_c];\r
-               }\r
-       yy_current_state = yy_nxt[yy_base[yy_current_state] + (unsigned int) yy_c];\r
-       yy_is_jam = (yy_current_state == 27);\r
-\r
-       return yy_is_jam ? 0 : yy_current_state;\r
-       }\r
-\r
-\r
-#ifndef YY_NO_UNPUT\r
-#ifdef YY_USE_PROTOS\r
-static void yyunput( int c, register char *yy_bp )\r
-#else\r
-static void yyunput( c, yy_bp )\r
-int c;\r
-register char *yy_bp;\r
-#endif\r
-       {\r
-       register char *yy_cp = yy_c_buf_p;\r
-\r
-       /* undo effects of setting up yytext */\r
-       *yy_cp = yy_hold_char;\r
-\r
-       if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\r
-               { /* need to shift things up to make room */\r
-               /* +2 for EOB chars. */\r
-               register int number_to_move = yy_n_chars + 2;\r
-               register char *dest = &yy_current_buffer->yy_ch_buf[\r
-                                       yy_current_buffer->yy_buf_size + 2];\r
-               register char *source =\r
-                               &yy_current_buffer->yy_ch_buf[number_to_move];\r
-\r
-               while ( source > yy_current_buffer->yy_ch_buf )\r
-                       *--dest = *--source;\r
-\r
-               yy_cp += (int) (dest - source);\r
-               yy_bp += (int) (dest - source);\r
-               yy_current_buffer->yy_n_chars =\r
-                       yy_n_chars = yy_current_buffer->yy_buf_size;\r
-\r
-               if ( yy_cp < yy_current_buffer->yy_ch_buf + 2 )\r
-                       YY_FATAL_ERROR( "flex scanner push-back overflow" );\r
-               }\r
-\r
-       *--yy_cp = (char) c;\r
-\r
-\r
-       yytext_ptr = yy_bp;\r
-       yy_hold_char = *yy_cp;\r
-       yy_c_buf_p = yy_cp;\r
-       }\r
-#endif /* ifndef YY_NO_UNPUT */\r
-\r
-\r
-#ifdef __cplusplus\r
-static int yyinput()\r
-#else\r
-static int input()\r
-#endif\r
-       {\r
-       int c;\r
-\r
-       *yy_c_buf_p = yy_hold_char;\r
-\r
-       if ( *yy_c_buf_p == YY_END_OF_BUFFER_CHAR )\r
-               {\r
-               /* yy_c_buf_p now points to the character we want to return.\r
-                * If this occurs *before* the EOB characters, then it's a\r
-                * valid NUL; if not, then we've hit the end of the buffer.\r
-                */\r
-               if ( yy_c_buf_p < &yy_current_buffer->yy_ch_buf[yy_n_chars] )\r
-                       /* This was really a NUL. */\r
-                       *yy_c_buf_p = '\0';\r
-\r
-               else\r
-                       { /* need more input */\r
-                       int offset = yy_c_buf_p - yytext_ptr;\r
-                       ++yy_c_buf_p;\r
-\r
-                       switch ( yy_get_next_buffer() )\r
-                               {\r
-                               case EOB_ACT_LAST_MATCH:\r
-                                       /* This happens because yy_g_n_b()\r
-                                        * sees that we've accumulated a\r
-                                        * token and flags that we need to\r
-                                        * try matching the token before\r
-                                        * proceeding.  But for input(),\r
-                                        * there's no matching to consider.\r
-                                        * So convert the EOB_ACT_LAST_MATCH\r
-                                        * to EOB_ACT_END_OF_FILE.\r
-                                        */\r
-\r
-                                       /* Reset buffer status. */\r
-                                       yyrestart( yyin );\r
-\r
-                                       /* fall through */\r
-\r
-                               case EOB_ACT_END_OF_FILE:\r
-                                       {\r
-                                       if ( yywrap() )\r
-                                               return EOF;\r
-\r
-                                       if ( ! yy_did_buffer_switch_on_eof )\r
-                                               YY_NEW_FILE;\r
-#ifdef __cplusplus\r
-                                       return yyinput();\r
-#else\r
-                                       return input();\r
-#endif\r
-                                       }\r
-\r
-                               case EOB_ACT_CONTINUE_SCAN:\r
-                                       yy_c_buf_p = yytext_ptr + offset;\r
-                                       break;\r
-                               }\r
-                       }\r
-               }\r
-\r
-       c = *(unsigned char *) yy_c_buf_p;      /* cast for 8-bit char's */\r
-       *yy_c_buf_p = '\0';     /* preserve yytext */\r
-       yy_hold_char = *++yy_c_buf_p;\r
-\r
-\r
-       return c;\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yyrestart( FILE *input_file )\r
-#else\r
-void yyrestart( input_file )\r
-FILE *input_file;\r
-#endif\r
-       {\r
-       if ( ! yy_current_buffer )\r
-               yy_current_buffer = yy_create_buffer( yyin, YY_BUF_SIZE );\r
-\r
-       yy_init_buffer( yy_current_buffer, input_file );\r
-       yy_load_buffer_state();\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yy_switch_to_buffer( YY_BUFFER_STATE new_buffer )\r
-#else\r
-void yy_switch_to_buffer( new_buffer )\r
-YY_BUFFER_STATE new_buffer;\r
-#endif\r
-       {\r
-       if ( yy_current_buffer == new_buffer )\r
-               return;\r
-\r
-       if ( yy_current_buffer )\r
-               {\r
-               /* Flush out information for old buffer. */\r
-               *yy_c_buf_p = yy_hold_char;\r
-               yy_current_buffer->yy_buf_pos = yy_c_buf_p;\r
-               yy_current_buffer->yy_n_chars = yy_n_chars;\r
-               }\r
-\r
-       yy_current_buffer = new_buffer;\r
-       yy_load_buffer_state();\r
-\r
-       /* We don't actually know whether we did this switch during\r
-        * EOF (yywrap()) processing, but the only time this flag\r
-        * is looked at is after yywrap() is called, so it's safe\r
-        * to go ahead and always set it.\r
-        */\r
-       yy_did_buffer_switch_on_eof = 1;\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yy_load_buffer_state( void )\r
-#else\r
-void yy_load_buffer_state()\r
-#endif\r
-       {\r
-       yy_n_chars = yy_current_buffer->yy_n_chars;\r
-       yytext_ptr = yy_c_buf_p = yy_current_buffer->yy_buf_pos;\r
-       yyin = yy_current_buffer->yy_input_file;\r
-       yy_hold_char = *yy_c_buf_p;\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-YY_BUFFER_STATE yy_create_buffer( FILE *file, int size )\r
-#else\r
-YY_BUFFER_STATE yy_create_buffer( file, size )\r
-FILE *file;\r
-int size;\r
-#endif\r
-       {\r
-       YY_BUFFER_STATE b;\r
-\r
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\r
-       if ( ! b )\r
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );\r
-\r
-       b->yy_buf_size = size;\r
-\r
-       /* yy_ch_buf has to be 2 characters longer than the size given because\r
-        * we need to put in 2 end-of-buffer characters.\r
-        */\r
-       b->yy_ch_buf = (char *) yy_flex_alloc( b->yy_buf_size + 2 );\r
-       if ( ! b->yy_ch_buf )\r
-               YY_FATAL_ERROR( "out of dynamic memory in yy_create_buffer()" );\r
-\r
-       b->yy_is_our_buffer = 1;\r
-\r
-       yy_init_buffer( b, file );\r
-\r
-       return b;\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yy_delete_buffer( YY_BUFFER_STATE b )\r
-#else\r
-void yy_delete_buffer( b )\r
-YY_BUFFER_STATE b;\r
-#endif\r
-       {\r
-       if ( ! b )\r
-               return;\r
-\r
-       if ( b == yy_current_buffer )\r
-               yy_current_buffer = (YY_BUFFER_STATE) 0;\r
-\r
-       if ( b->yy_is_our_buffer )\r
-               yy_flex_free( (void *) b->yy_ch_buf );\r
-\r
-       yy_flex_free( (void *) b );\r
-       }\r
-\r
-\r
-#ifndef YY_ALWAYS_INTERACTIVE\r
-#ifndef YY_NEVER_INTERACTIVE\r
-extern int isatty YY_PROTO(( int ));\r
-#endif\r
-#endif\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yy_init_buffer( YY_BUFFER_STATE b, FILE *file )\r
-#else\r
-void yy_init_buffer( b, file )\r
-YY_BUFFER_STATE b;\r
-FILE *file;\r
-#endif\r
-\r
-\r
-       {\r
-       yy_flush_buffer( b );\r
-\r
-       b->yy_input_file = file;\r
-       b->yy_fill_buffer = 1;\r
-\r
-#if YY_ALWAYS_INTERACTIVE\r
-       b->yy_is_interactive = 1;\r
-#else\r
-#if YY_NEVER_INTERACTIVE\r
-       b->yy_is_interactive = 0;\r
-#else\r
-       b->yy_is_interactive = file ? (isatty( fileno(file) ) > 0) : 0;\r
-#endif\r
-#endif\r
-       }\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-void yy_flush_buffer( YY_BUFFER_STATE b )\r
-#else\r
-void yy_flush_buffer( b )\r
-YY_BUFFER_STATE b;\r
-#endif\r
-\r
-       {\r
-       if ( ! b )\r
-               return;\r
-\r
-       b->yy_n_chars = 0;\r
-\r
-       /* We always need two end-of-buffer characters.  The first causes\r
-        * a transition to the end-of-buffer state.  The second causes\r
-        * a jam in that state.\r
-        */\r
-       b->yy_ch_buf[0] = YY_END_OF_BUFFER_CHAR;\r
-       b->yy_ch_buf[1] = YY_END_OF_BUFFER_CHAR;\r
-\r
-       b->yy_buf_pos = &b->yy_ch_buf[0];\r
-\r
-       b->yy_at_bol = 1;\r
-       b->yy_buffer_status = YY_BUFFER_NEW;\r
-\r
-       if ( b == yy_current_buffer )\r
-               yy_load_buffer_state();\r
-       }\r
-\r
-\r
-#ifndef YY_NO_SCAN_BUFFER\r
-#ifdef YY_USE_PROTOS\r
-YY_BUFFER_STATE yy_scan_buffer( char *base, yy_size_t size )\r
-#else\r
-YY_BUFFER_STATE yy_scan_buffer( base, size )\r
-char *base;\r
-yy_size_t size;\r
-#endif\r
-       {\r
-       YY_BUFFER_STATE b;\r
-\r
-       if ( size < 2 ||\r
-            base[size-2] != YY_END_OF_BUFFER_CHAR ||\r
-            base[size-1] != YY_END_OF_BUFFER_CHAR )\r
-               /* They forgot to leave room for the EOB's. */\r
-               return 0;\r
-\r
-       b = (YY_BUFFER_STATE) yy_flex_alloc( sizeof( struct yy_buffer_state ) );\r
-       if ( ! b )\r
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_buffer()" );\r
-\r
-       b->yy_buf_size = size - 2;      /* "- 2" to take care of EOB's */\r
-       b->yy_buf_pos = b->yy_ch_buf = base;\r
-       b->yy_is_our_buffer = 0;\r
-       b->yy_input_file = 0;\r
-       b->yy_n_chars = b->yy_buf_size;\r
-       b->yy_is_interactive = 0;\r
-       b->yy_at_bol = 1;\r
-       b->yy_fill_buffer = 0;\r
-       b->yy_buffer_status = YY_BUFFER_NEW;\r
-\r
-       yy_switch_to_buffer( b );\r
-\r
-       return b;\r
-       }\r
-#endif\r
-\r
-\r
-#ifndef YY_NO_SCAN_STRING\r
-#ifdef YY_USE_PROTOS\r
-YY_BUFFER_STATE yy_scan_string( yyconst char *yy_str )\r
-#else\r
-YY_BUFFER_STATE yy_scan_string( yy_str )\r
-yyconst char *yy_str;\r
-#endif\r
-       {\r
-       int len;\r
-       for ( len = 0; yy_str[len]; ++len )\r
-               ;\r
-\r
-       return yy_scan_bytes( yy_str, len );\r
-       }\r
-#endif\r
-\r
-\r
-#ifndef YY_NO_SCAN_BYTES\r
-#ifdef YY_USE_PROTOS\r
-YY_BUFFER_STATE yy_scan_bytes( yyconst char *bytes, int len )\r
-#else\r
-YY_BUFFER_STATE yy_scan_bytes( bytes, len )\r
-yyconst char *bytes;\r
-int len;\r
-#endif\r
-       {\r
-       YY_BUFFER_STATE b;\r
-       char *buf;\r
-       yy_size_t n;\r
-       int i;\r
-\r
-       /* Get memory for full buffer, including space for trailing EOB's. */\r
-       n = len + 2;\r
-       buf = (char *) yy_flex_alloc( n );\r
-       if ( ! buf )\r
-               YY_FATAL_ERROR( "out of dynamic memory in yy_scan_bytes()" );\r
-\r
-       for ( i = 0; i < len; ++i )\r
-               buf[i] = bytes[i];\r
-\r
-       buf[len] = buf[len+1] = YY_END_OF_BUFFER_CHAR;\r
-\r
-       b = yy_scan_buffer( buf, n );\r
-       if ( ! b )\r
-               YY_FATAL_ERROR( "bad buffer in yy_scan_bytes()" );\r
-\r
-       /* It's okay to grow etc. this buffer, and we should throw it\r
-        * away when we're done.\r
-        */\r
-       b->yy_is_our_buffer = 1;\r
-\r
-       return b;\r
-       }\r
-#endif\r
-\r
-\r
-#ifndef YY_NO_PUSH_STATE\r
-#ifdef YY_USE_PROTOS\r
-static void yy_push_state( int new_state )\r
-#else\r
-static void yy_push_state( new_state )\r
-int new_state;\r
-#endif\r
-       {\r
-       if ( yy_start_stack_ptr >= yy_start_stack_depth )\r
-               {\r
-               yy_size_t new_size;\r
-\r
-               yy_start_stack_depth += YY_START_STACK_INCR;\r
-               new_size = yy_start_stack_depth * sizeof( int );\r
-\r
-               if ( ! yy_start_stack )\r
-                       yy_start_stack = (int *) yy_flex_alloc( new_size );\r
-\r
-               else\r
-                       yy_start_stack = (int *) yy_flex_realloc(\r
-                                       (void *) yy_start_stack, new_size );\r
-\r
-               if ( ! yy_start_stack )\r
-                       YY_FATAL_ERROR(\r
-                       "out of memory expanding start-condition stack" );\r
-               }\r
-\r
-       yy_start_stack[yy_start_stack_ptr++] = YY_START;\r
-\r
-       BEGIN(new_state);\r
-       }\r
-#endif\r
-\r
-\r
-#ifndef YY_NO_POP_STATE\r
-static void yy_pop_state()\r
-       {\r
-       if ( --yy_start_stack_ptr < 0 )\r
-               YY_FATAL_ERROR( "start-condition stack underflow" );\r
-\r
-       BEGIN(yy_start_stack[yy_start_stack_ptr]);\r
-       }\r
-#endif\r
-\r
-\r
-#ifndef YY_NO_TOP_STATE\r
-static int yy_top_state()\r
-       {\r
-       return yy_start_stack[yy_start_stack_ptr - 1];\r
-       }\r
-#endif\r
-\r
-#ifndef YY_EXIT_FAILURE\r
-#define YY_EXIT_FAILURE 2\r
-#endif\r
-\r
-#ifdef YY_USE_PROTOS\r
-static void yy_fatal_error( yyconst char msg[] )\r
-#else\r
-static void yy_fatal_error( msg )\r
-char msg[];\r
-#endif\r
-       {\r
-       (void) fprintf( stderr, "%s\n", msg );\r
-       exit( YY_EXIT_FAILURE );\r
-       }\r
-\r
-\r
-\r
-/* Redefine yyless() so it works in section 3 code. */\r
-\r
-#undef yyless\r
-#define yyless(n) \\r
-       do \\r
-               { \\r
-               /* Undo effects of setting up yytext. */ \\r
-               yytext[yyleng] = yy_hold_char; \\r
-               yy_c_buf_p = yytext + n; \\r
-               yy_hold_char = *yy_c_buf_p; \\r
-               *yy_c_buf_p = '\0'; \\r
-               yyleng = n; \\r
-               } \\r
-       while ( 0 )\r
-\r
-\r
-/* Internal utility routines. */\r
-\r
-#ifndef yytext_ptr\r
-#ifdef YY_USE_PROTOS\r
-static void yy_flex_strncpy( char *s1, yyconst char *s2, int n )\r
-#else\r
-static void yy_flex_strncpy( s1, s2, n )\r
-char *s1;\r
-yyconst char *s2;\r
-int n;\r
-#endif\r
-       {\r
-       register int i;\r
-       for ( i = 0; i < n; ++i )\r
-               s1[i] = s2[i];\r
-       }\r
-#endif\r
-\r
-#ifdef YY_NEED_STRLEN\r
-#ifdef YY_USE_PROTOS\r
-static int yy_flex_strlen( yyconst char *s )\r
-#else\r
-static int yy_flex_strlen( s )\r
-yyconst char *s;\r
-#endif\r
-       {\r
-       register int n;\r
-       for ( n = 0; s[n]; ++n )\r
-               ;\r
-\r
-       return n;\r
-       }\r
-#endif\r
-\r
-\r
-#ifdef YY_USE_PROTOS\r
-static void *yy_flex_alloc( yy_size_t size )\r
-#else\r
-static void *yy_flex_alloc( size )\r
-yy_size_t size;\r
-#endif\r
-       {\r
-       return (void *) malloc( size );\r
-       }\r
-\r
-#ifdef YY_USE_PROTOS\r
-static void *yy_flex_realloc( void *ptr, yy_size_t size )\r
-#else\r
-static void *yy_flex_realloc( ptr, size )\r
-void *ptr;\r
-yy_size_t size;\r
-#endif\r
-       {\r
-       /* The cast to (char *) in the following accommodates both\r
-        * implementations that use char* generic pointers, and those\r
-        * that use void* generic pointers.  It works with the latter\r
-        * because both ANSI C and C++ allow castless assignment from\r
-        * any pointer type to void*, and deal with argument conversions\r
-        * as though doing an assignment.\r
-        */\r
-       return (void *) realloc( (char *) ptr, size );\r
-       }\r
-\r
-#ifdef YY_USE_PROTOS\r
-static void yy_flex_free( void *ptr )\r
-#else\r
-static void yy_flex_free( ptr )\r
-void *ptr;\r
-#endif\r
-       {\r
-       free( ptr );\r
-       }\r
-\r
-#if YY_MAIN\r
-int main()\r
-       {\r
-       yylex();\r
-       return 0;\r
-       }\r
-#endif\r
-#line 105 "macro.lex.l"\r
-\r
-\r
-#if 0\r
-/* all code for testing macros */\r
-#include "winhelp.h"\r
-static CHAR szTestMacro[256];\r
-\r
-static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (msg == WM_COMMAND && wParam == IDOK)\r
-    {\r
-        GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro));\r
-        EndDialog(hDlg, IDOK);\r
-        return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-void macro_test(void)\r
-{\r
-    WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance);\r
-    DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg);\r
-    FreeProcInstance(lpfnDlg);\r
-    macro = szTestMacro;\r
-}\r
-#endif\r
-\r
-/* small helper function for debug messages */\r
-static const char* ts(int t)\r
-{\r
-    static char c[2] = {0,0};\r
-\r
-    switch (t)\r
-    {\r
-    case EMPTY: return "EMPTY";\r
-    case VOID_FUNCTION: return "VOID_FUNCTION";\r
-    case BOOL_FUNCTION: return "BOOL_FUNCTION";\r
-    case INTEGER: return "INTEGER";\r
-    case STRING: return "STRING";\r
-    case IDENTIFIER: return "IDENTIFIER";\r
-    default: c[0] = (char)t; return c;\r
-    }\r
-}\r
-\r
-static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret);\r
-\r
-/******************************************************************\r
- *             MACRO_CheckArgs\r
- *\r
- * checks number of arguments against prototype, and stores arguments on\r
- * stack pa for later call\r
- * returns -1 on error, otherwise the number of pushed parameters\r
- */\r
-static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args)\r
-{\r
-    int t;\r
-    unsigned int len = 0, idx = 0;\r
-\r
-    WINE_TRACE("Checking %s\n", args);\r
-\r
-    if (yylex() != '(') {WINE_WARN("missing (\n");return -1;}\r
-\r
-    if (*args)\r
-    {\r
-        len = strlen(args);\r
-        for (;;)\r
-        {\r
-            t = yylex();\r
-            WINE_TRACE("Got %s <=> %c\n", ts(t), *args);\r
-\r
-            switch (*args)\r
-            {\r
-            case 'S': \r
-                if (t != STRING)\r
-                {WINE_WARN("missing S\n");return -1;}\r
-                pa[idx] = (void*)yylval.string;  \r
-                break;\r
-            case 'U':\r
-            case 'I':\r
-                if (t != INTEGER)\r
-                {WINE_WARN("missing U\n");return -1;}   \r
-                pa[idx] = LongToPtr(yylval.integer);\r
-                break;\r
-            case 'B':\r
-                if (t != BOOL_FUNCTION) \r
-                {WINE_WARN("missing B\n");return -1;}   \r
-                if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0)\r
-                    return -1;\r
-                break;\r
-            default: \r
-                WINE_WARN("unexpected %s while args is %c\n", ts(t), *args);\r
-                return -1;\r
-            }\r
-            idx++;\r
-            if (*++args == '\0') break;\r
-            t = yylex();\r
-            if (t == ')') goto CheckArgs_end;\r
-            if (t != ',') {WINE_WARN("missing ,\n");return -1;}\r
-            if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;}\r
-        }\r
-    }\r
-    if (yylex() != ')') {WINE_WARN("missing )\n");return -1;}\r
-\r
-CheckArgs_end:\r
-    while (len > idx) pa[--len] = NULL;\r
-    return idx;\r
-}\r
-\r
-/******************************************************************\r
- *             MACRO_CallBoolFunc\r
- *\r
- * Invokes boolean function fn, which arguments are defined by args\r
- * stores bool result into ret\r
- */\r
-static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret)\r
-{\r
-    void*       pa[2];\r
-    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);\r
-\r
-    if (idx < 0) return 0;\r
-    if (!fn)     return 1;\r
-\r
-    WINE_TRACE("calling with %u pmts\n", idx);\r
-\r
-    switch (strlen(args))\r
-    {\r
-    case 0: *ret = (void*)(fn)();          break;\r
-    case 1: *ret = (void*)(fn)(pa[0]);     break;\r
-    default: WINE_FIXME("NIY\n");\r
-    }\r
-\r
-    return 1;\r
-}\r
-\r
-/******************************************************************\r
- *             MACRO_CallVoidFunc\r
- *\r
- *\r
- */\r
-static int MACRO_CallVoidFunc(FARPROC fn, const char* args)\r
-{\r
-    void*       pa[6];\r
-    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);\r
-\r
-    if (idx < 0) return 0;\r
-    if (!fn)     return 1;\r
-\r
-    WINE_TRACE("calling %p with %u pmts\n", fn, idx);\r
-\r
-    switch (strlen(args))\r
-    {\r
-    case 0: (fn)();                                     break;\r
-    case 1: (fn)(pa[0]);                                break;\r
-    case 2: (fn)(pa[0],pa[1]);                          break;\r
-    case 3: (fn)(pa[0],pa[1],pa[2]);                    break;\r
-    case 4: (fn)(pa[0],pa[1],pa[2],pa[3]);              break;\r
-    case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]);        break;\r
-    case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]);  break;\r
-    default: WINE_FIXME("NIY\n");\r
-    }\r
-\r
-    return 1;\r
-}\r
-\r
-BOOL MACRO_ExecuteMacro(LPCSTR macro)\r
-{\r
-    struct lex_data     curr_lex_data, *prev_lex_data;\r
-    BOOL ret = TRUE;\r
-    int t;\r
-\r
-    WINE_TRACE("%s\n", wine_dbgstr_a(macro));\r
-\r
-    prev_lex_data = lex_data;\r
-    lex_data = &curr_lex_data;\r
-\r
-    memset(lex_data, 0, sizeof(*lex_data));\r
-    lex_data->macroptr = macro;\r
-\r
-    while ((t = yylex()) != EMPTY)\r
-    {\r
-        switch (t)\r
-        {\r
-        case VOID_FUNCTION:\r
-            WINE_TRACE("got type void func(%s)\n", yylval.proto);\r
-            MACRO_CallVoidFunc(yylval.function, yylval.proto);\r
-            break;\r
-        case BOOL_FUNCTION:\r
-            WINE_WARN("got type bool func(%s)\n", yylval.proto);\r
-            break;\r
-        default:\r
-            WINE_WARN("got unexpected type %s\n", ts(t));\r
-            return 0;\r
-        }\r
-        switch (t = yylex())\r
-        {\r
-        case EMPTY:     goto done;\r
-        case ';':       break;\r
-        default:        ret = FALSE; goto done;\r
-        }\r
-    }\r
-\r
-done:\r
-    for (t = 0; t < lex_data->cache_used; t++)\r
-        HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]);\r
-    lex_data = prev_lex_data;\r
-\r
-    return ret;\r
-}\r
-\r
-#ifndef yywrap\r
-int yywrap(void) { return 1; }\r
-#endif\r
+/* 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 <stdio.h>
+
+
+/* cfront 1.2 defines "c_plusplus" instead of "__cplusplus" */
+#ifdef c_plusplus
+#ifndef __cplusplus
+#define __cplusplus
+#endif
+#endif
+
+
+#ifdef __cplusplus
+
+#include <stdlib.h>
+#include <unistd.h>
+
+/* 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 <io.h>
+#include <stdlib.h>
+#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 <assert.h>
+
+#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 <stdlib.h>
+#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
index 3108b02..0eeaa9b 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid\r
- * Copyright 2002, 2008 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#define WIN32_LEAN_AND_MEAN\r
-\r
-#include <stdio.h>\r
-\r
-#include "windows.h"\r
-#include "commdlg.h"\r
-#include "winhelp.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-/**************************************************/\r
-/*               Macro table                      */\r
-/**************************************************/\r
-struct MacroDesc {\r
-    const char* name;\r
-    const char* alias;\r
-    BOOL        isBool;\r
-    const char* arguments;\r
-    FARPROC     fn;\r
-};\r
-\r
-static struct MacroDesc*MACRO_Loaded /* = NULL */;\r
-static unsigned         MACRO_NumLoaded /* = 0 */;\r
-\r
-/*******      helper functions     *******/\r
-\r
-static WINHELP_BUTTON**        MACRO_LookupButton(WINHELP_WINDOW* win, LPCSTR name)\r
-{\r
-    WINHELP_BUTTON**    b;\r
-\r
-    for (b = &win->first_button; *b; b = &(*b)->next)\r
-        if (!lstrcmpi(name, (*b)->lpszID)) break;\r
-    return b;\r
-}\r
-\r
-/******* real macro implementation *******/\r
-\r
-void CALLBACK MACRO_CreateButton(LPCSTR id, LPCSTR name, LPCSTR macro)\r
-{\r
-    WINHELP_WINDOW *win = Globals.active_win;\r
-    WINHELP_BUTTON *button, **b;\r
-    LONG            size;\r
-    LPSTR           ptr;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\", %s)\n", id, name, macro);\r
-\r
-    size = sizeof(WINHELP_BUTTON) + lstrlen(id) + lstrlen(name) + lstrlen(macro) + 3;\r
-\r
-    button = HeapAlloc(GetProcessHeap(), 0, size);\r
-    if (!button) return;\r
-\r
-    button->next  = 0;\r
-    button->hWnd  = 0;\r
-\r
-    ptr = (char*)button + sizeof(WINHELP_BUTTON);\r
-\r
-    lstrcpy(ptr, id);\r
-    button->lpszID = ptr;\r
-    ptr += lstrlen(id) + 1;\r
-\r
-    lstrcpy(ptr, name);\r
-    button->lpszName = ptr;\r
-    ptr += lstrlen(name) + 1;\r
-\r
-    lstrcpy(ptr, macro);\r
-    button->lpszMacro = ptr;\r
-\r
-    button->wParam = WH_FIRST_BUTTON;\r
-    for (b = &win->first_button; *b; b = &(*b)->next)\r
-        button->wParam = max(button->wParam, (*b)->wParam + 1);\r
-    *b = button;\r
-\r
-    WINHELP_LayoutMainWindow(win);\r
-}\r
-\r
-static void CALLBACK MACRO_DestroyButton(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-void CALLBACK MACRO_DisableButton(LPCSTR id)\r
-{\r
-    WINHELP_BUTTON**    b;\r
-\r
-    WINE_TRACE("(\"%s\")\n", id);\r
-\r
-    b = MACRO_LookupButton(Globals.active_win, id);\r
-    if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;}\r
-\r
-    EnableWindow((*b)->hWnd, FALSE);\r
-}\r
-\r
-static void CALLBACK MACRO_EnableButton(LPCSTR id)\r
-{\r
-    WINHELP_BUTTON**    b;\r
-\r
-    WINE_TRACE("(\"%s\")\n", id);\r
-\r
-    b = MACRO_LookupButton(Globals.active_win, id);\r
-    if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;}\r
-\r
-    EnableWindow((*b)->hWnd, TRUE);\r
-}\r
-\r
-void CALLBACK MACRO_JumpContents(LPCSTR lpszPath, LPCSTR lpszWindow)\r
-{\r
-    HLPFILE*    hlpfile;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\")\n", lpszPath, lpszWindow);\r
-    if ((hlpfile = WINHELP_LookupHelpFile(lpszPath)))\r
-        WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, 0,\r
-                               WINHELP_GetWindowInfo(hlpfile, lpszWindow),\r
-                               SW_NORMAL);\r
-}\r
-\r
-\r
-void CALLBACK MACRO_About(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_AddAccelerator(LONG u1, LONG u2, LPCSTR str)\r
-{\r
-    WINE_FIXME("(%u, %u, \"%s\")\n", u1, u2, str);\r
-}\r
-\r
-static void CALLBACK MACRO_ALink(LPCSTR str1, LONG u, LPCSTR str2)\r
-{\r
-    WINE_FIXME("(\"%s\", %u, \"%s\")\n", str1, u, str2);\r
-}\r
-\r
-void CALLBACK MACRO_Annotate(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_AppendItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\")\n", str1, str2, str3, str4);\r
-}\r
-\r
-static void CALLBACK MACRO_Back(void)\r
-{\r
-    WINHELP_WINDOW* win = Globals.active_win;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    if (win && win->back.index >= 2)\r
-        WINHELP_CreateHelpWindow(&win->back.set[--win->back.index - 1], SW_SHOW, FALSE);\r
-}\r
-\r
-static void CALLBACK MACRO_BackFlush(void)\r
-{\r
-    WINHELP_WINDOW* win = Globals.active_win;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    if (win) WINHELP_DeleteBackSet(win);\r
-}\r
-\r
-void CALLBACK MACRO_BookmarkDefine(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_BookmarkMore(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_BrowseButtons(void)\r
-{\r
-    HLPFILE_PAGE*       page = Globals.active_win->page;\r
-    ULONG               relative;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    MACRO_CreateButton("BTN_PREV", "&<<", "Prev()");\r
-    MACRO_CreateButton("BTN_NEXT", "&>>", "Next()");\r
-\r
-    if (!HLPFILE_PageByOffset(page->file, page->browse_bwd, &relative))\r
-        MACRO_DisableButton("BTN_PREV");\r
-    if (!HLPFILE_PageByOffset(page->file, page->browse_fwd, &relative))\r
-        MACRO_DisableButton("BTN_NEXT");\r
-}\r
-\r
-static void CALLBACK MACRO_ChangeButtonBinding(LPCSTR id, LPCSTR macro)\r
-{\r
-    WINHELP_WINDOW*     win = Globals.active_win;\r
-    WINHELP_BUTTON*     button;\r
-    WINHELP_BUTTON**    b;\r
-    LONG                size;\r
-    LPSTR               ptr;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\")\n", id, macro);\r
-\r
-    b = MACRO_LookupButton(win, id);\r
-    if (!*b) {WINE_FIXME("Couldn't find button '%s'\n", id); return;}\r
-\r
-    size = sizeof(WINHELP_BUTTON) + lstrlen(id) +\r
-        lstrlen((*b)->lpszName) + lstrlen(macro) + 3;\r
-\r
-    button = HeapAlloc(GetProcessHeap(), 0, size);\r
-    if (!button) return;\r
-\r
-    button->next  = (*b)->next;\r
-    button->hWnd  = (*b)->hWnd;\r
-    button->wParam = (*b)->wParam;\r
-\r
-    ptr = (char*)button + sizeof(WINHELP_BUTTON);\r
-\r
-    lstrcpy(ptr, id);\r
-    button->lpszID = ptr;\r
-    ptr += lstrlen(id) + 1;\r
-\r
-    lstrcpy(ptr, (*b)->lpszName);\r
-    button->lpszName = ptr;\r
-    ptr += lstrlen((*b)->lpszName) + 1;\r
-\r
-    lstrcpy(ptr, macro);\r
-    button->lpszMacro = ptr;\r
-\r
-    *b = button;\r
-\r
-    WINHELP_LayoutMainWindow(win);\r
-}\r
-\r
-static void CALLBACK MACRO_ChangeEnable(LPCSTR id, LPCSTR macro)\r
-{\r
-    WINE_TRACE("(\"%s\", \"%s\")\n", id, macro);\r
-\r
-    MACRO_ChangeButtonBinding(id, macro);\r
-    MACRO_EnableButton(id);\r
-}\r
-\r
-static void CALLBACK MACRO_ChangeItemBinding(LPCSTR str1, LPCSTR str2)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2);\r
-}\r
-\r
-static void CALLBACK MACRO_CheckItem(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_CloseSecondarys(void)\r
-{\r
-    WINHELP_WINDOW *win;\r
-\r
-    WINE_TRACE("()\n");\r
-    for (win = Globals.win_list; win; win = win->next)\r
-        if (win->lpszName && lstrcmpi(win->lpszName, "main"))\r
-            DestroyWindow(win->hMainWnd);\r
-}\r
-\r
-static void CALLBACK MACRO_CloseWindow(LPCSTR lpszWindow)\r
-{\r
-    WINHELP_WINDOW *win;\r
-\r
-    WINE_TRACE("(\"%s\")\n", lpszWindow);\r
-\r
-    if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main";\r
-\r
-    for (win = Globals.win_list; win; win = win->next)\r
-        if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow))\r
-            DestroyWindow(win->hMainWnd);\r
-}\r
-\r
-static void CALLBACK MACRO_Compare(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_Contents(void)\r
-{\r
-    WINE_TRACE("()\n");\r
-\r
-    if (Globals.active_win->page)\r
-        MACRO_JumpContents(Globals.active_win->page->file->lpszPath, NULL);\r
-}\r
-\r
-static void CALLBACK MACRO_ControlPanel(LPCSTR str1, LPCSTR str2, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u);\r
-}\r
-\r
-void CALLBACK MACRO_CopyDialog(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_CopyTopic(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_DeleteItem(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_DeleteMark(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_DisableItem(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_EnableItem(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_EndMPrint(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_ExecFile(LPCSTR str1, LPCSTR str2, LONG u, LPCSTR str3)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", %u, \"%s\")\n", str1, str2, u, str3);\r
-}\r
-\r
-static void CALLBACK MACRO_ExecProgram(LPCSTR str, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", %u)\n", str, u);\r
-}\r
-\r
-void CALLBACK MACRO_Exit(void)\r
-{\r
-    WINE_TRACE("()\n");\r
-\r
-    while (Globals.win_list)\r
-        DestroyWindow(Globals.win_list->hMainWnd);\r
-}\r
-\r
-static void CALLBACK MACRO_ExtAbleItem(LPCSTR str, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", %u)\n", str, u);\r
-}\r
-\r
-static void CALLBACK MACRO_ExtInsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u1, LONG u2)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, str4, u1, u2);\r
-}\r
-\r
-static void CALLBACK MACRO_ExtInsertMenu(LPCSTR str1, LPCSTR str2, LPCSTR str3, LONG u1, LONG u2)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", \"%s\", %u, %u)\n", str1, str2, str3, u1, u2);\r
-}\r
-\r
-static BOOL CALLBACK MACRO_FileExist(LPCSTR str)\r
-{\r
-    WINE_TRACE("(\"%s\")\n", str);\r
-    return GetFileAttributes(str) != INVALID_FILE_ATTRIBUTES;\r
-}\r
-\r
-void CALLBACK MACRO_FileOpen(void)\r
-{\r
-    char szFile[MAX_PATH];\r
-\r
-    if (WINHELP_GetOpenFileName(szFile, MAX_PATH))\r
-    {\r
-        MACRO_JumpContents(szFile, "main");\r
-    }\r
-}\r
-\r
-static void CALLBACK MACRO_Find(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_Finder(void)\r
-{\r
-    WINHELP_CreateIndexWindow(FALSE);\r
-}\r
-\r
-static void CALLBACK MACRO_FloatingMenu(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_Flush(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_FocusWindow(LPCSTR lpszWindow)\r
-{\r
-    WINHELP_WINDOW *win;\r
-\r
-    WINE_TRACE("(\"%s\")\n", lpszWindow);\r
-\r
-    if (!lpszWindow || !lpszWindow[0]) lpszWindow = "main";\r
-\r
-    for (win = Globals.win_list; win; win = win->next)\r
-        if (win->lpszName && !lstrcmpi(win->lpszName, lpszWindow))\r
-            SetFocus(win->hMainWnd);\r
-}\r
-\r
-static void CALLBACK MACRO_Generate(LPCSTR str, LONG w, LONG l)\r
-{\r
-    WINE_FIXME("(\"%s\", %x, %x)\n", str, w, l);\r
-}\r
-\r
-static void CALLBACK MACRO_GotoMark(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-void CALLBACK MACRO_HelpOn(void)\r
-{\r
-    LPCSTR      file;\r
-\r
-    WINE_TRACE("()\n");\r
-    file = Globals.active_win->page->file->help_on_file;\r
-    if (!file)\r
-        file = (Globals.wVersion > 4) ? "winhlp32.hlp" : "winhelp.hlp";\r
-\r
-    MACRO_JumpContents(file, NULL);\r
-}\r
-\r
-void CALLBACK MACRO_HelpOnTop(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-void CALLBACK MACRO_History(void)\r
-{\r
-    WINE_TRACE("()\n");\r
-\r
-    if (Globals.active_win && !Globals.active_win->hHistoryWnd)\r
-    {\r
-        HWND hWnd = CreateWindow(HISTORY_WIN_CLASS_NAME, "History", WS_OVERLAPPEDWINDOW,\r
-                                 0, 0, 0, 0, 0, 0, Globals.hInstance, Globals.active_win);\r
-        ShowWindow(hWnd, SW_NORMAL);\r
-    }\r
-}\r
-\r
-static void CALLBACK MACRO_IfThen(BOOL b, LPCSTR t)\r
-{\r
-    if (b) MACRO_ExecuteMacro(t);\r
-}\r
-\r
-static void CALLBACK MACRO_IfThenElse(BOOL b, LPCSTR t, LPCSTR f)\r
-{\r
-    if (b) MACRO_ExecuteMacro(t); else MACRO_ExecuteMacro(f);\r
-}\r
-\r
-static BOOL CALLBACK MACRO_InitMPrint(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-    return FALSE;\r
-}\r
-\r
-static void CALLBACK MACRO_InsertItem(LPCSTR str1, LPCSTR str2, LPCSTR str3, LPCSTR str4, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", \"%s\", \"%s\", %u)\n", str1, str2, str3, str4, u);\r
-}\r
-\r
-static void CALLBACK MACRO_InsertMenu(LPCSTR str1, LPCSTR str2, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", %u)\n", str1, str2, u);\r
-}\r
-\r
-static BOOL CALLBACK MACRO_IsBook(void)\r
-{\r
-    WINE_TRACE("()\n");\r
-    return Globals.isBook;\r
-}\r
-\r
-static BOOL CALLBACK MACRO_IsMark(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-    return FALSE;\r
-}\r
-\r
-static BOOL CALLBACK MACRO_IsNotMark(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-    return TRUE;\r
-}\r
-\r
-void CALLBACK MACRO_JumpContext(LPCSTR lpszPath, LPCSTR lpszWindow, LONG context)\r
-{\r
-    HLPFILE*    hlpfile;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\", %d)\n", lpszPath, lpszWindow, context);\r
-    hlpfile = WINHELP_LookupHelpFile(lpszPath);\r
-    /* Some madness: what user calls 'context', hlpfile calls 'map' */\r
-    WINHELP_OpenHelpWindow(HLPFILE_PageByMap, hlpfile, context,\r
-                           WINHELP_GetWindowInfo(hlpfile, lpszWindow),\r
-                           SW_NORMAL);\r
-}\r
-\r
-void CALLBACK MACRO_JumpHash(LPCSTR lpszPath, LPCSTR lpszWindow, LONG lHash)\r
-{\r
-    HLPFILE*    hlpfile;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\", %u)\n", lpszPath, lpszWindow, lHash);\r
-    hlpfile = WINHELP_LookupHelpFile(lpszPath);\r
-    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,\r
-                           WINHELP_GetWindowInfo(hlpfile, lpszWindow),\r
-                           SW_NORMAL);\r
-}\r
-\r
-static void CALLBACK MACRO_JumpHelpOn(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_JumpID(LPCSTR lpszPathWindow, LPCSTR topic_id)\r
-{\r
-    LPSTR       ptr;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\")\n", lpszPathWindow, topic_id);\r
-    if ((ptr = strchr(lpszPathWindow, '>')) != NULL)\r
-    {\r
-        LPSTR   tmp;\r
-        size_t  sz = ptr - lpszPathWindow;\r
-\r
-        tmp = HeapAlloc(GetProcessHeap(), 0, sz + 1);\r
-        if (tmp)\r
-        {\r
-            memcpy(tmp, lpszPathWindow, sz);\r
-            tmp[sz] = '\0';\r
-            MACRO_JumpHash(tmp, ptr + 1, HLPFILE_Hash(topic_id));\r
-            HeapFree(GetProcessHeap(), 0, tmp);\r
-        }\r
-    }\r
-    else\r
-        MACRO_JumpHash(lpszPathWindow, NULL, HLPFILE_Hash(topic_id));\r
-}\r
-\r
-/* FIXME: this macros is wrong\r
- * it should only contain 2 strings, path & window are coded as path>window\r
- */\r
-static void CALLBACK MACRO_JumpKeyword(LPCSTR lpszPath, LPCSTR lpszWindow, LPCSTR keyword)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", \"%s\")\n", lpszPath, lpszWindow, keyword);\r
-}\r
-\r
-static void CALLBACK MACRO_KLink(LPCSTR str1, LONG u, LPCSTR str2, LPCSTR str3)\r
-{\r
-    WINE_FIXME("(\"%s\", %u, \"%s\", \"%s\")\n", str1, u, str2, str3);\r
-}\r
-\r
-static void CALLBACK MACRO_Menu(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_MPrintHash(LONG u)\r
-{\r
-    WINE_FIXME("(%u)\n", u);\r
-}\r
-\r
-static void CALLBACK MACRO_MPrintID(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_Next(void)\r
-{\r
-    WINHELP_WNDPAGE     wp;\r
-\r
-    WINE_TRACE("()\n");\r
-    wp.page = Globals.active_win->page;\r
-    wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_fwd, &wp.relative);\r
-    if (wp.page)\r
-    {\r
-        wp.page->file->wRefCount++;\r
-        wp.wininfo = Globals.active_win->info;\r
-        WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE);\r
-    }\r
-}\r
-\r
-static void CALLBACK MACRO_NoShow(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-void CALLBACK MACRO_PopupContext(LPCSTR str, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", %u)\n", str, u);\r
-}\r
-\r
-static void CALLBACK MACRO_PopupHash(LPCSTR str, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", %u)\n", str, u);\r
-}\r
-\r
-static void CALLBACK MACRO_PopupId(LPCSTR str1, LPCSTR str2)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2);\r
-}\r
-\r
-static void CALLBACK MACRO_PositionWindow(LONG i1, LONG i2, LONG u1, LONG u2, LONG u3, LPCSTR str)\r
-{\r
-    WINE_FIXME("(%i, %i, %u, %u, %u, \"%s\")\n", i1, i2, u1, u2, u3, str);\r
-}\r
-\r
-static void CALLBACK MACRO_Prev(void)\r
-{\r
-    WINHELP_WNDPAGE     wp;\r
-\r
-    WINE_TRACE("()\n");\r
-    wp.page = Globals.active_win->page;\r
-    wp.page = HLPFILE_PageByOffset(wp.page->file, wp.page->browse_bwd, &wp.relative);\r
-    if (wp.page)\r
-    {\r
-        wp.page->file->wRefCount++;\r
-        wp.wininfo = Globals.active_win->info;\r
-        WINHELP_CreateHelpWindow(&wp, SW_NORMAL, TRUE);\r
-    }\r
-}\r
-\r
-void CALLBACK MACRO_Print(void)\r
-{\r
-    PRINTDLG printer;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    printer.lStructSize         = sizeof(printer);\r
-    printer.hwndOwner           = Globals.active_win->hMainWnd;\r
-    printer.hInstance           = Globals.hInstance;\r
-    printer.hDevMode            = 0;\r
-    printer.hDevNames           = 0;\r
-    printer.hDC                 = 0;\r
-    printer.Flags               = 0;\r
-    printer.nFromPage           = 0;\r
-    printer.nToPage             = 0;\r
-    printer.nMinPage            = 0;\r
-    printer.nMaxPage            = 0;\r
-    printer.nCopies             = 0;\r
-    printer.lCustData           = 0;\r
-    printer.lpfnPrintHook       = 0;\r
-    printer.lpfnSetupHook       = 0;\r
-    printer.lpPrintTemplateName = 0;\r
-    printer.lpSetupTemplateName = 0;\r
-    printer.hPrintTemplate      = 0;\r
-    printer.hSetupTemplate      = 0;\r
-\r
-    if (PrintDlgA(&printer)) {\r
-        WINE_FIXME("Print()\n");\r
-    }\r
-}\r
-\r
-void CALLBACK MACRO_PrinterSetup(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_RegisterRoutine(LPCSTR dll_name, LPCSTR proc, LPCSTR args)\r
-{\r
-    FARPROC             fn = NULL;\r
-    int                 size;\r
-    WINHELP_DLL*        dll;\r
-\r
-    WINE_TRACE("(\"%s\", \"%s\", \"%s\")\n", dll_name, proc, args);\r
-\r
-    /* FIXME: are the registered DLLs global or linked to the current file ???\r
-     * We assume globals (as we did for macros, but is this really the case ???)\r
-     */\r
-    for (dll = Globals.dlls; dll; dll = dll->next)\r
-    {\r
-        if (!strcmp(dll->name, dll_name)) break;\r
-    }\r
-    if (!dll)\r
-    {\r
-        HANDLE hLib = LoadLibrary(dll_name);\r
-\r
-        /* FIXME: the library will not be unloaded until exit of program \r
-         * We don't send the DW_TERM message\r
-         */\r
-        WINE_TRACE("Loading %s\n", dll_name);\r
-        /* FIXME: should look in the directory where current hlpfile\r
-         * is loaded from\r
-         */\r
-        if (hLib == NULL)\r
-        {\r
-            /* FIXME: internationalisation for error messages */\r
-            WINE_FIXME("Cannot find dll %s\n", dll_name);\r
-        }\r
-        else if ((dll = HeapAlloc(GetProcessHeap(), 0, sizeof(*dll))))\r
-        {\r
-            dll->hLib = hLib;\r
-            dll->name = strdup(dll_name); /* FIXME */\r
-            dll->next = Globals.dlls;\r
-            Globals.dlls = dll;\r
-            dll->handler = (WINHELP_LDLLHandler)GetProcAddress(dll->hLib, "LDLLHandler");\r
-            dll->class = dll->handler ? (dll->handler)(DW_WHATMSG, 0, 0) : DC_NOMSG;\r
-            WINE_TRACE("Got class %x for DLL %s\n", dll->class, dll_name);\r
-            if (dll->class & DC_INITTERM) dll->handler(DW_INIT, 0, 0);\r
-            if (dll->class & DC_CALLBACKS) dll->handler(DW_CALLBACKS, (DWORD)Callbacks, 0);\r
-        }\r
-        else WINE_WARN("OOM\n");\r
-    }\r
-    if (dll && !(fn = GetProcAddress(dll->hLib, proc)))\r
-    {\r
-        /* FIXME: internationalisation for error messages */\r
-        WINE_FIXME("Cannot find proc %s in dll %s\n", dll_name, proc);\r
-    }\r
-\r
-    size = ++MACRO_NumLoaded * sizeof(struct MacroDesc);\r
-    if (!MACRO_Loaded) MACRO_Loaded = HeapAlloc(GetProcessHeap(), 0, size);\r
-    else MACRO_Loaded = HeapReAlloc(GetProcessHeap(), 0, MACRO_Loaded, size);\r
-    MACRO_Loaded[MACRO_NumLoaded - 1].name      = strdup(proc); /* FIXME */\r
-    MACRO_Loaded[MACRO_NumLoaded - 1].alias     = NULL;\r
-    MACRO_Loaded[MACRO_NumLoaded - 1].isBool    = 0;\r
-    MACRO_Loaded[MACRO_NumLoaded - 1].arguments = strdup(args); /* FIXME */\r
-    MACRO_Loaded[MACRO_NumLoaded - 1].fn        = fn;\r
-    WINE_TRACE("Added %s(%s) at %p\n", proc, args, fn);\r
-}\r
-\r
-static void CALLBACK MACRO_RemoveAccelerator(LONG u1, LONG u2)\r
-{\r
-    WINE_FIXME("(%u, %u)\n", u1, u2);\r
-}\r
-\r
-static void CALLBACK MACRO_ResetMenu(void)\r
-{\r
-    WINE_FIXME("()\n");\r
-}\r
-\r
-static void CALLBACK MACRO_SaveMark(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_Search(void)\r
-{\r
-    WINHELP_CreateIndexWindow(TRUE);\r
-}\r
-\r
-void CALLBACK MACRO_SetContents(LPCSTR str, LONG u)\r
-{\r
-    WINE_FIXME("(\"%s\", %u)\n", str, u);\r
-}\r
-\r
-static void CALLBACK MACRO_SetHelpOnFile(LPCSTR str)\r
-{\r
-    WINE_TRACE("(\"%s\")\n", str);\r
-\r
-    HeapFree(GetProcessHeap(), 0, Globals.active_win->page->file->help_on_file);\r
-    Globals.active_win->page->file->help_on_file = HeapAlloc(GetProcessHeap(), 0, strlen(str) + 1);\r
-    if (Globals.active_win->page->file->help_on_file)\r
-        strcpy(Globals.active_win->page->file->help_on_file, str);\r
-}\r
-\r
-static void CALLBACK MACRO_SetPopupColor(LONG r, LONG g, LONG b)\r
-{\r
-    WINE_TRACE("(%x, %x, %x)\n", r, g, b);\r
-    Globals.active_win->page->file->has_popup_color = TRUE;\r
-    Globals.active_win->page->file->popup_color = RGB(r, g, b);\r
-}\r
-\r
-static void CALLBACK MACRO_ShellExecute(LPCSTR str1, LPCSTR str2, LONG u1, LONG u2, LPCSTR str3, LPCSTR str4)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", %u, %u, \"%s\", \"%s\")\n", str1, str2, u1, u2, str3, str4);\r
-}\r
-\r
-static void CALLBACK MACRO_ShortCut(LPCSTR str1, LPCSTR str2, LONG w, LONG l, LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\", %x, %x, \"%s\")\n", str1, str2, w, l, str);\r
-}\r
-\r
-static void CALLBACK MACRO_TCard(LONG u)\r
-{\r
-    WINE_FIXME("(%u)\n", u);\r
-}\r
-\r
-static void CALLBACK MACRO_Test(LONG u)\r
-{\r
-    WINE_FIXME("(%u)\n", u);\r
-}\r
-\r
-static BOOL CALLBACK MACRO_TestALink(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-    return FALSE;\r
-}\r
-\r
-static BOOL CALLBACK MACRO_TestKLink(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-    return FALSE;\r
-}\r
-\r
-static void CALLBACK MACRO_UncheckItem(LPCSTR str)\r
-{\r
-    WINE_FIXME("(\"%s\")\n", str);\r
-}\r
-\r
-static void CALLBACK MACRO_UpdateWindow(LPCSTR str1, LPCSTR str2)\r
-{\r
-    WINE_FIXME("(\"%s\", \"%s\")\n", str1, str2);\r
-}\r
-\r
-\r
-/**************************************************/\r
-/*               Macro table                      */\r
-/**************************************************/\r
-\r
-/* types:\r
- *      U:      32 bit unsigned int\r
- *      I:      32 bit signed int\r
- *      S:      string\r
- *      v:      unknown (32 bit entity)\r
- */\r
-\r
-static struct MacroDesc MACRO_Builtins[] = {\r
-    {"About",               NULL, 0, "",       (FARPROC)MACRO_About},\r
-    {"AddAccelerator",      "AA", 0, "UUS",    (FARPROC)MACRO_AddAccelerator},\r
-    {"ALink",               "AL", 0, "SUS",    (FARPROC)MACRO_ALink},\r
-    {"Annotate",            NULL, 0, "",       (FARPROC)MACRO_Annotate},\r
-    {"AppendItem",          NULL, 0, "SSSS",   (FARPROC)MACRO_AppendItem},\r
-    {"Back",                NULL, 0, "",       (FARPROC)MACRO_Back},\r
-    {"BackFlush",           "BF", 0, "",       (FARPROC)MACRO_BackFlush},\r
-    {"BookmarkDefine",      NULL, 0, "",       (FARPROC)MACRO_BookmarkDefine},\r
-    {"BookmarkMore",        NULL, 0, "",       (FARPROC)MACRO_BookmarkMore},\r
-    {"BrowseButtons",       NULL, 0, "",       (FARPROC)MACRO_BrowseButtons},\r
-    {"ChangeButtonBinding", "CBB",0, "SS",     (FARPROC)MACRO_ChangeButtonBinding},\r
-    {"ChangeEnable",        "CE", 0, "SS",     (FARPROC)MACRO_ChangeEnable},\r
-    {"ChangeItemBinding",   "CIB",0, "SS",     (FARPROC)MACRO_ChangeItemBinding},\r
-    {"CheckItem",           "CI", 0, "S",      (FARPROC)MACRO_CheckItem},\r
-    {"CloseSecondarys",     "CS", 0, "",       (FARPROC)MACRO_CloseSecondarys},\r
-    {"CloseWindow",         "CW", 0, "S",      (FARPROC)MACRO_CloseWindow},\r
-    {"Compare",             NULL, 0, "S",      (FARPROC)MACRO_Compare},\r
-    {"Contents",            NULL, 0, "",       (FARPROC)MACRO_Contents},\r
-    {"ControlPanel",        NULL, 0, "SSU",    (FARPROC)MACRO_ControlPanel},\r
-    {"CopyDialog",          NULL, 0, "",       (FARPROC)MACRO_CopyDialog},\r
-    {"CopyTopic",           "CT", 0, "",       (FARPROC)MACRO_CopyTopic},\r
-    {"CreateButton",        "CB", 0, "SSS",    (FARPROC)MACRO_CreateButton},\r
-    {"DeleteItem",          NULL, 0, "S",      (FARPROC)MACRO_DeleteItem},\r
-    {"DeleteMark",          NULL, 0, "S",      (FARPROC)MACRO_DeleteMark},\r
-    {"DestroyButton",       NULL, 0, "S",      (FARPROC)MACRO_DestroyButton},\r
-    {"DisableButton",       "DB", 0, "S",      (FARPROC)MACRO_DisableButton},\r
-    {"DisableItem",         "DI", 0, "S",      (FARPROC)MACRO_DisableItem},\r
-    {"EnableButton",        "EB", 0, "S",      (FARPROC)MACRO_EnableButton},\r
-    {"EnableItem",          "EI", 0, "S",      (FARPROC)MACRO_EnableItem},\r
-    {"EndMPrint",           NULL, 0, "",       (FARPROC)MACRO_EndMPrint},\r
-    {"ExecFile",            "EF", 0, "SSUS",   (FARPROC)MACRO_ExecFile},\r
-    {"ExecProgram",         "EP", 0, "SU",     (FARPROC)MACRO_ExecProgram},\r
-    {"Exit",                NULL, 0, "",       (FARPROC)MACRO_Exit},\r
-    {"ExtAbleItem",         NULL, 0, "SU",     (FARPROC)MACRO_ExtAbleItem},\r
-    {"ExtInsertItem",       NULL, 0, "SSSSUU", (FARPROC)MACRO_ExtInsertItem},\r
-    {"ExtInsertMenu",       NULL, 0, "SSSUU",  (FARPROC)MACRO_ExtInsertMenu},\r
-    {"FileExist",           "FE", 1, "S",      (FARPROC)MACRO_FileExist},\r
-    {"FileOpen",            "FO", 0, "",       (FARPROC)MACRO_FileOpen},\r
-    {"Find",                NULL, 0, "",       (FARPROC)MACRO_Find},\r
-    {"Finder",              "FD", 0, "",       (FARPROC)MACRO_Finder},\r
-    {"FloatingMenu",        NULL, 0, "",       (FARPROC)MACRO_FloatingMenu},\r
-    {"Flush",               "FH", 0, "",       (FARPROC)MACRO_Flush},\r
-    {"FocusWindow",         NULL, 0, "S",      (FARPROC)MACRO_FocusWindow},\r
-    {"Generate",            NULL, 0, "SUU",    (FARPROC)MACRO_Generate},\r
-    {"GotoMark",            NULL, 0, "S",      (FARPROC)MACRO_GotoMark},\r
-    {"HelpOn",              NULL, 0, "",       (FARPROC)MACRO_HelpOn},\r
-    {"HelpOnTop",           NULL, 0, "",       (FARPROC)MACRO_HelpOnTop},\r
-    {"History",             NULL, 0, "",       (FARPROC)MACRO_History},\r
-    {"InitMPrint",          NULL, 1, "",       (FARPROC)MACRO_InitMPrint},\r
-    {"InsertItem",          NULL, 0, "SSSSU",  (FARPROC)MACRO_InsertItem},\r
-    {"InsertMenu",          NULL, 0, "SSU",    (FARPROC)MACRO_InsertMenu},\r
-    {"IfThen",              "IF", 0, "BS",     (FARPROC)MACRO_IfThen},\r
-    {"IfThenElse",          "IE", 0, "BSS",    (FARPROC)MACRO_IfThenElse},\r
-    {"IsBook",              NULL, 1, "",       (FARPROC)MACRO_IsBook},\r
-    {"IsMark",              NULL, 1, "S",      (FARPROC)MACRO_IsMark},\r
-    {"IsNotMark",           "NM", 1, "S",      (FARPROC)MACRO_IsNotMark},\r
-    {"JumpContents",        NULL, 0, "SS",     (FARPROC)MACRO_JumpContents},\r
-    {"JumpContext",         "JC", 0, "SSU",    (FARPROC)MACRO_JumpContext},\r
-    {"JumpHash",            "JH", 0, "SSU",    (FARPROC)MACRO_JumpHash},\r
-    {"JumpHelpOn",          NULL, 0, "",       (FARPROC)MACRO_JumpHelpOn},\r
-    {"JumpID",              "JI", 0, "SS",     (FARPROC)MACRO_JumpID},\r
-    {"JumpKeyword",         "JK", 0, "SSS",    (FARPROC)MACRO_JumpKeyword},\r
-    {"KLink",               "KL", 0, "SUSS",   (FARPROC)MACRO_KLink},\r
-    {"Menu",                "MU", 0, "",       (FARPROC)MACRO_Menu},\r
-    {"MPrintHash",          NULL, 0, "U",      (FARPROC)MACRO_MPrintHash},\r
-    {"MPrintID",            NULL, 0, "S",      (FARPROC)MACRO_MPrintID},\r
-    {"Next",                NULL, 0, "",       (FARPROC)MACRO_Next},\r
-    {"NoShow",              NULL, 0, "",       (FARPROC)MACRO_NoShow},\r
-    {"PopupContext",        "PC", 0, "SU",     (FARPROC)MACRO_PopupContext},\r
-    {"PopupHash",           NULL, 0, "SU",     (FARPROC)MACRO_PopupHash},\r
-    {"PopupId",             "PI", 0, "SS",     (FARPROC)MACRO_PopupId},\r
-    {"PositionWindow",      "PW", 0, "IIUUUS", (FARPROC)MACRO_PositionWindow},\r
-    {"Prev",                NULL, 0, "",       (FARPROC)MACRO_Prev},\r
-    {"Print",               NULL, 0, "",       (FARPROC)MACRO_Print},\r
-    {"PrinterSetup",        NULL, 0, "",       (FARPROC)MACRO_PrinterSetup},\r
-    {"RegisterRoutine",     "RR", 0, "SSS",    (FARPROC)MACRO_RegisterRoutine},\r
-    {"RemoveAccelerator",   "RA", 0, "UU",     (FARPROC)MACRO_RemoveAccelerator},\r
-    {"ResetMenu",           NULL, 0, "",       (FARPROC)MACRO_ResetMenu},\r
-    {"SaveMark",            NULL, 0, "S",      (FARPROC)MACRO_SaveMark},\r
-    {"Search",              NULL, 0, "",       (FARPROC)MACRO_Search},\r
-    {"SetContents",         NULL, 0, "SU",     (FARPROC)MACRO_SetContents},\r
-    {"SetHelpOnFile",       NULL, 0, "S",      (FARPROC)MACRO_SetHelpOnFile},\r
-    {"SetPopupColor",       "SPC",0, "UUU",    (FARPROC)MACRO_SetPopupColor},\r
-    {"ShellExecute",        "SE", 0, "SSUUSS", (FARPROC)MACRO_ShellExecute},\r
-    {"ShortCut",            "SH", 0, "SSUUS",  (FARPROC)MACRO_ShortCut},\r
-    {"TCard",               NULL, 0, "U",      (FARPROC)MACRO_TCard},\r
-    {"Test",                NULL, 0, "U",      (FARPROC)MACRO_Test},\r
-    {"TestALink",           NULL, 1, "S",      (FARPROC)MACRO_TestALink},\r
-    {"TestKLink",           NULL, 1, "S",      (FARPROC)MACRO_TestKLink},\r
-    {"UncheckItem",         "UI", 0, "S",      (FARPROC)MACRO_UncheckItem},\r
-    {"UpdateWindow",        "UW", 0, "SS",     (FARPROC)MACRO_UpdateWindow},\r
-    {NULL,                  NULL, 0, NULL,     NULL}\r
-};\r
-\r
-static int MACRO_DoLookUp(struct MacroDesc* start, const char* name, struct lexret* lr, unsigned len)\r
-{\r
-    struct MacroDesc*   md;\r
-\r
-    for (md = start; md->name && len != 0; md++, len--)\r
-    {\r
-        if (strcasecmp(md->name, name) == 0 || (md->alias != NULL && strcasecmp(md->alias, name) == 0))\r
-        {\r
-            lr->proto = md->arguments;\r
-            lr->function = md->fn;\r
-            return md->isBool ? BOOL_FUNCTION : VOID_FUNCTION;\r
-        }\r
-    }\r
-    return EMPTY;\r
-}\r
-\r
-int MACRO_Lookup(const char* name, struct lexret* lr)\r
-{\r
-    int ret;\r
-\r
-    if ((ret = MACRO_DoLookUp(MACRO_Builtins, name, lr, -1)) != EMPTY)\r
-        return ret;\r
-    if (MACRO_Loaded && (ret = MACRO_DoLookUp(MACRO_Loaded, name, lr, MACRO_NumLoaded)) != EMPTY)\r
-        return ret;\r
-\r
-    lr->string = name;\r
-    return IDENTIFIER;\r
-}\r
+/*
+ * 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 <stdio.h>
+
+#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;
+}
index 7af99b6..8b15719 100644 (file)
@@ -1,62 +1,62 @@
-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid\r
- * Copyright 2002 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#include <stdarg.h>\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-\r
-struct lexret {\r
-  LPCSTR        proto;\r
-  BOOL          bool;\r
-  LONG          integer;\r
-  LPCSTR        string;\r
-  FARPROC       function;\r
-};\r
-\r
-extern struct lexret yylval;\r
-\r
-BOOL MACRO_ExecuteMacro(LPCSTR);\r
-int  MACRO_Lookup(const char* name, struct lexret* lr);\r
-\r
-enum token_types {EMPTY, VOID_FUNCTION, BOOL_FUNCTION, INTEGER, STRING, IDENTIFIER};\r
-void CALLBACK MACRO_About(void);\r
-void CALLBACK MACRO_Annotate(void);\r
-void CALLBACK MACRO_BookmarkDefine(void);\r
-void CALLBACK MACRO_CopyDialog(void);\r
-void CALLBACK MACRO_CreateButton(LPCSTR, LPCSTR, LPCSTR);\r
-void CALLBACK MACRO_DisableButton(LPCSTR);\r
-void CALLBACK MACRO_Exit(void);\r
-void CALLBACK MACRO_FileOpen(void);\r
-void CALLBACK MACRO_HelpOn(void);\r
-void CALLBACK MACRO_HelpOnTop(void);\r
-void CALLBACK MACRO_History(void);\r
-void CALLBACK MACRO_JumpContents(LPCSTR, LPCSTR);\r
-void CALLBACK MACRO_JumpContext(LPCSTR, LPCSTR, LONG);\r
-void CALLBACK MACRO_JumpHash(LPCSTR, LPCSTR, LONG);\r
-void CALLBACK MACRO_PopupContext(LPCSTR, LONG);\r
-void CALLBACK MACRO_Print(void);\r
-void CALLBACK MACRO_PrinterSetup(void);\r
-void CALLBACK MACRO_SetContents(LPCSTR, LONG);\r
-\r
-/* Local Variables:    */\r
-/* c-file-style: "GNU" */\r
-/* End:                */\r
+/*
+ * 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 <stdarg.h>
+
+#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:                */
index 0594a2d..f3366b0 100644 (file)
-%{ /* -*-C-*- */\r
-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid\r
- * Copyright 2002,2008 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-%}\r
-%option noinput nounput interactive 8bit\r
-%x quote\r
-%{\r
-#include "config.h"\r
-#include <assert.h>\r
-\r
-#ifndef HAVE_UNISTD_H\r
-#define YY_NO_UNISTD_H\r
-#endif\r
-\r
-#include "macro.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-struct lex_data {\r
-    LPCSTR   macroptr;\r
-    LPSTR    strptr;\r
-    int      quote_stack[32];\r
-    unsigned quote_stk_idx;\r
-    LPSTR    cache_string[32];\r
-    int      cache_used;\r
-};\r
-static struct lex_data* lex_data = NULL;\r
-\r
-struct lexret  yylval;\r
-\r
-#define YY_INPUT(buf,result,max_size)\\r
-  if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++;\r
-\r
-%}\r
-%%\r
-\r
-[-+]?[0-9]+             yylval.integer = strtol(yytext, NULL, 10);     return INTEGER;\r
-[-+]?0[xX][0-9a-f]+    yylval.integer = strtol(yytext, NULL, 16);      return INTEGER;\r
-\r
-[a-zA-Z][_0-9a-zA-Z]*   return MACRO_Lookup(yytext, &yylval);\r
-\r
-\`         |\r
-\"         |\r
-\'          |\r
-<quote>\`   |\r
-<quote>\"   |\r
-<quote>\'   {\r
-    if (lex_data->quote_stk_idx == 0 ||\r
-        (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') ||\r
-        (yytext[0] == '`'))\r
-    {\r
-        /* opening a new one */\r
-        if (lex_data->quote_stk_idx == 0)\r
-        {\r
-            assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0]));\r
-            lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1);\r
-            yylval.string = lex_data->strptr;\r
-            lex_data->cache_used++;\r
-            BEGIN(quote);\r
-        }\r
-        else *lex_data->strptr++ = yytext[0];\r
-        lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0];\r
-        assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0]));\r
-    }\r
-    else\r
-    {\r
-        if (yytext[0] == '`') assert(0);\r
-        /* close the current quote */\r
-        if (--lex_data->quote_stk_idx == 0)\r
-        {\r
-            BEGIN INITIAL;\r
-            *lex_data->strptr++ = '\0';\r
-            return STRING;\r
-        }\r
-        else *lex_data->strptr++ = yytext[0];\r
-    }\r
-}\r
-\r
-<quote>.                *lex_data->strptr++ = yytext[0];\r
-<quote>\\.             *lex_data->strptr++ = yytext[1];\r
-<quote><<EOF>>         return 0;\r
-\r
-" "\r
-.                      return yytext[0];\r
-%%\r
-\r
-#if 0\r
-/* all code for testing macros */\r
-#include "winhelp.h"\r
-static CHAR szTestMacro[256];\r
-\r
-static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (msg == WM_COMMAND && wParam == IDOK)\r
-    {\r
-        GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro));\r
-        EndDialog(hDlg, IDOK);\r
-        return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-void macro_test(void)\r
-{\r
-    WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance);\r
-    DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg);\r
-    FreeProcInstance(lpfnDlg);\r
-    macro = szTestMacro;\r
-}\r
-#endif\r
-\r
-/* small helper function for debug messages */\r
-static const char* ts(int t)\r
-{\r
-    static char c[2] = {0,0};\r
-\r
-    switch (t)\r
-    {\r
-    case EMPTY: return "EMPTY";\r
-    case VOID_FUNCTION: return "VOID_FUNCTION";\r
-    case BOOL_FUNCTION: return "BOOL_FUNCTION";\r
-    case INTEGER: return "INTEGER";\r
-    case STRING: return "STRING";\r
-    case IDENTIFIER: return "IDENTIFIER";\r
-    default: c[0] = (char)t; return c;\r
-    }\r
-}\r
-\r
-static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret);\r
-\r
-/******************************************************************\r
- *             MACRO_CheckArgs\r
- *\r
- * checks number of arguments against prototype, and stores arguments on\r
- * stack pa for later call\r
- * returns -1 on error, otherwise the number of pushed parameters\r
- */\r
-static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args)\r
-{\r
-    int t;\r
-    unsigned int len = 0, idx = 0;\r
-\r
-    WINE_TRACE("Checking %s\n", args);\r
-\r
-    if (yylex() != '(') {WINE_WARN("missing (\n");return -1;}\r
-\r
-    if (*args)\r
-    {\r
-        len = strlen(args);\r
-        for (;;)\r
-        {\r
-            t = yylex();\r
-            WINE_TRACE("Got %s <=> %c\n", ts(t), *args);\r
-\r
-            switch (*args)\r
-            {\r
-            case 'S': \r
-                if (t != STRING)\r
-                {WINE_WARN("missing S\n");return -1;}\r
-                pa[idx] = (void*)yylval.string;  \r
-                break;\r
-            case 'U':\r
-            case 'I':\r
-                if (t != INTEGER)\r
-                {WINE_WARN("missing U\n");return -1;}   \r
-                pa[idx] = LongToPtr(yylval.integer);\r
-                break;\r
-            case 'B':\r
-                if (t != BOOL_FUNCTION) \r
-                {WINE_WARN("missing B\n");return -1;}   \r
-                if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0)\r
-                    return -1;\r
-                break;\r
-            default: \r
-                WINE_WARN("unexpected %s while args is %c\n", ts(t), *args);\r
-                return -1;\r
-            }\r
-            idx++;\r
-            if (*++args == '\0') break;\r
-            t = yylex();\r
-            if (t == ')') goto CheckArgs_end;\r
-            if (t != ',') {WINE_WARN("missing ,\n");return -1;}\r
-            if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;}\r
-        }\r
-    }\r
-    if (yylex() != ')') {WINE_WARN("missing )\n");return -1;}\r
-\r
-CheckArgs_end:\r
-    while (len > idx) pa[--len] = NULL;\r
-    return idx;\r
-}\r
-\r
-/******************************************************************\r
- *             MACRO_CallBoolFunc\r
- *\r
- * Invokes boolean function fn, which arguments are defined by args\r
- * stores bool result into ret\r
- */\r
-static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret)\r
-{\r
-    void*       pa[2];\r
-    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);\r
-\r
-    if (idx < 0) return 0;\r
-    if (!fn)     return 1;\r
-\r
-    WINE_TRACE("calling with %u pmts\n", idx);\r
-\r
-    switch (strlen(args))\r
-    {\r
-    case 0: *ret = (void*)(fn)();          break;\r
-    case 1: *ret = (void*)(fn)(pa[0]);     break;\r
-    default: WINE_FIXME("NIY\n");\r
-    }\r
-\r
-    return 1;\r
-}\r
-\r
-/******************************************************************\r
- *             MACRO_CallVoidFunc\r
- *\r
- *\r
- */\r
-static int MACRO_CallVoidFunc(FARPROC fn, const char* args)\r
-{\r
-    void*       pa[6];\r
-    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);\r
-\r
-    if (idx < 0) return 0;\r
-    if (!fn)     return 1;\r
-\r
-    WINE_TRACE("calling %p with %u pmts\n", fn, idx);\r
-\r
-    switch (strlen(args))\r
-    {\r
-    case 0: (fn)();                                     break;\r
-    case 1: (fn)(pa[0]);                                break;\r
-    case 2: (fn)(pa[0],pa[1]);                          break;\r
-    case 3: (fn)(pa[0],pa[1],pa[2]);                    break;\r
-    case 4: (fn)(pa[0],pa[1],pa[2],pa[3]);              break;\r
-    case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]);        break;\r
-    case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]);  break;\r
-    default: WINE_FIXME("NIY\n");\r
-    }\r
-\r
-    return 1;\r
-}\r
-\r
-BOOL MACRO_ExecuteMacro(LPCSTR macro)\r
-{\r
-    struct lex_data     curr_lex_data, *prev_lex_data;\r
-    BOOL ret = TRUE;\r
-    int t;\r
-\r
-    WINE_TRACE("%s\n", wine_dbgstr_a(macro));\r
-\r
-    prev_lex_data = lex_data;\r
-    lex_data = &curr_lex_data;\r
-\r
-    memset(lex_data, 0, sizeof(*lex_data));\r
-    lex_data->macroptr = macro;\r
-\r
-    while ((t = yylex()) != EMPTY)\r
-    {\r
-        switch (t)\r
-        {\r
-        case VOID_FUNCTION:\r
-            WINE_TRACE("got type void func(%s)\n", yylval.proto);\r
-            MACRO_CallVoidFunc(yylval.function, yylval.proto);\r
-            break;\r
-        case BOOL_FUNCTION:\r
-            WINE_WARN("got type bool func(%s)\n", yylval.proto);\r
-            break;\r
-        default:\r
-            WINE_WARN("got unexpected type %s\n", ts(t));\r
-            return 0;\r
-        }\r
-        switch (t = yylex())\r
-        {\r
-        case EMPTY:     goto done;\r
-        case ';':       break;\r
-        default:        ret = FALSE; goto done;\r
-        }\r
-    }\r
-\r
-done:\r
-    for (t = 0; t < lex_data->cache_used; t++)\r
-        HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]);\r
-    lex_data = prev_lex_data;\r
-\r
-    return ret;\r
-}\r
-\r
-#ifndef yywrap\r
-int yywrap(void) { return 1; }\r
-#endif\r
+%{ /* -*-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 <assert.h>
+
+#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);
+
+\`         |
+\"         |
+\'          |
+<quote>\`   |
+<quote>\"   |
+<quote>\'   {
+    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];
+    }
+}
+
+<quote>.                *lex_data->strptr++ = yytext[0];
+<quote>\\.             *lex_data->strptr++ = yytext[1];
+<quote><<EOF>>         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
index ba9713d..b931948 100644 (file)
@@ -1,34 +1,34 @@
-/*\r
- * Help Viewer\r
- *\r
- * Copyright 1996 Ulrich Schmid\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-/* Class names */\r
-\r
-const char MAIN_WIN_CLASS_NAME[]       = "MS_WINHELP";\r
-const char BUTTON_BOX_WIN_CLASS_NAME[] = "WHButtonBox";\r
-const char SHADOW_WIN_CLASS_NAME[]     = "WHShadow";\r
-const char HISTORY_WIN_CLASS_NAME[]    = "WHHistory";\r
-const char STRING_BUTTON[]             = "BUTTON";\r
-\r
-/* Resource names */\r
-const char STRING_DIALOG_TEST[]        = "DIALOG_TEST";\r
-\r
-/* Local Variables:    */\r
-/* c-file-style: "GNU" */\r
-/* End:                */\r
+/*
+ * 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:                */
index 6f293ea..15e17f6 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright    1996 Ulrich Schmid <uschmid@mail.hh.provi.de>\r
- *              2002 Sylvain Petreolle <spetreolle@yahoo.fr>\r
- *              2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>\r
- *              2004 Ken Belleau <jamez@ivic.qc.ca>\r
- *              2008 Kirill K. Smirnov <lich@math.spbu.ru>\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#include <assert.h>\r
-#include <stdio.h>\r
-#include <string.h>\r
-#include <stdarg.h>\r
-#include <stdlib.h>\r
-\r
-#define NONAMELESSUNION\r
-#define NONAMELESSSTRUCT\r
-\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "wingdi.h"\r
-#include "winuser.h"\r
-#include "commdlg.h"\r
-#include "winhelp.h"\r
-#include "winhelp_res.h"\r
-#include "shellapi.h"\r
-#include "richedit.h"\r
-#include "commctrl.h"\r
-\r
-#include "wine/debug.h"\r
-\r
-WINE_DEFAULT_DEBUG_CHANNEL(winhelp);\r
-\r
-WINHELP_GLOBALS Globals = {3, NULL, TRUE, NULL, NULL, NULL, NULL, NULL, {{{NULL,NULL}},0}, NULL};\r
-\r
-#define CTL_ID_BUTTON   0x700\r
-#define CTL_ID_TEXT     0x701\r
-\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_InitFonts\r
- */\r
-static void WINHELP_InitFonts(HWND hWnd)\r
-{\r
-    WINHELP_WINDOW *win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-    LOGFONT logfontlist[] = {\r
-        {-10, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-12, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        {-10, 0, 0, 0, 700, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"},\r
-        { -8, 0, 0, 0, 400, 0, 0, 0, DEFAULT_CHARSET, 0, 0, 0, 32, "Helv"}};\r
-#define FONTS_LEN (sizeof(logfontlist)/sizeof(*logfontlist))\r
-\r
-    static HFONT fonts[FONTS_LEN];\r
-    static BOOL init = 0;\r
-\r
-    win->fonts_len = FONTS_LEN;\r
-    win->fonts = fonts;\r
-\r
-    if (!init)\r
-    {\r
-        UINT i;\r
-\r
-        for (i = 0; i < FONTS_LEN; i++)\r
-       {\r
-            fonts[i] = CreateFontIndirect(&logfontlist[i]);\r
-       }\r
-\r
-        init = 1;\r
-    }\r
-}\r
-\r
-static DWORD CALLBACK WINHELP_RtfStreamIn(DWORD_PTR cookie, BYTE* buff,\r
-                                          LONG cb, LONG* pcb)\r
-{\r
-    struct RtfData*     rd = (struct RtfData*)cookie;\r
-\r
-    if (rd->where >= rd->ptr) return 1;\r
-    if (rd->where + cb > rd->ptr)\r
-        cb = rd->ptr - rd->where;\r
-    memcpy(buff, rd->where, cb);\r
-    rd->where += cb;\r
-    *pcb = cb;\r
-    return 0;\r
-}\r
-\r
-static void WINHELP_SetupText(HWND hTextWnd, WINHELP_WINDOW* win, ULONG relative)\r
-{\r
-    /* At first clear area - needed by EM_POSFROMCHAR/EM_SETSCROLLPOS */\r
-    SendMessage(hTextWnd, WM_SETTEXT, 0, (LPARAM)"");\r
-    SendMessage(hTextWnd, WM_SETREDRAW, FALSE, 0);\r
-    SendMessage(hTextWnd, EM_SETBKGNDCOLOR, 0, (LPARAM)win->info->sr_color);\r
-    /* set word-wrap to window size (undocumented) */\r
-    SendMessage(hTextWnd, EM_SETTARGETDEVICE, 0, 0);\r
-    if (win->page)\r
-    {\r
-        struct RtfData  rd;\r
-        EDITSTREAM      es;\r
-        unsigned        cp = 0;\r
-        POINTL          ptl;\r
-        POINT           pt;\r
-\r
-\r
-        if (HLPFILE_BrowsePage(win->page, &rd, win->font_scale, relative))\r
-        {\r
-            rd.where = rd.data;\r
-            es.dwCookie = (DWORD_PTR)&rd;\r
-            es.dwError = 0;\r
-            es.pfnCallback = WINHELP_RtfStreamIn;\r
-\r
-            SendMessageW(hTextWnd, EM_STREAMIN, SF_RTF, (LPARAM)&es);\r
-            cp = rd.char_pos_rel;\r
-        }\r
-        /* FIXME: else leaking potentially the rd.first_link chain */\r
-        HeapFree(GetProcessHeap(), 0, rd.data);\r
-        SendMessage(hTextWnd, EM_POSFROMCHAR, (WPARAM)&ptl, cp ? cp - 1 : 0);\r
-        pt.x = 0; pt.y = ptl.y;\r
-        SendMessage(hTextWnd, EM_SETSCROLLPOS, 0, (LPARAM)&pt);\r
-    }\r
-    SendMessage(hTextWnd, WM_SETREDRAW, TRUE, 0);\r
-    InvalidateRect(hTextWnd, NULL, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_GetOpenFileName\r
- */\r
-BOOL WINHELP_GetOpenFileName(LPSTR lpszFile, int len)\r
-{\r
-    OPENFILENAME openfilename;\r
-    CHAR szDir[MAX_PATH];\r
-    CHAR szzFilter[2 * MAX_STRING_LEN + 100];\r
-    LPSTR p = szzFilter;\r
-\r
-    WINE_TRACE("()\n");\r
-\r
-    LoadString(Globals.hInstance, STID_HELP_FILES_HLP, p, MAX_STRING_LEN);\r
-    p += strlen(p) + 1;\r
-    lstrcpy(p, "*.hlp");\r
-    p += strlen(p) + 1;\r
-    LoadString(Globals.hInstance, STID_ALL_FILES, p, MAX_STRING_LEN);\r
-    p += strlen(p) + 1;\r
-    lstrcpy(p, "*.*");\r
-    p += strlen(p) + 1;\r
-    *p = '\0';\r
-\r
-    GetCurrentDirectory(sizeof(szDir), szDir);\r
-\r
-    lpszFile[0]='\0';\r
-\r
-    openfilename.lStructSize       = sizeof(OPENFILENAME);\r
-    openfilename.hwndOwner         = NULL;\r
-    openfilename.hInstance         = Globals.hInstance;\r
-    openfilename.lpstrFilter       = szzFilter;\r
-    openfilename.lpstrCustomFilter = 0;\r
-    openfilename.nMaxCustFilter    = 0;\r
-    openfilename.nFilterIndex      = 1;\r
-    openfilename.lpstrFile         = lpszFile;\r
-    openfilename.nMaxFile          = len;\r
-    openfilename.lpstrFileTitle    = 0;\r
-    openfilename.nMaxFileTitle     = 0;\r
-    openfilename.lpstrInitialDir   = szDir;\r
-    openfilename.lpstrTitle        = 0;\r
-    openfilename.Flags             = 0;\r
-    openfilename.nFileOffset       = 0;\r
-    openfilename.nFileExtension    = 0;\r
-    openfilename.lpstrDefExt       = 0;\r
-    openfilename.lCustData         = 0;\r
-    openfilename.lpfnHook          = 0;\r
-    openfilename.lpTemplateName    = 0;\r
-\r
-    return GetOpenFileName(&openfilename);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_MessageBoxIDS_s\r
- */\r
-static INT WINHELP_MessageBoxIDS_s(UINT ids_text, LPCSTR str, UINT ids_title, WORD type)\r
-{\r
-    CHAR text[MAX_STRING_LEN];\r
-    CHAR newtext[MAX_STRING_LEN + MAX_PATH];\r
-\r
-    LoadString(Globals.hInstance, ids_text, text, sizeof(text));\r
-    wsprintf(newtext, text, str);\r
-\r
-    return MessageBox(0, newtext, MAKEINTRESOURCE(ids_title), type);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_LookupHelpFile\r
- */\r
-HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile)\r
-{\r
-    HLPFILE*        hlpfile;\r
-    char szFullName[MAX_PATH];\r
-    char szAddPath[MAX_PATH];\r
-    char *p;\r
-\r
-    /*\r
-     * NOTE: This is needed by popup windows only.\r
-     * In other cases it's not needed but does not hurt though.\r
-     */\r
-    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
-    {\r
-        strcpy(szAddPath, Globals.active_win->page->file->lpszPath);\r
-        p = strrchr(szAddPath, '\\');\r
-        if (p) *p = 0;\r
-    }\r
-\r
-    /*\r
-     * FIXME: Should we swap conditions?\r
-     */\r
-    if (!SearchPath(NULL, lpszFile, ".hlp", MAX_PATH, szFullName, NULL) &&\r
-        !SearchPath(szAddPath, lpszFile, ".hlp", MAX_PATH, szFullName, NULL))\r
-    {\r
-        if (WINHELP_MessageBoxIDS_s(STID_FILE_NOT_FOUND_s, lpszFile, STID_WHERROR,\r
-                                    MB_YESNO|MB_ICONQUESTION) != IDYES)\r
-            return NULL;\r
-        if (!WINHELP_GetOpenFileName(szFullName, MAX_PATH))\r
-            return NULL;\r
-    }\r
-    hlpfile = HLPFILE_ReadHlpFile(szFullName);\r
-    if (!hlpfile)\r
-        WINHELP_MessageBoxIDS_s(STID_HLPFILE_ERROR_s, lpszFile,\r
-                                STID_WHERROR, MB_OK|MB_ICONSTOP);\r
-    return hlpfile;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_GetWindowInfo\r
- *\r
- *\r
- */\r
-HLPFILE_WINDOWINFO*     WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name)\r
-{\r
-    static      HLPFILE_WINDOWINFO      mwi;\r
-    unsigned int     i;\r
-\r
-    if (!name || !name[0])\r
-        name = Globals.active_win->lpszName;\r
-\r
-    if (hlpfile)\r
-        for (i = 0; i < hlpfile->numWindows; i++)\r
-            if (!strcmp(hlpfile->windows[i].name, name))\r
-                return &hlpfile->windows[i];\r
-\r
-    if (strcmp(name, "main") != 0)\r
-    {\r
-        WINE_FIXME("Couldn't find window info for %s\n", name);\r
-        assert(0);\r
-        return NULL;\r
-    }\r
-    if (!mwi.name[0])\r
-    {\r
-        strcpy(mwi.type, "primary");\r
-        strcpy(mwi.name, "main");\r
-        if (!LoadString(Globals.hInstance, STID_WINE_HELP, \r
-                        mwi.caption, sizeof(mwi.caption)))\r
-            strcpy(mwi.caption, hlpfile->lpszTitle);\r
-        mwi.origin.x = mwi.origin.y = mwi.size.cx = mwi.size.cy = CW_USEDEFAULT;\r
-        mwi.style = SW_SHOW;\r
-        mwi.win_style = WS_OVERLAPPEDWINDOW;\r
-        mwi.sr_color = mwi.sr_color = 0xFFFFFF;\r
-    }\r
-    return &mwi;\r
-}\r
-\r
-/******************************************************************\r
- *             HLPFILE_GetPopupWindowInfo\r
- *\r
- *\r
- */\r
-static HLPFILE_WINDOWINFO*     WINHELP_GetPopupWindowInfo(HLPFILE* hlpfile,\r
-                                                          WINHELP_WINDOW* parent, LPARAM mouse)\r
-{\r
-    static      HLPFILE_WINDOWINFO      wi;\r
-\r
-    RECT parent_rect;\r
-    \r
-    wi.type[0] = wi.name[0] = wi.caption[0] = '\0';\r
-\r
-    /* Calculate horizontal size and position of a popup window */\r
-    GetWindowRect(parent->hMainWnd, &parent_rect);\r
-    wi.size.cx = (parent_rect.right  - parent_rect.left) / 2;\r
-    wi.size.cy = 10; /* need a non null value, so that border are taken into account while computing */\r
-\r
-    wi.origin.x = (short)LOWORD(mouse);\r
-    wi.origin.y = (short)HIWORD(mouse);\r
-    ClientToScreen(parent->hMainWnd, &wi.origin);\r
-    wi.origin.x -= wi.size.cx / 2;\r
-    wi.origin.x  = min(wi.origin.x, GetSystemMetrics(SM_CXSCREEN) - wi.size.cx);\r
-    wi.origin.x  = max(wi.origin.x, 0);\r
-\r
-    wi.style = SW_SHOW;\r
-    wi.win_style = WS_POPUP | WS_BORDER;\r
-    if (parent->page->file->has_popup_color)\r
-        wi.sr_color = parent->page->file->popup_color;\r
-    else\r
-        wi.sr_color = parent->info->sr_color;\r
-    wi.nsr_color = 0xFFFFFF;\r
-\r
-    return &wi;\r
-}\r
-\r
-typedef struct\r
-{\r
-    WORD size;\r
-    WORD command;\r
-    LONG data;\r
-    LONG reserved;\r
-    WORD ofsFilename;\r
-    WORD ofsData;\r
-} WINHELP,*LPWINHELP;\r
-\r
-static BOOL WINHELP_HasWorkingWindow(void)\r
-{\r
-    if (!Globals.active_win) return FALSE;\r
-    if (Globals.active_win->next || Globals.win_list != Globals.active_win) return TRUE;\r
-    return Globals.active_win->page != NULL && Globals.active_win->page->file != NULL;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HandleCommand\r
- *\r
- *\r
- */\r
-static LRESULT  WINHELP_HandleCommand(HWND hSrcWnd, LPARAM lParam)\r
-{\r
-    COPYDATASTRUCT*     cds = (COPYDATASTRUCT*)lParam;\r
-    WINHELP*            wh;\r
-\r
-    if (cds->dwData != 0xA1DE505)\r
-    {\r
-        WINE_FIXME("Wrong magic number (%08lx)\n", cds->dwData);\r
-        return 0;\r
-    }\r
-\r
-    wh = (WINHELP*)cds->lpData;\r
-\r
-    if (wh)\r
-    {\r
-        char*   ptr = (wh->ofsFilename) ? (LPSTR)wh + wh->ofsFilename : NULL;\r
-\r
-        WINE_TRACE("Got[%u]: cmd=%u data=%08x fn=%s\n",\r
-                   wh->size, wh->command, wh->data, ptr);\r
-        switch (wh->command)\r
-        {\r
-        case HELP_CONTEXT:\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpContext(ptr, "main", wh->data);\r
-            }\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        case HELP_QUIT:\r
-            MACRO_Exit();\r
-            break;\r
-        case HELP_CONTENTS:\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpContents(ptr, "main");\r
-            }\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        case HELP_HELPONHELP:\r
-            MACRO_HelpOn();\r
-            if (!WINHELP_HasWorkingWindow()) MACRO_Exit();\r
-            break;\r
-        /* case HELP_SETINDEX: */\r
-        case HELP_SETCONTENTS:\r
-            if (ptr)\r
-            {\r
-                MACRO_SetContents(ptr, wh->data);\r
-            }\r
-            break;\r
-        case HELP_CONTEXTPOPUP:\r
-            if (ptr)\r
-            {\r
-                MACRO_PopupContext(ptr, wh->data);\r
-            }\r
-            break;\r
-        /* case HELP_FORCEFILE:*/\r
-        /* case HELP_CONTEXTMENU: */\r
-        case HELP_FINDER:\r
-            /* in fact, should be the topic dialog box */\r
-            WINE_FIXME("HELP_FINDER: stub\n");\r
-            if (ptr)\r
-            {\r
-                MACRO_JumpHash(ptr, "main", 0);\r
-            }\r
-            break;\r
-        /* case HELP_WM_HELP: */\r
-        /* case HELP_SETPOPUP_POS: */\r
-        /* case HELP_KEY: */\r
-        /* case HELP_COMMAND: */\r
-        /* case HELP_PARTIALKEY: */\r
-        /* case HELP_MULTIKEY: */\r
-        /* case HELP_SETWINPOS: */\r
-        default:\r
-            WINE_FIXME("Unhandled command (%x) for remote winhelp control\n", wh->command);\r
-            break;\r
-        }\r
-    }\r
-    /* Always return success for now */\r
-    return 1;\r
-}\r
-\r
-void            WINHELP_LayoutMainWindow(WINHELP_WINDOW* win)\r
-{\r
-    RECT        rect, button_box_rect;\r
-    INT         text_top = 0;\r
-    HWND        hButtonBoxWnd = GetDlgItem(win->hMainWnd, CTL_ID_BUTTON);\r
-    HWND        hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-\r
-    GetClientRect(win->hMainWnd, &rect);\r
-\r
-    /* Update button box and text Window */\r
-    SetWindowPos(hButtonBoxWnd, HWND_TOP,\r
-                 rect.left, rect.top,\r
-                 rect.right - rect.left,\r
-                 rect.bottom - rect.top, 0);\r
-\r
-    if (GetWindowRect(hButtonBoxWnd, &button_box_rect))\r
-        text_top = rect.top + button_box_rect.bottom - button_box_rect.top;\r
-\r
-    SetWindowPos(hTextWnd, HWND_TOP,\r
-                 rect.left, text_top,\r
-                 rect.right - rect.left,\r
-                 rect.bottom - text_top, 0);\r
-\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeleteButtons\r
- *\r
- */\r
-static void WINHELP_DeleteButtons(WINHELP_WINDOW* win)\r
-{\r
-    WINHELP_BUTTON*     b;\r
-    WINHELP_BUTTON*     bp;\r
-\r
-    for (b = win->first_button; b; b = bp)\r
-    {\r
-        DestroyWindow(b->hWnd);\r
-        bp = b->next;\r
-        HeapFree(GetProcessHeap(), 0, b);\r
-    }\r
-    win->first_button = NULL;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeleteBackSet\r
- *\r
- */\r
-void WINHELP_DeleteBackSet(WINHELP_WINDOW* win)\r
-{\r
-    unsigned int i;\r
-\r
-    for (i = 0; i < win->back.index; i++)\r
-    {\r
-        HLPFILE_FreeHlpFile(win->back.set[i].page->file);\r
-        win->back.set[i].page = NULL;\r
-    }\r
-    win->back.index = 0;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_DeletePageLinks\r
- *\r
- */\r
-static void WINHELP_DeletePageLinks(HLPFILE_PAGE* page)\r
-{\r
-    HLPFILE_LINK*       curr;\r
-    HLPFILE_LINK*       next;\r
-\r
-    for (curr = page->first_link; curr; curr = next)\r
-    {\r
-        next = curr->next;\r
-        HeapFree(GetProcessHeap(), 0, curr);\r
-    }\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_DeleteWindow\r
- */\r
-static void WINHELP_DeleteWindow(WINHELP_WINDOW* win)\r
-{\r
-    WINHELP_WINDOW**    w;\r
-\r
-    for (w = &Globals.win_list; *w; w = &(*w)->next)\r
-    {\r
-        if (*w == win)\r
-        {\r
-            *w = win->next;\r
-            break;\r
-        }\r
-    }\r
-\r
-    if (Globals.active_win == win)\r
-    {\r
-        Globals.active_win = Globals.win_list;\r
-        if (Globals.win_list)\r
-            SetActiveWindow(Globals.win_list->hMainWnd);\r
-    }\r
-\r
-    if (win == Globals.active_popup)\r
-        Globals.active_popup = NULL;\r
-\r
-    WINHELP_DeleteButtons(win);\r
-\r
-    if (win->page) WINHELP_DeletePageLinks(win->page);\r
-    if (win->hShadowWnd) DestroyWindow(win->hShadowWnd);\r
-    if (win->hHistoryWnd) DestroyWindow(win->hHistoryWnd);\r
-\r
-    DeleteObject(win->hBrush);\r
-\r
-    WINHELP_DeleteBackSet(win);\r
-\r
-    if (win->page) HLPFILE_FreeHlpFile(win->page->file);\r
-    HeapFree(GetProcessHeap(), 0, win);\r
-}\r
-\r
-static char* WINHELP_GetCaption(WINHELP_WNDPAGE* wpage)\r
-{\r
-    if (wpage->wininfo->caption[0]) return wpage->wininfo->caption;\r
-    return wpage->page->file->lpszTitle;\r
-}\r
-\r
-static void WINHELP_RememberPage(WINHELP_WINDOW* win, WINHELP_WNDPAGE* wpage)\r
-{\r
-    unsigned        num;\r
-\r
-    if (!Globals.history.index || Globals.history.set[0].page != wpage->page)\r
-    {\r
-        num = sizeof(Globals.history.set) / sizeof(Globals.history.set[0]);\r
-        /* we're full, remove latest entry */\r
-        if (Globals.history.index == num)\r
-        {\r
-            HLPFILE_FreeHlpFile(Globals.history.set[num - 1].page->file);\r
-            Globals.history.index--;\r
-        }\r
-        memmove(&Globals.history.set[1], &Globals.history.set[0],\r
-                Globals.history.index * sizeof(Globals.history.set[0]));\r
-        Globals.history.set[0] = *wpage;\r
-        Globals.history.index++;\r
-        wpage->page->file->wRefCount++;\r
-    }\r
-    if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
-    num = sizeof(win->back.set) / sizeof(win->back.set[0]);\r
-    if (win->back.index == num)\r
-    {\r
-        /* we're full, remove latest entry */\r
-        HLPFILE_FreeHlpFile(win->back.set[0].page->file);\r
-        memmove(&win->back.set[0], &win->back.set[1],\r
-                (num - 1) * sizeof(win->back.set[0]));\r
-        win->back.index--;\r
-    }\r
-    win->back.set[win->back.index++] = *wpage;\r
-    wpage->page->file->wRefCount++;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_CreateHelpWindow\r
- */\r
-BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE* wpage, int nCmdShow, BOOL remember)\r
-{\r
-    WINHELP_WINDOW*     win = NULL;\r
-    BOOL                bPrimary, bPopup, bReUsed = FALSE;\r
-    LPSTR               name;\r
-    HICON               hIcon;\r
-    HWND                hTextWnd = NULL;\r
-\r
-    bPrimary = !lstrcmpi(wpage->wininfo->name, "main");\r
-    bPopup = !bPrimary && (wpage->wininfo->win_style & WS_POPUP);\r
-\r
-    if (!bPopup)\r
-    {\r
-        for (win = Globals.win_list; win; win = win->next)\r
-        {\r
-            if (!lstrcmpi(win->lpszName, wpage->wininfo->name))\r
-            {\r
-                POINT   pt = {0, 0};\r
-                SIZE    sz = {0, 0};\r
-                DWORD   flags = SWP_NOSIZE | SWP_NOMOVE;\r
-\r
-                WINHELP_DeleteButtons(win);\r
-                bReUsed = TRUE;\r
-                SetWindowText(win->hMainWnd, WINHELP_GetCaption(wpage));\r
-                if (wpage->wininfo->origin.x != CW_USEDEFAULT &&\r
-                    wpage->wininfo->origin.y != CW_USEDEFAULT)\r
-                {\r
-                    pt = wpage->wininfo->origin;\r
-                    flags &= ~SWP_NOSIZE;\r
-                }\r
-                if (wpage->wininfo->size.cx != CW_USEDEFAULT &&\r
-                    wpage->wininfo->size.cy != CW_USEDEFAULT)\r
-                {\r
-                    sz = wpage->wininfo->size;\r
-                    flags &= ~SWP_NOMOVE;\r
-                }\r
-                SetWindowPos(win->hMainWnd, HWND_TOP, pt.x, pt.y, sz.cx, sz.cy, flags);\r
-\r
-                if (wpage->page && win->page && wpage->page->file != win->page->file)\r
-                    WINHELP_DeleteBackSet(win);\r
-                WINHELP_InitFonts(win->hMainWnd);\r
-\r
-                win->page = wpage->page;\r
-                win->info = wpage->wininfo;\r
-                hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-                WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
-                InvalidateRect(win->hMainWnd, NULL, TRUE);\r
-                if (win->hHistoryWnd) InvalidateRect(win->hHistoryWnd, NULL, TRUE);\r
-\r
-                break;\r
-            }\r
-        }\r
-    }\r
-\r
-    if (!win)\r
-    {\r
-        /* Initialize WINHELP_WINDOW struct */\r
-        win = HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY,\r
-                        sizeof(WINHELP_WINDOW) + strlen(wpage->wininfo->name) + 1);\r
-        if (!win) return FALSE;\r
-        win->next = Globals.win_list;\r
-        Globals.win_list = win;\r
-\r
-        name = (char*)win + sizeof(WINHELP_WINDOW);\r
-        lstrcpy(name, wpage->wininfo->name);\r
-        win->lpszName = name;\r
-        win->hHandCur = LoadCursorW(0, (LPWSTR)IDC_HAND);\r
-        win->back.index = 0;\r
-        win->font_scale = 1;\r
-    }\r
-    win->page = wpage->page;\r
-    win->info = wpage->wininfo;\r
-\r
-    if (!bPopup && wpage->page && remember)\r
-    {\r
-        WINHELP_RememberPage(win, wpage);\r
-    }\r
-\r
-    if (bPopup)\r
-        Globals.active_popup = win;\r
-    else\r
-        Globals.active_win = win;\r
-\r
-    /* Initialize default pushbuttons */\r
-    if (bPrimary && wpage->page)\r
-    {\r
-        CHAR    buffer[MAX_STRING_LEN];\r
-\r
-        LoadString(Globals.hInstance, STID_CONTENTS, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_CONTENTS", buffer, "Contents()");\r
-        LoadString(Globals.hInstance, STID_INDEX, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_INDEX", buffer, "Finder()");\r
-        LoadString(Globals.hInstance, STID_BACK, buffer, sizeof(buffer));\r
-        MACRO_CreateButton("BTN_BACK", buffer, "Back()");\r
-        if (win->back.index <= 1) MACRO_DisableButton("BTN_BACK");\r
-    }\r
-\r
-    if (!bReUsed)\r
-    {\r
-        win->hMainWnd = CreateWindowEx((bPopup) ? WS_EX_TOOLWINDOW : 0, MAIN_WIN_CLASS_NAME,\r
-                                       WINHELP_GetCaption(wpage),\r
-                                       bPrimary ? WS_OVERLAPPEDWINDOW : wpage->wininfo->win_style,\r
-                                       wpage->wininfo->origin.x, wpage->wininfo->origin.y,\r
-                                       wpage->wininfo->size.cx, wpage->wininfo->size.cy,\r
-                                       bPopup ? Globals.active_win->hMainWnd : NULL,\r
-                                       bPrimary ? LoadMenu(Globals.hInstance, MAKEINTRESOURCE(MAIN_MENU)) : 0,\r
-                                       Globals.hInstance, win);\r
-        if (!bPopup)\r
-            /* Create button box and text Window */\r
-            CreateWindow(BUTTON_BOX_WIN_CLASS_NAME, "", WS_CHILD | WS_VISIBLE,\r
-                         0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_BUTTON, Globals.hInstance, NULL);\r
-\r
-        hTextWnd = CreateWindow(RICHEDIT_CLASS, NULL,\r
-                                ES_MULTILINE | ES_READONLY | WS_CHILD | WS_HSCROLL | WS_VSCROLL | WS_VISIBLE,\r
-                                0, 0, 0, 0, win->hMainWnd, (HMENU)CTL_ID_TEXT, Globals.hInstance, NULL);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0,\r
-                    SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0) | ENM_MOUSEEVENTS);\r
-    }\r
-\r
-    hIcon = (wpage->page) ? wpage->page->file->hIcon : NULL;\r
-    if (!hIcon) hIcon = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
-    SendMessage(win->hMainWnd, WM_SETICON, ICON_SMALL, (DWORD_PTR)hIcon);\r
-\r
-    /* Initialize file specific pushbuttons */\r
-    if (!(wpage->wininfo->win_style & WS_POPUP) && wpage->page)\r
-    {\r
-        HLPFILE_MACRO  *macro;\r
-        for (macro = wpage->page->file->first_macro; macro; macro = macro->next)\r
-            MACRO_ExecuteMacro(macro->lpszMacro);\r
-\r
-        for (macro = wpage->page->first_macro; macro; macro = macro->next)\r
-            MACRO_ExecuteMacro(macro->lpszMacro);\r
-    }\r
-\r
-    if (bPopup)\r
-    {\r
-        DWORD   mask = SendMessage(hTextWnd, EM_GETEVENTMASK, 0, 0);\r
-        RECT    rect;\r
-\r
-        win->font_scale = Globals.active_win->font_scale;\r
-        WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-\r
-        /* we need the window to be shown for richedit to compute the size */\r
-        ShowWindow(win->hMainWnd, nCmdShow);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask | ENM_REQUESTRESIZE);\r
-        SendMessage(hTextWnd, EM_REQUESTRESIZE, 0, 0);\r
-        SendMessage(hTextWnd, EM_SETEVENTMASK, 0, mask);\r
-\r
-        GetWindowRect(win->hMainWnd, &rect);\r
-        win->hShadowWnd = CreateWindowEx(WS_EX_TOOLWINDOW, SHADOW_WIN_CLASS_NAME,\r
-                                         "", WS_POPUP | WS_VISIBLE,\r
-                                         rect.left + SHADOW_DX, rect.top + SHADOW_DY,\r
-                                         rect.right - rect.left,\r
-                                         rect.bottom - rect.top,\r
-                                         Globals.active_win->hMainWnd, 0,\r
-                                         Globals.hInstance, NULL);\r
-        SetWindowPos(win->hMainWnd, win->hShadowWnd, 0, 0, 0, 0,\r
-                     SWP_NOSIZE | SWP_NOMOVE);\r
-    }\r
-    else\r
-    {\r
-        WINHELP_SetupText(hTextWnd, win, wpage->relative);\r
-        WINHELP_LayoutMainWindow(win);\r
-        ShowWindow(win->hMainWnd, nCmdShow);\r
-    }\r
-\r
-    return TRUE;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_OpenHelpWindow\r
- * Main function to search for a page and display it in a window\r
- */\r
-BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*lookup)(HLPFILE*, LONG, ULONG*),\r
-                            HLPFILE* hlpfile, LONG val, HLPFILE_WINDOWINFO* wi,\r
-                            int nCmdShow)\r
-{\r
-    WINHELP_WNDPAGE     wpage;\r
-\r
-    wpage.page = lookup(hlpfile, val, &wpage.relative);\r
-    if (wpage.page) wpage.page->file->wRefCount++;\r
-    wpage.wininfo = wi;\r
-    return WINHELP_CreateHelpWindow(&wpage, nCmdShow, TRUE);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_FindLink\r
- */\r
-static HLPFILE_LINK* WINHELP_FindLink(WINHELP_WINDOW* win, LPARAM pos)\r
-{\r
-    HLPFILE_LINK*           link;\r
-    POINTL                  mouse_ptl, char_ptl, char_next_ptl;\r
-    DWORD                   cp;\r
-\r
-    if (!win->page) return NULL;\r
-\r
-    mouse_ptl.x = (short)LOWORD(pos);\r
-    mouse_ptl.y = (short)HIWORD(pos);\r
-    cp = SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_CHARFROMPOS,\r
-                      0, (LPARAM)&mouse_ptl);\r
-\r
-    for (link = win->page->first_link; link; link = link->next)\r
-    {\r
-        if (link->cpMin <= cp && cp <= link->cpMax)\r
-        {\r
-            /* check whether we're at end of line */\r
-            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
-                         (LPARAM)&char_ptl, cp);\r
-            SendMessageW(GetDlgItem(win->hMainWnd, CTL_ID_TEXT), EM_POSFROMCHAR,\r
-                         (LPARAM)&char_next_ptl, cp + 1);\r
-            if (char_next_ptl.y != char_ptl.y || mouse_ptl.x >= char_next_ptl.x)\r
-                link = NULL;\r
-            break;\r
-        }\r
-    }\r
-    return link;\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HandleTextMouse\r
- *\r
- */\r
-static BOOL WINHELP_HandleTextMouse(WINHELP_WINDOW* win, UINT msg, LPARAM lParam)\r
-{\r
-    HLPFILE*                hlpfile;\r
-    HLPFILE_LINK*           link;\r
-    BOOL                    ret = FALSE;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_MOUSEMOVE:\r
-        if (WINHELP_FindLink(win, lParam))\r
-            SetCursor(win->hHandCur);\r
-        else\r
-            SetCursor(LoadCursor(0, IDC_ARROW));\r
-        break;\r
-\r
-     case WM_LBUTTONDOWN:\r
-         if ((win->current_link = WINHELP_FindLink(win, lParam)))\r
-             ret = TRUE;\r
-         break;\r
-\r
-    case WM_LBUTTONUP:\r
-        if ((link = WINHELP_FindLink(win, lParam)) && link == win->current_link)\r
-        {\r
-            HLPFILE_WINDOWINFO*     wi;\r
-\r
-            switch (link->cookie)\r
-            {\r
-            case hlp_link_link:\r
-                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
-                {\r
-                    if (link->window == -1)\r
-                        wi = win->info;\r
-                    else if (link->window < hlpfile->numWindows)\r
-                        wi = &hlpfile->windows[link->window];\r
-                    else\r
-                    {\r
-                        WINE_WARN("link to window %d/%d\n", link->window, hlpfile->numWindows);\r
-                        break;\r
-                    }\r
-                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash, wi, SW_NORMAL);\r
-                }\r
-                break;\r
-            case hlp_link_popup:\r
-                if ((hlpfile = WINHELP_LookupHelpFile(link->string)))\r
-                    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, link->hash,\r
-                                           WINHELP_GetPopupWindowInfo(hlpfile, win, lParam),\r
-                                           SW_NORMAL);\r
-                break;\r
-            case hlp_link_macro:\r
-                MACRO_ExecuteMacro(link->string);\r
-                break;\r
-            default:\r
-                WINE_FIXME("Unknown link cookie %d\n", link->cookie);\r
-            }\r
-            ret = TRUE;\r
-        }\r
-        win->current_link = NULL;\r
-        break;\r
-    }\r
-    return ret;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_CheckPopup\r
- */\r
-static BOOL WINHELP_CheckPopup(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam, LRESULT* lret)\r
-{\r
-    HWND        hPopup;\r
-\r
-    if (!Globals.active_popup) return FALSE;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NOTIFY:\r
-        {\r
-            MSGFILTER*  msgf = (MSGFILTER*)lParam;\r
-            if (msgf->nmhdr.code == EN_MSGFILTER)\r
-            {\r
-                if (!WINHELP_CheckPopup(hWnd, msgf->msg, msgf->wParam, msgf->lParam, NULL))\r
-                    return FALSE;\r
-                if (lret) *lret = 1;\r
-                return TRUE;\r
-            }\r
-        }\r
-        break;\r
-    case WM_ACTIVATE:\r
-        if (wParam != WA_INACTIVE || (HWND)lParam == Globals.active_win->hMainWnd ||\r
-            (HWND)lParam == Globals.active_popup->hMainWnd ||\r
-            GetWindow((HWND)lParam, GW_OWNER) == Globals.active_win->hMainWnd)\r
-            break;\r
-    case WM_LBUTTONUP:\r
-    case WM_LBUTTONDOWN:\r
-        if (WINHELP_HandleTextMouse(Globals.active_popup, msg, lParam) && msg == WM_LBUTTONDOWN)\r
-            return FALSE;\r
-        /* fall through */\r
-    case WM_MBUTTONDOWN:\r
-    case WM_RBUTTONDOWN:\r
-    case WM_NCLBUTTONDOWN:\r
-    case WM_NCMBUTTONDOWN:\r
-    case WM_NCRBUTTONDOWN:\r
-        hPopup = Globals.active_popup->hMainWnd;\r
-        Globals.active_popup = NULL;\r
-        DestroyWindow(hPopup);\r
-        return TRUE;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ButtonWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
-\r
-    if (msg == WM_KEYDOWN)\r
-    {\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-        case VK_ESCAPE:\r
-            return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        }\r
-    }\r
-\r
-    return CallWindowProc(Globals.button_proc, hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ButtonBoxWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ButtonBoxWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINDOWPOS      *winpos;\r
-    WINHELP_WINDOW *win;\r
-    WINHELP_BUTTON *button;\r
-    SIZE button_size;\r
-    INT  x, y;\r
-\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0L;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_WINDOWPOSCHANGING:\r
-        winpos = (WINDOWPOS*) lParam;\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(GetParent(hWnd), 0);\r
-\r
-        /* Update buttons */\r
-        button_size.cx = 0;\r
-        button_size.cy = 0;\r
-        for (button = win->first_button; button; button = button->next)\r
-       {\r
-            HDC  hDc;\r
-            SIZE textsize;\r
-            if (!button->hWnd)\r
-            {\r
-                button->hWnd = CreateWindow(STRING_BUTTON, button->lpszName,\r
-                                            WS_CHILD | WS_VISIBLE | BS_PUSHBUTTON,\r
-                                            0, 0, 0, 0,\r
-                                            hWnd, (HMENU) button->wParam,\r
-                                            Globals.hInstance, 0);\r
-                if (button->hWnd)\r
-                {\r
-                    if (Globals.button_proc == NULL)\r
-                    {\r
-                        NONCLIENTMETRICSW ncm;\r
-                        Globals.button_proc = (WNDPROC) GetWindowLongPtr(button->hWnd, GWLP_WNDPROC);\r
-\r
-                        ncm.cbSize = sizeof(NONCLIENTMETRICSW);\r
-                        SystemParametersInfoW(SPI_GETNONCLIENTMETRICS,\r
-                                              sizeof(NONCLIENTMETRICSW), &ncm, 0);\r
-                        Globals.hButtonFont = CreateFontIndirectW(&ncm.lfMenuFont);\r
-                    }\r
-                    SetWindowLongPtr(button->hWnd, GWLP_WNDPROC, (LONG_PTR) WINHELP_ButtonWndProc);\r
-                    if (Globals.hButtonFont)\r
-                        SendMessage(button->hWnd, WM_SETFONT, (WPARAM)Globals.hButtonFont, TRUE);\r
-                }\r
-            }\r
-            hDc = GetDC(button->hWnd);\r
-            GetTextExtentPoint(hDc, button->lpszName,\r
-                               lstrlen(button->lpszName), &textsize);\r
-            ReleaseDC(button->hWnd, hDc);\r
-\r
-            button_size.cx = max(button_size.cx, textsize.cx + BUTTON_CX);\r
-            button_size.cy = max(button_size.cy, textsize.cy + BUTTON_CY);\r
-       }\r
-\r
-        x = 0;\r
-        y = 0;\r
-        for (button = win->first_button; button; button = button->next)\r
-       {\r
-            SetWindowPos(button->hWnd, HWND_TOP, x, y, button_size.cx, button_size.cy, 0);\r
-\r
-            if (x + 2 * button_size.cx <= winpos->cx)\r
-                x += button_size.cx;\r
-            else\r
-                x = 0, y += button_size.cy;\r
-       }\r
-        winpos->cy = y + (x ? button_size.cy : 0);\r
-        break;\r
-\r
-    case WM_COMMAND:\r
-        SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        break;\r
-\r
-    case WM_KEYDOWN:\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-        case VK_ESCAPE:\r
-            return SendMessage(GetParent(hWnd), msg, wParam, lParam);\r
-        }\r
-        break;\r
-    }\r
-\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/******************************************************************\r
- *             WINHELP_HistoryWndProc\r
- *\r
- *\r
- */\r
-static LRESULT CALLBACK WINHELP_HistoryWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINHELP_WINDOW*     win;\r
-    PAINTSTRUCT         ps;\r
-    HDC                 hDc;\r
-    TEXTMETRIC          tm;\r
-    unsigned int        i;\r
-    RECT                r;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NCCREATE:\r
-        win = (WINHELP_WINDOW*)((LPCREATESTRUCT)lParam)->lpCreateParams;\r
-        SetWindowLongPtr(hWnd, 0, (ULONG_PTR)win);\r
-        win->hHistoryWnd = hWnd;\r
-        break;\r
-    case WM_CREATE:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        hDc = GetDC(hWnd);\r
-        GetTextMetrics(hDc, &tm);\r
-        GetWindowRect(hWnd, &r);\r
-\r
-        r.right = r.left + 30 * tm.tmAveCharWidth;\r
-        r.bottom = r.top + (sizeof(Globals.history.set) / sizeof(Globals.history.set[0])) * tm.tmHeight;\r
-        AdjustWindowRect(&r, GetWindowLong(hWnd, GWL_STYLE), FALSE);\r
-        if (r.left < 0) {r.right -= r.left; r.left = 0;}\r
-        if (r.top < 0) {r.bottom -= r.top; r.top = 0;}\r
-\r
-        MoveWindow(hWnd, r.left, r.top, r.right, r.bottom, TRUE);\r
-        ReleaseDC(hWnd, hDc);\r
-        break;\r
-    case WM_LBUTTONDOWN:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        hDc = GetDC(hWnd);\r
-        GetTextMetrics(hDc, &tm);\r
-        i = HIWORD(lParam) / tm.tmHeight;\r
-        if (i < Globals.history.index)\r
-            WINHELP_CreateHelpWindow(&Globals.history.set[i], SW_SHOW, TRUE);\r
-        ReleaseDC(hWnd, hDc);\r
-        break;\r
-    case WM_PAINT:\r
-        hDc = BeginPaint(hWnd, &ps);\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        GetTextMetrics(hDc, &tm);\r
-\r
-        for (i = 0; i < Globals.history.index; i++)\r
-        {\r
-            if (Globals.history.set[i].page->file == Globals.active_win->page->file)\r
-            {\r
-                TextOut(hDc, 0, i * tm.tmHeight,\r
-                        Globals.history.set[i].page->lpszTitle,\r
-                        strlen(Globals.history.set[i].page->lpszTitle));\r
-            }\r
-            else\r
-            {\r
-                char        buffer[1024];\r
-                const char* ptr1;\r
-                const char* ptr2;\r
-                unsigned    len;\r
-\r
-                ptr1 = strrchr(Globals.history.set[i].page->file->lpszPath, '\\');\r
-                if (!ptr1) ptr1 = Globals.history.set[i].page->file->lpszPath;\r
-                else ptr1++;\r
-                ptr2 = strrchr(ptr1, '.');\r
-                len = ptr2 ? ptr2 - ptr1 : strlen(ptr1);\r
-                if (len > sizeof(buffer)) len = sizeof(buffer);\r
-                memcpy(buffer, ptr1, len);\r
-                if (len < sizeof(buffer)) buffer[len++] = ':';\r
-                strncpy(&buffer[len], Globals.history.set[i].page->lpszTitle, sizeof(buffer) - len);\r
-                buffer[sizeof(buffer) - 1] = '\0';\r
-                TextOut(hDc, 0, i * tm.tmHeight, buffer, strlen(buffer));\r
-            }\r
-        }\r
-        EndPaint(hWnd, &ps);\r
-        break;\r
-    case WM_DESTROY:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        if (hWnd == win->hHistoryWnd)\r
-            win->hHistoryWnd = 0;\r
-        break;\r
-    }\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_ShadowWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_ShadowWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL)) return 0;\r
-    return WINHELP_CheckPopup(hWnd, msg, wParam, lParam, NULL) ? 0L : DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/**************************************************************************\r
- * cb_KWBTree\r
- *\r
- * HLPFILE_BPTreeCallback enumeration function for '|KWBTREE' internal file.\r
- *\r
- */\r
-static void cb_KWBTree(void *p, void **next, void *cookie)\r
-{\r
-    HWND hListWnd = (HWND)cookie;\r
-    int count;\r
-\r
-    WINE_TRACE("Adding '%s' to search list\n", (char *)p);\r
-    SendMessage(hListWnd, LB_INSERTSTRING, -1, (LPARAM)p);\r
-    count = SendMessage(hListWnd, LB_GETCOUNT, 0, 0);\r
-    SendMessage(hListWnd, LB_SETITEMDATA, count-1, (LPARAM)p);\r
-    *next = (char*)p + strlen((char*)p) + 7;\r
-}\r
-\r
-struct index_data\r
-{\r
-    HLPFILE*    hlpfile;\r
-    BOOL        jump;\r
-    ULONG       offset;\r
-};\r
-\r
-/**************************************************************************\r
- * WINHELP_IndexDlgProc\r
- *\r
- */\r
-static INT_PTR CALLBACK WINHELP_IndexDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    static struct index_data* id;\r
-    int sel;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_INITDIALOG:\r
-        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
-        HLPFILE_BPTreeEnum(id->hlpfile->kwbtree, cb_KWBTree,\r
-                           GetDlgItem(hWnd, IDC_INDEXLIST));\r
-        id->jump = FALSE;\r
-        id->offset = 1;\r
-        return TRUE;\r
-    case WM_COMMAND:\r
-        switch (HIWORD(wParam))\r
-        {\r
-        case LBN_DBLCLK:\r
-            if (LOWORD(wParam) == IDC_INDEXLIST)\r
-                SendMessage(GetParent(hWnd), PSM_PRESSBUTTON, PSBTN_OK, 0);\r
-            break;\r
-        }\r
-        break;\r
-    case WM_NOTIFY:\r
-       switch (((NMHDR*)lParam)->code)\r
-       {\r
-       case PSN_APPLY:\r
-            sel = SendDlgItemMessage(hWnd, IDC_INDEXLIST, LB_GETCURSEL, 0, 0);\r
-            if (sel != LB_ERR)\r
-            {\r
-                BYTE *p;\r
-                int count;\r
-\r
-                p = (BYTE*)SendDlgItemMessage(hWnd, IDC_INDEXLIST,\r
-                                              LB_GETITEMDATA, sel, 0);\r
-                count = *(short*)((char *)p + strlen((char *)p) + 1);\r
-                if (count > 1)\r
-                {\r
-                    MessageBox(hWnd, "count > 1 not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
-                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
-                    return TRUE;\r
-                }\r
-                id->offset = *(ULONG*)((char *)p + strlen((char *)p) + 3);\r
-                id->offset = *(long*)(id->hlpfile->kwdata + id->offset + 9);\r
-                if (id->offset == 0xFFFFFFFF)\r
-                {\r
-                    MessageBox(hWnd, "macro keywords not supported yet", "Error", MB_OK | MB_ICONSTOP);\r
-                    SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_INVALID);\r
-                    return TRUE;\r
-                }\r
-                id->jump = TRUE;\r
-                SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
-            }\r
-            return TRUE;\r
-        default:\r
-            return FALSE;\r
-        }\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_SearchDlgProc\r
- *\r
- */\r
-static INT_PTR CALLBACK WINHELP_SearchDlgProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    static struct index_data* id;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_INITDIALOG:\r
-        id = (struct index_data*)((PROPSHEETPAGE*)lParam)->lParam;\r
-        return TRUE;\r
-    case WM_NOTIFY:\r
-       switch (((NMHDR*)lParam)->code)\r
-       {\r
-       case PSN_APPLY:\r
-            SetWindowLongPtr(hWnd, DWLP_MSGRESULT, PSNRET_NOERROR);\r
-            return TRUE;\r
-        default:\r
-            return FALSE;\r
-        }\r
-        break;\r
-    default:\r
-        break;\r
-    }\r
-    return FALSE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WINHELP_MainWndProc\r
- */\r
-static LRESULT CALLBACK WINHELP_MainWndProc(HWND hWnd, UINT msg, WPARAM wParam, LPARAM lParam)\r
-{\r
-    WINHELP_WINDOW *win;\r
-    WINHELP_BUTTON *button;\r
-    RECT rect;\r
-    INT  curPos, min, max, dy, keyDelta;\r
-    HWND hTextWnd;\r
-    LRESULT ret;\r
-\r
-    if (WINHELP_CheckPopup(hWnd, msg, wParam, lParam, &ret)) return ret;\r
-\r
-    switch (msg)\r
-    {\r
-    case WM_NCCREATE:\r
-        win = (WINHELP_WINDOW*) ((LPCREATESTRUCT) lParam)->lpCreateParams;\r
-        SetWindowLongPtr(hWnd, 0, (ULONG_PTR) win);\r
-        if (!win->page && Globals.isBook)\r
-            PostMessage(hWnd, WM_COMMAND, MNID_FILE_OPEN, 0);\r
-        win->hMainWnd = hWnd;\r
-        break;\r
-\r
-    case WM_WINDOWPOSCHANGED:\r
-        WINHELP_LayoutMainWindow((WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0));\r
-        break;\r
-\r
-    case WM_COMMAND:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        switch (wParam)\r
-       {\r
-            /* Menu FILE */\r
-       case MNID_FILE_OPEN:    MACRO_FileOpen();       break;\r
-       case MNID_FILE_PRINT:   MACRO_Print();          break;\r
-       case MNID_FILE_SETUP:   MACRO_PrinterSetup();   break;\r
-       case MNID_FILE_EXIT:    MACRO_Exit();           break;\r
-\r
-            /* Menu EDIT */\r
-       case MNID_EDIT_COPYDLG:\r
-            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
-            break;\r
-       case MNID_EDIT_ANNOTATE:MACRO_Annotate();       break;\r
-\r
-            /* Menu Bookmark */\r
-       case MNID_BKMK_DEFINE:  MACRO_BookmarkDefine(); break;\r
-\r
-            /* Menu Help */\r
-       case MNID_HELP_HELPON:  MACRO_HelpOn();         break;\r
-       case MNID_HELP_HELPTOP: MACRO_HelpOnTop();      break;\r
-       case MNID_HELP_ABOUT:   MACRO_About();          break;\r
-       case MNID_HELP_WINE:    ShellAbout(hWnd, "WINE", "Help", 0); break;\r
-\r
-            /* Context help */\r
-        case MNID_CTXT_ANNOTATE:MACRO_Annotate();       break;\r
-        case MNID_CTXT_COPY:    MACRO_CopyDialog();     break;\r
-        case MNID_CTXT_PRINT:   MACRO_Print();          break;\r
-        case MNID_OPTS_HISTORY: MACRO_History();        break;\r
-        case MNID_OPTS_FONTS_SMALL:\r
-        case MNID_CTXT_FONTS_SMALL:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            if (win->font_scale != 0)\r
-            {\r
-                win->font_scale = 0;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_FONTS_NORMAL:\r
-        case MNID_CTXT_FONTS_NORMAL:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            if (win->font_scale != 1)\r
-            {\r
-                win->font_scale = 1;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_FONTS_LARGE:\r
-        case MNID_CTXT_FONTS_LARGE:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            if (win->font_scale != 2)\r
-            {\r
-                win->font_scale = 2;\r
-                WINHELP_SetupText(GetDlgItem(hWnd, CTL_ID_TEXT), win, 0 /* FIXME */);\r
-            }\r
-            break;\r
-        case MNID_OPTS_HELP_DEFAULT:\r
-        case MNID_OPTS_HELP_VISIBLE:\r
-        case MNID_OPTS_HELP_NONVISIBLE:\r
-        case MNID_OPTS_SYSTEM_COLORS:\r
-        case MNID_CTXT_HELP_DEFAULT:\r
-        case MNID_CTXT_HELP_VISIBLE:\r
-        case MNID_CTXT_HELP_NONVISIBLE:\r
-        case MNID_CTXT_SYSTEM_COLORS:\r
-            /* FIXME: NIY */\r
-\r
-       default:\r
-            /* Buttons */\r
-            for (button = win->first_button; button; button = button->next)\r
-                if (wParam == button->wParam) break;\r
-            if (button)\r
-                MACRO_ExecuteMacro(button->lpszMacro);\r
-            else if (!HIWORD(wParam))\r
-                MessageBox(0, MAKEINTRESOURCE(STID_NOT_IMPLEMENTED),\r
-                           MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
-            break;\r
-       }\r
-        break;\r
-/* EPP     case WM_DESTROY: */\r
-/* EPP         if (Globals.hPopupWnd) DestroyWindow(Globals.hPopupWnd); */\r
-/* EPP         break; */\r
-    case WM_COPYDATA:\r
-        return WINHELP_HandleCommand((HWND)wParam, lParam);\r
-\r
-    case WM_CHAR:\r
-        if (wParam == 3)\r
-        {\r
-            SendMessage(GetDlgItem(hWnd, CTL_ID_TEXT), WM_COPY, 0, 0);\r
-            return 0;\r
-        }\r
-        break;\r
-\r
-    case WM_KEYDOWN:\r
-        keyDelta = 0;\r
-\r
-        switch (wParam)\r
-        {\r
-        case VK_UP:\r
-        case VK_DOWN:\r
-            keyDelta = GetSystemMetrics(SM_CXVSCROLL);\r
-            if (wParam == VK_UP)\r
-                keyDelta = -keyDelta;\r
-\r
-        case VK_PRIOR:\r
-        case VK_NEXT:\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            hTextWnd = GetDlgItem(win->hMainWnd, CTL_ID_TEXT);\r
-            curPos = GetScrollPos(hTextWnd, SB_VERT);\r
-            GetScrollRange(hTextWnd, SB_VERT, &min, &max);\r
-\r
-            if (keyDelta == 0)\r
-            {\r
-                GetClientRect(hTextWnd, &rect);\r
-                keyDelta = (rect.bottom - rect.top) / 2;\r
-                if (wParam == VK_PRIOR)\r
-                    keyDelta = -keyDelta;\r
-            }\r
-\r
-            curPos += keyDelta;\r
-            if (curPos > max)\r
-                 curPos = max;\r
-            else if (curPos < min)\r
-                 curPos = min;\r
-\r
-            dy = GetScrollPos(hTextWnd, SB_VERT) - curPos;\r
-            SetScrollPos(hTextWnd, SB_VERT, curPos, TRUE);\r
-            ScrollWindow(hTextWnd, 0, dy, NULL, NULL);\r
-            UpdateWindow(hTextWnd);\r
-            return 0;\r
-\r
-        case VK_ESCAPE:\r
-            MACRO_Exit();\r
-            return 0;\r
-        }\r
-        break;\r
-\r
-    case WM_NOTIFY:\r
-        if (wParam == CTL_ID_TEXT)\r
-        {\r
-            RECT        rc;\r
-\r
-            switch (((NMHDR*)lParam)->code)\r
-            {\r
-            case EN_MSGFILTER:\r
-                {\r
-                    const MSGFILTER*    msgf = (const MSGFILTER*)lParam;\r
-                    switch (msgf->msg)\r
-                    {\r
-                    case WM_KEYUP:\r
-                        if (msgf->wParam == VK_ESCAPE) DestroyWindow(hWnd);\r
-                        break;\r
-                    case WM_RBUTTONDOWN:\r
-                    {\r
-                        HMENU       hMenu;\r
-                        POINT       pt;\r
-\r
-                        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-                        hMenu = LoadMenu(Globals.hInstance, (LPSTR)CONTEXT_MENU);\r
-                        switch (win->font_scale)\r
-                        {\r
-                        case 0:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_SMALL,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        default:\r
-                            WINE_FIXME("Unsupported %d\n", win->font_scale);\r
-                        case 1:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_NORMAL,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        case 2:\r
-                            CheckMenuItem(hMenu, MNID_CTXT_FONTS_LARGE,\r
-                                          MF_BYCOMMAND|MF_CHECKED);\r
-                            break;\r
-                        }\r
-                        pt.x = (int)(short)LOWORD(msgf->lParam);\r
-                        pt.y = (int)(short)HIWORD(msgf->lParam);\r
-                        ClientToScreen(msgf->nmhdr.hwndFrom, &pt);\r
-                        TrackPopupMenu(GetSubMenu(hMenu, 0), TPM_LEFTALIGN|TPM_TOPALIGN,\r
-                                       pt.x, pt.y, 0, hWnd, NULL);\r
-                        DestroyMenu(hMenu);\r
-                    }\r
-                    break;\r
-                    default:\r
-                        return WINHELP_HandleTextMouse((WINHELP_WINDOW*)GetWindowLongPtr(hWnd, 0),\r
-                                                       msgf->msg, msgf->lParam);\r
-                    }\r
-                }\r
-                break;\r
-\r
-            case EN_REQUESTRESIZE:\r
-                rc = ((REQRESIZE*)lParam)->rc;\r
-                win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-                AdjustWindowRect(&rc, GetWindowLong(win->hMainWnd, GWL_STYLE),\r
-                                 FALSE);\r
-                SetWindowPos(win->hMainWnd, HWND_TOP, 0, 0,\r
-                             rc.right - rc.left, rc.bottom - rc.top,\r
-                             SWP_NOMOVE | SWP_NOZORDER);\r
-                WINHELP_LayoutMainWindow(win);\r
-                break;\r
-            }\r
-        }\r
-        break;\r
-\r
-    case WM_INITMENUPOPUP:\r
-        win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_SMALL,\r
-                      MF_BYCOMMAND | (win->font_scale == 0) ? MF_CHECKED : 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_NORMAL,\r
-                      MF_BYCOMMAND | (win->font_scale == 1) ? MF_CHECKED : 0);\r
-        CheckMenuItem((HMENU)wParam, MNID_OPTS_FONTS_LARGE,\r
-                      MF_BYCOMMAND | (win->font_scale == 2) ? MF_CHECKED : 0);\r
-        break;\r
-\r
-    case WM_NCDESTROY:\r
-        {\r
-            BOOL bExit;\r
-            win = (WINHELP_WINDOW*) GetWindowLongPtr(hWnd, 0);\r
-            bExit = (Globals.wVersion >= 4 && !lstrcmpi(win->lpszName, "main"));\r
-            WINHELP_DeleteWindow(win);\r
-\r
-            if (bExit) MACRO_Exit();\r
-            if (!Globals.win_list)\r
-                PostQuitMessage(0);\r
-        }\r
-        break;\r
-    }\r
-    return DefWindowProc(hWnd, msg, wParam, lParam);\r
-}\r
-\r
-/**************************************************************************\r
- * WINHELP_CreateIndexWindow\r
- *\r
- * Displays a dialog with keywords of current help file.\r
- *\r
- */\r
-BOOL WINHELP_CreateIndexWindow(BOOL is_search)\r
-{\r
-    HPROPSHEETPAGE      psPage[3];\r
-    PROPSHEETPAGE       psp;\r
-    PROPSHEETHEADER     psHead;\r
-    struct index_data   id;\r
-    char                buf[256];\r
-\r
-    if (Globals.active_win && Globals.active_win->page && Globals.active_win->page->file)\r
-        id.hlpfile = Globals.active_win->page->file;\r
-    else\r
-        return FALSE;\r
-\r
-    if (id.hlpfile->kwbtree == NULL)\r
-    {\r
-        WINE_TRACE("No index provided\n");\r
-        return FALSE;\r
-    }\r
-\r
-    InitCommonControls();\r
-\r
-    id.jump = FALSE;\r
-    memset(&psp, 0, sizeof(psp));\r
-    psp.dwSize = sizeof(psp);\r
-    psp.dwFlags = 0;\r
-    psp.hInstance = Globals.hInstance;\r
-\r
-    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_INDEX);\r
-    psp.lParam = (LPARAM)&id;\r
-    psp.pfnDlgProc = WINHELP_IndexDlgProc;\r
-    psPage[0] = CreatePropertySheetPage(&psp);\r
-\r
-    psp.u.pszTemplate = MAKEINTRESOURCE(IDD_SEARCH);\r
-    psp.lParam = (LPARAM)&id;\r
-    psp.pfnDlgProc = WINHELP_SearchDlgProc;\r
-    psPage[1] = CreatePropertySheetPage(&psp);\r
-\r
-    memset(&psHead, 0, sizeof(psHead));\r
-    psHead.dwSize = sizeof(psHead);\r
-\r
-    LoadString(Globals.hInstance, STID_PSH_INDEX, buf, sizeof(buf));\r
-    strcat(buf, Globals.active_win->info->caption);\r
-\r
-    psHead.pszCaption = buf;\r
-    psHead.nPages = 2;\r
-    psHead.u2.nStartPage = is_search ? 1 : 0;\r
-    psHead.hwndParent = Globals.active_win->hMainWnd;\r
-    psHead.u3.phpage = psPage;\r
-    psHead.dwFlags = PSH_NOAPPLYNOW;\r
-\r
-    PropertySheet(&psHead);\r
-    if (id.jump)\r
-    {\r
-        WINE_TRACE("got %d as an offset\n", id.offset);\r
-        WINHELP_OpenHelpWindow(HLPFILE_PageByOffset, id.hlpfile, id.offset,\r
-                               Globals.active_win->info, SW_NORMAL);\r
-    }\r
-    return TRUE;\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           RegisterWinClasses\r
- */\r
-static BOOL WINHELP_RegisterWinClasses(void)\r
-{\r
-    WNDCLASS class_main, class_button_box, class_shadow, class_history;\r
-\r
-    class_main.style               = CS_HREDRAW | CS_VREDRAW;\r
-    class_main.lpfnWndProc         = WINHELP_MainWndProc;\r
-    class_main.cbClsExtra          = 0;\r
-    class_main.cbWndExtra          = sizeof(WINHELP_WINDOW *);\r
-    class_main.hInstance           = Globals.hInstance;\r
-    class_main.hIcon               = LoadIcon(Globals.hInstance, MAKEINTRESOURCE(IDI_WINHELP));\r
-    class_main.hCursor             = LoadCursor(0, IDC_ARROW);\r
-    class_main.hbrBackground       = (HBRUSH)(COLOR_WINDOW+1);\r
-    class_main.lpszMenuName        = 0;\r
-    class_main.lpszClassName       = MAIN_WIN_CLASS_NAME;\r
-\r
-    class_button_box               = class_main;\r
-    class_button_box.lpfnWndProc   = WINHELP_ButtonBoxWndProc;\r
-    class_button_box.cbWndExtra    = 0;\r
-    class_button_box.hbrBackground = (HBRUSH)(COLOR_BTNFACE+1);\r
-    class_button_box.lpszClassName = BUTTON_BOX_WIN_CLASS_NAME;\r
-\r
-    class_shadow                   = class_main;\r
-    class_shadow.lpfnWndProc       = WINHELP_ShadowWndProc;\r
-    class_shadow.cbWndExtra        = 0;\r
-    class_shadow.hbrBackground     = (HBRUSH)(COLOR_3DDKSHADOW+1);\r
-    class_shadow.lpszClassName     = SHADOW_WIN_CLASS_NAME;\r
-\r
-    class_history                  = class_main;\r
-    class_history.lpfnWndProc      = WINHELP_HistoryWndProc;\r
-    class_history.lpszClassName    = HISTORY_WIN_CLASS_NAME;\r
-\r
-    return (RegisterClass(&class_main) &&\r
-            RegisterClass(&class_button_box) &&\r
-            RegisterClass(&class_shadow) &&\r
-            RegisterClass(&class_history));\r
-}\r
-\r
-/***********************************************************************\r
- *\r
- *           WinMain\r
- */\r
-int PASCAL WinMain(HINSTANCE hInstance, HINSTANCE prev, LPSTR cmdline, int show)\r
-{\r
-    MSG                 msg;\r
-    LONG                lHash = 0;\r
-    HLPFILE*            hlpfile;\r
-    static CHAR         default_wndname[] = "main";\r
-    LPSTR               wndname = default_wndname;\r
-    WINHELP_DLL*        dll;\r
-\r
-    Globals.hInstance = hInstance;\r
-\r
-    if (LoadLibrary("riched20.dll") == NULL)\r
-        return MessageBox(0, MAKEINTRESOURCE(STID_NO_RICHEDIT),\r
-                          MAKEINTRESOURCE(STID_WHERROR), MB_OK);\r
-\r
-    /* Get options */\r
-    while (*cmdline && (*cmdline == ' ' || *cmdline == '-'))\r
-    {\r
-        CHAR   option;\r
-        LPCSTR topic_id;\r
-        if (*cmdline++ == ' ') continue;\r
-\r
-        option = *cmdline;\r
-        if (option) cmdline++;\r
-        while (*cmdline && *cmdline == ' ') cmdline++;\r
-        switch (option)\r
-       {\r
-       case 'i':\r
-       case 'I':\r
-            topic_id = cmdline;\r
-            while (*cmdline && *cmdline != ' ') cmdline++;\r
-            if (*cmdline) *cmdline++ = '\0';\r
-            lHash = HLPFILE_Hash(topic_id);\r
-            break;\r
-\r
-       case '3':\r
-       case '4':\r
-            Globals.wVersion = option - '0';\r
-            break;\r
-\r
-        case 'x':\r
-            show = SW_HIDE;\r
-            Globals.isBook = FALSE;\r
-            break;\r
-\r
-        default:\r
-            WINE_FIXME("Unsupported cmd line: %s\n", cmdline);\r
-            break;\r
-       }\r
-    }\r
-\r
-    /* Create primary window */\r
-    if (!WINHELP_RegisterWinClasses())\r
-    {\r
-        WINE_FIXME("Couldn't register classes\n");\r
-        return 0;\r
-    }\r
-\r
-    if (*cmdline)\r
-    {\r
-        char*   ptr;\r
-        if ((*cmdline == '"') && (ptr = strchr(cmdline+1, '"')))\r
-        {\r
-            cmdline++;\r
-            *ptr = '\0';\r
-        }\r
-        if ((ptr = strchr(cmdline, '>')))\r
-        {\r
-            *ptr = '\0';\r
-            wndname = ptr + 1;\r
-        }\r
-        hlpfile = WINHELP_LookupHelpFile(cmdline);\r
-        if (!hlpfile) return 0;\r
-    }\r
-    else hlpfile = NULL;\r
-    WINHELP_OpenHelpWindow(HLPFILE_PageByHash, hlpfile, lHash,\r
-                           WINHELP_GetWindowInfo(hlpfile, wndname), show);\r
-\r
-    /* Message loop */\r
-    while (GetMessage(&msg, 0, 0, 0))\r
-    {\r
-        TranslateMessage(&msg);\r
-        DispatchMessage(&msg);\r
-    }\r
-    for (dll = Globals.dlls; dll; dll = dll->next)\r
-    {\r
-        if (dll->class & DC_INITTERM) dll->handler(DW_TERM, 0, 0);\r
-    }\r
-    return 0;\r
-}\r
+/*
+ * Help Viewer
+ *
+ * Copyright    1996 Ulrich Schmid <uschmid@mail.hh.provi.de>
+ *              2002 Sylvain Petreolle <spetreolle@yahoo.fr>
+ *              2002, 2008 Eric Pouech <eric.pouech@wanadoo.fr>
+ *              2004 Ken Belleau <jamez@ivic.qc.ca>
+ *              2008 Kirill K. Smirnov <lich@math.spbu.ru>
+ *
+ * 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 <assert.h>
+#include <stdio.h>
+#include <string.h>
+#include <stdarg.h>
+#include <stdlib.h>
+
+#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;
+}
index c4bb00f..feaf637 100644 (file)
-/*\r
- * Help Viewer\r
- *\r
- * Copyright    1996 Ulrich Schmid\r
- * Copyright    2002 Sylvain Petreolle <spetreolle@yahoo.fr>\r
- *              2002 Eric Pouech\r
- *\r
- * This library is free software; you can redistribute it and/or\r
- * modify it under the terms of the GNU Lesser General Public\r
- * License as published by the Free Software Foundation; either\r
- * version 2.1 of the License, or (at your option) any later version.\r
- *\r
- * This library is distributed in the hope that it will be useful,\r
- * but WITHOUT ANY WARRANTY; without even the implied warranty of\r
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU\r
- * Lesser General Public License for more details.\r
- *\r
- * You should have received a copy of the GNU Lesser General Public\r
- * License along with this library; if not, write to the Free Software\r
- * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA\r
- */\r
-\r
-#define MAX_LANGUAGE_NUMBER     255\r
-#define MAX_STRING_LEN          255\r
-\r
-#define INTERNAL_BORDER_WIDTH   5\r
-#define POPUP_YDISTANCE         20\r
-#define SHADOW_DX               10\r
-#define SHADOW_DY               10\r
-#define BUTTON_CX               6\r
-#define BUTTON_CY               6\r
-\r
-#ifndef RC_INVOKED\r
-\r
-#include <stdarg.h>\r
-\r
-#include "hlpfile.h"\r
-#include "windef.h"\r
-#include "winbase.h"\r
-#include "macro.h"\r
-#include "winhelp_res.h"\r
-\r
-typedef struct tagHelpButton\r
-{\r
-    HWND                hWnd;\r
-\r
-    LPCSTR              lpszID;\r
-    LPCSTR              lpszName;\r
-    LPCSTR              lpszMacro;\r
-\r
-    WPARAM              wParam;\r
-\r
-    RECT                rect;\r
-\r
-    struct tagHelpButton*next;\r
-} WINHELP_BUTTON;\r
-\r
-typedef struct\r
-{\r
-    HLPFILE_PAGE*       page;\r
-    HLPFILE_WINDOWINFO* wininfo;\r
-    ULONG               relative;\r
-} WINHELP_WNDPAGE;\r
-\r
-typedef struct tagPageSet\r
-{\r
-    /* FIXME: for now it's a fixed size */\r
-    WINHELP_WNDPAGE     set[40];\r
-    unsigned            index;\r
-} WINHELP_PAGESET;\r
-\r
-typedef struct tagWinHelp\r
-{\r
-    LPCSTR              lpszName;\r
-\r
-    WINHELP_BUTTON*     first_button;\r
-    HLPFILE_PAGE*       page;\r
-\r
-    HWND                hMainWnd;\r
-    HWND                hShadowWnd;\r
-    HWND                hHistoryWnd;\r
-\r
-    HFONT*              fonts;\r
-    UINT                fonts_len;\r
-\r
-    HCURSOR             hHandCur;\r
-\r
-    HBRUSH              hBrush;\r
-\r
-    HLPFILE_WINDOWINFO* info;\r
-    HLPFILE_LINK*       current_link;\r
-\r
-    WINHELP_PAGESET     back;\r
-    unsigned            font_scale; /* 0 = small, 1 = normal, 2 = large */\r
-\r
-    struct tagWinHelp*  next;\r
-} WINHELP_WINDOW;\r
-\r
-#define DC_NOMSG     0x00000000\r
-#define DC_MINMAX    0x00000001\r
-#define DC_INITTERM  0x00000002\r
-#define DC_JUMP      0x00000004\r
-#define DC_ACTIVATE  0x00000008\r
-#define DC_CALLBACKS 0x00000010\r
-\r
-#define DW_NOTUSED    0\r
-#define DW_WHATMSG    1\r
-#define DW_MINMAX     2\r
-#define DW_SIZE       3\r
-#define DW_INIT       4\r
-#define DW_TERM       5\r
-#define DW_STARTJUMP  6\r
-#define DW_ENDJUMP    7\r
-#define DW_CHGFILE    8\r
-#define DW_ACTIVATE   9\r
-#define        DW_CALLBACKS 10\r
-\r
-typedef long (CALLBACK *WINHELP_LDLLHandler)(WORD, LONG, LONG);\r
-\r
-typedef struct tagDll\r
-{\r
-    HANDLE              hLib;\r
-    const char*         name;\r
-    WINHELP_LDLLHandler handler;\r
-    DWORD               class;\r
-    struct tagDll*      next;\r
-} WINHELP_DLL;\r
-\r
-typedef struct\r
-{\r
-    UINT                wVersion;\r
-    HANDLE              hInstance;\r
-    BOOL                isBook;\r
-    WINHELP_WINDOW*     active_win;\r
-    WINHELP_WINDOW*     active_popup;\r
-    WINHELP_WINDOW*     win_list;\r
-    WNDPROC             button_proc;\r
-    WINHELP_DLL*        dlls;\r
-    WINHELP_PAGESET     history;\r
-    HFONT               hButtonFont;\r
-} WINHELP_GLOBALS;\r
-\r
-extern WINHELP_GLOBALS Globals;\r
-extern FARPROC         Callbacks[];\r
-\r
-BOOL WINHELP_CreateHelpWindow(WINHELP_WNDPAGE*, int, BOOL);\r
-BOOL WINHELP_OpenHelpWindow(HLPFILE_PAGE* (*)(HLPFILE*, LONG, ULONG*),\r
-                            HLPFILE*, LONG, HLPFILE_WINDOWINFO*, int);\r
-BOOL WINHELP_GetOpenFileName(LPSTR, int);\r
-BOOL WINHELP_CreateIndexWindow(BOOL);\r
-void WINHELP_DeleteBackSet(WINHELP_WINDOW*);\r
-HLPFILE* WINHELP_LookupHelpFile(LPCSTR lpszFile);\r
-HLPFILE_WINDOWINFO* WINHELP_GetWindowInfo(HLPFILE* hlpfile, LPCSTR name);\r
-void WINHELP_LayoutMainWindow(WINHELP_WINDOW* win);\r
-\r
-extern const char MAIN_WIN_CLASS_NAME[];\r
-extern const char BUTTON_BOX_WIN_CLASS_NAME[];\r
-extern const char TEXT_WIN_CLASS_NAME[];\r
-extern const char SHADOW_WIN_CLASS_NAME[];\r
-extern const char HISTORY_WIN_CLASS_NAME[];\r
-extern const char STRING_BUTTON[];\r
-extern const char STRING_MENU_Xx[];\r
-extern const char STRING_DIALOG_TEST[];\r
-#endif\r
-\r
-/* Buttons */\r
-#define WH_FIRST_BUTTON     500\r
+/*
+ * Help Viewer
+ *
+ * Copyright    1996 Ulrich Schmid
+ * Copyright    2002 Sylvain Petreolle <spetreolle@yahoo.fr>
+ *              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 <stdarg.h>
+
+#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
index 5869809..e1c72ff 100644 (file)
@@ -1,59 +1,59 @@
-#define MNID_FILE_OPEN          0x101\r
-#define MNID_FILE_PRINT         0x104\r
-#define MNID_FILE_SETUP         0x106\r
-#define MNID_FILE_EXIT          0x108\r
-\r
-#define MNID_EDIT_COPYDLG       0x111\r
-#define MNID_EDIT_ANNOTATE      0x112\r
-\r
-#define MNID_BKMK_DEFINE        0x121\r
-\r
-#define MNID_OPTS_HELP_DEFAULT  0x131\r
-#define MNID_OPTS_HELP_VISIBLE  0x132\r
-#define MNID_OPTS_HELP_NONVISIBLE 0x133\r
-#define MNID_OPTS_HISTORY       0x134\r
-#define MNID_OPTS_FONTS_SMALL   0x135\r
-#define MNID_OPTS_FONTS_NORMAL  0x136\r
-#define MNID_OPTS_FONTS_LARGE   0x137\r
-#define MNID_OPTS_SYSTEM_COLORS 0x138\r
-\r
-#define MNID_HELP_HELPON        0x141\r
-#define MNID_HELP_HELPTOP       0x142\r
-#define MNID_HELP_ABOUT         0x143\r
-#define MNID_HELP_WINE          0x144\r
-\r
-#define MNID_CTXT_ANNOTATE      0x200\r
-#define MNID_CTXT_COPY          0x201\r
-#define MNID_CTXT_PRINT         0x202\r
-#define MNID_CTXT_FONTS_SMALL   0x210\r
-#define MNID_CTXT_FONTS_NORMAL  0x211\r
-#define MNID_CTXT_FONTS_LARGE   0x212\r
-#define MNID_CTXT_HELP_DEFAULT  0x220\r
-#define MNID_CTXT_HELP_VISIBLE  0x221\r
-#define MNID_CTXT_HELP_NONVISIBLE 0x222\r
-#define MNID_CTXT_SYSTEM_COLORS 0x230\r
-\r
-#define MAIN_MENU              0xF000\r
-#define CONTEXT_MENU            0xF001\r
-\r
-#define STID_WINE_HELP         0x120\r
-#define STID_WHERROR           0x121\r
-#define STID_WARNING           0x122\r
-#define STID_INFO              0x123\r
-#define STID_NOT_IMPLEMENTED   0x124\r
-#define STID_HLPFILE_ERROR_s   0x125\r
-#define STID_CONTENTS          0x126\r
-#define STID_INDEX             0x127\r
-#define STID_BACK              0x128\r
-#define STID_ALL_FILES                 0x12B\r
-#define STID_HELP_FILES_HLP    0x12C\r
-#define STID_DIALOG_TEST       0x12D\r
-#define STID_FILE_NOT_FOUND_s  0x12E\r
-#define STID_NO_RICHEDIT        0x12F\r
-#define STID_PSH_INDEX          0x130\r
-\r
-#define IDD_INDEX               0x150\r
-#define IDC_INDEXLIST           0x151\r
-#define IDD_SEARCH              0x152\r
-\r
-#define IDI_WINHELP             0xF00\r
+#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