push e263afdf8dbf9f9408e8594e045d25c4af1d55cd
[wine/hacks.git] / programs / winhlp32 / macro.lex.l
blobf3366b02bbdb708e4a46d910bc975fd94c77706e
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  */
23 %option noinput nounput interactive 8bit
24 %x quote
26 #include "config.h"
27 #include <assert.h>
29 #ifndef HAVE_UNISTD_H
30 #define YY_NO_UNISTD_H
31 #endif
33 #include "macro.h"
35 #include "wine/debug.h"
37 WINE_DEFAULT_DEBUG_CHANNEL(winhelp);
39 struct lex_data {
40     LPCSTR   macroptr;
41     LPSTR    strptr;
42     int      quote_stack[32];
43     unsigned quote_stk_idx;
44     LPSTR    cache_string[32];
45     int      cache_used;
47 static struct lex_data* lex_data = NULL;
49 struct lexret  yylval;
51 #define YY_INPUT(buf,result,max_size)\
52   if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++;
57 [-+]?[0-9]+             yylval.integer = strtol(yytext, NULL, 10);      return INTEGER;
58 [-+]?0[xX][0-9a-f]+     yylval.integer = strtol(yytext, NULL, 16);      return INTEGER;
60 [a-zA-Z][_0-9a-zA-Z]*   return MACRO_Lookup(yytext, &yylval);
62 \`          |
63 \"          |
64 \'          |
65 <quote>\`   |
66 <quote>\"   |
67 <quote>\'   {
68     if (lex_data->quote_stk_idx == 0 ||
69         (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') ||
70         (yytext[0] == '`'))
71     {
72         /* opening a new one */
73         if (lex_data->quote_stk_idx == 0)
74         {
75             assert(lex_data->cache_used < sizeof(lex_data->cache_string) / sizeof(lex_data->cache_string[0]));
76             lex_data->strptr = lex_data->cache_string[lex_data->cache_used] = HeapAlloc(GetProcessHeap(), 0, strlen(lex_data->macroptr) + 1);
77             yylval.string = lex_data->strptr;
78             lex_data->cache_used++;
79             BEGIN(quote);
80         }
81         else *lex_data->strptr++ = yytext[0];
82         lex_data->quote_stack[lex_data->quote_stk_idx++] = yytext[0];
83         assert(lex_data->quote_stk_idx < sizeof(lex_data->quote_stack) / sizeof(lex_data->quote_stack[0]));
84     }
85     else
86     {
87         if (yytext[0] == '`') assert(0);
88         /* close the current quote */
89         if (--lex_data->quote_stk_idx == 0)
90         {
91             BEGIN INITIAL;
92             *lex_data->strptr++ = '\0';
93             return STRING;
94         }
95         else *lex_data->strptr++ = yytext[0];
96     }
99 <quote>.                *lex_data->strptr++ = yytext[0];
100 <quote>\\.              *lex_data->strptr++ = yytext[1];
101 <quote><<EOF>>          return 0;
103 " "
104 .                       return yytext[0];
107 #if 0
108 /* all code for testing macros */
109 #include "winhelp.h"
110 static CHAR szTestMacro[256];
112 static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
114     if (msg == WM_COMMAND && wParam == IDOK)
115     {
116         GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro));
117         EndDialog(hDlg, IDOK);
118         return TRUE;
119     }
120     return FALSE;
123 void macro_test(void)
125     WNDPROC lpfnDlg = MakeProcInstance(MACRO_TestDialogProc, Globals.hInstance);
126     DialogBox(Globals.hInstance, STRING_DIALOG_TEST, Globals.active_win->hMainWnd, (DLGPROC)lpfnDlg);
127     FreeProcInstance(lpfnDlg);
128     macro = szTestMacro;
130 #endif
132 /* small helper function for debug messages */
133 static const char* ts(int t)
135     static char c[2] = {0,0};
137     switch (t)
138     {
139     case EMPTY: return "EMPTY";
140     case VOID_FUNCTION: return "VOID_FUNCTION";
141     case BOOL_FUNCTION: return "BOOL_FUNCTION";
142     case INTEGER: return "INTEGER";
143     case STRING: return "STRING";
144     case IDENTIFIER: return "IDENTIFIER";
145     default: c[0] = (char)t; return c;
146     }
149 static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret);
151 /******************************************************************
152  *              MACRO_CheckArgs
154  * checks number of arguments against prototype, and stores arguments on
155  * stack pa for later call
156  * returns -1 on error, otherwise the number of pushed parameters
157  */
158 static int MACRO_CheckArgs(void* pa[], unsigned max, const char* args)
160     int t;
161     unsigned int len = 0, idx = 0;
163     WINE_TRACE("Checking %s\n", args);
165     if (yylex() != '(') {WINE_WARN("missing (\n");return -1;}
167     if (*args)
168     {
169         len = strlen(args);
170         for (;;)
171         {
172             t = yylex();
173             WINE_TRACE("Got %s <=> %c\n", ts(t), *args);
175             switch (*args)
176             {
177             case 'S': 
178                 if (t != STRING)
179                 {WINE_WARN("missing S\n");return -1;}
180                 pa[idx] = (void*)yylval.string;  
181                 break;
182             case 'U':
183             case 'I':
184                 if (t != INTEGER)
185                 {WINE_WARN("missing U\n");return -1;}   
186                 pa[idx] = LongToPtr(yylval.integer);
187                 break;
188             case 'B':
189                 if (t != BOOL_FUNCTION) 
190                 {WINE_WARN("missing B\n");return -1;}   
191                 if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0)
192                     return -1;
193                 break;
194             default: 
195                 WINE_WARN("unexpected %s while args is %c\n", ts(t), *args);
196                 return -1;
197             }
198             idx++;
199             if (*++args == '\0') break;
200             t = yylex();
201             if (t == ')') goto CheckArgs_end;
202             if (t != ',') {WINE_WARN("missing ,\n");return -1;}
203             if (idx >= max) {WINE_FIXME("stack overflow (%d)\n", max);return -1;}
204         }
205     }
206     if (yylex() != ')') {WINE_WARN("missing )\n");return -1;}
208 CheckArgs_end:
209     while (len > idx) pa[--len] = NULL;
210     return idx;
213 /******************************************************************
214  *              MACRO_CallBoolFunc
216  * Invokes boolean function fn, which arguments are defined by args
217  * stores bool result into ret
218  */
219 static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret)
221     void*       pa[2];
222     int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);
224     if (idx < 0) return 0;
225     if (!fn)     return 1;
227     WINE_TRACE("calling with %u pmts\n", idx);
229     switch (strlen(args))
230     {
231     case 0: *ret = (void*)(fn)();          break;
232     case 1: *ret = (void*)(fn)(pa[0]);     break;
233     default: WINE_FIXME("NIY\n");
234     }
236     return 1;
239 /******************************************************************
240  *              MACRO_CallVoidFunc
243  */
244 static int MACRO_CallVoidFunc(FARPROC fn, const char* args)
246     void*       pa[6];
247     int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);
249     if (idx < 0) return 0;
250     if (!fn)     return 1;
252     WINE_TRACE("calling %p with %u pmts\n", fn, idx);
254     switch (strlen(args))
255     {
256     case 0: (fn)();                                     break;
257     case 1: (fn)(pa[0]);                                break;
258     case 2: (fn)(pa[0],pa[1]);                          break;
259     case 3: (fn)(pa[0],pa[1],pa[2]);                    break;
260     case 4: (fn)(pa[0],pa[1],pa[2],pa[3]);              break;
261     case 5: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4]);        break;
262     case 6: (fn)(pa[0],pa[1],pa[2],pa[3],pa[4],pa[5]);  break;
263     default: WINE_FIXME("NIY\n");
264     }
266     return 1;
269 BOOL MACRO_ExecuteMacro(LPCSTR macro)
271     struct lex_data     curr_lex_data, *prev_lex_data;
272     BOOL ret = TRUE;
273     int t;
275     WINE_TRACE("%s\n", wine_dbgstr_a(macro));
277     prev_lex_data = lex_data;
278     lex_data = &curr_lex_data;
280     memset(lex_data, 0, sizeof(*lex_data));
281     lex_data->macroptr = macro;
283     while ((t = yylex()) != EMPTY)
284     {
285         switch (t)
286         {
287         case VOID_FUNCTION:
288             WINE_TRACE("got type void func(%s)\n", yylval.proto);
289             MACRO_CallVoidFunc(yylval.function, yylval.proto);
290             break;
291         case BOOL_FUNCTION:
292             WINE_WARN("got type bool func(%s)\n", yylval.proto);
293             break;
294         default:
295             WINE_WARN("got unexpected type %s\n", ts(t));
296             return 0;
297         }
298         switch (t = yylex())
299         {
300         case EMPTY:     goto done;
301         case ';':       break;
302         default:        ret = FALSE; goto done;
303         }
304     }
306 done:
307     for (t = 0; t < lex_data->cache_used; t++)
308         HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]);
309     lex_data = prev_lex_data;
311     return ret;
314 #ifndef yywrap
315 int yywrap(void) { return 1; }
316 #endif