1 %{ /* -*-C-*- */ 2 /* 3 * Help Viewer 4 * 5 * Copyright 1996 Ulrich Schmid 6 * Copyright 2002,2008 Eric Pouech 7 * 8 * This library is free software; you can redistribute it and/or 9 * modify it under the terms of the GNU Lesser General Public 10 * License as published by the Free Software Foundation; either 11 * version 2.1 of the License, or (at your option) any later version. 12 * 13 * This library is distributed in the hope that it will be useful, 14 * but WITHOUT ANY WARRANTY; without even the implied warranty of 15 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU 16 * Lesser General Public License for more details. 17 * 18 * You should have received a copy of the GNU Lesser General Public 19 * License along with this library; if not, write to the Free Software 20 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA 21 */ 22 %} 23 %option noinput nounput never-interactive 8bit 24 %x quote 25 %{ 26 #include "config.h" 27 #include <assert.h> 28 #include <stdarg.h> 29 30 #define YY_NO_UNISTD_H 31 #include "windef.h" 32 #include "winbase.h" 33 #include "wingdi.h" 34 #include "winuser.h" 35 #include "winhelp.h" 36 37 #include "wine/debug.h" 38 39 WINE_DEFAULT_DEBUG_CHANNEL(winhelp); 40 41 struct lex_data { 42 LPCSTR macroptr; 43 LPSTR strptr; 44 int quote_stack[32]; 45 unsigned quote_stk_idx; 46 LPSTR cache_string[32]; 47 int cache_used; 48 WINHELP_WINDOW* window; 49 }; 50 static struct lex_data* lex_data = NULL; 51 52 struct lexret yylval; 53 54 #define YY_INPUT(buf,result,max_size)\ 55 if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++; 56 57 %} 58 %% 59 60 [-+]?[0-9]+ yylval.integer = strtol(yytext, NULL, 10); return INTEGER; 61 [-+]?0[xX][0-9a-f]+ yylval.integer = strtol(yytext, NULL, 16); return INTEGER; 62 63 [a-zA-Z][_0-9a-zA-Z]* return MACRO_Lookup(yytext, &yylval); 64 65 \` | 66 \" | 67 \' | 68 <quote>\` | 69 <quote>\" | 70 <quote>\' { 71 if (lex_data->quote_stk_idx == 0 || 72 (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') || 73 (yytext[0] == '`')) 74 { 75 /* opening a new one */ 76 if (lex_data->quote_stk_idx == 0) 77 { 78 assert(lex_data->cache_used < ARRAY_SIZE(lex_data->cache_string)); 79 lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1); 80 yylval.string = lex_data->strptr; 81 lex_data->cache_used++; 82 BEGIN(quote); 83 } 84 else *lex_data->strptr++ = yytext[0]; 85 lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0]; 86 assert(lex_data->quote_stk_idx < ARRAY_SIZE(lex_data->quote_stack)); 87 } 88 else 89 { 90 if (yytext[0] == '`') assert(0); 91 /* close the current quote */ 92 if (--lex_data->quote_stk_idx == 0) 93 { 94 BEGIN INITIAL; 95 *lex_data->strptr++ = '\0'; 96 return STRING; 97 } 98 else *lex_data->strptr++ = yytext[0]; 99 } 100 } 101 102 <quote>. *lex_data->strptr++ = yytext[0]; 103 <quote>\\. *lex_data->strptr++ = yytext[1]; 104 <quote><<EOF>> return 0; 105 106 " " 107 . return yytext[0]; 108 %% 109 110 #if 0 111 /* all code for testing macros */ 112 #include "winhelp.h" 113 static CHAR szTestMacro[256]; 114 115 static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam) 116 { 117 if (msg == WM_COMMAND && wParam == IDOK) 118 { 119 GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro)); 120 EndDialog(hDlg, IDOK); 121 return TRUE; 122 } 123 return FALSE; 124 } 125 126 void macro_test(void) 127 { 128 WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance); 129 DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg); 130 FreeProcInstance(lpfnDlg); 131 macro = szTestMacro; 132 } 133 #endif 134 135 /* small helper function for debug messages */ 136 static const char* ts(int t) 137 { 138 static char c[2] = {0,0}; 139 140 switch (t) 141 { 142 case EMPTY: return "EMPTY"; 143 case VOID_FUNCTION: return "VOID_FUNCTION"; 144 case BOOL_FUNCTION: return "BOOL_FUNCTION"; 145 case INTEGER: return "INTEGER"; 146 case STRING: return "STRING"; 147 case IDENTIFIER: return "IDENTIFIER"; 148 default: c[0] = (char)t; return c; 149 } 150 } 151 152 static int MACRO_CallBoolFunc(void *fn, const char* args, void** ret); 153 154 /****************************************************************** 155 * MACRO_CheckArgs 156 * 157 * checks number of arguments against prototype, and stores arguments on 158 * stack pa for later call 159 * returns -1 on error, otherwise the number of pushed parameters 160 */ 161 static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args) 162 { 163 int t; 164 unsigned int len = 0, idx = 0; 165 166 WINE_TRACE("Checking %s\n", debugstr_a(args)); 167 168 if (yylex() != '(') {WINE_WARN("missing (\n");return -1;} 169 170 if (*args) 171 { 172 len = strlen(args); 173 for (;;) 174 { 175 t = yylex(); 176 WINE_TRACE("Got %s <=> %c\n", debugstr_a(ts(t)), *args); 177 178 switch (*args) 179 { 180 case 'S': 181 if (t != STRING) 182 {WINE_WARN("missing S\n");return -1;} 183 pa[idx] = (void*)yylval.string; 184 break; 185 case 'U': 186 case 'I': 187 if (t != INTEGER) 188 {WINE_WARN("missing U\n");return -1;} 189 pa[idx] = LongToPtr(yylval.integer); 190 break; 191 case 'B': 192 if (t != BOOL_FUNCTION) 193 {WINE_WARN("missing B\n");return -1;} 194 if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0) 195 return -1; 196 break; 197 default: 198 WINE_WARN("unexpected %s while args is %c\n", debugstr_a(ts(t)), *args); 199 return -1; 200 } 201 idx++; 202 if (*++args == '\0') break; 203 t = yylex(); 204 if (t == ')') goto CheckArgs_end; 205 if (t != ',') {WINE_WARN("missing ,\n");return -1;} 206 if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;} 207 } 208 } 209 if (yylex() != ')') {WINE_WARN("missing )\n");return -1;} 210 211 CheckArgs_end: 212 while (len > idx) pa[--len] = NULL; 213 return idx; 214 } 215 216 /****************************************************************** 217 * MACRO_CallBoolFunc 218 * 219 * Invokes boolean function fn, which arguments are defined by args 220 * stores bool result into ret 221 */ 222 static int MACRO_CallBoolFunc(void *fn, const char* args, void** ret) 223 { 224 void* pa[2]; 225 int idx = MACRO_CheckArgs(pa, ARRAY_SIZE(pa), args); 226 227 if (idx < 0) return 0; 228 if (!fn) return 1; 229 230 WINE_TRACE("calling with %u pmts\n", idx); 231 232 switch (strlen(args)) 233 { 234 case 0: 235 { 236 BOOL (WINAPI *func)(void) = fn; 237 *ret = (void *)(ULONG_PTR)func(); 238 break; 239 } 240 case 1: 241 { 242 BOOL (WINAPI *func)(void *) = fn; 243 *ret = (void *)(ULONG_PTR)func( pa[0]); 244 break; 245 } 246 default: WINE_FIXME("NIY\n"); 247 } 248 249 return 1; 250 } 251 252 /****************************************************************** 253 * MACRO_CallVoidFunc 254 * 255 * 256 */ 257 static int MACRO_CallVoidFunc(void *fn, const char* args) 258 { 259 void* pa[6]; 260 int idx = MACRO_CheckArgs(pa, ARRAY_SIZE(pa), args); 261 262 if (idx < 0) return 0; 263 if (!fn) return 1; 264 265 WINE_TRACE("calling %p with %u pmts\n", fn, idx); 266 267 switch (strlen(args)) 268 { 269 case 0: 270 { 271 void (WINAPI *func)(void) = fn; 272 func(); 273 break; 274 } 275 case 1: 276 { 277 void (WINAPI *func)(void*) = fn; 278 func( pa[0] ); 279 break; 280 } 281 case 2: 282 { 283 void (WINAPI *func)(void*,void*) = fn; 284 func( pa[0], pa[1] ); 285 break; 286 } 287 case 3: 288 { 289 void (WINAPI *func)(void*,void*,void*) = fn; 290 func( pa[0], pa[1], pa[2] ); 291 break; 292 } 293 case 4: 294 { 295 void (WINAPI *func)(void*,void*,void*,void*) = fn; 296 func( pa[0], pa[1], pa[2], pa[3] ); 297 break; 298 } 299 case 5: 300 { 301 void (WINAPI *func)(void*,void*,void*,void*,void*) = fn; 302 func( pa[0], pa[1], pa[2], pa[3], pa[4] ); 303 break; 304 } 305 case 6: 306 { 307 void (WINAPI *func)(void*,void*,void*,void*,void*,void*) = fn; 308 func( pa[0], pa[1], pa[2], pa[3], pa[4], pa[5] ); 309 break; 310 } 311 default: WINE_FIXME("NIY\n"); 312 } 313 314 return 1; 315 } 316 317 BOOL MACRO_ExecuteMacro(WINHELP_WINDOW* window, LPCSTR macro) 318 { 319 struct lex_data curr_lex_data, *prev_lex_data; 320 BOOL ret = TRUE; 321 int t; 322 323 WINE_TRACE("%s\n", debugstr_a(macro)); 324 325 prev_lex_data = lex_data; 326 lex_data = &curr_lex_data; 327 328 memset(lex_data, 0, sizeof(*lex_data)); 329 lex_data->macroptr = macro; 330 lex_data->window = WINHELP_GrabWindow(window); 331 332 while ((t = yylex()) != EMPTY) 333 { 334 switch (t) 335 { 336 case VOID_FUNCTION: 337 WINE_TRACE("got type void func(%s)\n", debugstr_a(yylval.proto)); 338 MACRO_CallVoidFunc(yylval.function, yylval.proto); 339 break; 340 case BOOL_FUNCTION: 341 WINE_WARN("got type bool func(%s)\n", debugstr_a(yylval.proto)); 342 break; 343 default: 344 WINE_WARN("got unexpected type %s\n", debugstr_a(ts(t))); 345 YY_FLUSH_BUFFER; 346 ret = FALSE; 347 goto done; 348 } 349 switch (t = yylex()) 350 { 351 case EMPTY: goto done; 352 case ';': break; 353 default: ret = FALSE; YY_FLUSH_BUFFER; goto done; 354 } 355 } 356 357 done: 358 for (t = 0; t < lex_data->cache_used; t++) 359 HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]); 360 lex_data = prev_lex_data; 361 WINHELP_ReleaseWindow(window); 362 363 return ret; 364 } 365 366 WINHELP_WINDOW* MACRO_CurrentWindow(void) 367 { 368 return lex_data ? lex_data->window : Globals.active_win; 369 } 370 371 #ifndef yywrap 372 int yywrap(void) { return 1; } 373 #endif 374