-/*\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
+};
-/*\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;
+}
-/*\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);
-/* 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
-/*\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;
+}
-/*\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: */
-%{ /* -*-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
-/*\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: */
-/*\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;
+}
-/*\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
-#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