macro.lex.l 9.72 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 never-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

#define YY_NO_UNISTD_H
31 32 33 34 35
#include "windef.h"
#include "winbase.h"
#include "wingdi.h"
#include "winuser.h"
#include "winhelp.h"
Alexandre Julliard's avatar
Alexandre Julliard committed
36

37 38 39 40
#include "wine/debug.h"

WINE_DEFAULT_DEBUG_CHANNEL(winhelp);

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

52
struct lexret  yylval;
Alexandre Julliard's avatar
Alexandre Julliard committed
53 54

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

%}
%%
59 60

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

63 64 65 66 67 68 69 70
[a-zA-Z][_0-9a-zA-Z]*   return MACRO_Lookup(yytext, &yylval);

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

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

" "
107
.			return yytext[0];
Alexandre Julliard's avatar
Alexandre Julliard committed
108
%%
109 110 111

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

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

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

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

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

166
    WINE_TRACE("Checking %s\n", debugstr_a(args));
167 168 169 170

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

    if (*args)
171
    {
172
        len = strlen(args);
173 174 175
        for (;;)
        {
            t = yylex();
176
            WINE_TRACE("Got %s <=> %c\n", debugstr_a(ts(t)), *args);
177 178 179 180 181 182 183 184 185 186 187 188

            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;}   
189
                pa[idx] = LongToPtr(yylval.integer);
190 191 192 193
                break;
            case 'B':
                if (t != BOOL_FUNCTION) 
                {WINE_WARN("missing B\n");return -1;}   
194
                if (MACRO_CallBoolFunc(yylval.function, yylval.proto, &pa[idx]) == 0)
195 196 197
                    return -1;
                break;
            default: 
198
                WINE_WARN("unexpected %s while args is %c\n", debugstr_a(ts(t)), *args);
199 200 201 202
                return -1;
            }
            idx++;
            if (*++args == '\0') break;
203 204 205 206
            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;}
207
        }
208
    }
209
    if (yylex() != ')') {WINE_WARN("missing )\n");return -1;}
210 211 212

CheckArgs_end:
    while (len > idx) pa[--len] = NULL;
213 214 215 216 217 218 219 220 221
    return idx;
}

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

227 228
    if (idx < 0) return 0;
    if (!fn)     return 1;
229 230 231

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

232
    switch (strlen(args))
233
    {
234 235 236 237 238 239 240 241 242 243 244 245
    case 0:
    {
        BOOL (WINAPI *func)(void) = fn;
        *ret = (void *)(ULONG_PTR)func();
        break;
    }
    case 1:
    {
        BOOL (WINAPI *func)(void *) = fn;
        *ret = (void *)(ULONG_PTR)func( pa[0]);
        break;
    }
246 247 248 249
    default: WINE_FIXME("NIY\n");
    }

    return 1;
Alexandre Julliard's avatar
Alexandre Julliard committed
250 251
}

252 253 254 255 256
/******************************************************************
 *		MACRO_CallVoidFunc
 *
 *
 */
257
static int MACRO_CallVoidFunc(void *fn, const char* args)
Alexandre Julliard's avatar
Alexandre Julliard committed
258
{
259 260 261
    void*       pa[6];
    int         idx = MACRO_CheckArgs(pa, sizeof(pa)/sizeof(pa[0]), args);

262 263
    if (idx < 0) return 0;
    if (!fn)     return 1;
264

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

267
    switch (strlen(args))
268
    {
269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310
    case 0:
    {
        void (WINAPI *func)(void) = fn;
        func();
        break;
    }
    case 1:
    {
        void (WINAPI *func)(void*) = fn;
        func( pa[0] );
        break;
    }
    case 2:
    {
        void (WINAPI *func)(void*,void*) = fn;
        func( pa[0], pa[1] );
        break;
    }
    case 3:
    {
        void (WINAPI *func)(void*,void*,void*) = fn;
        func( pa[0], pa[1], pa[2] );
        break;
    }
    case 4:
    {
        void (WINAPI *func)(void*,void*,void*,void*) = fn;
        func( pa[0], pa[1], pa[2], pa[3] );
        break;
    }
    case 5:
    {
        void (WINAPI *func)(void*,void*,void*,void*,void*) = fn;
        func( pa[0], pa[1], pa[2], pa[3], pa[4] );
        break;
    }
    case 6:
    {
        void (WINAPI *func)(void*,void*,void*,void*,void*,void*) = fn;
        func( pa[0], pa[1], pa[2], pa[3], pa[4], pa[5] );
        break;
    }
311 312 313 314 315 316
    default: WINE_FIXME("NIY\n");
    }

    return 1;
}

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 322
    int t;

323
    WINE_TRACE("%s\n", debugstr_a(macro));
324

325 326 327 328 329
    prev_lex_data = lex_data;
    lex_data = &curr_lex_data;

    memset(lex_data, 0, sizeof(*lex_data));
    lex_data->macroptr = macro;
330
    lex_data->window = WINHELP_GrabWindow(window);
331 332 333 334 335 336

    while ((t = yylex()) != EMPTY)
    {
        switch (t)
        {
        case VOID_FUNCTION:
337
            WINE_TRACE("got type void func(%s)\n", debugstr_a(yylval.proto));
338
            MACRO_CallVoidFunc(yylval.function, yylval.proto);
339 340
            break;
        case BOOL_FUNCTION:
341
            WINE_WARN("got type bool func(%s)\n", debugstr_a(yylval.proto));
342 343
            break;
        default:
344
            WINE_WARN("got unexpected type %s\n", debugstr_a(ts(t)));
345 346 347
            YY_FLUSH_BUFFER;
            ret = FALSE;
            goto done;
348 349 350
        }
        switch (t = yylex())
        {
351
        case EMPTY:     goto done;
352
        case ';':       break;
353
        default:        ret = FALSE; YY_FLUSH_BUFFER; goto done;
354 355 356
        }
    }

357
done:
358 359 360
    for (t = 0; t < lex_data->cache_used; t++)
        HeapFree(GetProcessHeap(), 0, lex_data->cache_string[t]);
    lex_data = prev_lex_data;
361
    WINHELP_ReleaseWindow(window);
362

363
    return ret;
Alexandre Julliard's avatar
Alexandre Julliard committed
364
}
Alexandre Julliard's avatar
Alexandre Julliard committed
365

366 367 368 369 370
WINHELP_WINDOW* MACRO_CurrentWindow(void)
{
    return lex_data ? lex_data->window : Globals.active_win;
}

Alexandre Julliard's avatar
Alexandre Julliard committed
371 372 373
#ifndef yywrap
int yywrap(void) { return 1; }
#endif