macro.lex.l 9.08 KB
Newer Older
1
%{ /* -*-C-*- */
Alexandre Julliard's avatar
Alexandre Julliard committed
2 3 4 5
/*
 * Help Viewer
 *
 * Copyright 1996 Ulrich Schmid
6
 * Copyright 2002,2008 Eric Pouech
7 8 9 10 11 12 13 14 15 16 17 18 19
 *
 * 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
20
 * Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301, USA
Alexandre Julliard's avatar
Alexandre Julliard committed
21 22
 */
%}
23
%option noinput nounput interactive 8bit
24
%x quote
Alexandre Julliard's avatar
Alexandre Julliard committed
25
%{
26
#include "config.h"
27
#include <assert.h>
28
#include <stdarg.h>
29 30 31 32 33

#ifndef HAVE_UNISTD_H
#define YY_NO_UNISTD_H
#endif

34 35 36 37 38
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winhelp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
39

40 41 42 43
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(winhelp);

44 45 46 47 48 49 50
struct lex_data {
    LPCSTR   macroptr;
    LPSTR    strptr;
    int      quote_stack[32];
    unsigned quote_stk_idx;
    LPSTR    cache_string[32];
    int      cache_used;
51
    WINHELP_WINDOW* window;
52 53 54
};
static struct lex_data* lex_data = NULL;

55
struct lexret  yylval;
Alexandre Julliard's avatar
Alexandre Julliard committed
56 57

#define YY_INPUT(buf,result,max_size)\
58
  if ((result = *lex_data->macroptr ? 1 : 0)) buf[0] = *lex_data->macroptr++;
Alexandre Julliard's avatar
Alexandre Julliard committed
59 60 61

%}
%%
62 63

[-+]?[0-9]+             yylval.integer = strtol(yytext, NULL, 10);	return INTEGER;
Alexandre Julliard's avatar
Alexandre Julliard committed
64 65
[-+]?0[xX][0-9a-f]+	yylval.integer = strtol(yytext, NULL, 16);	return INTEGER;

66 67 68 69 70 71 72 73
[a-zA-Z][_0-9a-zA-Z]*   return MACRO_Lookup(yytext, &yylval);

\`	    |
\"	    |
\'          |
<quote>\`   |
<quote>\"   |
<quote>\'   {
74 75
    if (lex_data->quote_stk_idx == 0 ||
        (yytext[0] == '\"' && lex_data->quote_stack[lex_data->quote_stk_idx - 1] != '\"') ||
76 77 78
        (yytext[0] == '`'))
    {
        /* opening a new one */
79
        if (lex_data->quote_stk_idx == 0)
80
        {
81 82 83 84
            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++;
85 86
            BEGIN(quote);
        }
87 88 89
        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]));
90 91 92 93 94
    }
    else
    {
        if (yytext[0] == '`') assert(0);
        /* close the current quote */
95
        if (--lex_data->quote_stk_idx == 0)
96 97
        {
            BEGIN INITIAL;
98
            *lex_data->strptr++ = '\0';
99 100
            return STRING;
        }
101
        else *lex_data->strptr++ = yytext[0];
102 103
    }
}
Alexandre Julliard's avatar
Alexandre Julliard committed
104

105 106
<quote>.                *lex_data->strptr++ = yytext[0];
<quote>\\.	        *lex_data->strptr++ = yytext[1];
107
<quote><<EOF>>	        return 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
108 109

" "
110
.			return yytext[0];
Alexandre Julliard's avatar
Alexandre Julliard committed
111
%%
112 113 114

#if 0
/* all code for testing macros */
Alexandre Julliard's avatar
Alexandre Julliard committed
115 116 117
#include "winhelp.h"
static CHAR szTestMacro[256];

118
static LRESULT CALLBACK MACRO_TestDialogProc(HWND hDlg, UINT msg, WPARAM wParam, LPARAM lParam)
Alexandre Julliard's avatar
Alexandre Julliard committed
119
{
120
    if (msg == WM_COMMAND && wParam == IDOK)
Alexandre Julliard's avatar
Alexandre Julliard committed
121
    {
122 123 124
        GetDlgItemText(hDlg, 99, szTestMacro, sizeof(szTestMacro));
        EndDialog(hDlg, IDOK);
        return TRUE;
Alexandre Julliard's avatar
Alexandre Julliard committed
125
    }
126
    return FALSE;
Alexandre Julliard's avatar
Alexandre Julliard committed
127 128
}

129
void macro_test(void)
Alexandre Julliard's avatar
Alexandre Julliard committed
130
{
131 132 133 134 135 136 137 138 139 140 141 142 143
    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)
Alexandre Julliard's avatar
Alexandre Julliard committed
144
    {
145 146 147 148 149 150 151
    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;
Alexandre Julliard's avatar
Alexandre Julliard committed
152
    }
153
}
Alexandre Julliard's avatar
Alexandre Julliard committed
154

155
static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret);
Alexandre Julliard's avatar
Alexandre Julliard committed
156

157 158 159 160 161 162 163 164 165
/******************************************************************
 *		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)
{
166 167
    int t;
    unsigned int len = 0, idx = 0;
Alexandre Julliard's avatar
Alexandre Julliard committed
168

169 170 171 172 173
    WINE_TRACE("Checking %s\n", args);

    if (yylex() != '(') {WINE_WARN("missing (\n");return -1;}

    if (*args)
174
    {
175
        len = strlen(args);
176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191
        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;}   
192
                pa[idx] = LongToPtr(yylval.integer);
193 194 195 196
                break;
            case 'B':
                if (t != BOOL_FUNCTION) 
                {WINE_WARN("missing B\n");return -1;}   
197
                if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0)
198 199 200 201 202 203 204 205
                    return -1;
                break;
            default: 
                WINE_WARN("unexpected %s while args is %c\n", ts(t), *args);
                return -1;
            }
            idx++;
            if (*++args == '\0') break;
206 207 208 209
            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;}
210
        }
211
    }
212
    if (yylex() != ')') {WINE_WARN("missing )\n");return -1;}
213 214 215

CheckArgs_end:
    while (len > idx) pa[--len] = NULL;
216 217 218 219 220 221 222 223 224
    return idx;
}

/******************************************************************
 *		MACRO_CallBoolFunc
 *
 * Invokes boolean function fn, which arguments are defined by args
 * stores bool result into ret
 */
225
static int MACRO_CallBoolFunc(FARPROC fn, const char* args, void** ret)
226 227 228 229
{
    void*       pa[2];
    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);

230 231
    if (idx < 0) return 0;
    if (!fn)     return 1;
232 233 234

    WINE_TRACE("calling with %u pmts\n", idx);

235
    switch (strlen(args))
236 237 238 239 240 241 242
    {
    case 0: *ret = (void*)(fn)();          break;
    case 1: *ret = (void*)(fn)(pa[0]);     break;
    default: WINE_FIXME("NIY\n");
    }

    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
243 244
}

245 246 247 248 249
/******************************************************************
 *		MACRO_CallVoidFunc
 *
 *
 */
250
static int MACRO_CallVoidFunc(FARPROC fn, const char* args)
Alexandre Julliard's avatar
Alexandre Julliard committed
251
{
252 253 254
    void*       pa[6];
    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);

255 256
    if (idx < 0) return 0;
    if (!fn)     return 1;
257

258
    WINE_TRACE("calling %p with %u pmts\n", fn, idx);
259

260
    switch (strlen(args))
261 262 263 264 265 266 267 268 269 270 271 272 273 274
    {
    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;
}

275
BOOL MACRO_ExecuteMacro(WINHELP_WINDOW* window, LPCSTR macro)
276
{
277
    struct lex_data     curr_lex_data, *prev_lex_data;
278
    BOOL ret = TRUE;
279 280 281 282
    int t;

    WINE_TRACE("%s\n", wine_dbgstr_a(macro));

283 284 285 286 287
    prev_lex_data = lex_data;
    lex_data = &curr_lex_data;

    memset(lex_data, 0, sizeof(*lex_data));
    lex_data->macroptr = macro;
288
    lex_data->window = WINHELP_GrabWindow(window);
289 290 291 292 293 294 295

    while ((t = yylex()) != EMPTY)
    {
        switch (t)
        {
        case VOID_FUNCTION:
            WINE_TRACE("got type void func(%s)\n", yylval.proto);
296
            MACRO_CallVoidFunc(yylval.function, yylval.proto);
297 298 299 300 301 302
            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));
303 304 305
            YY_FLUSH_BUFFER;
            ret = FALSE;
            goto done;
306 307 308
        }
        switch (t = yylex())
        {
309
        case EMPTY:     goto done;
310
        case ';':       break;
311
        default:        ret = FALSE; YY_FLUSH_BUFFER; goto done;
312 313 314
        }
    }

315
done:
316 317 318
    for (t = 0; t < lex_data->cache_used; t++)
        HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]);
    lex_data = prev_lex_data;
319
    WINHELP_ReleaseWindow(window);
320

321
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
322
}
Alexandre Julliard's avatar
Alexandre Julliard committed
323

324 325 326 327 328
WINHELP_WINDOW* MACRO_CurrentWindow(void)
{
    return lex_data ? lex_data->window : Globals.active_win;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
329 330 331
#ifndef yywrap
int yywrap(void) { return 1; }
#endif